“I only want winter products in this list.”—tax_query is how you filter by custom taxonomy terms. Learning this basic shape is enough to get going.
<?php
$query = new WP_Query([
'post_type' => 'shohin',
'tax_query' => [
[
'taxonomy' => 'season', // the taxonomy name
'field' => 'slug', // what you're passing to terms
'terms' => 'winter', // the term you want
],
],
]);
?>tax_query has a nested structure—an array of condition arrays. That’s the first hurdle, so getting your eye used to the shape keeps you out of trouble.
What the three keys mean
| Key | Role | Values you can use |
|---|---|---|
taxonomy | Which taxonomy | The slug you registered with register_taxonomy() (category / post_tag work too) |
field | What you’re passing to terms | 'slug' / 'term_id' (default) / 'name' |
terms | The term(s) you want | A single value or an array |
operator | The direction of the condition | 'IN' (default) / 'NOT IN' / 'AND' / 'EXISTS' / 'NOT EXISTS' |
Choosing an operator
// winter or spring (has either one)
[
'taxonomy' => 'season',
'field' => 'slug',
'terms' => ['winter', 'spring'],
'operator' => 'IN', // the default
],
// anything but winter
[
'taxonomy' => 'season',
'field' => 'slug',
'terms' => 'winter',
'operator' => 'NOT IN',
],
// only items that have both winter and limited
[
'taxonomy' => 'season',
'field' => 'slug',
'terms' => ['winter', 'limited'],
'operator' => 'AND',
],
// everything that has any season at all
[
'taxonomy' => 'season',
'operator' => 'EXISTS',
],The difference between IN and AND when terms is an array comes up a lot in practice. “Any one of these” is IN; “all of these” is AND.
Combining several taxonomies
Line up two or more conditions and let relation decide how they’re joined.
<?php
$query = new WP_Query([
'post_type' => 'shohin',
'tax_query' => [
'relation' => 'AND', // only items satisfying both
[
'taxonomy' => 'season',
'field' => 'slug',
'terms' => 'winter',
],
[
'taxonomy' => 'brand',
'field' => 'slug',
'terms' => ['shimaenaga', 'kotori'],
],
],
]);
?>'relation' => 'AND'—satisfy every condition (this is also the default)'relation' => 'OR'—satisfy any one of them
For categories and tags, the dedicated arguments are shorter
Standard categories and tags have shorter forms available. For simple filtering, these are plenty.
'category_name' => 'news', // category slug
'category__in' => [3, 7], // category IDs
'tag' => 'sale', // tag slug
'tag__in' => [12], // tag IDsYou need tax_query when you’re using a custom taxonomy, or when you need finer conditions like NOT IN and AND, or combinations of taxonomies.
Example: filter by the term you’re currently viewing
For when you want conditional output of a term’s posts on its taxonomy archive page.
<?php
$term = get_queried_object(); // the term currently being displayed
$query = new WP_Query([
'post_type' => 'shohin',
'tax_query' => [
[
'taxonomy' => $term->taxonomy,
'field' => 'term_id',
'terms' => $term->term_id,
],
],
'posts_per_page' => 12,
]);
?>get_queried_object() returns “the subject of the current page,” which on a taxonomy archive is a term object.
Example: show posts sharing a term as related posts
<?php
$terms = wp_get_post_terms(get_the_ID(), 'season', ['fields' => 'ids']);
$related = new WP_Query([
'post_type' => 'shohin',
'post__not_in' => [get_the_ID()],
'posts_per_page' => 4,
'tax_query' => [
[
'taxonomy' => 'season',
'field' => 'term_id',
'terms' => $terms,
],
],
]);
?>Pass ['fields' => 'ids'] to wp_get_post_terms() and you get an array of IDs, which drops straight into terms.
Combining with custom field conditions
tax_query and meta_query can be used together—filtering like “winter products that are in stock.”
'tax_query' => [['taxonomy' => 'season', 'field' => 'slug', 'terms' => 'winter']],
'meta_query' => [['key' => 'stock', 'value' => 0, 'compare' => '>', 'type' => 'NUMERIC']],TipsFiltering and sorting by custom field with meta_queryHow to write meta_query, and how to sort with itSummary
tax_queryhas a nested structure—condition arrays inside an array. The three-part set istaxonomy/field/terms- Passing a slug means
'field' => 'slug'is required (the default is term_id) - Switch between
IN/NOT IN/ANDwithoperator, and join multiple conditions withrelation - For standard categories and tags,
category_nameandtagare shorter. When nothing works, check the names withvar_dump
Once filtering is second nature, you can build many different lists from the same post data.