From 235fd7438a11cea97a5f9fde87cac5e2de422f03 Mon Sep 17 00:00:00 2001 From: Felipe Elia Date: Sun, 27 Mar 2022 18:54:30 -0300 Subject: [PATCH 1/2] Add support for multiple aggregations --- includes/classes/Indexable/Post/Post.php | 56 +++++++++++++++++------- tests/php/indexables/TestPost.php | 32 ++++++++++++++ 2 files changed, 71 insertions(+), 17 deletions(-) diff --git a/includes/classes/Indexable/Post/Post.php b/includes/classes/Indexable/Post/Post.php index aabd88bbc1..9b34e8a974 100644 --- a/includes/classes/Indexable/Post/Post.php +++ b/includes/classes/Indexable/Post/Post.php @@ -1800,24 +1800,15 @@ public function format_args( $args, $wp_query ) { /** * Aggregations */ - if ( isset( $args['aggs'] ) && ! empty( $args['aggs']['aggs'] ) ) { - $agg_obj = $args['aggs']; - - // Add a name to the aggregation if it was passed through - if ( ! empty( $agg_obj['name'] ) ) { - $agg_name = $agg_obj['name']; - } else { - $agg_name = 'aggregation_name'; - } - - // Add/use the filter if warranted - if ( isset( $agg_obj['use-filter'] ) && false !== $agg_obj['use-filter'] && $use_filters ) { - - // If a filter is being used, use it on the aggregation as well to receive relevant information to the query - $formatted_args['aggs'][ $agg_name ]['filter'] = $filter; - $formatted_args['aggs'][ $agg_name ]['aggs'] = $agg_obj['aggs']; + if ( isset( $args['aggs'] ) ) { + // An array of aggregations. + if ( isset( $args['aggs'][0] ) ) { + foreach ( $args['aggs'] as $agg ) { + $formatted_args = $this->apply_aggregations( $formatted_args, $agg, $use_filters, $filter ); + } } else { - $formatted_args['aggs'][ $agg_name ] = $agg_obj['aggs']; + // Single aggregation. + $formatted_args = $this->apply_aggregations( $formatted_args, $args['aggs'], $use_filters, $filter ); } } @@ -2224,4 +2215,35 @@ protected function determine_mapping_version_based_on_existing( $mapping, $index return 'unknown'; } + + /** + * Given ES args, add aggregations to it. + * + * @since 4.1.0 + * @param array $formatted_args Formatted Elasticsearch query. + * @param array $agg Aggregation data. + * @param boolean $use_filters Whether filters should be used or not. + * @param array $filter Filters defined so far. + * @return array Formatted Elasticsearch query with the aggregation added. + */ + protected function apply_aggregations( $formatted_args, $agg, $use_filters, $filter ) { + if ( empty( $agg['aggs'] ) ) { + return $formatted_args; + } + + // Add a name to the aggregation if it was passed through + $agg_name = ( ! empty( $agg['name'] ) ) ? $agg['name'] : 'aggregation_name'; + + // Add/use the filter if warranted + if ( isset( $agg['use-filter'] ) && false !== $agg['use-filter'] && $use_filters ) { + + // If a filter is being used, use it on the aggregation as well to receive relevant information to the query + $formatted_args['aggs'][ $agg_name ]['filter'] = $filter; + $formatted_args['aggs'][ $agg_name ]['aggs'] = $agg['aggs']; + } else { + $formatted_args['aggs'][ $agg_name ] = $agg['aggs']; + } + + return $formatted_args; + } } diff --git a/tests/php/indexables/TestPost.php b/tests/php/indexables/TestPost.php index d936c80c16..691bc30010 100644 --- a/tests/php/indexables/TestPost.php +++ b/tests/php/indexables/TestPost.php @@ -5939,6 +5939,38 @@ public function testFormatArgsAggs() { ); $this->assertSame( 'terms.post_type', $args['aggs']['aggregation_name']['terms']['field'] ); + + // Multiple aggs. + $args = $post->format_args( + [ + // Triggers $use_filter to be true. + 'post_status' => 'publish', + + 'aggs' => [ + [ + 'name' => 'taxonomies', + 'use-filter' => true, + 'aggs' => [ + 'terms' => [ + 'field' => 'terms.category.slug', + ], + ], + ], + [ + 'aggs' => [ + 'terms' => [ + 'field' => 'terms.post_type', + ], + ], + ] + ], + ], + new \WP_Query() + ); + + $this->assertSame( 'publish', $args['aggs']['taxonomies']['filter']['bool']['must'][1]['term']['post_status'] ); + $this->assertSame( 'terms.category.slug', $args['aggs']['taxonomies']['aggs']['terms']['field'] ); + $this->assertSame( 'terms.post_type', $args['aggs']['aggregation_name']['terms']['field'] ); } /** From f3df048bfe711b830e4fa344b3d6332165b3e034 Mon Sep 17 00:00:00 2001 From: Felipe Elia Date: Tue, 29 Mar 2022 11:06:47 -0300 Subject: [PATCH 2/2] Improve check for numeric array keys --- includes/classes/Indexable/Post/Post.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/includes/classes/Indexable/Post/Post.php b/includes/classes/Indexable/Post/Post.php index 9b34e8a974..15d9c89d13 100644 --- a/includes/classes/Indexable/Post/Post.php +++ b/includes/classes/Indexable/Post/Post.php @@ -1800,9 +1800,13 @@ public function format_args( $args, $wp_query ) { /** * Aggregations */ - if ( isset( $args['aggs'] ) ) { - // An array of aggregations. - if ( isset( $args['aggs'][0] ) ) { + if ( ! empty( $args['aggs'] ) && is_array( $args['aggs'] ) ) { + // Check if the array indexes are all numeric. + $agg_keys = array_keys( $args['aggs'] ); + $agg_num_keys = array_filter( $agg_keys, 'is_int' ); + $has_only_num_keys = count( $agg_num_keys ) === count( $args['aggs'] ); + + if ( $has_only_num_keys ) { foreach ( $args['aggs'] as $agg ) { $formatted_args = $this->apply_aggregations( $formatted_args, $agg, $use_filters, $filter ); }