Combine Category and Tag Conditions in WP_Query

Quick Summary
- Put a category condition and a post_tag condition in one tax_query with relation AND to show only posts matching both.
- Each condition names the taxonomy, the field such as slug and a terms array; switching relation to OR matches either one.
- With posts_per_page set to -1 all matches load and paged does nothing, so set a positive number for pagination.
A tax_query in WP_Query can hold several conditions, and its relation key decides how they are joined. The example below shows WordPress posts that are in the category new and have the tag special. A post that has only one of the two is left out.
Use the code in the template file where the list should appear, such as a page template or home.php.
<?php
$paged = get_query_var( "paged" )?get_query_var( "paged" ) : 1;
$posts_per_page = -1;
$_p = new WP_Query(array(
'posts_per_page' => $posts_per_page,
'paged' => $paged,
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array('new')
),
array(
'taxonomy' => 'post_tag',
'field' => 'slug',
'terms' => array('special')
)
)
));
while( $_p->have_posts() ):
$_p->the_post();
?>
//POST TITLE
<h3><a href="<?php the_permalink( ); ?>">
<?php the_title( ); ?>
</a>
</h3>
<?php
endwhile;
wp_reset_query();
?>How it works
'relation' => 'AND'requires every condition in the array to match. Change it to'OR'to show posts that match either one.- Each inner array is one condition: the
taxonomy(categoryorpost_tag), the field you match on (slug), and theterms. You can also match byterm_idorname. termsis an array, so one condition can list several slugs; by default a post matches if it has any of them.posts_per_pageis-1, which returns all matching posts at once, so thepagedvalue has no effect. Set a positive number if you want pagination.
The loop prints each post’s title linked to the post. The //POST TITLE line is outside PHP and prints as text, so remove it. After a custom WP_Query loop, wp_reset_postdata() is the usual reset; wp_reset_query() is only needed after query_posts().
Related articles
- querying posts by post format: a tax_query on the built-in post_format taxonomy
- posts from a custom taxonomy term ID: the same structure for custom taxonomies
- custom field conditions with meta_query: the relation key works the same way there

