Skip to main content
1 of 4
cfx
  • 1.6k
  • 15
  • 27

Single meta_query query using OR instead of AND

I want the native WordPress search input to search metadata in addition to its standard title and content search, however setting a meta_query adds an AND clause to the request when what I need is an OR.

My function:

function search_faqs_metadata($query) {
  if(!is_admin() && $query->is_main_query()) {
    if($query->is_search) {
      $query->set('meta_query', array(array(
        'key' => '_faqs',
        'value' => $query->query_vars['s'],
        'compare' => 'LIKE'
      )));
    }
  }
}
add_action('pre_get_posts', 'search_faqs_metadata');

The problem is the query it generates:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE 1=1
AND (
  (
    (wp_posts.post_title LIKE '%foobar%') OR (wp_posts.post_content LIKE '%foobar%')
  )
)
AND (wp_posts.post_password = '')
AND wp_posts.post_type IN ('post', 'page', 'attachment')
AND (wp_posts.post_status = 'publish')
AND (  //I need this to be an OR!
  (wp_postmeta.meta_key = '_faqs' AND CAST(wp_postmeta.meta_value AS CHAR) LIKE '%foobar%')
)
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_title LIKE '%foobar%' DESC, wp_posts.post_date DESC LIMIT 0, 10

So I don't get a match unless the post title/content AND the metadata match the search term.

I understand there is a relation parameter for the meta_query but it only works when comparing multiple metadata values.

Currently I'm running str_replace() on the final query to change the last AND into an OR. I chose this method is because, while hacky, it is lean on the amount of code I need to add for this adjustment to succeed.

Is there a better way to change that final AND into an OR?

cfx
  • 1.6k
  • 15
  • 27