WP REST API allows you to manipulate your website’s data using the REST API, so it’s a good choice if you want to communicate with a WordPress website from another website or app. Although working with WordPress REST API, you’ll probably discover the following problems:
- The official WP REST API handbook is not comprehensive
- There’s a lot of questions that even Google can’t answer
Well, at least that’s what I noticed when I first tried to experiment with the WP REST API. Back in the days, it was a problem for me because I had to dig through the WordPress source code, StackOverflow, and a lot of different online forums and communities to solve the problems I stumbled upon. Now, being a blogger, when I see that there’s a WordPress problem or question without a good answer, I think: “Wow, that’s a great opportunity to write a post about this!”.
So, as you might have guessed, today, I want to tell you how to filter WordPress posts by a meta field using the WP REST API. I hope you’ll find this post helpful; let’s get started!
How to filter posts by a meta field?
Let’s start with the regular WordPress posts that every WordPress website has by default. When the WordPress core team was working on the WP REST API, there was the filter parameter you could use. In those days, when you wanted to filter your WordPress posts by a meta field, you just used this parameter similarly to the meta_query parameter.
The WordPress core team decided to remove this parameter, understanding that it could cause some issues in the future. There are some plugins and snippets that return this feature to WordPress, but I do not recommend using any of them.
Instead, I’m going to show you a better (at least in my opinion) way to filter posts by a meta field in WP REST API. This method is really similar to the one we use to add custom filters in the WooCommerce orders table.
Let’s imagine that you have a post meta field called Source. The purpose of this meta field is to store the name of the source of the post you’re reposting or maybe citing. I’ve created a post with some random text and set its source meta field to “LinkedIn”.
How can I get WordPress posts with a meta field “source” equaling to “LinkedIn”?
We’re going to use the rest_post_query filter hook, allowing us to modify a WP_Query instance’s arguments before the query was executed. This hook takes two arguments: $args and $request. Using the last one, we can get a request’s parameters. So we can modify the $args argument based on a request’s parameters.
Here’s the code I’m going to use to change the WP_Query arguments based on the source query parameter’s value.
add_filter( 'rest_post_query', 'filter_posts_by_source_field', 999, 2 );
function filter_posts_by_source_field( $args, $request ) {
if ( ! isset( $request['source'] ) ) {
return $args;
}
$source_value = sanitize_text_field( $request['source'] );
$source_meta_query = array(
'key' => 'source',
'value' => $source_value
);
if ( isset( $args['meta_query'] ) ) {
$args['meta_query']['relation'] = 'AND';
$args['meta_query'][] = $source_meta_query;
} else {
$args['meta_query'] = array();
$args['meta_query'][] = $source_meta_query;
}
return $args;
}
To check if the code above works as expected, you need to send a GET request to the following URL: https://www.myblog.com/wp-json/wp/v2/posts/?source=LinkedIn.
Obviously, you’ll need to experiment with this code example to achieve the desired result. So I just wanted to communicate the main idea here: if you want to modify a posts’ query coming from your REST API, you need to use the rest_post_query filter hook.
How to filter a custom post type by a meta field?
The same logic will work for custom post types too. If you check the rest_post_query hook’s documentation page, you’ll see that it’s called rest_{$this->post_type}_query. What does that mean? It means that this hook will trigger for each registered post type.
All you need to do is pass your custom post type’s slug there, for example:
- rest_job_posting_query
- rest_porfolio_item_query
So, if the Source field I’ve created for the example above belonged to the job_posting custom post type, I’d need to rewrite my code just a little bit:
add_filter( 'rest_job_posting_query', 'filter_job_postings_by_source_field', 999, 2 );
function filter_job_postings_by_source_field( $args, $request ) {
if ( ! isset( $request['source'] ) ) {
return $args;
}
$source_value = sanitize_text_field( $request['source'] );
$source_meta_query = array(
'key' => 'source',
'value' => $source_value
);
if ( isset( $args['meta_query'] ) ) {
$args['meta_query']['relation'] = 'AND';
$args['meta_query'][] = $source_meta_query;
} else {
$args['meta_query'] = array();
$args['meta_query'][] = $source_meta_query;
}
return $args;
}
Now, a GET request to the https://www.myblog.com/wp-json/wp/v2/job_postings?source=LinkedIn URL will return an array of all job_posting post type’s posts where the source meta field equals to “LinkedIn“.
Summary
I see the lack of content about WP REST API compared to other WordPress features and related topics, so I really want to write more about it. If you’ve got any questions about WP REST API, feel free to contact me or just describe your problem in the comments section below.
In the next post, I want to discuss a similar topic: how to filter WooCommerce products and orders by a meta field using WooCommerce REST API. Thank you for your attention; see you in the next one!
Helpful. Thanks.
Glad to hear! You’re welcome
Nice article! How do I do when there is multiple fields I want to filter by?
Hi Tho! It depends. You can create a separate function for each filtered param or you can combine them in one function. Something like this:
https://pastebin.com/0vKdwncv
Thank you so much! I use Advanced Custom Fields, do I need to do something special then? The acf in the response is:
“acf”: {
“sku”: “”,
“artist”: “”,
“label”: “”,
“buying_price”: 0,
“asking_price”: 0,
“sold_for”: 0,
“sold_date”: null,
“sold”: false
},
I tried your code and then GET on http://www.mydomain.com/wp/v2/posts?acf.sold=0/1/true/false and http://www.mydomain.com/wp/v2/posts?sold=0/1/true/false
But the response is all posts?
I’m not sure that you’re doing it right. Why do you have dots in your meta fields names? Why do you use the JSON format?
Please, ping me at @kayart.dev">artemy@kayart.dev because the comments section is obviously not the best way to discuss such things 🙂
I’m sory, I’m not used to WordPress in general… but where is that function “add_filter()” declared?
I’m building some app that needs to get product information from WooCommerce database using its REST API, and need to filter by metadata… what am I missing?
Hi Hernan! This function is a part of the WordPress core. You can learn more about it and other in-built WordPress functions here:
https://developer.wordpress.org/reference/functions/add_filter/
It works with simple field, but in my case I have a subfield of repeter. Do you know how to modificate the code to filter by subfield?
Hi Elena! It depends on what exactly you need to achieve but maybe this post will be helpful for you:
https://penguin-arts.com/how-to-get-posts-in-wordpress-by-repeater-value/