WordPress как на ладони

Добавляем поиск по метаполю в обычный поиск 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() фильтр работать не будет - там этот параметр включен по умолчанию!

-

При создании кода, была использована статья: adambalee.com

campusboy 4742youtube.com/c/wpplus
Создатель YouTube канала wp-plus, на котором делюсь своим опытом. Активный пользователь wp-kama.ru. WordPress-разработчик. Разработка сайтов и лендингов. Доработка существующих проектов. Сопровождение ресурсов.
Редакторы: Kama 9601
8 комментариев
    Войти