I am trying to alter WP_Query
on the pre_get_posts
action hook, for filtering the posts returned, depending on the built-in category
and post_tag
taxonomies.
I would like that the only posts returned by the query have either both taxonomies not registered at all, or no term is set for both taxonomies for the post, or, last case, both taxonomies have a specific value.
It is stated in the Codex WP_Query
page that for this kind of purpose "Nested Taxonomies" should be used (see here).
Though in my particular case it is not working - here is my code:
// In a function hooked on 'pre_get_posts' action
$query->set('post_type', array('post','wpgdacces_acces', 'page'));
$query_tax_param = array(
'relation' => 'OR',
array(
'relation' => 'AND',
array( 'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'private' ),
'operator' => 'IN'),
array( 'taxonomy' => 'post_tag',
'field' => 'slug',
'terms' => array('private'),
'operator' => 'IN')
),
array(
'relation' => 'AND',
array( 'taxonomy' => 'category',
'field' => 'slug',
'operator' => 'NOT EXISTS'
),
array( 'taxonomy' => 'post_tag',
'field' => 'slug',
'operator' => 'NOT EXISTS'
)
)
);
Before that, I have registered the custom post type 'wpgdacces_acces', and also registered both built-in taxonomies category
and post_tag
for the page
post type.
I am testing the query on a local environment, on a WP 4.3 installation with the default theme. On this setup, I have 3 standard posts, of which only one has the 'private' term for both Category and Tags. The 2 remaining posts have "Unclassified" as Category term. I also have 3 pages, for which no term is set for both taxonomies. And in my Custom Post Type 'wpgdacces_acces', for which both taxonomies have not been registered at all, I have 2 posts.
So on the home page, the query is altered for showing the 3 post types post
, page
and 'wpgdacces_acces' (the first line of code in the block here above). And therefore I should see 1 post + 3 pages + 2 wpgdacces_acces posts.
But the only element which is showing off is the standard post with both Category and Tags set to 'private'.
Really odd: when I modify and run the query with the two conditions separately (altering the query for getting only posts with taxonomies not set, on one side, and altering the query for getting posts with taxonomies set to private, on the other side) it is perfectly working.
This lets me think that the SQL statement that is generated by WP_Query
after pre_get_posts
might be wrong somewhere. Here it is, printed with echo $GLOBALS['wp_query']->request;
on the 'wp_footer' hook :
SELECT SQL_CALC_FOUND_ROWS wptom_posts.ID
FROM wptom_posts
INNER JOIN wptom_term_relationships
ON (wptom_posts.ID = wptom_term_relationships.object_id)
INNER JOIN wptom_term_relationships
AS tt1
ON (wptom_posts.ID = tt1.object_id)
WHERE 1=1
AND (
(
wptom_term_relationships.term_taxonomy_id IN (7)
AND
tt1.term_taxonomy_id IN (8)
)
OR
(
NOT EXISTS (
SELECT 1
FROM wptom_term_relationships
INNER JOIN wptom_term_taxonomy
ON wptom_term_taxonomy.term_taxonomy_id = wptom_term_relationships.term_taxonomy_id
WHERE wptom_term_taxonomy.taxonomy = 'category'
AND wptom_term_relationships.object_id = wptom_posts.ID
)
AND
NOT EXISTS (
SELECT 1
FROM wptom_term_relationships
INNER JOIN wptom_term_taxonomy
ON wptom_term_taxonomy.term_taxonomy_id =
wptom_term_relationships.term_taxonomy_id
WHERE wptom_term_taxonomy.taxonomy = 'post_tag'
AND wptom_term_relationships.object_id = wptom_posts.ID
)
)
) AND wptom_posts.post_type
IN ('post', 'wpgdacces_acces', 'page')
AND (wptom_posts.post_status = 'publish'
OR wptom_posts.post_author = 1
AND wptom_posts.post_status = 'private')
GROUP BY wptom_posts.ID
ORDER BY wptom_posts.post_date
DESC LIMIT 0, 10
Do you see anything wrong in the above SQL statement? I would like to find out what is wrong in that SQL statement. If I know what is wrong, maybe I will be able to use one of the WP_Query
filters provided to modify the query after pre_get_posts
, but before it is actually executed.