Ultimate Guide to meta_query – Get and Order Posts by Meta Values
In this post I assume that you already have basic knowledge how to work with WP_Query class in WordPress. Before I begin, I want to show you some very simple examples. The similar examples you can find in WordPress Codex.
As you know all the posts have the metadata you can populate in "Custom fields" metabox (the metabox by the way can be hidden). So, for example, if you want to get a post with meta key show_on_homepage
and meta value on
, you can do it the following way:
$rd_args = array( 'meta_key' => 'show_on_homepage', 'meta_value' => 'on' ); $rd_query = new WP_Query( $rd_args );
Otherwise, if you need to query all posts except the ones with this pair of meta key and value, you can use the following parameters:
$rd_args = array( 'meta_key' => 'show_on_homepage', 'meta_value' => 'on', 'meta_compare' => '!=' ); $rd_query = new WP_Query( $rd_args );
Do not forget that all examples in this post are simplified, so, some of WP_Query parameters are missing, e.g posts_per_page
or post_type
.
If you are interested in other meta_compare
parameter values, please look at "compare" parameter description below, because both of them accept the same values.
This was very very simple examples, just an introdution. But this post is about meta_query
parameter. This parameter allows us to create a really cool post filters and search scripts.
Query Posts by a Meta Value
The simple example below allows you to get all the posts with a specific custom field value. Let’s just get all the posts with custom field name "color" and custom field value white
.
// the meta_key 'color' with the meta_value 'white' $rd_args = array( 'meta_query' => array( array( 'key' => 'color', 'value' => 'white' ) ) ); $rd_query = new WP_Query( $rd_args );
If you look at the post edit page (in admin area) in any post which matches the query, you will see the following in the "Custom Fields" section:

