Добавляем поиск по метаполю в обычный поиск WordPress
Базовый поиск WordPress ищет указанный текст в заголовке, контенте и отрывке (в полях post_title, post_content, post_excerpt). Ниже показано, как к этим базовым полям поиска добавить поиск и по метаполю. Т.е. ниже будем решать задача: как в стандартный поиск по записям добавить поиск по указанному метаполю.
Смотрите также: Добавляем название таксономии (термина) в поиск по записям
Решение задачи на хуке posts_clauses
add_filter( 'posts_clauses', 'km_metadata_search' );
# Добавляем поиск по метаполям в базовый поиск WordPress
function km_metadata_search( $clauses ){
global $wpdb;
if( ! is_search() || ! is_main_query() )
return $clauses;
$clauses['join'] .= " LEFT JOIN $wpdb->postmeta kmpm ON (ID = kmpm.post_id)";
$clauses['where'] = preg_replace(
"/OR +\( *$wpdb->posts.post_content +LIKE +('[^']+')/",
"OR (kmpm.meta_value LIKE $1) $0",
$clauses['where']
);
// если нужно искать в указанном метаполе
//$clauses['where'] .= $wpdb->prepare(' AND kmpm.meta_key = %s', 'my_meta_key' );
$clauses['distinct'] = 'DISTINCT';
// дебаг итогового запроса
0 && add_filter( 'posts_request', function( $sql ){ die( $sql ); } );
return $clauses;
}
Что делается в коде:
Шаг 1: Добавление таблицы метаданных в запрос (JOIN)
Расширим базовую таблицу posts, добавим к ней таблицу метаданных. Нужно это для того, чтобы появилась возможность указать поле таблицы метаполей в котором нужно искать. Поле указываем во втором шаге.
Шаг 2: Изменение выборки в запросе (WHERE)
Дополним WHERE часть запроса, чтобы "стандартный поиск" в дополнение искал ещё и по всем метаполям постов.
Шаг 3: Изменение выборки в запросе (DISTINCT)
Из-за LEFT JOIN в 1 шаге могут появится дубликаты. Избавимся от них.
Решение задачи на хуках: posts_join, posts_where, posts_distinct
add_filter( 'posts_join', 'cf_search_join' );
add_filter( 'posts_where', 'cf_search_where' );
add_filter( 'posts_distinct', 'cf_search_distinct' );
# Объединяет таблицы записей и таблиц метаданных.
function cf_search_join( $join ){
global $wpdb;
if( is_search() )
$join .= " LEFT JOIN $wpdb->postmeta ON ID = $wpdb->postmeta.post_id ";
return $join;
}
# Указывает по каким метаполям и какое значение искать в секции WHERE.
function cf_search_where( $where ){
global $wpdb;
if ( is_search() ) {
$where = preg_replace(
"/\(\s*$wpdb->posts.post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
"($wpdb->posts.post_title LIKE $1) OR ($wpdb->postmeta.meta_value LIKE $1)", $where );
}
return $where;
}
# Предотвращает появление дубликатов в выборке.
function cf_search_distinct( $where ){
return is_search() ? 'DISTINCT' : $where;
}
Фильтры работать не будут, если для запроса включен параметр suppress_filters.
Для запроса get_posts() фильтр работать не будет - там этот параметр включен по умолчанию!
--
При создании кода, была использована статья: http://adambalee.com/search-wordpress-by-custom-fields-without-a-plugin/