Using meta_query to Query Posts by Postmeta
A frequently overlooked enhancement that shipped with WordPress 3.1 has made querying posts by postmeta values significantly simpler. The WordPress core team made this improvement by adding the “meta_query” parameter to the WP_Query class. Previously, you could query and filter posts using a combination of the “meta_key”, “meta_value”, and “meta_compare” parameters; however, this came with a major limitation–you could only filter by a single postmeta field. With WordPress 3.1 and the addition of the “meta_query” parameter, you can query for posts based on numerous postmeta values.
To illustrate the power of this enhancement, imagine that you have a custom post type called “product” that allows you to manage your T-shirt inventory. Upon saving each product, you enter custom field values for “price”, “size”, and “sex”. Recognizing that you have an overstock of size “S” shirts for “men” that are under “$15.00″, you want to run a marketing campaign on your website to highlight shirts that fit this criteria. As such, you are faced with the task of creating a page that only displays these items. In order to query for these products, you can use “meta_query” in the following manner.
$args = array( 'post_type' => 'product', 'meta_query' => array( array( 'key' => 'price', 'value' => '15.00', 'compare' => '<', 'type' => 'NUMERIC' ), array( 'key' => 'size', 'value' => 'S', 'compare' => '=', 'type' => 'CHAR' ), array( 'key' => 'sex', 'value' => 'men', 'compare' => '=', 'type' => 'NUMERIC' ) ) ); $query = new WP_Query( $args );
In this example, for each key that you want to search by, you need to create a new array with parameters for the search. The first criteria for our query is that the price is less than $15. As such, I created an array that specified the key to be ‘price’, the criterion value to be ’15.00′, and the comparison operator to be ‘<'. Additionally, I added the type parameter and specified it to be 'NUMERIC' to inform the search that it is comparing numeric values. This array tells WP_Query that my first criteria is a post with an associated price less than $5. The remaining two criteria are specified in the same manner. As a result, I will only grab those posts that needed for the promotion. The results can then be printed out using the WordPress loop as usual.
Now, imagine that you want to order these posts by price, from lowest to highest. While one might think that simply specifying "orderby=price" would complete the task, it is not quite that easy. Rather strangely, to order your posts by postmeta values, you still need to specify the "meta_key" parameter in your arguments. Having to do this is confusing as this parameter is marked as "deprecated" in the WordPress Codex. This ordering would be accomplished with the following code.
$args = array( 'post_type' => 'product', 'meta_query' => array( array( 'key' => 'price', 'value' => '15.00', 'compare' => '<', 'type' => 'NUMERIC' ), array( 'key' => 'size', 'value' => 'S', 'compare' => '=', 'type' => 'CHAR' ), array( 'key' => 'sex', 'value' => 'men', 'compare' => '=', 'type' => 'NUMERIC' ) ), 'meta_key' => 'price', 'orderby' => 'meta_value', 'order' => 'ASC' ); $query = new WP_Query( $args );
Specifying the ‘meta_key’ parameter tells the function which field should be used for ordering the posts according to meta_values.
Prior to WordPress 3.1, this task was much more difficult. One would have to write a custom query or filter results after retrieving them from the database. While both strategies can be made to work, they are significantly more complicated and are not as future proof as using “meta_query”.
In summary, the addition of the “meta_query” parameter to the WP_Query class has made querying for posts based on meta_values a much simpler task and has introduced the ability to query by multiple meta_values.