So far in this series, you’ve learned how WP_Query
is structured and what its properties and methods are. Now we’re looking at the various arguments you can use with WP_Query
and how you code them.
WP_Query
has a large number of possible arguments, which makes it extremely flexible. As you can use it to query just about anything held in your wp_posts
table, it has arguments for every permutation of query you might want to run on your content.
In this tutorial I’ll look at arguments for querying taxonomy terms.
A Recap on How Arguments Work in WP_Query
Before we start, let’s have a quick recap on how arguments work in WP_Query
. When you code WP_Query
in your themes or plugins, you need to include four main elements:
- the arguments for the query, using parameters which will be covered in this tutorial
- the query itself
- the loop
- finishing off: closing
if
andwhile
tags and resetting post data
In practice this will look something like the following:
<?php $args = array( // Arguments for your query. ); // Custom query. $query = new WP_Query( $args ); // Check that we have query results. if ( $query->have_posts() ) { // Start looping over the query results. while ( $query->have_posts() ) { $query->the_post(); // Contents of the queried post results go here. } } // Restore original post data. wp_reset_postdata(); ?>
The arguments are what tells WordPress what data to fetch from the database and it’s those that I’ll cover here. So all we’re focusing on here is the first part of the code:
$args = array( // Arguments for your query. );
As you can see, the arguments are contained in an array. You’ll learn how to code them as you work through this tutorial.
Coding Your Arguments
There is a specific way to code the arguments in the array, which is as follows:
$args = array( 'parameter1' => 'value', 'parameter2' => 'value', 'parameter3' => 'value' );
You must enclose the parameters and their values in single quotation marks, use =>
between them, and separate them with a comma. If you get this wrong, WordPress may not add all of your arguments to the query or you may get a white screen.
The Taxonomy Parameters
Setting parameters for taxonomy terms is a little more complicated than for categories and tags since you use tax_query
. Within this argument you write a nested array of arguments to specify the taxonomy and term using these parameters:
-
taxonomy
(string): taxonomy -
field
(string): select taxonomy term by ('term_id
(default),'name'
or'slug'
) -
terms
(int/string/array): taxonomy term(s) -
include_children
(boolean): whether or not to include children for hierarchical taxonomies. Defaults to true. -
operator
(string): operator to test. Possible values are'IN'
(default),'NOT IN'
,'AND'
,'EXISTS'
and'NOT EXISTS'
.
The fact that you have the operator
parameter means you don’t need to choose from one of a range of available arguments to define whether you’re including or excluding terms (as you do for tags and categories), but use tax_query
for everything taxonomy-related instead.
If you want to query for multiple taxonomies, you can also use the relation
parameter before all of your arrays (one for each taxonomy) with AND
or OR
to specify whether you want to find posts with all of the terms or any of them.
This is most easily explained with some examples.
Querying for One Taxonomy Term
This is the simplest scenario and involves just using one nested array:
$args = array( 'tax_query' => array( array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => 'tutorial', ) ) );
The above queries for posts with the tutorial
term in the category
taxonomy. Note that you also need to use the field
parameter to identify which field you’re using to identify the term, unless you’re using the term ID which is the default. If you wanted to use the term ID you’d use something like this:
$args = array( 'tax_query' => array( array( 'taxonomy' => 'category', 'terms' => '11' ) ) );
Using the ID makes it harder for you to identify what your query is looking for at a later date, but avoids any potential problems if you think your users might edit the term slugs.
Querying For Multiple Terms in One Taxonomy
If you want to identify posts with one or more of an array of terms in the same taxonomy, you still write one nested array, but add an array of terms.
For example, to query posts with any of a list of term IDs from your taxonomy, you use:
$args = array( 'tax_query' => array( array( 'taxonomy' => 'post_tag', 'terms' => [14, 17] ) ) );
But what if you wanted to query posts with all of these terms? You’ll need to use the operator
parameter inside your nested array:
$args = array( 'tax_query' => array( array( 'taxonomy' => 'post_tag', 'terms' => [14, 17], 'operator' => 'AND' ) ) );
Note that the first example actually uses the IN
operator to find posts with any of the terms, but as this is the default you don’t have to specify it in your arguments.
Another scenario is if you want to query for posts which don’t have any of an array of terms in one taxonomy, which you do like this:
$args = array( 'tax_query' => array( array( 'taxonomy' => 'post_tag', 'terms' => [14, 17], 'operator' => 'NOT IN' ) ) );
Here I’ve replaced the AND
operator with NOT IN
, which means WordPress will find posts without any of the terms in the array.
Note that if you prefer to use slugs instead of term IDs, you can do so with any of these scenarios. The last example would look like this:
$args = array( 'tax_query' => array( array( 'taxonomy' => 'post_tag', 'field' => 'slug', 'terms' => ['php', 'strings'], 'operator' => 'NOT IN' ) ) );
Querying Terms From Multiple Taxonomies
If you want to work with more than one taxonomy, you’ll need to create more than one array. Let’s look at the simplest example, to query posts with one term from category taxonomy and one term from tag taxonomy:
$args = array( 'tax_query' => array( 'relation' => 'AND', array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => ['tutorial'] ), array( 'taxonomy' => 'post_tag', 'field' => 'slug', 'terms' => ['javascript'] ) ) );
Here I’ve written two nested arrays: one for each taxonomy, using the same arguments as I did for the examples using just one taxonomy. I’ve preceded these with the relation
argument. You need to include the relation
argument to tell WordPress whether it’s looking for all or some of the posts output by each array. This works as follows:
- If you use
'relation' => 'AND'
, WordPress will fetch the posts specified in the first array and the second array. So in the example above, only posts with both thetutorial
slug incategory
and thejavascript
slug inpost_tag
will be queried. - If you use
'relation' => 'OR'
, WordPress will fetch posts output by the first array or the second array. So in this case you’ll get posts with either thetutorial
slug or thejavascript
slug (or both).
This is the code you’d use if you were looking for posts with either of the two slugs:
$args = array( 'tax_query' => array( 'relation' => 'OR', array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => ['tutorial'] ), array( 'taxonomy' => 'post_tag', 'field' => 'slug', 'terms' => ['javascript'] ) ) );
You can also look for more than one term in a given taxonomy by adding it to the array:
$args = array( 'tax_query' => array( 'relation' => 'OR', array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => ['guide'] ), array( 'taxonomy' => 'post_tag', 'field' => 'slug', 'terms' => ['php', 'strings'] ) ) );
By combining the relation
argument with queries and also using the operator
argument, you can create sophisticated queries. The arguments below would query posts with a term from one taxonomy but without a term from another taxonomy:
$args = array( 'orderby' => 'title', 'tax_query' => array( 'relation' => 'AND', array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => ['tutorial'], 'operator' => 'NOT IN' ), array( 'taxonomy' => 'post_tag', 'field' => 'slug', 'terms' => ['php', 'math'], 'operator' => 'AND' ) ) );
Note that I’ve used 'relation' => 'AND'
here: if I used OR
, it would query posts with slug-two
and posts without slug-one
, rather than posts which have slug-two
but not slug-one
, which is what I’m looking for.
You could conceivably take this further to query your taxonomies’ terms however you wanted: using the operator
argument in both nested queries or adding an additional nested query to query terms in another taxonomy.
Nested Taxonomy Queries
It is possible for you to create nested taxonomy queries to create much more complex filters to get your posts. Support for nested taxonomies was added to WordPress core in version 4.1. It was either a lot more complicated or downright impossible to get similar results earlier.
$args = array( 'tax_query' => array( 'relation' => 'OR', array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => ['guide'], ), array( 'relation' => 'AND', array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => ['tutorial'], ), array( 'taxonomy' => 'post_tag', 'field' => 'slug', 'terms' => ['php', 'strings'], 'operator' => 'AND' ) ) ) );
The above query will select posts under category
taxonomy with the guide
slug or posts that have the tutorial
slug under category
and have the php
, strings
slug combination under post_tag
.
A Note on the tax Argument
You may be wondering why I haven’t included the {tax}
argument, where you simply write your argument as follows:
$args = array( 'taxonomy1' => 'slug-one' );
You may be familiar with this way of querying taxonomies if you’ve done it in the past, but it’s now deprecated and you shouldn’t use it. So stick to tax_query
! Using tax_query
gives you a lot more flexibility anyway.
Summary
Querying taxonomies is a bit more complicated than categories and tags, as you need to get to grips with the tax_query
argument.
However, as we’ve seen, this is a very powerful argument that gives you a lot of scope and flexibility to query your database in whatever way you wish.
This post has been updated with contributions from Nitish Kumar. Nitish is a web developer with experience in creating eCommerce websites on various platforms. He spends his free time time working on personal projects that make his everyday life easier or taking long evening walks with friends.