I've a pre_get_posts
filter with a check for main query and search, in this check I add a meta query:
$meta_query = array(
'relation' => 'OR',
array(
'key' => 'exclude',
'value' => '1',
'compare' => '!=',
),
array(
'key' => 'exclude',
'value' => '',
'compare' => '=',
),
);
$query->set('meta_query', $meta_query);
I've tried a couple of ways for 'NOT EXISTS' with the key exclude
, but to no avail.
However the output I am getting for this seems to be an excessive nested set of joins. Dumping the query from the global wp_query
I get the following:
SELECT SQL_CALC_FOUND_ROWS DISTINCT wp_posts.ID
FROM wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
LEFT JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id
WHERE 1=1
AND (((wp_posts.post_title LIKE '%exclude%')
OR (wp_postmeta.meta_value LIKE '%exclude%')
OR (wp_posts.post_excerpt LIKE '%exclude%')
OR (wp_posts.post_content LIKE '%exclude%')))
AND ((wp_postmeta.meta_key = 'exclude'
AND wp_postmeta.meta_value != '1')
OR (mt1.meta_key = 'exclude'
AND mt1.meta_value = ''))
AND wp_posts.post_type IN ('post',
'page',
'attachment',
'cpt_people',
'cpt_history',
'cpt_case_studies')
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'acf-disabled'
OR wp_posts.post_author = 1
AND wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_title LIKE '%exclude%' DESC, wp_posts.post_date DESC
LIMIT 0, 9
Now if I manually build the query in SQL I can get the results I expect, however WordPress seems to be creating excessive joins for wp_postmeta
and the result is an error:
Not unique table/alias: 'wp_postmeta'
Removing the first join:
INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
manually with the query returns the expected results.