This post assumes you have basic knowledge of the WP_Query class in WordPress. I’ll start with some basic examples similar to those in the WordPress Codex, then move to the real power: meta_query.
These examples are relevant when you want to create a filter for posts or an advanced search in WordPress or in a WooCommerce store.
As you probably know, you can add meta fields (metadata) to all posts under the ” Custom Fields ” box.
For example, if you want to retrieve all posts with a meta key named show_on_homepage and a meta value equal to on, you can do this as follows:
$sv_args = array(
'meta_key' => 'show_on_homepage',
'meta_value' => 'on'
);
$sv_query = new WP_Query( $sv_args );On the other hand, if you want to retrieve all posts except those with the meta key and value mentioned above, you can do this as follows with the following parameters:
$sv_args = array(
'meta_key' => 'show_on_homepage',
'meta_value' => 'on',
'meta_compare' => '!='
);
$sv_query = new WP_Query( $sv_args );The examples in this post are simplified and omit common WP_Query parameters like
posts_per_pageorpost_type. Add those in your actual implementation.
These are basic examples. This post is mainly about the meta_query parameter, which lets you build more complex filters for your posts or products.
Examples of using meta_query
Retrieving posts with a specific value in the custom field
A simple example – retrieve all posts with a custom field named color and a value of white:
// the meta_key 'color' with the meta_value 'white'
$sv_args = array(
'meta_query' => array(
array(
'key' => 'color',
'value' => 'white'
)
)
);
$sv_query = new WP_Query( $sv_args );If you go to the WordPress admin interface and look at the edit page of each of those posts that are returned in this loop, you will find the following custom field:

To retrieve all posts but not those with the custom field color with the value white:
$sv_args = array(
'meta_query' => array(
array(
'key' => 'color',
'value' => 'white',
'compare' => '!='
)
)
);
$sv_query = new WP_Query( $sv_args );Now let’s retrieve all posts with the value white or green:
// custom field name is color and custom field value is 'white' OR 'green'
$sv_args = array(
'meta_query' => array(
array(
'key' => 'color',
'value' => array('white','green'),
'compare' => 'IN'
)
)
);
$sv_query = new WP_Query( $sv_args );Retrieve all posts (products in a WooCommerce store, for example) except for white or green products:
$sv_args = array(
'meta_query' => array(
array(
'key' => 'color',
'value' => array('white','green'),
'compare' => 'NOT IN'
)
)
);
$sv_query = new WP_Query( $sv_args );Retrieving all fields within a specific numeric range
For example, let’s filter in a WooCommerce store all products priced between 2000 and 4000:
// the product price is more than 2000 and less than 4000
$sv_args = array(
'meta_query' => array(
array(
'key' => 'price',
'value' => array( 2000, 4000 ),
'type' => 'numeric',
'compare' => 'BETWEEN'
)
)
);
$sv_query = new WP_Query( $sv_args );Numeric comparison
In the next example, let’s filter all products priced at 2000 and above:
$sv_args = array(
'meta_query' => array(
array(
'key' => 'price',
'value' => 2000,
'type' => 'numeric',
'compare' => '>='
)
)
);
$sv_query = new WP_Query( $sv_args );Products priced below 4000:
$sv_args = array(
'meta_query' => array(
array(
'key' => 'price',
'value' => 4000,
'type' => 'numeric',
'compare' => '<'
)
)
);
$sv_query = new WP_Query( $sv_args );Retrieving posts by multiple custom fields
Let’s combine several of the examples we presented earlier:
// the 'color' is 'white' AND the 'price' is more than 2000 and less than 4000
$sv_args = array(
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'show_on_homepage',
'value' => 'on'
),
array(
'relation' => 'OR',
array(
'key' => 'color',
'value' => 'white'
),
array(
'key' => 'price',
'value' => array( 2000, 4000 ),
'type' => 'numeric',
'compare' => 'BETWEEN'
)
)
)
);
$sv_query = new WP_Query( $sv_args );Performance tip
Meta queries hit the wp_postmeta table with JOINs, which can get slow on large sites. If you are filtering by the same meta fields frequently, consider using a custom taxonomy instead – taxonomies are indexed by default and scale better. For ACF users, I wrote a separate post on optimizing database queries in ACF.
Summary
The meta_query parameter in WP_Query is one of the most useful tools for building custom loops. Once you get comfortable with the compare operators and the relation key for combining conditions, you can filter posts by almost anything stored in custom fields.
I use meta_query constantly on client sites, especially in WooCommerce stores where product filtering gets complex fast. If you want to go deeper into WordPress queries, check out my post on modifying the WordPress loop with pre_get_posts.
FAQs
Common questions about WP_Query and meta_query:
meta_key/meta_value and meta_query?
meta_key and meta_value are legacy parameters that handle simple single-field lookups. meta_query supports multiple fields, nested conditions with AND/OR relations, type casting, and advanced comparison operators. Use meta_query for anything beyond the simplest case.meta_query?
relation key. The outer array can have 'relation' => 'AND' while an inner array uses 'relation' => 'OR', as shown in the last example in this post.meta_query work with custom post types?
meta_query works with any post type. Just add 'post_type' => 'your_cpt' to the WP_Query arguments alongside your meta_query.meta_query calls can become slow. For frequently filtered data, consider using custom taxonomies or adding a database index on the relevant meta keys.meta_query clause a named key (e.g. 'price_clause'), then set 'orderby' => 'price_clause' in the main WP_Query args. This is cleaner than using the legacy meta_key parameter for ordering.
