GeneratorsQueryTax Query Builder

Tax Query Builder

Taxonomy clauses that mean what you think they mean — the field matching your terms, the operator matching your intent, and one JOIN per clause accounted for.

post-tax-query.php
Saved just now
Clauses
2 clauses · 2 JOINs
Matchevery clause must match
categoryIN
include_children
IN 2 × slug
post_tagNOT IN
include_children
NOT IN 1 × slug
The query around it
no_found_rows
Skips the COUNT query, correct whenever you are not paginating.
Skip the meta cache
Right when the loop never touches post meta.
A secondary query with its own loop and wp_reset_postdata().
// Generated with WP CodeKit — powered by GrowQuest (https://growquest.io).
$args = array(
	'post_type'      => 'post',
	'posts_per_page' => 12,
	'tax_query'      => array(
		'relation' => 'AND',
		array(
			'taxonomy' => 'category',
			'field'    => 'slug',
			'terms'    => array( 'guides', 'tutorials' ),
		),
		array(
			'taxonomy' => 'post_tag',
			'field'    => 'slug',
			'terms'    => 'archived',
			'operator' => 'NOT IN',
		),
	),
);

$query = new WP_Query( $args );

if ( $query->have_posts() ) {
	echo '<ul>';

	while ( $query->have_posts() ) {
		$query->the_post();
		printf(
			'<li><a href="%1$s">%2$s</a></li>',
			esc_url( get_permalink() ),
			esc_html( get_the_title() )
		);
	}

	echo '</ul>';
	wp_reset_postdata();
} else {
	esc_html_e( 'Nothing found.', 'mytheme' );
}

About this generator

Tax Query Generator Online

Write a tax_query where the field matches the values you actually have. This tax_query generator builds one clause per taxonomy — taxonomy slug, field, operator, terms and include_children — sets the relation between them, and wraps the result in a WP_Query, a bare args array or a pre_get_posts callback.

A Reference tab restates the clause set in plain English, documents every clause key with its type, and shows the nested-group syntax you need when one relation is not enough. Free, client-side only, nothing uploaded.

Reviewed Output tested on WordPress 6.8 · PHP 8.3

Why the tax_query builder beats hand-writing the clause array

A tax_query fails quietly. Give it a taxonomy that is not registered, or terms that do not match the field you named, and WP_Tax_Query drops the clause instead of erroring — so the query returns everything and looks like a caching bug. This builder catches those mismatches while you are still typing them.

Field and terms checked against each other

Asking to match on term_id or term_taxonomy_id while your term list contains a word is an error, named with the offending value and a one-click "Match on slug" fix. The reverse — matching on slug when every term you listed is numeric — is a warning with a "Match on term_id" fix.

Empty clauses are errors, not silence

A clause with no taxonomy, or with an operator that needs terms and has none, is flagged as an error with the exact reason: the clause is dropped and the query returns everything.

include_children advice that knows your taxonomy

It recognises hierarchical taxonomies such as category and product_cat. Turning include_children off on one of them warns that posts in child terms will stop matching; leaving it on for a flat taxonomy such as post_tag is flagged as harmless noise.

The JOIN count is stated out loud

Every clause is a JOIN against wp_term_relationships. Two or more clauses with AND gets a note that each condition must match the same post; more than three clauses gets a warning to measure the query before shipping it.

Operators that read the way you meant

AND with a single term behaves identically to IN and is called out as misleading. EXISTS and NOT EXISTS ignore the terms field entirely, so listing terms alongside them raises a warning. A single category clause on term_id is pointed at category__in, which does the same thing in one line.

Nested groups documented, not guessed

The Reference tab shows the exact shape of a nested tax_query — an outer relation, a plain clause, then an inner array with its own relation — which is the only way to express "A and (B or C)".

How does the tax query generator work?

