I don’t suspect that your tax_query
is failing you, but actually your tag
parameter is. single_tag_title()
returns the name of the tag, not the slug.
All tag and category queries are converted to a tax_query
in the WP_Query
class before being passed to the WP_Tax_Query
class to build the relative string for the SQL query. Term names and slugs gets sanitized before validation and before getting the term ID of the passed term/s. (Just for interest sake, read why you should not use term names and the name
parameter inside a tax_query
, check my answer here)
Now, slugs should always be lowercase and multiple words separated by hyphens. You are passing a name as a slug. Because the term name matches nothing in the term slug column (because you have told the tax_query
to look in the slug column), WP_Tax_Query
accepts that the term is invalid and does not exist and therefor simply bails out and return an empty string. This is where the big flaw comes in (which in my opinion is a bug that should be fixed). WP_Tax_Query
sends an empty SQL join string back to WP_Query
, WP_Query
wrongly reads this as if there were never a tax_query
and continues to build and then executes the SQL without the join clause. This unexpectedly then returns all posts regardless, where in my opinion it should just return no posts at all. This is what you are seeing
So lets look at a solution and also clean up your code and make it more reliable
First, your pre_get_post
action
-
Add a check to target the front end only, otherwise back end queries will be affected as well
-
Set
is_tag()
to the current instance -
Get the current
tax_query
on the tag page and modify it to add the the post format section and pass that as a newtax_query
You can adjust your code to something like this: (I’m using closures, but you can revert to the old style as in your question 😉)
add_action('pre_get_posts', function ($q)
{
if ( !is_admin() // Only targets front end queries
&& $q->is_main_query() // Only targets the main query
&& $q->is_tag() // Only targets tag archive pages
) {
// Gets the current tax_query
$tax_query_obj = $q->tax_query->queries;
// Add the post format query part to the current tax_query
$tax_query_obj[] = [
'taxonomy' => 'post_format',
'field' => 'slug',
'terms' => ['post-format-aside'],
'operator' => 'NOT IN'
];
//Build a proper tax query
$tax_query = [
'relation' => 'AND',
$tax_query_obj
];
// Set the modified tax_query
$q->set( 'tax_query', $tax_query );
// Set any additional parameters here except tag parameters
}
}, PHP_INT_MAX );
As for your custom query, we can get the current tag ID being viewed by simply using get_queried_object_id()
and then using that in a tax_query
with our post format . You can try the following in your arguments: (Requires PHP 5.4+ due to new short array syntax ([]
))
$args = [
'tax_query' => [
[
'taxonomy' => 'post_tag', // Default tag taxonomy
'terms' => get_queried_object_id(), // Gets current tag archive tag ID
],
[
'taxonomy' => 'post_format',
'field' => 'slug',
'terms' => 'post-format-aside'
],
],
// Rest of your arguments excluding tag parameter
];