Let’s do the opposite thing – get all the posts except the ones with meta key "color" and meta value white
:
$rd_args = array( 'meta_query' => array( array( 'key' => 'color', 'value' => 'white', 'compare' => '!=' ) ) ); $rd_query = new WP_Query( $rd_args );
Get Posts by Multiple Meta Values
Now let’s get all the posts with white
OR green
"color" custom field value:
// custom field name is color and custom field value is 'white' OR 'green' $rd_args = array( 'meta_query' => array( array( 'key' => 'color', 'value' => array('white','green'), 'compare' => 'IN' ) ) ); $rd_query = new WP_Query( $rd_args );
Get all the posts (products in online shop for example) except white products and green products:
$rd_args = array( 'meta_query' => array( array( 'key' => 'color', 'value' => array('white','green'), 'compare' => 'NOT IN' ) ) ); $rd_query = new WP_Query( $rd_args );
How to use "compare" in meta_query
As you can see in example below and in further examples too, there is a compare
parameter in every of them. Now I would like to show which values it can accept and what do they mean.
=
(or not set) Equal to,!=
– Not equal to,<
– Less than,<=
– Less or equal to,>
– Greater than,>=
– Greater than or equal to, example:// the product price in this example is 2000 or more than 2000: $args = array( 'meta_query' => array( array( 'key' => 'price', 'value' => 2000, 'type' => 'numeric', // specify it for numeric values 'compare' => '>=' ) ) );
LIKE
– Allows to search in meta values for a specific string, in the example below the query returns all the posts where "first_name" name containsJohn
, it can be alsoJohnny
,Johnathan
,somethingJohnsomething
:$args = array( 'meta_query' => array( array( 'key' => 'first_name', 'value' => 'John', 'compare' => 'LIKE' ) ) );
Two more things: first – it is not case sensitive, second – wildcard symbols
@
are not necessary.NOT LIKE
– similar toLIKE
just works in an opposite way – meta value mustn’t contain the given string.IN
– posts meta value must contain one of the values of the given array, you can see the example aboveNOT IN
– meta values must not contain ANY of the values in the given array.BETWEEN
– post meta value should be between the given range of values, example:// the product price is more than 2000 and less than 4000 $args = array( 'meta_query' => array( array( 'key' => 'price', 'value' => array( 2000, 4000 ), 'type' => 'numeric', 'compare' => 'BETWEEN' ) ) );
It can also work for dates, check the example below too.
NOT BETWEEN
– not in a given range.EXISTS
(WordPress >= 3.5) – If meta value of a specific meta key exists or empty / null.$args = array( 'meta_query' => array( array( 'key' => 'misha_key', 'compare' => 'EXISTS' ) ) );
So, actually it checks if a meta key exists, you do not even have to pass any value with this parameter.
NOT EXISTS
(WordPress >= 3.5) – if a given meta key doesn’t exist at allREGEXP
(WordPress >= 3.7) – it allows you to compare meta values with regular expression, example:$args = array( 'meta_query' => array( array( 'key' => 'misha_key', 'value' => '^[0-9]*$', // "misha_key" must be only numbers 'compare' => 'REGEXP' ) ) );
NOT REGEXP
(WordPress >= 3.7) – Similar toREGEXP
but meta values must not match your given regular expressionRLIKE
(WordPress >= 3.7) – it is the synonym toREGEXP
How to Use "compare => between" for Dates in meta_query
You can also use meta_query
to check if a custom field is between two dates.
The most important thing you have to keep in mind is that your date format should be like YYYY-MM-DD
or YYYY/MM/DD
or something like that (year goes first, then month, then day, then time if you need it too). Check how it is stored in database – if it is stored in another format, for example days go first, then filtering won’t work for you until you change dates presence in database.
array( 'key' => 'sale_day', 'value' => array( '2018-01-01', '2018-01-09' ), 'compare' => 'BETWEEN' )
If the date is stored in UNIX time, example: 1543391233
, everything became super simple:
array( 'key' => 'sale_day', 'value' => array( strtotime('2018-01-01'), strtotime('2018-01-09') ), 'type' => 'numeric', 'compare' => 'BETWEEN' )
Multiple meta queries – get posts by multiple pairs of keys and values
Now I will show you how to combine posts by several (two or more) custom field values. First of all let me introduce you relation
parameter which can accept two vaues – OR
or AND
(default).
// the 'color' is 'white' AND the 'price' is more than 2000 and less than 4000 $rd_query = new WP_Query( array( 'meta_query' => array( 'relation' => 'AND', // both of below conditions must match array( 'key' => 'show_on_homepage', 'value' => 'on' ), array( 'relation' => 'OR', // only 'color' OR 'price' must match array( 'key' => 'color', 'value' => 'white' ), array( 'key' => 'price', 'value' => array( 2000, 4000 ), 'type' => 'numeric', 'compare' => 'BETWEEN' ) ) ) ) );
As you can see, in meta_query
above we used multiple relation
.
How to Sort Posts by Meta Values ("orderby" and "order" parameters)
I will show you different examples of how you can order your posts by meta values. First of all, look at this simple code sample, where we don’t even use meta query:
$args = array( 'meta_key' => 'misha_key', 'orderby' => 'meta_value' );
Now, let’s say that misha_key
contains only numeric values, we can change our code for that case just a little bit.
$args = array( 'meta_key' => 'misha_key', 'orderby' => 'meta_value_num' );
But how to use it together with meta query? Simple, just change our code the following way:
$args = array( 'meta_query' => array( 'misha_clause' => array( 'key' => 'misha_key', 'compare' => 'EXIST' ) ), 'orderby' => 'misha_clause' );
How to Order by Two and More Meta Keys
Yes, it is also possible since WordPress 4.2
$args = array( 'meta_query' => array( 'relation' => 'AND', 'price_clause' => array( 'key' => 'price', 'value' => array( 2000, 4000 ), 'type' => 'numeric', 'compare' => 'BETWEEN' ), 'misha_clause' => array( 'key' => 'misha_key', 'compare' => 'EXISTS' ), ), 'orderby' => array( 'price_clause' => 'ASC', 'misha_clause' => 'DESC' ), );
So, first of all we order posts by price_clause
ascending and then we order posts by misha_clause
descending.
Comments — 50
I’m trying to figure out how I would wrap a short code function around your code sample so that the admin could put in their own values to filter the meta content displayed on a page
[product_list color=”white” price=”100″]
I can’t seem to get the values to pass into the meta_query array? Could you please share an example of this.
Thank You
I hope it helps.
Hi man,
This seems like some nice clear examples of the WP_Query. I was working with the WP_Meta_Query and wondered how it was possible to just query for all values under a particular meta key. Say for example you have a custom field called member_city, and many posts use this to give location informations such as “This user is from London”.
What I’m actually trying to do is kind of hard to explain. I’m trying to get all custom meta data from the database, i.e all the cities, then output them into an array which can be used to generate a drop down menu that users can then select from to search users by location. I also don’t want this to duplicate cities, i.e if two people are from London, I don’t want London in the list twice. I’m using WordPress Advanced Search by Growth Spark for my search.
I’m able to query the database and get an output such as:
I just don’t know how to extract that information, then get it into my drop down. Does this make sense to you? May be confusing without code examples and understanding of the site architecture.
Fine and useful examples, happy new year!
Thanks a lot !!!
You are welcome!
Hi, i found this examples very good, but i have a doubt, what if i want to order by a metabox value. For example, I have a custom post type named team_member and this post-type have a metabox named order, later in the loop, i need query the post but ordering by this order that i defined in the metabox, How i could do this?
Thanks in advance.
Please sorry my english….
Hi,
WP_Query supports the
orderby
parameter, so it should look like this:thanks Misha, I try your code, but instead ‘orderby’=>’meta_value’ I used ‘orderby’=>’meta_value_num’ and it’s working perfect!!!! Thanks a lot for the answer.
Regards
Juankql
How would I come about showing all post if meta value doesn’t exist.
In my case I am querying post based on dropdown selection. And based on your example, the script is working just fine. It loads the post based on meta value. But what if in the dropdown selection I have a show all option. How can I come about doing that?
Thanks!
Do you need to get posts with exact meta key and with any meta value?
Here is the code I’m working with right now:
So here I get posts with specific meta selected from the dropdown menu, but if the user selects ALL i want to grab from all terms that exist.
I think you need something like this:
I just want to thank you for all the examples you’ve posted. It has given me some way to be able to start off with the project I’m doing, based on a query on premium post listing. Again, thank you.
I have a key that has 2 meta options: “id”:”12345″ , and “select new”
How can i return only the first? (the ome with the id?
Let me clarify — you have two meta values with the same key and you want to get posts with the first value only, is that right?
thanks @Misha for your reply :)
yes, the key is the same and i want to get in return only {“id”:”12345″} << which comes like this (including the ' " ' charachter and the ' : '.)
thanks !
I hope it helps :)
sure did!
thank you very much :)
Every custom field have two type of values. brand key values [ Apple or Nokia ] and Price key values [ 100$ or 200$ ]..
How to get posts for these checkboxs using custom field vlaue ??
Hello,
if I understand you properly, this is the part of the form filter, so put in your php file which process the form data the following code:
i put this code on single.php page inside php tag.. there is no output of this code..
is there need for any kind of echo for this value or fields????
Of course this is just the part of
$args
array, just a algorithm to you how to do it :)P.S. I think you need to read the official WP_Query reference as well.
Hello Misha,
Finally i make a custom field value filter form using AJAX and JSON but not working, can you please check it? When i check any box nothing happen, still remain as it was…. I also check console J query working properly..
Form.php
Script:-
function.php
If you send me a working filter form through email using this code. i will be really thankful to you..
Tomorrow I plan to publish a post about it.
Hi Misha, thanks for this info…. and since you seem to be very proficient in Wp_Query… Can I pick your brain a little bit and ask for your help:
I need to display posts (tours) that are in a specific location (city) so in my location_taxonomy.php I have a meta query in the form of:
When the key stored in the tour has only one value (one city), it displays the posts. When the key has more than one value (multiple cities or a string of ids separated by commas), it doesn’t.
How can I change the $args so the query would determine that the current city ($term->term_id) exists within the comma separated values stored as a string in ‘trav_tour_city’?
I have tried something in the line of:
and also I tried “LIKE”, but obviously I don’t know what I’m doing… haha..
any help would be greatly appreciated!
Regards,
Ivan
Hi Ivan,
LIKE should help:
This did the trick:
I will try yours also…
Thanks a lot for your input!
i have a custom -post-type that has 2 custom filed checkboxes
and i need to print only one cpt value for each selected field
and for each field i wan to have different ouptput
howcan i do that?
I’m not sure that I understand you, but maybe this post is what you are looking for.
Hi, Misha How are you? Just have little question about meta query. My meta query working fine in single data, but it can’t working if i use array in there. Any other need to do? i have follow all your step. Thanks :)
Hi Diaz,
Can I look at your meta query? 🙃
Thank you! Really helped me!
Hi Misha,
This is a great article!
I have a situation where a user enters a search terms and that populates the value in the argument via a variable. However, the field expects something to be entered before any results show.
So, do you know if it is possible to set the argument to show all results that can be later filtered to a smaller list of results?
I raised a ticket about it here that shows the code:
https://stackoverflow.com/questions/48725474/show-all-wordpress-authors-then-filter-the-list-by-meta-key
Thanks for your time
Damien
Hi Misha,
No need to worry about this, I actually had a misplaced IF statement in my code that caused this to not work. All good now.
Thanks
Hi Damien,
I’m glad you figured it out 🙂
For me, this didn’t work until I replaced “key” with “meta_key” and “value” with “meta_value”. ie:
I suggest looking into your phpAdmin page and opening the “metadata” table “structure” tab to make sure.
Very strange,
meta_key
andmeta_value
params are OK when using them outside meta_query.Hi,
Thank you for this post.
I am trying to put up a meta query to search for values that are in serialised format, for example:
a:3:{i:0;s:28:”Primary School (Classes 1-5)”;i:1;s:27:”Middle School (Classes 6-8)”;i:2;s:31:”Secondary School (Classes 9-10)”;}
My code is below:
But it does not give me desired results. Any help is appreciated.
Thanks!
Hello,
I have a problem with the sorting of my products. I have products which have no price and I want them to be in the end after all products with price. Can you please help me? Thanks!
Hello,
thank you for the post.
I wanted to get all the posts if the user selects no meta query. I tried this but it does not work.
This return no posts, I wanted if the value is empty, all posts should be shown.
Can you Please help me?
Hello,
Did you try
NOT EXISTS
? Example:Hi!
I looking for solution for my problem and find your post.
The intention is to search for customers who do not have coupon X or do not have any coupon.
I am doing according to other answers I found on the web, but the query returns wrong when it finds a post that has a meta_value different from the one searched.
Great article full of really helpful examples. Helped me out a lot today – thanks!
Hey, thanks for this!
what about this goal: to get all the posts (and cpts) that have a meta_key ‘my_meta_name’ corresponding to the post’s title, and to order them by their other meta_key ‘my_meta_date’, in DESC order.
I’ve tried this:
But no luck so far. The above stuff returns a bunch of posts not corresponding to my needs and not even correctly ordered :-)
Could you please enlighten me?
P.S. WP version is 5.3.2
Hey Marco,
Well, you code is far away from perfection, sorry 🙃
Hey Misha,
thanks for replying, hehe yeah I kinda thought it was a mess :-)
I also came out after a couple of hours with almost the exact code you’ve posted, but I still get mixed results so I guess the catch is somewhere else.
Thanks again!
Thanks for the nice write up! Helped me a lot today.
Hello Misha , i am totally new to the wp 😍 …
I have the following case :
there is a taxonomy calles restricted-sport for the certain type of post “user”.
So i have value $sport = ‘basket’, and i want to get from the query the 10 best user bases on overall rating and that the ‘basket’ is not in restricted-sport taxonomy.
After a research i have found that i can use tax_query, is that a correct approach?
and if yes how it is implemented ?
add to the wp_query array the following :
Comments are closed.