From 26ce24591cde6b70631aba8fcf25e5ac2841a7b5 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 15 Dec 2025 08:55:28 +0200 Subject: [PATCH 1/7] Update `build_query_vars_from_query_block` to handle new `taxQuery` structure --- src/wp-includes/blocks.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index a8ed76d3bd71f..f50163e60c474 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -2632,6 +2632,7 @@ function wp_migrate_old_typography_shape( $metadata ) { * @since 5.8.0 * @since 6.1.0 Added `query_loop_block_query_vars` filter and `parents` support in query. * @since 6.7.0 Added support for the `format` property in query. + * @since 7.0.0 Updated `taxQuery` structure. * * @param WP_Block $block Block instance. * @param int $page Current query's page. From 27b130ef5899b5688cf7314f886f60d4ef6b86d5 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 15 Dec 2025 10:42:13 +0200 Subject: [PATCH 2/7] add the code and tests --- src/wp-includes/blocks.php | 58 +++++++++++++--- tests/phpunit/tests/blocks/wpBlock.php | 96 ++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 9 deletions(-) diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index f50163e60c474..f0b01ce25581e 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -2714,18 +2714,58 @@ function build_query_vars_from_query_block( $block, $page ) { } $query['tax_query'] = array_merge( $query['tax_query'], $tax_query_back_compat ); } - if ( ! empty( $block->context['query']['taxQuery'] ) ) { + $tax_query_input = $block->context['query']['taxQuery']; + if ( ! empty( $tax_query_input ) && is_array( $tax_query_input ) ) { $tax_query = array(); - foreach ( $block->context['query']['taxQuery'] as $taxonomy => $terms ) { - if ( is_taxonomy_viewable( $taxonomy ) && ! empty( $terms ) ) { - $tax_query[] = array( - 'taxonomy' => $taxonomy, - 'terms' => array_filter( array_map( 'intval', $terms ) ), - 'include_children' => false, - ); + // If there are keys other than include/exclude, it's the old + // format e.g. "taxQuery":{"category":[4]} + if ( ! empty( array_diff( array_keys( $tax_query_input ), array( 'include', 'exclude' ) ) ) ) { + foreach ( $block->context['query']['taxQuery'] as $taxonomy => $terms ) { + if ( is_taxonomy_viewable( $taxonomy ) && ! empty( $terms ) ) { + $tax_query[] = array( + 'taxonomy' => $taxonomy, + 'terms' => array_filter( array_map( 'intval', $terms ) ), + 'include_children' => false, + ); + } } + } else { + // This is the new format e.g. "taxQuery":{"include":{"category":[4]},"exclude":{"post_tag":[5]}} + + // Helper function to build tax_query conditions from taxonomy terms. + $build_conditions = static function ( $terms, $operator = 'IN' ) { + $conditions = array(); + foreach ( $terms as $taxonomy => $terms ) { + if ( ! empty( $terms ) && is_taxonomy_viewable( $taxonomy ) ) { + $conditions[] = array( + 'taxonomy' => $taxonomy, + 'terms' => array_filter( array_map( 'intval', $terms ) ), + 'operator' => $operator, + 'include_children' => false, + ); + } + } + return $conditions; + }; + + // Separate exclude from include terms. + $exclude_terms = isset( $tax_query_input['exclude'] ) && is_array( $tax_query_input['exclude'] ) + ? $tax_query_input['exclude'] + : array(); + $include_terms = isset( $tax_query_input['include'] ) && is_array( $tax_query_input['include'] ) + ? $tax_query_input['include'] + : array(); + + $tax_query = array_merge( + $build_conditions( $include_terms ), + $build_conditions( $exclude_terms, 'NOT IN' ) + ); + } + + if ( ! empty( $tax_query ) ) { + // Merge with any existing `tax_query` conditions. + $query['tax_query'] = array_merge( $query['tax_query'], $tax_query ); } - $query['tax_query'] = array_merge( $query['tax_query'], $tax_query ); } if ( ! empty( $block->context['query']['format'] ) && is_array( $block->context['query']['format'] ) ) { $formats = $block->context['query']['format']; diff --git a/tests/phpunit/tests/blocks/wpBlock.php b/tests/phpunit/tests/blocks/wpBlock.php index f7c4710c9c3fe..4cee7345c38d6 100644 --- a/tests/phpunit/tests/blocks/wpBlock.php +++ b/tests/phpunit/tests/blocks/wpBlock.php @@ -797,6 +797,102 @@ public function test_build_query_vars_from_query_block() { ); } + /** + * @ticket 64416 + */ + public function test_build_query_vars_from_query_block_tax_query_old_format() { + $this->registry->register( + 'core/example', + array( 'uses_context' => array( 'query' ) ) + ); + + $parsed_blocks = parse_blocks( 'ab' ); + $parsed_block = $parsed_blocks[0]; + $context = array( + 'query' => array( + 'taxQuery' => array( + 'category' => array( 1, 2, 3 ), + 'post_tag' => array( 10, 20 ), + ), + ), + ); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + $query = build_query_vars_from_query_block( $block, 1 ); + + $this->assertSame( + array( + 'post_type' => 'post', + 'order' => 'DESC', + 'orderby' => 'date', + 'post__not_in' => array(), + 'tax_query' => array( + array( + 'taxonomy' => 'category', + 'terms' => array( 1, 2, 3 ), + 'include_children' => false, + ), + array( + 'taxonomy' => 'post_tag', + 'terms' => array( 10, 20 ), + 'include_children' => false, + ), + ), + ), + $query + ); + } + + /** + * @ticket 64416 + */ + public function test_build_query_vars_from_query_block_tax_query_include_exclude() { + $this->registry->register( + 'core/example', + array( 'uses_context' => array( 'query' ) ) + ); + + $parsed_blocks = parse_blocks( 'ab' ); + $parsed_block = $parsed_blocks[0]; + $context = array( + 'query' => array( + 'taxQuery' => array( + 'include' => array( + 'category' => array( 1, 2, 3 ), + ), + 'exclude' => array( + 'post_tag' => array( 15 ), + ), + ), + ), + ); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + $query = build_query_vars_from_query_block( $block, 1 ); + + $this->assertSame( + array( + 'post_type' => 'post', + 'order' => 'DESC', + 'orderby' => 'date', + 'post__not_in' => array(), + 'tax_query' => array( + array( + 'taxonomy' => 'category', + 'terms' => array( 1, 2, 3 ), + 'operator' => 'IN', + 'include_children' => false, + ), + array( + 'taxonomy' => 'post_tag', + 'terms' => array( 15 ), + 'operator' => 'NOT IN', + 'include_children' => false, + ), + ), + ), + $query + ); + } + /** * @ticket 62014 */ From 1855dd398f8a19c4e2651ff9bd4b15961e604347 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 15 Dec 2025 10:57:21 +0200 Subject: [PATCH 3/7] check for empty `taxQuery` key --- src/wp-includes/blocks.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index f0b01ce25581e..3bbae62ef2b5b 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -2714,9 +2714,10 @@ function build_query_vars_from_query_block( $block, $page ) { } $query['tax_query'] = array_merge( $query['tax_query'], $tax_query_back_compat ); } - $tax_query_input = $block->context['query']['taxQuery']; - if ( ! empty( $tax_query_input ) && is_array( $tax_query_input ) ) { - $tax_query = array(); + + if ( ! empty( $block->context['query']['taxQuery'] ) && is_array( $block->context['query']['taxQuery'] ) ) { + $tax_query_input = $block->context['query']['taxQuery']; + $tax_query = array(); // If there are keys other than include/exclude, it's the old // format e.g. "taxQuery":{"category":[4]} if ( ! empty( array_diff( array_keys( $tax_query_input ), array( 'include', 'exclude' ) ) ) ) { From 40192f7467e626c3401af68a67525b973eda02c4 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Tue, 16 Dec 2025 09:11:35 +0200 Subject: [PATCH 4/7] Update src/wp-includes/blocks.php Co-authored-by: Weston Ruter --- src/wp-includes/blocks.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index 3bbae62ef2b5b..8cc2efb7bcf80 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -2751,11 +2751,11 @@ function build_query_vars_from_query_block( $block, $page ) { // Separate exclude from include terms. $exclude_terms = isset( $tax_query_input['exclude'] ) && is_array( $tax_query_input['exclude'] ) - ? $tax_query_input['exclude'] - : array(); + ? $tax_query_input['exclude'] + : array(); $include_terms = isset( $tax_query_input['include'] ) && is_array( $tax_query_input['include'] ) - ? $tax_query_input['include'] - : array(); + ? $tax_query_input['include'] + : array(); $tax_query = array_merge( $build_conditions( $include_terms ), From 3bebb24cec51246c70c7d6d3dddc5443b1cafdf8 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Wed, 17 Dec 2025 10:23:38 +0200 Subject: [PATCH 5/7] Update src/wp-includes/blocks.php Co-authored-by: Weston Ruter --- src/wp-includes/blocks.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index 8cc2efb7bcf80..50d635314956f 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -2734,7 +2734,7 @@ function build_query_vars_from_query_block( $block, $page ) { // This is the new format e.g. "taxQuery":{"include":{"category":[4]},"exclude":{"post_tag":[5]}} // Helper function to build tax_query conditions from taxonomy terms. - $build_conditions = static function ( $terms, $operator = 'IN' ) { + $build_conditions = static function ( array $terms, string $operator = 'IN' ): array { $conditions = array(); foreach ( $terms as $taxonomy => $terms ) { if ( ! empty( $terms ) && is_taxonomy_viewable( $taxonomy ) ) { From 293533af8645f7137446a77f6cbdc38cd1718678 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Thu, 18 Dec 2025 10:52:56 +0200 Subject: [PATCH 6/7] Update src/wp-includes/blocks.php Co-authored-by: Weston Ruter --- src/wp-includes/blocks.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index 50d635314956f..4d06281ba0a76 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -2736,11 +2736,11 @@ function build_query_vars_from_query_block( $block, $page ) { // Helper function to build tax_query conditions from taxonomy terms. $build_conditions = static function ( array $terms, string $operator = 'IN' ): array { $conditions = array(); - foreach ( $terms as $taxonomy => $terms ) { - if ( ! empty( $terms ) && is_taxonomy_viewable( $taxonomy ) ) { + foreach ( $terms as $taxonomy => $tax_terms ) { + if ( ! empty( $tax_terms ) && is_taxonomy_viewable( $taxonomy ) ) { $conditions[] = array( 'taxonomy' => $taxonomy, - 'terms' => array_filter( array_map( 'intval', $terms ) ), + 'terms' => array_filter( array_map( 'intval', $tax_terms ) ), 'operator' => $operator, 'include_children' => false, ); From b4769ecfaae69ba7b5fb1a42e318843e788c5325 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Thu, 18 Dec 2025 10:54:57 +0200 Subject: [PATCH 7/7] Update src/wp-includes/blocks.php Co-authored-by: Weston Ruter --- src/wp-includes/blocks.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index 4d06281ba0a76..77b8c6cba2f9d 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -2734,7 +2734,8 @@ function build_query_vars_from_query_block( $block, $page ) { // This is the new format e.g. "taxQuery":{"include":{"category":[4]},"exclude":{"post_tag":[5]}} // Helper function to build tax_query conditions from taxonomy terms. - $build_conditions = static function ( array $terms, string $operator = 'IN' ): array { + $build_conditions = static function ( $terms, string $operator = 'IN' ): array { + $terms = (array) $terms; $conditions = array(); foreach ( $terms as $taxonomy => $tax_terms ) { if ( ! empty( $tax_terms ) && is_taxonomy_viewable( $taxonomy ) ) {