As my first foray into WP5-era theme development I am trying to develop blocks to replace where I would normally use shortcodes and a metabox plugin. After a lot of learning I have finally managed to do everything I needed besides one (hopefully tiny) snag in a dynamic block that I am not sure how to get around.

The block I have made displays posts from a custom post type (“team”) where a custom field (“featured”) is set to true. I was naively hoping that I could just add meta parameters to my query like in WP Query but it seems not (at least with the various syntax I have tried..!) It works fine besides that it returns everything not just “featured” ones.

posts: select( 'core' ).getEntityRecords( 'postType', 'team', { order: 'asc', orderBy: 'menu_order', per_page: -1, metaKey: 'featured', metaValue: true } )

When I log the returned posts to the console, the value for featured is there so worst case I can use that to only render the ones I want but I would prefer to do it properly and only query the ones I need if that’s not terribly convoluted.

Can anyone help please?

1 Answer
1

(In hurry? Skip to the bottom for the code..)

So Gutenberg or the Block Editor uses the WordPress REST API when retrieving entity (e.g. postType>post and taxonomy>category) records (e.g. posts and terms).

For examples, for posts (post type of post), the route is /wp/v2/posts.

And for custom post types such as team, the default route is /wp/v2/team — you can change the team part via the rest_base parameter when you register the post type, which defaults to the post type slug.

But despite the routes are different, the default controller for posts (i.e. postType entity records) request is WP_REST_Posts_Controller, which you could change via the rest_controller_class parameter when registering the post type.

Having said that, you can see here for all the default parameters supported by that controller, and which one would supply as properties of the object in the third parameter of the wp.data.select( 'core' ).getEntityRecords():

wp.data.select( 'core' ).getEntityRecords( 'postType', 'post', {
  per_page: 2,
  orderby: 'title',
  ...
} );

Now if you look at those default parameters list, filtering the posts by metadata is (currently) not supported.

However, the good thing is that the default posts controller (WP_REST_Posts_Controller) has a hook you can use to modify the query/WP_Query parameters:

/**
 * Filters the query arguments for a request.
 *
 * Enables adding extra arguments or setting defaults for a post collection request.
 *
 * @since 4.7.0
 *
 * @link https://developer.wordpress.org/reference/classes/wp_query/
 *
 * @param array           $args    Key value array of query var to query value.
 * @param WP_REST_Request $request The request used.
 */
$args       = apply_filters( "rest_{$this->post_type}_query", $args, $request );

So in your case, you could make the meta query works like so:

add_filter( 'rest_team_query', function( $args, $request ){
    if ( $meta_key = $request->get_param( 'metaKey' ) ) {
        $args['meta_key'] = $meta_key;
        $args['meta_value'] = $request->get_param( 'metaValue' );
    }
    return $args;
}, 10, 2 );

That is just a basic example, but the main point is that you can use the rest_{post type slug}_query hook to filter the query.

And then in your getEntityRecords() call:

wp.data.select( 'core' ).getEntityRecords( 'postType', 'team', {
  // Default args.
  per_page: 2,
  orderby: 'title',

  // Custom args.
  metaKey: 'featured', // filter by metadata
  metaValue: '1' // not "true" unless the database value is exactly "true" (string)
} );

Leave a Reply

Your email address will not be published. Required fields are marked *