Make WordPress Core

Changeset 61650


Ignore:
Timestamp:
02/16/2026 01:11:50 PM (8 weeks ago)
Author:
ntsekouras
Message:

Editor: Update build_query_vars_from_query_block to handle new taxQuery structure.

The Query Loop block's taxQuery attribute now supports an include/exclude structure for term filtering. This updates the server-side query building to handle both the old format (e.g. {"category":[4]}) and the new format (e.g. {"include":{"category":[4]},"exclude":{"post_tag":[5]}}).

Props ntsekouras, westonruter, peterwilsoncc, mcsf.
Fixes #64416.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/blocks.php

    r61617 r61650  
    26612661 * @since 6.1.0 Added `query_loop_block_query_vars` filter and `parents` support in query.
    26622662 * @since 6.7.0 Added support for the `format` property in query.
     2663 * @since 7.0.0 Updated `taxQuery` structure.
    26632664 *
    26642665 * @param WP_Block $block Block instance.
     
    27422743            $query['tax_query'] = array_merge( $query['tax_query'], $tax_query_back_compat );
    27432744        }
    2744         if ( ! empty( $block->context['query']['taxQuery'] ) ) {
    2745             $tax_query = array();
    2746             foreach ( $block->context['query']['taxQuery'] as $taxonomy => $terms ) {
    2747                 if ( is_taxonomy_viewable( $taxonomy ) && ! empty( $terms ) ) {
    2748                     $tax_query[] = array(
    2749                         'taxonomy'         => $taxonomy,
    2750                         'terms'            => array_filter( array_map( 'intval', $terms ) ),
    2751                         'include_children' => false,
    2752                     );
     2745
     2746        if ( ! empty( $block->context['query']['taxQuery'] ) && is_array( $block->context['query']['taxQuery'] ) ) {
     2747            $tax_query_input = $block->context['query']['taxQuery'];
     2748            $tax_query       = array();
     2749            // If there are keys other than include/exclude, it's the old
     2750            // format e.g. "taxQuery":{"category":[4]}
     2751            if ( ! empty( array_diff( array_keys( $tax_query_input ), array( 'include', 'exclude' ) ) ) ) {
     2752                foreach ( $block->context['query']['taxQuery'] as $taxonomy => $terms ) {
     2753                    if ( is_taxonomy_viewable( $taxonomy ) && ! empty( $terms ) ) {
     2754                        $tax_query[] = array(
     2755                            'taxonomy'         => $taxonomy,
     2756                            'terms'            => array_filter( array_map( 'intval', $terms ) ),
     2757                            'include_children' => false,
     2758                        );
     2759                    }
    27532760                }
    2754             }
    2755             $query['tax_query'] = array_merge( $query['tax_query'], $tax_query );
     2761            } else {
     2762                // This is the new format e.g. "taxQuery":{"include":{"category":[4]},"exclude":{"post_tag":[5]}}
     2763
     2764                // Helper function to build tax_query conditions from taxonomy terms.
     2765                $build_conditions = static function ( $terms, string $operator = 'IN' ): array {
     2766                    $terms      = (array) $terms;
     2767                    $conditions = array();
     2768                    foreach ( $terms as $taxonomy => $tax_terms ) {
     2769                        if ( ! empty( $tax_terms ) && is_taxonomy_viewable( $taxonomy ) ) {
     2770                            $conditions[] = array(
     2771                                'taxonomy'         => $taxonomy,
     2772                                'terms'            => array_filter( array_map( 'intval', $tax_terms ) ),
     2773                                'operator'         => $operator,
     2774                                'include_children' => false,
     2775                            );
     2776                        }
     2777                    }
     2778                    return $conditions;
     2779                };
     2780
     2781                // Separate exclude from include terms.
     2782                $exclude_terms = isset( $tax_query_input['exclude'] ) && is_array( $tax_query_input['exclude'] )
     2783                    ? $tax_query_input['exclude']
     2784                    : array();
     2785                $include_terms = isset( $tax_query_input['include'] ) && is_array( $tax_query_input['include'] )
     2786                    ? $tax_query_input['include']
     2787                    : array();
     2788
     2789                $tax_query = array_merge(
     2790                    $build_conditions( $include_terms ),
     2791                    $build_conditions( $exclude_terms, 'NOT IN' )
     2792                );
     2793            }
     2794
     2795            if ( ! empty( $tax_query ) ) {
     2796                // Merge with any existing `tax_query` conditions.
     2797                $query['tax_query'] = array_merge( $query['tax_query'], $tax_query );
     2798            }
    27562799        }
    27572800        if ( ! empty( $block->context['query']['format'] ) && is_array( $block->context['query']['format'] ) ) {
  • trunk/tests/phpunit/tests/blocks/wpBlock.php

    r61519 r61650  
    839839
    840840    /**
     841     * @ticket 64416
     842     */
     843    public function test_build_query_vars_from_query_block_tax_query_old_format() {
     844        $this->registry->register(
     845            'core/example',
     846            array( 'uses_context' => array( 'query' ) )
     847        );
     848
     849        $parsed_blocks = parse_blocks( '<!-- wp:example {"ok":true} -->a<!-- wp:example /-->b<!-- /wp:example -->' );
     850        $parsed_block  = $parsed_blocks[0];
     851        $context       = array(
     852            'query' => array(
     853                'taxQuery' => array(
     854                    'category' => array( 1, 2, 3 ),
     855                    'post_tag' => array( 10, 20 ),
     856                ),
     857            ),
     858        );
     859        $block         = new WP_Block( $parsed_block, $context, $this->registry );
     860        $query         = build_query_vars_from_query_block( $block, 1 );
     861
     862        $this->assertSame(
     863            array(
     864                'post_type'    => 'post',
     865                'order'        => 'DESC',
     866                'orderby'      => 'date',
     867                'post__not_in' => array(),
     868                'tax_query'    => array(
     869                    array(
     870                        'taxonomy'         => 'category',
     871                        'terms'            => array( 1, 2, 3 ),
     872                        'include_children' => false,
     873                    ),
     874                    array(
     875                        'taxonomy'         => 'post_tag',
     876                        'terms'            => array( 10, 20 ),
     877                        'include_children' => false,
     878                    ),
     879                ),
     880            ),
     881            $query
     882        );
     883    }
     884
     885    /**
     886     * @ticket 64416
     887     */
     888    public function test_build_query_vars_from_query_block_tax_query_include_exclude() {
     889        $this->registry->register(
     890            'core/example',
     891            array( 'uses_context' => array( 'query' ) )
     892        );
     893
     894        $parsed_blocks = parse_blocks( '<!-- wp:example {"ok":true} -->a<!-- wp:example /-->b<!-- /wp:example -->' );
     895        $parsed_block  = $parsed_blocks[0];
     896        $context       = array(
     897            'query' => array(
     898                'taxQuery' => array(
     899                    'include' => array(
     900                        'category' => array( 1, 2, 3 ),
     901                    ),
     902                    'exclude' => array(
     903                        'post_tag' => array( 15 ),
     904                    ),
     905                ),
     906            ),
     907        );
     908        $block         = new WP_Block( $parsed_block, $context, $this->registry );
     909        $query         = build_query_vars_from_query_block( $block, 1 );
     910
     911        $this->assertSame(
     912            array(
     913                'post_type'    => 'post',
     914                'order'        => 'DESC',
     915                'orderby'      => 'date',
     916                'post__not_in' => array(),
     917                'tax_query'    => array(
     918                    array(
     919                        'taxonomy'         => 'category',
     920                        'terms'            => array( 1, 2, 3 ),
     921                        'operator'         => 'IN',
     922                        'include_children' => false,
     923                    ),
     924                    array(
     925                        'taxonomy'         => 'post_tag',
     926                        'terms'            => array( 15 ),
     927                        'operator'         => 'NOT IN',
     928                        'include_children' => false,
     929                    ),
     930                ),
     931            ),
     932            $query
     933        );
     934    }
     935
     936    /**
    841937     * @ticket 62014
    842938     */
Note: See TracChangeset for help on using the changeset viewer.