Make WordPress Core

Opened 5 weeks ago

Closed 12 days ago

Last modified 8 days ago

#62014 closed enhancement (fixed)

Editor: Add a 'format' parameter to query to enable filtering post formats in the Query Loop block

Reported by: poena's profile poena Owned by: peterwilsoncc's profile peterwilsoncc
Milestone: 6.7 Priority: normal
Severity: normal Version:
Component: Editor Keywords: has-patch has-testing-info needs-testing needs-unit-tests
Focuses: Cc:

Description (last modified by poena)

This ticket is for adding the PHP changes from this Gutenberg PR:
Query loop / Post template: Enable post format filter

The Gutenberg PR linked above adds a new filter and a new interface control to the Query Loop block, that the user can use to display posts (or other post types) that have post formats assigned.

The PR for this Trac ticket adds a new parameter called 'format' to the class
WP_REST_Posts_Controller. Changes are made to these class methods: 'get_item' and 'get_collection_params'.

'Format' is also added to the function build_query_vars_from_query_block, to ensure that it is passed correctly to 'WP_Query' during the server-side render of the block.

The test test_registered_query_params on the test class WP_Test_REST_Posts_Controller is also updated to include the format parameter.


Testing instructions

How to test the post formats filter without the rest of the Gutenberg changes.

First, please enable post formats on the active theme. Example:

function twentytwentyfour_post_formats() {
	add_theme_support( 'post-formats', array( 'aside', 'gallery', 'link', 'image', 'quote', 'status', 'video', 'audio', 'chat' ) );
}
add_action( 'after_setup_theme', 'twentytwentyfour_post_formats' );

On your WordPress test install, create a few posts with and without formats assigned.

In the Site Editor or block editor, insert a query loop with a format filter.
Since the control itself is not included in this PR, you will need to open the code editor mode in the editor and manually add the format.
In this example, I have used the gallery post format. I have added
"format":["gallery"] inside query:

<!-- wp:query {"query":{"perPage":10,"pages":0,"offset":0,"postType":"post","order":"desc","orderBy":"date","author":"","search":"","exclude":[],"sticky":"","inherit":true,"format":["gallery"]}} -->
<div class="wp-block-query">
    <!-- wp:post-template -->
    <!-- wp:post-title /-->
    <!-- /wp:post-template -->
</div>
<!-- /wp:query -->

In the editor and front, the query loop should only display posts with the gallery post format.

Next, change the format to standard:

<!-- wp:query {"query":{"perPage":10,"pages":0,"offset":0,"postType":"post","order":"desc","orderBy":"date","author":"","search":"","exclude":[],"sticky":"","inherit":true,"format":["standard"]}} -->
<div class="wp-block-query">
    <!-- wp:post-template -->
    <!-- wp:post-title /-->
    <!-- /wp:post-template -->
</div>
<!-- /wp:query -->

In the editor and front, the query loop should only display posts that have no post format assigned.

Testing the query pagination:
Set the number of posts to display per page to something low, so that the query pagination block shows on the front.
Then move between the listed pages and confirm that page 2 etc also shows posts with the correct post formats.

Change History (27)

This ticket was mentioned in PR #7314 on WordPress/wordpress-develop by @poena.


5 weeks ago
#1

  • Keywords has-patch added

Adds handling the format property ($request['format'] ) in the class WP_REST_Posts_Controller.
Adds handling the format property ($block->context['query']['format']) in the function build_query_vars_from_query_block.

Trac ticket: https://core.trac.wordpress.org/ticket/62014

#2 @poena
5 weeks ago

  • Description modified (diff)

#3 @sabernhardt
5 weeks ago

  • Component changed from General to Editor

#4 @poena
4 weeks ago

  • Description modified (diff)

#5 @poena
4 weeks ago

  • Description modified (diff)
  • Keywords has-testing-info needs-testing added

#6 @poena
4 weeks ago

  • Description modified (diff)

