From 3919d10517b482f34fb3a56b6fc03345c84d3469 Mon Sep 17 00:00:00 2001 From: Kevin Fodness <2650828+kevinfodness@users.noreply.github.com> Date: Fri, 6 Oct 2023 07:44:40 -0400 Subject: [PATCH 1/6] Add generic Term aggregation --- lib/adapters/class-adapter.php | 11 ++++ lib/aggregations/class-post-meta.php | 43 ++++++++++++++ lib/aggregations/class-post-type.php | 33 ++--------- lib/aggregations/class-taxonomy.php | 60 ++----------------- lib/aggregations/class-term.php | 89 ++++++++++++++++++++++++++++ lib/class-controller.php | 14 +++++ 6 files changed, 166 insertions(+), 84 deletions(-) create mode 100644 lib/aggregations/class-post-meta.php create mode 100644 lib/aggregations/class-term.php diff --git a/lib/adapters/class-adapter.php b/lib/adapters/class-adapter.php index 8a4391a..a226161 100644 --- a/lib/adapters/class-adapter.php +++ b/lib/adapters/class-adapter.php @@ -11,6 +11,7 @@ use Elasticsearch_Extensions\Aggregations\CAP_Author; use Elasticsearch_Extensions\Aggregations\Custom_Date_Range; use Elasticsearch_Extensions\Aggregations\Post_Date; +use Elasticsearch_Extensions\Aggregations\Post_Meta; use Elasticsearch_Extensions\Aggregations\Post_Type; use Elasticsearch_Extensions\Aggregations\Relative_Date; use Elasticsearch_Extensions\Aggregations\Taxonomy; @@ -132,6 +133,16 @@ public function add_post_date_aggregation( array $args = [] ): void { $this->add_aggregation( new Post_Date( $this->dsl, $args ) ); } + /** + * Adds a new post meta aggregation to the list of active aggregations. + * + * @param string $meta_key The meta key to aggregate on. + * @param array $args Optional. Additional arguments to pass to the aggregation. + */ + public function add_post_meta_aggregation( string $meta_key, array $args = [] ): void { + $this->add_aggregation( new Post_Meta( $this->dsl, wp_parse_args( $args, [ 'meta_key' => $meta_key ] ) ) ); + } + /** * Adds a new post type aggregation to the list of active aggregations. * diff --git a/lib/aggregations/class-post-meta.php b/lib/aggregations/class-post-meta.php new file mode 100644 index 0000000..0ed3627 --- /dev/null +++ b/lib/aggregations/class-post-meta.php @@ -0,0 +1,43 @@ +label = ucwords( str_replace( [ '-', '_' ], ' ', $args['meta_key'] ) ); + $this->meta_key = $args['meta_key']; + $this->query_var = 'post_meta_' . $args['meta_key']; + $this->term_field = $dsl->map_meta_field( $args['meta_key'] ); + unset( $args['meta_key'] ); + } + + parent::__construct( $dsl, $args ); + } +} diff --git a/lib/aggregations/class-post-type.php b/lib/aggregations/class-post-type.php index 3cc8152..cb2780c 100644 --- a/lib/aggregations/class-post-type.php +++ b/lib/aggregations/class-post-type.php @@ -14,7 +14,7 @@ * for aggregations as well as holding the result of the aggregation after a * response was received. */ -class Post_Type extends Aggregation { +class Post_Type extends Term { /** * Configure the Post Type aggregation. @@ -23,23 +23,12 @@ class Post_Type extends Aggregation { * @param array $args Optional. Additional arguments to pass to the aggregation. */ public function __construct( DSL $dsl, array $args ) { - $this->label = __( 'Content Type', 'elasticsearch-extensions' ); - $this->query_var = 'post_type'; + $this->label = __( 'Content Type', 'elasticsearch-extensions' ); + $this->query_var = 'post_type'; + $this->term_field = $dsl->map_field( 'post_type' ); parent::__construct( $dsl, $args ); } - /** - * Gets an array of DSL representing each filter for this aggregation that - * should be applied in the query in order to match the requested values. - * - * @return array Array of DSL fragments to apply. - */ - public function filter(): array { - return ! empty( $this->query_values ) - ? [ $this->dsl->terms( 'post_type', $this->query_values ) ] - : []; - } - /** * Given a raw array of Elasticsearch aggregation buckets, parses it into * Bucket objects and saves them in this object. @@ -67,18 +56,4 @@ public function parse_buckets( array $buckets ): void { } $this->set_buckets( $bucket_objects ); } - - /** - * Get DSL for the aggregation to add to the Elasticsearch request object. - * Instructs Elasticsearch to return buckets for this aggregation in the - * response. - * - * @return array DSL fragment. - */ - public function request(): array { - return $this->dsl->aggregate_terms( - $this->query_var, - $this->dsl->map_field( 'post_type' ) - ); - } } diff --git a/lib/aggregations/class-taxonomy.php b/lib/aggregations/class-taxonomy.php index 4091674..47b55e0 100644 --- a/lib/aggregations/class-taxonomy.php +++ b/lib/aggregations/class-taxonomy.php @@ -15,19 +15,7 @@ * for aggregations as well as holding the result of the aggregation after a * response was received. */ -class Taxonomy extends Aggregation { - - /** - * The logical relationship between each selected term when there is more - * than one. If set to AND, all specified terms must be present on a single - * post in order for it to be included in the results. If set to OR, only - * one of the specified terms needs to be present on a single post in order - * for it to be included in the results. Defaults to AND so that selecting - * additional terms makes the result set smaller, not larger. - * - * @var string - */ - protected string $relation = 'AND'; +class Taxonomy extends Term { /** * A reference to the taxonomy this aggregation is associated with. @@ -46,9 +34,10 @@ public function __construct( DSL $dsl, array $args ) { // Try to get a taxonomy object based on the provided taxonomy slug. $taxonomy = get_taxonomy( $args['taxonomy'] ?? null ); if ( ! empty( $taxonomy ) ) { - $this->taxonomy = $taxonomy; - $this->label = $taxonomy->labels->singular_name; - $this->query_var = 'taxonomy_' . $taxonomy->name; + $this->taxonomy = $taxonomy; + $this->label = $taxonomy->labels->singular_name; + $this->query_var = 'taxonomy_' . $taxonomy->name; + $this->term_field = $dsl->map_tax_field( $this->taxonomy->name, $this->get_term_field() ); } // Remove the taxonomy slug from arguments before passing them to the constructor so we don't overwrite $this->taxonomy. @@ -59,31 +48,6 @@ public function __construct( DSL $dsl, array $args ) { parent::__construct( $dsl, $args ); } - /** - * Gets an array of DSL representing each filter for this aggregation that - * should be applied in the query in order to match the requested values. - * - * @return array Array of DSL fragments to apply. - */ - public function filter(): array { - if ( empty( $this->query_values ) ) { - return []; - } - - // Fork for AND vs. OR logic. - $filters = []; - $field = $this->dsl->map_tax_field( $this->taxonomy->name, $this->get_term_field() ); - if ( 'OR' === $this->relation ) { - $filters[] = $this->dsl->terms( $field, $this->query_values ); - } else { - foreach ( $this->query_values as $query_value ) { - $filters[] = $this->dsl->terms( $field, $query_value ); - } - } - - return $filters; - } - /** * Gets the WP Taxonomy Object for this aggregation. * @@ -131,18 +95,4 @@ public function parse_buckets( array $buckets ): void { } $this->set_buckets( $bucket_objects ); } - - /** - * Get DSL for the aggregation to add to the Elasticsearch request object. - * Instructs Elasticsearch to return buckets for this aggregation in the - * response. - * - * @return array DSL fragment. - */ - public function request(): array { - return $this->dsl->aggregate_terms( - $this->query_var, - $this->dsl->map_tax_field( $this->taxonomy->name, $this->get_term_field() ) - ); - } } diff --git a/lib/aggregations/class-term.php b/lib/aggregations/class-term.php new file mode 100644 index 0000000..0f999dd --- /dev/null +++ b/lib/aggregations/class-term.php @@ -0,0 +1,89 @@ +query_values ) ) { + return []; + } + + // Fork for AND vs. OR logic. + $filters = []; + if ( 'OR' === $this->relation ) { + $filters[] = $this->dsl->terms( $this->term_field, $this->query_values ); + } else { + foreach ( $this->query_values as $query_value ) { + $filters[] = $this->dsl->terms( $this->term_field, $query_value ); + } + } + + return $filters; + } + + /** + * Given a raw array of Elasticsearch aggregation buckets, parses it into + * Bucket objects and saves them in this object. + * + * @param array $buckets The raw aggregation buckets from Elasticsearch. + */ + public function parse_buckets( array $buckets ): void { + $bucket_objects = []; + foreach ( $buckets as $bucket ) { + $bucket_objects[] = new Bucket( + $bucket['key'], + $bucket['doc_count'], + $bucket['key'], + $this->is_selected( $bucket['key'] ), + ); + } + $this->set_buckets( $bucket_objects ); + } + + /** + * Get DSL for the aggregation to add to the Elasticsearch request object. + * Instructs Elasticsearch to return buckets for this aggregation in the + * response. + * + * @return array DSL fragment. + */ + public function request(): array { + return $this->dsl->aggregate_terms( $this->query_var, $this->term_field ); + } +} diff --git a/lib/class-controller.php b/lib/class-controller.php index 9a7df83..1cc50d9 100644 --- a/lib/class-controller.php +++ b/lib/class-controller.php @@ -104,6 +104,20 @@ public function enable_post_date_aggregation( array $args = [] ): Controller { return $this; } + /** + * Enables an aggregation based on post meta. + * + * @param string $meta_key The meta key to aggregate on. + * @param array $args Arguments to pass to the adapter's aggregation configuration. + * + * @return Controller The instance of the class to allow for chaining. + */ + public function enable_post_meta_aggregation( string $meta_key, array $args = [] ): Controller { + $this->adapter->add_post_meta_aggregation( $meta_key, $args ); + + return $this; + } + /** * Enables an aggregation based on post type. * From ea0fa1f78a1d9271b1fef112e0e28c580d7f787a Mon Sep 17 00:00:00 2001 From: Kevin Fodness <2650828+kevinfodness@users.noreply.github.com> Date: Fri, 6 Oct 2023 09:09:39 -0400 Subject: [PATCH 2/6] Add ability to register a generic term aggregation --- lib/adapters/class-adapter.php | 23 +++++++++++++++++++++++ lib/class-controller.php | 18 ++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/lib/adapters/class-adapter.php b/lib/adapters/class-adapter.php index a226161..6742f5b 100644 --- a/lib/adapters/class-adapter.php +++ b/lib/adapters/class-adapter.php @@ -15,6 +15,7 @@ use Elasticsearch_Extensions\Aggregations\Post_Type; use Elasticsearch_Extensions\Aggregations\Relative_Date; use Elasticsearch_Extensions\Aggregations\Taxonomy; +use Elasticsearch_Extensions\Aggregations\Term; use Elasticsearch_Extensions\DSL; use Elasticsearch_Extensions\Interfaces\Hookable; @@ -171,6 +172,28 @@ public function add_taxonomy_aggregation( string $taxonomy, array $args = [] ): $this->add_aggregation( new Taxonomy( $this->dsl, wp_parse_args( $args, [ 'taxonomy' => $taxonomy ] ) ) ); } + /** + * Adds a new generic term aggregation to the list of active aggregations. + * + * @param string $term_field The term field to aggregate on. + * @param string $query_var The query var to use for this aggregation for filters on the front-end. + * @param array $args Arguments to pass to the adapter's aggregation configuration. + */ + public function add_term_aggregation( string $term_field, string $query_var, array $args = [] ): void { + $this->add_aggregation( + new Term( + $this->dsl, + wp_parse_args( + $args, + [ + 'query_var' => $query_var, + 'term_field' => $this->dsl->map_field( $term_field ), + ] + ) + ) + ); + } + /** * Get an aggregation by its label. * diff --git a/lib/class-controller.php b/lib/class-controller.php index 1cc50d9..cdddc8e 100644 --- a/lib/class-controller.php +++ b/lib/class-controller.php @@ -189,6 +189,24 @@ public function enable_taxonomy_aggregation( string $taxonomy, array $args = [] return $this; } + /** + * A function to enable a generic Elasticsearch 'term' aggregation. Users must provide an + * Elasticsearch term field to aggregate on and a query var to use. This function should only + * be used if a more specific term-type aggregation (e.g., taxonomy, post type) is not + * available for the kind of aggregation you want to create. + * + * @param string $term_field The term field to aggregate on. + * @param string $query_var The query var to use for this aggregation for filters on the front-end. + * @param array $args Arguments to pass to the adapter's aggregation configuration. + * + * @return Controller The instance of the class to allow for chaining. + */ + public function enable_term_aggregation( string $term_field, string $query_var, array $args = [] ): Controller { + $this->adapter->add_term_aggregation( $term_field, $query_var, $args ); + + return $this; + } + /** * Get a specific aggregation from the adapter by its label. * From a58f909414378cd46eeace2f3c508d8800859b3d Mon Sep 17 00:00:00 2001 From: Kevin Fodness <2650828+kevinfodness@users.noreply.github.com> Date: Fri, 6 Oct 2023 10:19:20 -0400 Subject: [PATCH 3/6] Apply suggestions from code review Co-authored-by: Matthew Boynes --- lib/aggregations/class-post-meta.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aggregations/class-post-meta.php b/lib/aggregations/class-post-meta.php index 0ed3627..50dd519 100644 --- a/lib/aggregations/class-post-meta.php +++ b/lib/aggregations/class-post-meta.php @@ -34,7 +34,7 @@ public function __construct( DSL $dsl, array $args ) { $this->label = ucwords( str_replace( [ '-', '_' ], ' ', $args['meta_key'] ) ); $this->meta_key = $args['meta_key']; $this->query_var = 'post_meta_' . $args['meta_key']; - $this->term_field = $dsl->map_meta_field( $args['meta_key'] ); + $this->term_field = $dsl->map_meta_field( $args['meta_key'], $args['data_type'] ?? '' ); unset( $args['meta_key'] ); } From a8ad346ea4ef2814c8970b8d381569743880bcc3 Mon Sep 17 00:00:00 2001 From: Kevin Fodness <2650828+kevinfodness@users.noreply.github.com> Date: Sat, 7 Oct 2023 10:22:14 -0400 Subject: [PATCH 4/6] Add more robust parameter and return type documentation to the controller --- lib/adapters/class-adapter.php | 4 +- lib/class-controller.php | 134 ++++++++++++++++++++++++++++----- 2 files changed, 120 insertions(+), 18 deletions(-) diff --git a/lib/adapters/class-adapter.php b/lib/adapters/class-adapter.php index 6742f5b..f932447 100644 --- a/lib/adapters/class-adapter.php +++ b/lib/adapters/class-adapter.php @@ -175,17 +175,19 @@ public function add_taxonomy_aggregation( string $taxonomy, array $args = [] ): /** * Adds a new generic term aggregation to the list of active aggregations. * + * @param string $label The human-readable label for this aggregation. * @param string $term_field The term field to aggregate on. * @param string $query_var The query var to use for this aggregation for filters on the front-end. * @param array $args Arguments to pass to the adapter's aggregation configuration. */ - public function add_term_aggregation( string $term_field, string $query_var, array $args = [] ): void { + public function add_term_aggregation( string $label, string $term_field, string $query_var, array $args = [] ): void { $this->add_aggregation( new Term( $this->dsl, wp_parse_args( $args, [ + 'label' => $label, 'query_var' => $query_var, 'term_field' => $this->dsl->map_field( $term_field ), ] diff --git a/lib/class-controller.php b/lib/class-controller.php index cdddc8e..7def5ae 100644 --- a/lib/class-controller.php +++ b/lib/class-controller.php @@ -57,7 +57,21 @@ public function disable_empty_search(): Controller { /** * Enables an aggregation for Co-Authors Plus authors. * - * @param array $args Arguments to pass to the adapter's aggregation configuration. + * @param array{label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'display_name'|'first_name'|'key'|'label'|'last_name', query_var?: string, relation?: 'AND'|'OR', term_field?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $label Optional. The human-readable name for this aggregation. Defaults to 'Author'. + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'display_name', + * 'first_name', 'key', 'label', 'last_name'. Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'taxonomy_author'. + * @type string $relation Optional. The logical relationship between each selected author when there is more + * than one. Valid options are 'AND', 'OR'. Defaults to 'AND'. + * @type string $term_field Optional. The term field to use in the DSL for this aggregation. Defaults to the + * value of the taxonomy name for the 'author' taxonomy, as looked up in the DSL map. + * } * * @return Controller The instance of the class to allow for chaining. */ @@ -70,8 +84,14 @@ public function enable_cap_author_aggregation( array $args = [] ): Controller { /** * Enables a custom date range aggregation. * - * @param array $args Arguments to pass to the adapter's aggregation configuration. + * @param array{label?: string, query_var?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. * + * @type string $label Optional. The human-readable name for this aggregation. Defaults to 'Custom Date + * Range'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'custom_date_range'. + * } * @return Controller The instance of the class to allow for chaining. */ public function enable_custom_date_range_aggregation( array $args = [] ): Controller { @@ -94,7 +114,19 @@ public function enable_empty_search(): Controller { /** * Enables an aggregation based on post dates. * - * @param array $args Arguments to pass to the adapter's aggregation configuration. + * @param array{interval?: 'year'|'quarter'|'month'|'week'|'day'|'hour'|'minute', label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', query_var?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $interval Optional. The unit of time to aggregate results by. Valid options are 'year', + * 'quarter', 'month', 'week', 'day', 'hour', 'minute'. Defaults to 'year'. + * @type string $label Optional. The human-readable name for this aggregation. Defaults to 'Date'. + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'post_date'. + * } * * @return Controller The instance of the class to allow for chaining. */ @@ -108,7 +140,24 @@ public function enable_post_date_aggregation( array $args = [] ): Controller { * Enables an aggregation based on post meta. * * @param string $meta_key The meta key to aggregate on. - * @param array $args Arguments to pass to the adapter's aggregation configuration. + * @param array{data_type?: string, label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', query_var?: string, relation?: 'AND'|'OR', term_field?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $data_type Optional. The data type of the meta key, if the meta key is indexed using multiple + * data types (e.g., 'long'). Defaults to empty and uses the "raw" postmeta value. + * @type string $label Optional. The human-readable name for this aggregation. Defaults to a halfhearted + * attempt at turning the meta key into a title case string. + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'post_meta_%s' where %s is the meta key. + * @type string $relation Optional. The logical relationship between each selected meta value when there is + * more than one. Valid options are 'AND', 'OR'. Defaults to 'AND'. + * @type string $term_field Optional. The term field to use in the DSL for this aggregation. Defaults to the + * value of the post meta key, as looked up in the DSL map. + * } * * @return Controller The instance of the class to allow for chaining. */ @@ -121,7 +170,21 @@ public function enable_post_meta_aggregation( string $meta_key, array $args = [] /** * Enables an aggregation based on post type. * - * @param array $args Arguments to pass to the adapter's aggregation configuration. + * @param array{label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', query_var?: string, relation?: 'AND'|'OR', term_field?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $label Optional. The human-readable name for this aggregation. Defaults to 'Content Type'. + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'post_type'. + * @type string $relation Optional. The logical relationship between each selected author when there is more + * than one. Valid options are 'AND', 'OR'. Defaults to 'AND'. + * @type string $term_field Optional. The term field to use in the DSL for this aggregation. Defaults to the + * 'post_type' field, as looked up in the DSL map. + * } * * @return Controller The instance of the class to allow for chaining. */ @@ -134,7 +197,19 @@ public function enable_post_type_aggregation( array $args = [] ): Controller { /** * Enables an aggregation based on relative dates. * - * @param array $args Arguments to pass to the adapter's aggregation configuration. + * @param array{intervals: int[], label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', query_var?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type int[] $intervals Optional. The number of days prior to the current date to include in each bucket. + * Accepts an array of integers. Defaults to `[7, 30, 90]`. + * @type string $label Optional. The human-readable name for this aggregation. Defaults to 'Relative Date'. + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'relative_date'. + * } * * @return Controller The instance of the class to allow for chaining. */ @@ -147,13 +222,13 @@ public function enable_relative_date_aggregation( array $args = [] ): Controller /** * Enables search-as-you-type suggestions. * - * @param array $args { + * @param array{post_types?: string[], show_in_rest?: bool} $args { * Optional. An array of arguments. * - * @type string[] $post_types Limit suggestions to this subset of all - * indexed post types. - * @type bool $show_in_rest Whether to register REST API search handlers - * for querying suggestions. Default true. + * @type string[] $post_types Optional. Limit suggestions to this subset of all indexed post types. Accepts an + * array of strings containing post type slugs. Defaults to all post types. + * @type bool $show_in_rest Optional. Whether to register REST API search handlers for querying suggestions. + * Default true. * } * @return Controller The instance of the class to allow for chaining. */ @@ -179,7 +254,22 @@ public function enable_search_suggestions( array $args = [] ): Controller { * A function to enable an aggregation for a specific taxonomy. * * @param string $taxonomy The taxonomy slug for which to enable an aggregation. - * @param array $args Arguments to pass to the adapter's aggregation configuration. + * @param array{label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', query_var?: string, relation?: 'AND'|'OR', term_field?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $label Optional. The human-readable name for this aggregation. Defaults to the singular + * name of the taxonomy (e.g., 'Category'). + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'taxonomy_%s' where %s is the taxonomy slug. + * @type string $relation Optional. The logical relationship between each term when there is more than one. + * Valid options are 'AND', 'OR'. Defaults to 'AND'. + * @type string $term_field Optional. The term field to use in the DSL for this aggregation. Defaults to the + * taxonomy's slug field, as looked up in the DSL map. + * } * * @return Controller The instance of the class to allow for chaining. */ @@ -195,14 +285,24 @@ public function enable_taxonomy_aggregation( string $taxonomy, array $args = [] * be used if a more specific term-type aggregation (e.g., taxonomy, post type) is not * available for the kind of aggregation you want to create. * + * @param string $label The human-readable label for this aggregation. * @param string $term_field The term field to aggregate on. - * @param string $query_var The query var to use for this aggregation for filters on the front-end. - * @param array $args Arguments to pass to the adapter's aggregation configuration. + * @param string $query_var The query var to use for this aggregation for filters on the front-end. + * @param array{label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', relation?: 'AND'|'OR'} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $relation Optional. The logical relationship between each term when there is more than one. + * Valid options are 'AND', 'OR'. Defaults to 'AND'. + * } * * @return Controller The instance of the class to allow for chaining. */ - public function enable_term_aggregation( string $term_field, string $query_var, array $args = [] ): Controller { - $this->adapter->add_term_aggregation( $term_field, $query_var, $args ); + public function enable_term_aggregation( string $label, string $term_field, string $query_var, array $args = [] ): Controller { + $this->adapter->add_term_aggregation( $label, $term_field, $query_var, $args ); return $this; } @@ -232,7 +332,7 @@ public function get_aggregation_by_query_var( string $query_var = '' ): ?Aggrega /** * Get all aggregations from the adapter. * - * @return array An array of aggregation data grouped by aggregation type. + * @return Aggregation[] An array of aggregation data grouped by aggregation type. */ public function get_aggregations(): array { return $this->adapter->get_aggregations(); From b7176b449d66d15263cc11cc9196e822aa975349 Mon Sep 17 00:00:00 2001 From: Kevin Fodness <2650828+kevinfodness@users.noreply.github.com> Date: Mon, 16 Oct 2023 21:16:01 -0400 Subject: [PATCH 5/6] Add more phpdoc --- lib/adapters/class-adapter.php | 132 +++++++++++++++++++++++++++++---- lib/adapters/class-generic.php | 2 +- lib/class-controller.php | 1 + lib/class-factory.php | 16 ++-- 4 files changed, 126 insertions(+), 25 deletions(-) diff --git a/lib/adapters/class-adapter.php b/lib/adapters/class-adapter.php index f932447..c54b86c 100644 --- a/lib/adapters/class-adapter.php +++ b/lib/adapters/class-adapter.php @@ -110,7 +110,21 @@ private function add_aggregation( Aggregation $aggregation ): void { /** * Adds a new Co-Authors Plus author aggregation to the list of active aggregations. * - * @param array $args Optional. Additional arguments to pass to the aggregation. + * @param array{label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'display_name'|'first_name'|'key'|'label'|'last_name', query_var?: string, relation?: 'AND'|'OR', term_field?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $label Optional. The human-readable name for this aggregation. Defaults to 'Author'. + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'display_name', + * 'first_name', 'key', 'label', 'last_name'. Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'taxonomy_author'. + * @type string $relation Optional. The logical relationship between each selected author when there is more + * than one. Valid options are 'AND', 'OR'. Defaults to 'AND'. + * @type string $term_field Optional. The term field to use in the DSL for this aggregation. Defaults to the + * value of the taxonomy name for the 'author' taxonomy, as looked up in the DSL map. + * } */ public function add_cap_author_aggregation( array $args = [] ): void { $this->add_aggregation( new CAP_Author( $this->dsl, $args ) ); @@ -119,7 +133,14 @@ public function add_cap_author_aggregation( array $args = [] ): void { /** * Adds a new custom date range aggregation to the list of active aggregations. * - * @param array $args Optional. Additional arguments to pass to the aggregation. + * @param array{label?: string, query_var?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $label Optional. The human-readable name for this aggregation. Defaults to 'Custom Date + * Range'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'custom_date_range'. + * } */ public function add_custom_date_range_aggregation( array $args = [] ): void { $this->add_aggregation( new Custom_Date_Range( $this->dsl, $args ) ); @@ -128,7 +149,19 @@ public function add_custom_date_range_aggregation( array $args = [] ): void { /** * Adds a new post date aggregation to the list of active aggregations. * - * @param array $args Optional. Additional arguments to pass to the aggregation. + * @param array{interval?: 'year'|'quarter'|'month'|'week'|'day'|'hour'|'minute', label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', query_var?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $interval Optional. The unit of time to aggregate results by. Valid options are 'year', + * 'quarter', 'month', 'week', 'day', 'hour', 'minute'. Defaults to 'year'. + * @type string $label Optional. The human-readable name for this aggregation. Defaults to 'Date'. + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'post_date'. + * } */ public function add_post_date_aggregation( array $args = [] ): void { $this->add_aggregation( new Post_Date( $this->dsl, $args ) ); @@ -138,7 +171,24 @@ public function add_post_date_aggregation( array $args = [] ): void { * Adds a new post meta aggregation to the list of active aggregations. * * @param string $meta_key The meta key to aggregate on. - * @param array $args Optional. Additional arguments to pass to the aggregation. + * @param array{data_type?: string, label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', query_var?: string, relation?: 'AND'|'OR', term_field?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $data_type Optional. The data type of the meta key, if the meta key is indexed using multiple + * data types (e.g., 'long'). Defaults to empty and uses the "raw" postmeta value. + * @type string $label Optional. The human-readable name for this aggregation. Defaults to a halfhearted + * attempt at turning the meta key into a title case string. + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'post_meta_%s' where %s is the meta key. + * @type string $relation Optional. The logical relationship between each selected meta value when there is + * more than one. Valid options are 'AND', 'OR'. Defaults to 'AND'. + * @type string $term_field Optional. The term field to use in the DSL for this aggregation. Defaults to the + * value of the post meta key, as looked up in the DSL map. + * } */ public function add_post_meta_aggregation( string $meta_key, array $args = [] ): void { $this->add_aggregation( new Post_Meta( $this->dsl, wp_parse_args( $args, [ 'meta_key' => $meta_key ] ) ) ); @@ -147,7 +197,21 @@ public function add_post_meta_aggregation( string $meta_key, array $args = [] ): /** * Adds a new post type aggregation to the list of active aggregations. * - * @param array $args Optional. Additional arguments to pass to the aggregation. + * @param array{label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', query_var?: string, relation?: 'AND'|'OR', term_field?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $label Optional. The human-readable name for this aggregation. Defaults to 'Content Type'. + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'post_type'. + * @type string $relation Optional. The logical relationship between each selected author when there is more + * than one. Valid options are 'AND', 'OR'. Defaults to 'AND'. + * @type string $term_field Optional. The term field to use in the DSL for this aggregation. Defaults to the + * 'post_type' field, as looked up in the DSL map. + * } */ public function add_post_type_aggregation( array $args = [] ): void { $this->add_aggregation( new Post_Type( $this->dsl, $args ) ); @@ -156,7 +220,19 @@ public function add_post_type_aggregation( array $args = [] ): void { /** * Adds a new relative date aggregation to the list of active aggregations. * - * @param array $args Optional. Additional arguments to pass to the aggregation. + * @param array{intervals: int[], label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', query_var?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type int[] $intervals Optional. The number of days prior to the current date to include in each bucket. + * Accepts an array of integers. Defaults to `[7, 30, 90]`. + * @type string $label Optional. The human-readable name for this aggregation. Defaults to 'Relative Date'. + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'relative_date'. + * } */ public function add_relative_date_aggregation( array $args = [] ): void { $this->add_aggregation( new Relative_Date( $this->dsl, $args ) ); @@ -165,8 +241,23 @@ public function add_relative_date_aggregation( array $args = [] ): void { /** * Adds a new taxonomy aggregation to the list of active aggregations. * - * @param string $taxonomy The taxonomy slug to add (e.g., category, post_tag). - * @param array $args Optional. Additional arguments to pass to the aggregation. + * @param string $taxonomy The taxonomy slug for which to enable an aggregation. + * @param array{label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', query_var?: string, relation?: 'AND'|'OR', term_field?: string} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $label Optional. The human-readable name for this aggregation. Defaults to the singular + * name of the taxonomy (e.g., 'Category'). + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to + * 'taxonomy_%s' where %s is the taxonomy slug. + * @type string $relation Optional. The logical relationship between each term when there is more than one. + * Valid options are 'AND', 'OR'. Defaults to 'AND'. + * @type string $term_field Optional. The term field to use in the DSL for this aggregation. Defaults to the + * taxonomy's slug field, as looked up in the DSL map. + * } */ public function add_taxonomy_aggregation( string $taxonomy, array $args = [] ): void { $this->add_aggregation( new Taxonomy( $this->dsl, wp_parse_args( $args, [ 'taxonomy' => $taxonomy ] ) ) ); @@ -175,10 +266,19 @@ public function add_taxonomy_aggregation( string $taxonomy, array $args = [] ): /** * Adds a new generic term aggregation to the list of active aggregations. * - * @param string $label The human-readable label for this aggregation. + * @param string $label The human-readable label for this aggregation. * @param string $term_field The term field to aggregate on. - * @param string $query_var The query var to use for this aggregation for filters on the front-end. - * @param array $args Arguments to pass to the adapter's aggregation configuration. + * @param string $query_var The query var to use for this aggregation for filters on the front-end. + * @param array{label?: string, order?: 'ASC'|'DESC', orderby?: 'count'|'key'|'label', relation?: 'AND'|'OR'} $args { + * Optional. Arguments to pass to the adapter's aggregation configuration. + * + * @type string $order Optional. How to sort by the `orderby` field. Valid options are 'ASC', 'DESC'. + * Defaults to 'DESC'. + * @type string $orderby Optional. The field to order results by. Valid options are 'count', 'key', 'label'. + * Defaults to 'count'. + * @type string $relation Optional. The logical relationship between each term when there is more than one. + * Valid options are 'AND', 'OR'. Defaults to 'AND'. + * } */ public function add_term_aggregation( string $label, string $term_field, string $query_var, array $args = [] ): void { $this->add_aggregation( @@ -264,7 +364,7 @@ public function get_enable_search_suggestions(): bool { * between each plugin's Elasticsearch implementation, and use the result * of this function when initializing the DSL class in the constructor. * - * @return array The field map. + * @return array The field map. */ abstract protected function get_field_map(): array; @@ -310,9 +410,9 @@ protected function get_restricted_search_suggestions_post_types(): array { * depending on the context (e.g., main search vs. custom search * interfaces). * - * @param array $post_types The default list of post type slugs from the adapter. + * @param string[] $post_types The default list of post type slugs from the adapter. * - * @return array An array of searchable post type slugs. + * @return string[] An array of searchable post type slugs. */ protected function get_searchable_post_types( array $post_types ): array { /** @@ -340,7 +440,7 @@ public function is_show_search_suggestions_in_rest_enabled(): bool { * Parses aggregations from an aggregations object in an Elasticsearch * response into the loaded aggregations. * - * @param array $aggregations Aggregations from the Elasticsearch response. + * @param array $aggregations Aggregations from the Elasticsearch response. */ protected function parse_aggregations( array $aggregations ): void { foreach ( $aggregations as $aggregation_key => $aggregation ) { @@ -354,7 +454,7 @@ protected function parse_aggregations( array $aggregations ): void { * Suggest posts that match the given search term. * * @param string $search Search string. - * @param array $args { + * @param array{subtypes?: string[], page?: int, per_page?: int, include?: int[], exclude?: int[]} $args { * Optional. An array of arguments. * * @type string[] $subtypes Limit suggestions to this subset of all post diff --git a/lib/adapters/class-generic.php b/lib/adapters/class-generic.php index 6ee3946..705a241 100644 --- a/lib/adapters/class-generic.php +++ b/lib/adapters/class-generic.php @@ -16,7 +16,7 @@ class Generic extends Adapter { /** * Gets the field map for this adapter. * - * @return array The field map. + * @return array The field map. */ public function get_field_map(): array { return []; diff --git a/lib/class-controller.php b/lib/class-controller.php index 7def5ae..5055630 100644 --- a/lib/class-controller.php +++ b/lib/class-controller.php @@ -92,6 +92,7 @@ public function enable_cap_author_aggregation( array $args = [] ): Controller { * @type string $query_var Optional. The query var to use in the URL. Accepts any URL-safe string. Defaults to * 'custom_date_range'. * } + * * @return Controller The instance of the class to allow for chaining. */ public function enable_custom_date_range_aggregation( array $args = [] ): Controller { diff --git a/lib/class-factory.php b/lib/class-factory.php index 365e181..01252bf 100644 --- a/lib/class-factory.php +++ b/lib/class-factory.php @@ -67,20 +67,20 @@ public static function initialize( $object ) { } /** - * Returns an initialized VIP Enterprise Search adapter. + * Returns an initialized SearchPress adapter. * - * @return VIP_Enterprise_Search + * @return SearchPress */ - public static function vip_enterprise_search_adapter(): VIP_Enterprise_Search { - return self::initialize( new VIP_Enterprise_Search() ); + public static function searchpress_adapter(): SearchPress { + return self::initialize( new SearchPress() ); } /** - * Returns an initialized SearchPress adapter. + * Returns an initialized VIP Enterprise Search adapter. * - * @return SearchPress + * @return VIP_Enterprise_Search */ - public static function searchpress_adapter(): SearchPress { - return self::initialize( new SearchPress() ); + public static function vip_enterprise_search_adapter(): VIP_Enterprise_Search { + return self::initialize( new VIP_Enterprise_Search() ); } } From ccaad041b5df070c049128d23d58eac200eb727f Mon Sep 17 00:00:00 2001 From: Kevin Fodness <2650828+kevinfodness@users.noreply.github.com> Date: Mon, 16 Oct 2023 21:31:16 -0400 Subject: [PATCH 6/6] phpstan fixes --- .phpcs.xml | 5 ++++- lib/adapters/class-adapter.php | 2 +- lib/class-controller.php | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.phpcs.xml b/.phpcs.xml index af0e26c..796b610 100644 --- a/.phpcs.xml +++ b/.phpcs.xml @@ -3,7 +3,10 @@ PHP_CodeSniffer standard for Elasticsearch Extensions. - + + + +