Sorting wordpress posts by several numeric custom fields

Sorting by several custom fields (meta values) in WordPress seems like it should be easy. It is, but this is one of those things that are a little bit tricky to figure out how to do without having to write custom sql queries. I thought I would post the best solution I’ve found so far here in case it helps someone else in the future. Thanks to Rico at smartcode for the clearest explanation of the basics. This is more or less a replication of his post, with some minor edits and additions.

First, make sure you have the meta keys you want to sort by available in your arguments.


$args = array(
	'post_type'		=> 'your_post_type', 
	'meta_key'		=> 'your_first_metakey',
	'meta_query'	=> array(
		array(
		'key' => 'your_first_metakey'
		),
		array(
		'key' => 'your_second_metakey',
		),
	)
);

Next, we need a filter function for the query. This modifies your query to sort by the first and second meta keys values. mt1 is a synonym for “meta key 1” and mt2 refers to “meta key 2”. As you see, this function is generic and you could use it in several queries where you want to sort by any two meta keys that you have specified in your arguments.

Now there is a funny little +0 at the end of the second meta key reference. What it does is specify that we want to make a numeric comparison. In a simple meta query you would instead replace “meta_value” with “meta_value_num” but that doesn’t work in this filter. An alternative to the +0 trick is to cast your data as decimal. You would then replace mt2.meta_value+0 with cast(mt2.meta_value as decimal).


function customorderby($orderby) {
	return 'mt1.meta_value DESC, mt2.meta_value+0 DESC';
}

Now apply your filter. Add it before your query and remove it afterwards to make sure it doesn’t affect subsequent queries.


add_filter('posts_orderby','customorderby');
$query = new WP_Query( $args );
remove_filter('posts_orderby','customorderby');

When you start making more complex queries like this in WordPress you will probably notice some decrease in performance. My preferred way of dealing with that is to cache the results of complex queries with WordPress transients. If you haven’t worked with transients yet, I highly recommend checking them out when you have time.

Happy coding!