3

I’m trying to apply the pre_get_posts to a specific core/query block, in order to programatically modify the number of posts displayed when a custom attribute is set. If I use the render_block hook, the block is already pre-rendered and so modifying the query using pre_get_posts has no effect. Is there any way to achieve this?

(I don't need help adding the custom attribute; I've done so already using block filters.)

1

2 Answers 2

2

Update:

It's possible to use the render_block_data filter to modify the query block's data before it's rendered.

Since 6.1. the query_loop_block_query_vars filter is available if one needs to modify the underlying WP_Query arguments (e.g. those that are still unsupported by the query block's interface) but it only works for the front-end but not the editor preview that uses the REST API (see more on that in the docs here).

Original answer:

There's an open ticket for such a query args filter #54850.

In the meanwhile you can try this approach, replacing the render callback of the core/post-template block with a wrapper callback:

add_filter( 'block_type_metadata_settings', function( $settings ) {
    if ( $settings['parent'][0] !== 'core/query' ) {
        return $settings;
    }
    if ( $settings['render_callback'] !== 'render_block_core_post_template' ) {
        return $settings;
    }
    $settings['render_callback']= 'wpse_render_block_core_post_template';
    return $settings;
}); 

with the wrapper callback as:

function wpse_render_block_core_post_template($attributes, $content, $block ){
    $output = render_block_core_post_template( $attributes, $content, $block );
    return $output;
}

Now we have a better way to target the WP_Query instance within that core template.

Following are two such examples.

Example with pre_get_posts

Here's an example how to override the number of posts with the help of the pre_get_posts hook:

function wpse_render_block_core_post_template( $attributes, $content, $block ) {
    $cb = fn( $q ) => $q->set( 'posts_per_page', 2 );
    
    add_action( 'pre_get_posts', $cb, 999 );
    $output = render_block_core_post_template( $attributes, $content, $block );
    remove_action( 'pre_get_posts', $cb, 999 );

    return $output;
}

Example with block context

We could also change existing query arguments within build_query_vars_from_query_block(), like perPage, with:

function wpse_render_block_core_post_template( $attributes, $content, $block ) {
    $block->context['query']['perPage'] = 2;
    return render_block_core_post_template($attributes, $content, $block );
}

Then you can add further restrictions as needed to both approaches, from e.g. other block info, like queryId.

9
  • Thanks for the link; the ticket was raised by a colleague with the same problem. That's a clever idea with the simple customisation of the render process. May 13, 2022 at 17:37
  • Unfortunately, the code seems to have no effect. wpse_render_block_core_post_template is never called. May 13, 2022 at 17:44
  • Try e.g. $block->context['query']['perPage']=2; just before render_block_core_post_template() in our wrapper. This should also work to modify existing parameters (like perPage), not introducing new ones. @MarkHowells-Mead
    – birgire
    May 14, 2022 at 11:32
  • Updated the answer with two examples @MarkHowells-Mead
    – birgire
    May 14, 2022 at 11:51
  • Thanks for all your help. Re-defining the callback using block_type_metadata_settings works, but the render callback wpse_render_block_core_post_template is never called for the core/query block. May 16, 2022 at 9:22
1

A modified version of the suggestion from @birgire works. Note that this applies to the core/post-template block, not the core/query block.

add_filter('block_type_metadata_settings', function ($settings, $metadata) {
    if ($metadata['name'] !== 'core/post-template') {
        return $settings;
    }
    if ($settings['render_callback'] !== 'render_block_core_post_template') {
        return $settings;
    }
    $settings['render_callback'] = 'wpse_render_block_core_post_template';
    return $settings;
}, 10, 2);

function wpse_render_block_core_post_template($attributes, $content, $block)
{
    $callback = fn ($query) => $query->set('posts_per_page', 2);

    add_action('pre_get_posts', $callback, 999);
    $output = render_block_core_post_template($attributes, $content, $block);
    remove_action('pre_get_posts', $callback, 999);

    return $output;
}
1
  • good idea to use the metadata for better targetting
    – birgire
    May 19, 2022 at 10:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.