0

How can I retrieve posts, using backbone, that match a particular custom field value?

My custom fields are created through ACF.

Something like this doesn't work:

var data = {
    offset: 0, 
    _embed: 1,
    per_page: 100,
    _fields: "_embedded,_links,id,acf,title",
    meta_key: "status",
    meta_value: "new"
};
                                        
postsCollection
    .fetch({ data: data })
2
  • 1
    I posted an answer, but are you sure you don't want to use a custom taxonomy, because for example you could use a taxonomy named status, and then you would be able to easily filter the posts via the tax_relation parameter in the REST API, without having to use the filter hooks stated in my answer.
    – Sally CJ
    Commented Feb 7 at 19:00
  • Thanks. Yeah, I realised I could do this via a taxonomy, too. Though this would require converting the existing data structure and parts of the frontend, too.
    – MastaBaba
    Commented Feb 7 at 23:51

1 Answer 1

1

The REST API endpoint "List Posts" (e.g. GET /wp/v2/posts) does not support filtering the posts by a post meta (or custom field), therefore passing post meta parameters like meta_key and meta_value will by default do nothing.

But the rest_<post type>}_query filter can be used to manually add custom meta queries to the query arguments passed to WP_Query.

Here's an example for the core post type, but validation and sanitization is up to you…

add_filter( 'rest_post_query', 'my_filter_rest_post_query', 10, 2 );
function my_filter_rest_post_query( $args, $request ) {
    if ( isset( $request['meta_key'] ) ) {
        $args['meta_key'] = $request['meta_key'];

        // If the request did not include the meta_value parameter, or that it's a
        // null, then we do not set the meta_value argument. Which means, the API
        // response would include any posts that have the meta, regardless the value.
        if ( isset( $request['meta_value'] ) ) {
            $args['meta_value'] = $request['meta_value'];
        }
    }

    return $args;
}

So with that, your Backbone code should now work, but a better option, which makes use of the core validation functions, where validation is by default done automatically for you, is by registering your custom request parameter using the rest_<post type>_collection_params filter.

Here's an example where I used a single custom parameter named meta_status for your status meta:

add_filter( 'rest_post_collection_params', 'my_filter_rest_post_collection_params' );
function my_filter_rest_post_collection_params( $query_params ) {
    $query_params['meta_status'] = array(
        'anyOf' => array(
            array( 'type' => 'string' ),
            array( 'type' => 'null' ), // Allows a real null value.
        ),
        // Your other arguments here.
    );

    return $query_params;
}

Now the filter callback might look like:

add_filter( 'rest_post_query', 'my_filter_rest_post_query', 10, 2 );
function my_filter_rest_post_query( $args, $request ) {
    if ( array_key_exists( 'meta_status', $request->get_params() ) ) {
        $args['meta_key'] = 'status';

        // I've allowed a null value, therefore, if the meta_value parameter is a
        // null, then we do not set the meta_value argument. Which means, the API
        // response would include any posts that have the meta, regardless the value.
        if ( isset( $request['meta_status'] ) ) {
            $args['meta_value'] = $request['meta_status'];
        }
    }

    return $args;
}

Your Answer

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

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