Ultimate Guide to meta_query – Get and Order Posts by Meta Values

Basically meta_query parameter of WP_Query allows you to search WordPress posts / pages / custom post types by their meta data and sort the result.

/44 comments

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:

the meta_key and the meta_value

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.

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.

More about queries

Misha Rudrastyh

Misha Rudrastyh

I love WordPress, WooCommerce and Gutenberg so much. 10 yrs of experience.

Need some custom developer help? Let me know

Follow Misha

Need some help with WordPress?

If you need some professional developer help, I will be happy to assist you.

Contact me Who I am?

Comments — 44

Leave a comment

php js HTML CSS Code

I will only use your personal information to contact you. Privacy Policy