Tax_Query of WP_Query
In this guide, I would like to talk in-depth about using the tax_query parameter when creating custom loops with WP_Query, query_posts, get_posts or even when filtering existing loops with the pre_get_posts filter hook.
This one will be super-similar to a guide about Meta_Query, but, I guess, easier.
Getting Posts by Custom Taxonomy
Let’s start with the examples how you can use Tax_Query when creating custom loops with the WP_Query class.
1. Get posts by a custom taxonomy using its slug or ID
It is a pretty simple example. Let’s say, we want to get all coffee shops (a custom post type coffeeshop) in Athens (a custom taxonomy city), we can do it this way:
$q = new WP_Query( array(
'post_type' => 'coffeeshop',
'tax_query' => array(
// we have only one taxonomy condition in this tax_query
array(
'taxonomy' => 'city',
'field' => 'slug', // defaults to term_id
'terms' => array( 'athens' ),
),
),
) );We can easily query posts by a custom taxonomy ID instead of a slug, by changing these lines:
array(
'taxonomy' => 'city',
'terms' => array( 5 ),
),The field parameter default value is term_id, so we can feel free to remove it completely.
2. Get posts by multiple custom taxonomies
Before diving into the examples, I’d like to highlight that it can have two meanings:
- Either we get posts by multiple taxonomy terms of a single taxonomy,
- or we get posts by multiple custom taxonomies themselves.
Let’s take a look at both situations.
First of all, getting posts by multiple taxonomy terms is super simple – all we need to do is provide multiple values of the terms parameter. Something like this:
$q = new WP_Query( array(
'post_type' => 'coffeeshop',
'tax_query' => array(
array(
'taxonomy' => 'city',
'field' => 'slug',
'terms' => array( 'athens', 'lisbon', 'copenhagen' ),
),
),
) );The code above will return the posts that have at least one of the mentioned terms, if you need the posts to have all of them, read below about the operator parameter.
If we need to query multiple taxonomies, we need to add more arrays to tax_query:
$q = new WP_Query( array(
'post_type' => 'coffeeshop',
'tax_query' => array(
'relation' => 'AND',
// custom taxonomy condition 1
array(
'taxonomy' => 'city',
'field' => 'slug',
'terms' => array( 'athens', 'lisbon', 'copenhagen' ),
),
// custom taxonomy condition 2
array(
'taxonomy' => 'laptopfriendly',
'field' => 'slug',
'terms' => array( 'yes' ),
),
),
) );A couple of notes to the code below:
- As you can see, the
relationparameter comes into play. It allows us to define the relation between the taxonomy arrays, by default, its value isAND, it means that both conditions should apply, but you can change it toOR, if you need to. - Yes, I know, that the second condition can be better achieved with a custom field 😁
3. “operator” parameter of Tax_Query
Each taxonomy array of tax_query can have the operator parameter with one of the following values:
IN(default) – at least one of the terms,NOT IN– none of the terms,AND– all of the terms,EXISTS– any term from a given taxonomy,NOT EXISTS– none of the terms of a given taxonomy.
Let’s come back to our coffee shop example and try to get the ones that have any taxonomy term city assigned:
$q = new WP_Query( array(
'post_type' => 'coffeeshop',
'tax_query' => array(
array(
'taxonomy' => 'city',
'operator' => 'EXISTS',
),
),
) );4. Complex conditions
The cool thing about arrays inside the tax_query parameter is that you combine them together with the relation parameter in any order and on different levels.
$args = array(
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'taxonomy_1',
'field' => 'slug',
'terms' => array( 'taxonomy-1-term-1' ),
),
array(
'relation' => 'OR',
array(
'taxonomy' => 'taxonomy_2',
'operator' => 'EXISTS',
),
array(
'taxonomy' => 'taxonomy_3',
'operator' => 'EXISTS',
),
),
),
);
$q = new WP_Query( $args );With the help of this code snippet you can get posts that have the “Term 1” term of a “Taxonomy 1” AND any terms from either “Taxonomy 2” OR “Taxonomy 3”.
Modifying Tax_Query of an existing loop with pre_get_posts
I think it is also worth showing you examples of modifying the tax_query argument of an existing loop using the pre_get_posts action hook (or the query_loop_block_query_vars filter hook).
By the way, the same approach I am about to show is used by my Taxonomy Filter Block plugin.
Let’s say that we have a specific loop which may or may not have the tax_query parameter at this moment, and we need to add another condition into that. How we can do it?
add_action( 'pre_get_posts', function( $query ) {
// the result tax_query
$tax_query = array();
// let's get the current tax_query value from the loop
$current_tax_query = $query->get( 'tax_query' );
// that's what we need to add
$new_tax_query = array(
'taxonomy' => 'city',
'field' => 'slug',
'terms' => array( 'athens' ),
);
// if tax_query already exists, we need to merge them
if( ! empty( $current_tax_query ) ) {
$tax_query[ 'relation' ] = 'AND';
$tax_query[] = $current_tax_query;
}
$tax_query[] = $new_tax_query;
$query->set( 'tax_query', $tax_query );
} );This code can be written in different ways, I tried to make it as simple as possible for you.
Category and Tag Parameters of WP_Query
All the parameters in this chapter have been kind of obsolete since the moment the tax_query parameter appeared. However, you can find them pretty often when working with the code of other WordPress developers.
Let’s take a look at all of them.
Category parameters:
| Parameter | Description |
|---|---|
cat | Pass a category ID in this parameter. You can pass multiple values, comma-separated. |
category_name | Use a category slug (not name) here, multiple comma-separated values are also supported. |
category__and | An array of category IDs a post should have. |
category__in | An array of category IDs a post must have at least one of them. |
category__not_in | An array of category IDs a post shouldn’t have. |
For example, when we need to display posts from either “WordPress” or “WooCommerce” category:
$q = new WP_Query( array( 'category_name' => 'wordpress,woocommerce' ) );Or when we need to display posts that have posts of them at the same time:
$q = new WP_Query( array( 'category_name' => 'wordpress+woocommerce' ) );Tag parameters:
| Parameter | Description |
|---|---|
tag | Accepts a tag slug, multiple comma-separated values are supported. |
tag_id | Accepts a tag ID, multiple comma-separated values are supported. |
tag__and | An array of tag IDs, a post should have all of them. |
tag__in | An array of tag IDs, a post should have at least one of them. |
tag__not_in | An array of tag IDs a post shouldn’t have. |
tag_slug__and | An array of tag slugs, a post should have all of them. |
tag_slug__in | An array of tag slugs, a post should have at least one of them. |
Taxonomy parameters:
| Parameter | Description |
|---|---|
{$taxonomy_name} | This parameter accepts taxonomy term slugs. |
For example:
$q = new WP_Query( array( 'city' => 'athens' ) );
Misha Rudrastyh
Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
Thanks Misha!
I have such a scenario:
Products should filter by category and stock quantity.
If the category slug is “fabric”, then the stock quantity should be greater than 2,
If the category slug is “pattern”, then the stock quantity should be greater than 0.
How to achieve this?