Clauses first, then the query that carries them. The plain-English restatement in the Reference tab updates as you go, so you can read the filter back before you trust it.

  1. 01

    Add a clause per taxonomy

    Set the taxonomy slug — category, post_tag, product_cat or your own — then choose whether your values are term IDs, slugs, names or term_taxonomy_ids.

  2. 02

    Pick the operator and list the terms

    IN matches any of them, NOT IN excludes, AND requires every one, and EXISTS / NOT EXISTS only ask whether the post has any term in that taxonomy. Terms are comma separated. Toggle include_children per clause.

  3. 03

    Set the relation and the query around it

    Choose AND or OR between clauses, then set the post type, posts_per_page, ordering, fields and the no_found_rows and meta-cache flags for the query that wraps them.

  4. 04

    Clear the checks, then export

    Apply the suggested field swaps, then take the full WP_Query with its loop, the args array alone, or the pre_get_posts version that filters the archive instead of duplicating it.

Worked example — posts in Guides or Tutorials, excluding anything tagged archived

Two clauses joined with AND: the post must be in one of two categories and must not carry the archived tag. include_children is left at its default of true on the category clause, so posts filed in a subcategory still match.

$args = array(
	'post_type'      => 'post',
	'posts_per_page' => 12,
	'tax_query'      => array(
		'relation' => 'AND',
		array(
			'taxonomy' => 'category',
			'field'    => 'slug',
			'terms'    => array( 'guides', 'tutorials' ),
		),
		array(
			'taxonomy' => 'post_tag',
			'field'    => 'slug',
			'terms'    => 'archived',
			'operator' => 'NOT IN',
		),
	),
);

The operator key is only written when it is not the default IN, and include_children only when you turn it off — so the array stays as short as the intent requires.

tax_query — frequently asked questions

What people ask on the support forums when a taxonomy filter returns the wrong posts.

How do I combine AND and OR in the same tax_query?

Nest a clause group. Since WordPress 4.1 an entry in a tax_query can itself be an array with its own relation, so "in Guides AND (tagged php OR tagged js)" is an outer relation => AND containing one plain category clause and one inner array with relation => OR and two tag clauses. A single flat list only supports one relation for all clauses, which is why mixing them without nesting silently gives the wrong result.

Why is my tax_query returning every post instead of filtering?

Almost always a dropped clause. WP_Tax_Query discards a clause whose taxonomy is not registered at the time the query runs, or whose terms array is empty after sanitising, and the query then runs with no taxonomy condition at all. Check the taxonomy slug spelling, confirm registration happens on init before the query, and make sure your terms variable is not an empty array.

Should I use slug or term_id in a tax_query?

Whichever matches the values you hold, and set field to say so. term_id is stable across renames and is what most code has to hand; slug is readable and survives an export/import into a site with different IDs. Avoid name — display names are not unique across a taxonomy, so a name match can hit a term you did not mean. A mismatch between field and your values means the clause matches nothing.

Does a category query include posts in child categories?

Yes, by default. include_children defaults to true, so filtering on a parent category also returns posts filed only in its children. Set it to false when you want the parent term alone. On a flat taxonomy such as post_tag the setting does nothing, because there is no hierarchy to walk.

How many tax_query clauses is too many?

Each clause adds a JOIN against wp_term_relationships and wp_term_taxonomy. Two is routine, three is worth timing, and beyond that the query plan degrades quickly on a large site. If you regularly filter on four or more taxonomies at once, consider precomputing the combination into a single term or a lookup table rather than asking MySQL to intersect four sets on every page load.

What is the difference between tax_query and category__in or tag__in?

None functionally — category__in, category__not_in, tag__in and friends are shorthand that WordPress converts into tax_query clauses internally. Use the shorthand when you have one simple condition on a core taxonomy; use tax_query when you need a custom taxonomy, a non-ID field, the AND operator or more than one clause.

Where do I paste the code from the WP_Tax_Query generator?

You have three good options and one bad one. Best is a small site-specific plugin — the generator can output one for you, and it keeps working when you change theme. A code-snippets plugin is fine too. A child theme's functions.php works but ties the code to that theme. Never edit the parent theme: the next update overwrites it and your code is gone.

Can I use the generated code in client work or a commercial plugin?

Yes. The output is ordinary WordPress API calls that you configured — there is no licence attached to it and no attribution required. Use it in client sites, commercial plugins and themes, or products you sell. The generated file carries a short credit comment you are free to delete.

The other Query generators in the library, plus the WordPress tools most often used alongside this one.