#7 @poena
4 weeks ago

  • Description modified (diff)

This ticket was mentioned in Slack in #core-editor by poena. View the logs.


4 weeks ago

#9 @peterwilsoncc
4 weeks ago

Am I able to clarify the intent a little more here.

If I set up a Query Loop with the following:

  • Categories: some-category
  • Tags: some-tag
  • Post Format: link

Is the intention that it will perform the AND pseudo query post format == link AND ( post tag == some-tag OR post category == some-category)?

Or is the intention that it will perform the OR pseudo query post format == link OR post tag == some-tag OR post category == some-category?

Taxonomy queries within WP_Query are really flexible in that they allow for a combination matching the first option but I'm not sure if the REST API is as flexible, @TimothyBlynJacobs are you able to provide some guidance on this?

Once I hear back on whether it's an OR or AND, I can follow up further with code review on the pull request.

Last edited 4 weeks ago by peterwilsoncc (previous) (diff)

#10 @poena
4 weeks ago

If I enter both a category and a tag into the existing filter settings on the query loop block,
the block displays posts that have both the category and the tag. Not posts that have either.
It should work the same when the format filter is used.

Last edited 4 weeks ago by poena (previous) (diff)

#11 @TimothyBlynJacobs
4 weeks ago

Yeah right now, each REST API filter is "and"ed with each other. What makes this a bit more nebulous here potentially is that the Posts Controller introduced a tax_relation query parameter. That can be used by users to make the taxonomy queries ORed with each other. Right now, the patch isn't built as a tax query, so the tax_relation query parameter wouldn't apply.

I think this is the correct way of handling this. Because the API isn't treating post formats as just another taxonomy, but a specifically handled flag.

So right now, I believe, if I ran a query of /posts?category=5&tag=7&tax_relation=OR&format=audio, we would return posts that have (either cat:5 OR tag:7) AND (format=audio). Might be worth adding a unit test specifically demonstrating this?

#12 @TimothyBlynJacobs
4 weeks ago

  • Keywords needs-unit-tests added

#13 @peterwilsoncc
3 weeks ago

When building the query in blocks.php, I think it will need a nested query based on the above.

<?php

'tax_query' => array(
  'relation' = 'AND',
  array(
    // Taxonomy query from block args tags, cateagory and tax_query
  ),
  array(
    relation = 'OR',
    array(
      'taxonomy' => 'post_format',
      'slug' => ( 'link', 'gallery' ),
    ),
    array(
      'taxonomy' => 'post_format',
      'operator' => 'NOT EXISTS', // Standard post type
    )
  ),
);


#14 @poena
3 weeks ago

Yes, in blocks.php the condition that is already in WP_REST_Posts_Controller is missing.

#15 @poena
3 weeks ago

