Один запрос meta_query с использованием OR вместо AND в инструкции WHERE запроса

Я хочу, чтобы встроенный поиск WordPress meta_query поиск метаданных в дополнение к стандартным заголовкам и содержанию, однако установка meta_query добавляет предложение AND к запросу, когда мне нужен OR .

Моя функция:

 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'); 

Проблема заключается в том, что он генерирует запрос:

 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 

Поэтому я не получаю совпадение, если заголовок / содержание сообщения и метаданные не совпадают с поисковым запросом.

Я понимаю, что есть параметр relation для meta_query но он работает только при сравнении нескольких значений метаданных.

В настоящее время я запускаю str_replace() в последнем запросе, чтобы изменить последний AND в OR . Я выбрал этот метод, потому что, в то время как хак, он опирался на количество кода, который мне нужно добавить для этой настройки:

 function search_where_or_metadata($where) { if(is_search()) { global $wp_query; $new_where = $where; $new_where = str_replace('AND ( (wp_postmeta.meta_key', 'OR ( (wp_postmeta.meta_key', $where); return $new_where; } return $where; } add_filter('posts_where', 'search_where_or_metadata'); 

EDIT. Вот лучшая функция, использующая более подходящий фильтр, который изменяет AND на OR :

 function change_meta_key_where_from_and_to_or($sql) { if(is_search()) { $sql['where'] = substr($sql['where'], 1, 3) == 'AND' ? substr_replace($sql['where'], 'OR', 1, 3) : $sql['where']; } return $sql; } add_filter('get_meta_sql', 'change_meta_key_where_from_and_to_or'); 

Есть ли лучший способ изменить этот final AND в OR ?

Solutions Collecting From Web of "Один запрос meta_query с использованием OR вместо AND в инструкции WHERE запроса"

Я считаю, что самый короткий и лучший подход – (1) изменить запрос:

 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'); 

и затем (2) замените AND с помощью OR через фильтр get_meta_sql :

 function change_meta_key_where_from_and_to_or($sql) { if(is_search()) { $sql['where'] = substr($sql['where'], 1, 3) == 'AND' ? substr_replace($sql['where'], 'OR', 1, 3) : $sql['where']; } return $sql; } add_filter('get_meta_sql', 'change_meta_key_where_from_and_to_or'); 

Нашел учебник, который мог бы сделать трюк: http://www.deluxeblogtips.com/2012/04/search-all-custom-fields.html

Основной смысл состоит в том, чтобы использовать пользовательские запросы mySQL, чтобы найти идентификаторы сообщений в сообщениях с надлежащей мета-информацией, а затем передать эти идентификаторы в запрос:

 function wpse143477_parse_clauses($clauses, $query) { if(!is_admin() && $query->is_main_query()) { if($query->is_search) { $keyword = $query->get('s'); $keyword = '%' . like_escape( $keyword ) . '%'; $post_ids = $wpdb->get_col( $wpdb->prepare( " SELECT DISTINCT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_faqs' AND meta_value LIKE '%s' ", $keyword ) ); if( !empty( $post_ids )) { $clauses['where'] .= " OR {$wpdb->posts}.ID IN (" . implode( ', ', $post_ids ) . ')'; } } } return $clauses; } add_filter( 'posts_clauses', 'wpse143477_parse_clauses', 10, 2 );