Would this be correct?
The AND is not directly inside 'tax_query' => array(, it is still nested:

[19-Sep-2024 06:39:44 UTC] Array
(
    [post_type] => post
    [order] => DESC
    [orderby] => date
    [post__not_in] => Array
        (
        )

    [offset] => 0
    [posts_per_page] => 10
    [tax_query] => Array
        (
            [0] => Array
                (
                    [taxonomy] => category
                    [terms] => Array
                        (
                            [0] => 4
                        )

                    [include_children] => 
                )

            [1] => Array
                (
                    [relation] => AND
                    [0] => Array
                        (
                            [relation] => OR
                            [0] => Array
                                (
                                    [taxonomy] => post_format
                                    [field] => slug
                                    [operator] => NOT EXISTS
                                )

                            [1] => Array
                                (
                                    [taxonomy] => post_format
                                    [field] => slug
                                    [terms] => Array
                                        (
                                            [0] => post-format-link
                                            [2] => post-format-gallery
                                        )

                                    [operator] => IN
                                )

                        )

                )

        )

)

@noisysocks commented on PR #7314:


3 weeks ago
#16

Hey @carolinan. JavaScript packages were updated in r59072 so you might wish to rebase this for easier testing. The deadline to commit this backport is 6.7 Beta 1 which is scheduled for 1 October.

@peterwilsoncc commented on PR #7314:


3 weeks ago
#17

I tested this with the updated packages and was getting a block error when I tried to add the format. Is there something that needs to be merged to the packages in the GB repo before it should work?

https://github.com/user-attachments/assets/05e8f65e-0adc-4239-ba57-4540ed51c3dd

It's a little confusing with the same variable name in both the legacy query, the tax query so I'm wondering if we can do a little more tidying up there:

  • src/wp-includes/blocks.php

    diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php
    index f3d138475f..25cb1c0d24 100644
    a b function build_query_vars_from_query_block( $block, $page ) { 
    23462346                'order'        => 'DESC',
    23472347                'orderby'      => 'date',
    23482348                'post__not_in' => array(),
     2349                'tax_query'    => array(),
    23492350        );
    23502351
    23512352        if ( isset( $block->context['query'] ) ) {
    function build_query_vars_from_query_block( $block, $page ) { 
    23952396                }
    23962397                // Migrate `categoryIds` and `tagIds` to `tax_query` for backwards compatibility.
    23972398                if ( ! empty( $block->context['query']['categoryIds'] ) || ! empty( $block->context['query']['tagIds'] ) ) {
    2398                         $tax_query = array();
     2399                        $tax_query_back_compat = array();
    23992400                        if ( ! empty( $block->context['query']['categoryIds'] ) ) {
    2400                                 $tax_query[] = array(
     2401                                $tax_query_back_compat[] = array(
    24012402                                        'taxonomy'         => 'category',
    24022403                                        'terms'            => array_filter( array_map( 'intval', $block->context['query']['categoryIds'] ) ),
    24032404                                        'include_children' => false,
    24042405                                );
    24052406                        }
    24062407                        if ( ! empty( $block->context['query']['tagIds'] ) ) {
    2407                                 $tax_query[] = array(
     2408                                $tax_query_back_compat[] = array(
    24082409                                        'taxonomy'         => 'post_tag',
    24092410                                        'terms'            => array_filter( array_map( 'intval', $block->context['query']['tagIds'] ) ),
    24102411                                        'include_children' => false,
    24112412                                );
    24122413                        }
    2413                         $query['tax_query'] = $tax_query;
     2414                        $query['tax_query'] = array_merge( $query['tax_query'], $tax_query_back_compat );
    24142415                }
    24152416                if ( ! empty( $block->context['query']['taxQuery'] ) ) {
    2416                         $query['tax_query'] = array();
     2417                        $tax_query = array();
    24172418                        foreach ( $block->context['query']['taxQuery'] as $taxonomy => $terms ) {
    24182419                                if ( is_taxonomy_viewable( $taxonomy ) && ! empty( $terms ) ) {
    2419                                         $query['tax_query'][] = array(
     2420                                        $tax_query[] = array(
    24202421                                                'taxonomy'         => $taxonomy,
    24212422                                                'terms'            => array_filter( array_map( 'intval', $terms ) ),
    24222423                                                'include_children' => false,
    24232424                                        );
    24242425                                }
    24252426                        }
     2427                        $query['tax_query'] = array_merge( $query['tax_query'], $tax_query );
    24262428                }
    24272429                if ( ! empty( $block->context['query']['format'] ) && is_array( $block->context['query']['format'] ) ) {
    24282430                        $formats = $block->context['query']['format'];
    function build_query_vars_from_query_block( $block, $page ) { 
    24792481                         */
    24802482                        if ( count( $formats_query ) > 1 ) {
    24812483                                // Enable filtering by both post formats and other taxonomies by combining them with `AND`.
    2482                                 if ( isset( $query['tax_query'] ) ) {
    2483                                         $query['tax_query'][] = array(
     2484                                if ( empty( $query['tax_query'] ) ) {
     2485                                        $query['tax_query'] = $formats_query;
     2486                                } else {
     2487                                        $query['tax_query'] = array(
    24842488                                                'relation' => 'AND',
     2489                                                $query['tax_query'],
    24852490                                                $formats_query,
    24862491                                        );
    2487                                 } else {
    2488                                         $query['tax_query'] = $formats_query;
    24892492                                }
    24902493                        }
    24912494                }

However, the code looks good to me in terms of PHP, it's just the blcok crashing that needs to be figured out.

@poena commented on PR #7314:


3 weeks ago
#18

I have submitted a pull request that fixes this bug and it is waiting for review.

#19 @poena
3 weeks ago

Unfortunately, realistically I will not find the time to create the tests before Beta 1 as I also need to help finish Twenty Twenty-Five.

@poena commented on PR #7314:


2 weeks ago
#20

I'm wondering if we can do a little more tidying up there:

I don't mind :)

@poena commented on PR #7314:


2 weeks ago
#21

@peterwilsoncc My only question is about the first array_merge. The previous code replaced $query['tax_query'], the suggested update merges them, I would like to understand why?

-			$query['tax_query'] = $tax_query;
+			$query['tax_query'] = array_merge( $query['tax_query'], $tax_query_back_compat );

#22 @poena
2 weeks ago

I wanted to confirm that with the changes that @peterwilsoncc proposed, the log of the query is as follows, with the AND nested at the correct level:

[25-Sep-2024 05:22:23 UTC] Array
(
    [post_type] => post
    [order] => DESC
    [orderby] => date
    [post__not_in] => Array
        (
        )

    [tax_query] => Array
        (
            [relation] => AND
            [0] => Array
                (
                    [0] => Array
                        (
                            [taxonomy] => category
                            [terms] => Array
                                (
                                    [0] => 4
                                )

                            [include_children] => 
                        )

                )

            [1] => Array
                (
                    [relation] => OR
                    [0] => Array
                        (
                            [taxonomy] => post_format
                            [field] => slug
                            [operator] => NOT EXISTS
                        )

                    [1] => Array
                        (
                            [taxonomy] => post_format
                            [field] => slug
                            [terms] => Array
                                (
                                    [0] => post-format-link
                                    [2] => post-format-gallery
                                )

                            [operator] => IN
                        )

                )

        )

    [offset] => 0
    [posts_per_page] => 10
    [author__in] => Array
        (
        )

)

This ticket was mentioned in Slack in #core by poena. View the logs.


2 weeks ago

@peterwilsoncc commented on PR #7314:


13 days ago
#24

@peterwilsoncc[[Image(moz-extension://e0755463-33bf-47f8-a715-eba3a5588485/images/wp-logo.png)]] My only question is about the first array_merge. The previous code replaced $query['tax_query'], the suggested update merges them, I would like to understand why?

The suggested change always defined $query['tax_query'] and renamed the variables so they differed for the legacy queries, current query and formats. As a result it needed to merge rather than append the item.

However, I'm glad you asked because I want to double check I didn't just introduce a bug. I'll double check that prior to merge.

#25 @peterwilsoncc
12 days ago

  • Owner set to peterwilsoncc
  • Resolution set to fixed
  • Status changed from new to closed

In 59115:

REST API/Editor: Support post formats in Query Block & Posts API.

Introduces post format support for both the Query Block with the new parameter format. In the build_query_vars_from_query_block() function, this is converted to a post_format taxonomy query passed to WP_Query.

Also introduces the format parameter to the REST API's Posts controller to support the feature in the Query block. The parameter type is an enumerated string accepted the post formats supported by each post type.

Props poena, mukesh27, mamaduka, noisysocks, TimothyBlynJacobs.
Fixes #62014.

#27 @desrosj
8 days ago

In 59166:

Coding Standards: Committing changes after composer format.

This commits some minor changes made when running composer format.

Follow up to [58975], [59011], [59115].
See #61103, #62014, #61648.

Note: See TracTickets for help on using tickets.