/ Wordpress / Расширение стандартного поиска

Расширение стандартного поиска

15.10.2022

602

Включение в поиск метаполей

// Добавляем в поиск метаполе
function me_search_query( $query ) {
	if ( $query->is_search ) {
		$meta_query_args = array(
			array(
				'key' => 'meta_key', //нужное поле
				'value' => $query->query_vars['s'],
				'compare' => 'LIKE',
			),
		);
		$query->set('meta_query', $meta_query_args);
		add_filter( 'get_meta_sql', 'me_replace_and_with_or' );
	};
}

function me_replace_and_with_or( $sql ) {
	if ( 1 === strpos( $sql['where'], 'AND' ) ) {
		$sql['where'] = substr( $sql['where'], 4 );
		$sql['where'] = ' OR ' . $sql['where'];
	}

	//make sure that this filter will fire only once for the meta query
	remove_filter( 'get_meta_sql', 'me_replace_and_with_or' );
	return $sql;
}

add_filter( 'pre_get_posts', 'me_search_query');
Добавление в поиск нескольких метаполей
У этого способа есть существенный недостаток, в результатах поиска выводятся все типы записей, в т.ч. attachment

Правильный способ

Не могу сказать насчет оптимизации запроса с точки зрения обращения к базе данных, но я смог добиться нужного результата. Создав в pre_get_posts 2 запроса с условием: один обычный и один по метаполю, в результате получаем либо записи по запросу (стандартный поиск), либо записи по метаполю.

remove_action( ‘pre_get_posts’, __FUNCTION__ ); — обязательно, иначе будет бесконечный цикл и сервер вернет 502 Bad Gateway.

function custom_search_query( $query ) {
	if ( !is_admin() && $query->is_search ) {
		
		remove_action( 'pre_get_posts', __FUNCTION__ ); // чтобы не было бесконечного цикла
		
		$search = get_posts( array(
			's' => get_query_var('s'),
			'posts_per_page' => -1,
			'fields' => 'ids'
		) );
		
		if (empty($search)) {
			$search = get_posts( array(
				'meta_query' => array( array(
					'key' => 'sku',
					'value' => get_query_var('s'),
					'compare' => 'LIKE'
				) ),
				'posts_per_page' => -1,
				'fields' => 'ids'
			) );			
		}
		
		if (!empty($search)) {
		
			$query->set('s', ''); //отключаем поиск по слову
			$query->set('post__in', $search);
			$query->set('post_type', 'post');
			
		}

	};
}
add_filter( 'pre_get_posts', 'custom_search_query');
Тут тоже есть ошибка. В любом случае empty($search) или !empty($search) мы изменяем запрос поиска и обнуляем s, что не правильно. Ниже правильный код.

Изначально я прорабатывал это методом объединения двух массивов, но подумал что это более затратно по запросам:

function custom_search_query( $query ) {
	if ( !is_admin() && $query->is_search ) {
		
		remove_action( 'pre_get_posts', __FUNCTION__ ); // чтобы не было бесконечного цикла
		
		$search = get_posts( array(
			's' => get_query_var('s'),
			'posts_per_page' => -1,
			'fields' => 'ids'
		) );
		
		$second = get_posts( array(
			'meta_query' => array( array(
				'key' => 'sku',
				'value' => get_query_var('s'),
			) ),
			'posts_per_page' => -1,
			'fields' => 'ids'
		) );
		
		$result = array_merge($first, $second);
		
		$query->set('s', '');	
		$query->set('post__in', $result);
		$query->set('post_type', 'post');	

	};
}
add_filter( 'pre_get_posts', 'custom_search_query');

Но может быть как метод где-нибудь пригодится.

Поиск только по метаполю

Данная функция отключает поиск по слову в заголовке записи и ищет по соответствию значения в метаполе.

function custom_search_query( $query ) {
	if ( !is_admin() && $query->is_search ) {
		global $wp_query;
        if ($wp_query->post_count == 0) {
			
			$query->set('meta_query', array(
				array(
					'key' => 'sku',
					'value' => get_query_var('s'),
					'compare' => 'IN'
				)
			));
			//$query->set('post_type', 'post');			
			$query->set( 's', ''); // отключаем поиск по слову
			
		}
	};
}
add_filter( 'pre_get_posts', 'custom_search_query');

Правильное изменение поиска

function custom_search_query( $query ) {
	if ( !is_admin() && $query->is_search ) {
		
		remove_action( 'pre_get_posts', __FUNCTION__ ); // чтобы не было бесконечного цикла
		
		$search = get_posts( array(
			's' => get_query_var('s'),
			'posts_per_page' => -1,
			'fields' => 'ids'
		) );
		
		if (empty($search)) {
			
			$search = get_posts( array(
				'meta_query' => array( array(
					'key' => 'sku',
					'value' => get_query_var('s'),
					'compare' => 'LIKE'
				) ),
				'posts_per_page' => -1,
				'fields' => 'ids'
			) );	
			
			if (!empty($search)) {
				$query->set('s', '');	
				$query->set('post__in', $search);
				$query->set('post_type', 'post');
			}			
			
		}

	};
}
add_filter( 'pre_get_posts', 'custom_search_query');

Но в любом случае мы получаем (в случае измененном поиска) проблему, что мы не можем вывести get_search_query() (в заголовке: Результат поиска по «…»). Можно исправить это если изменить get_search_query() на $_GET[«s»]. Пример:

<?php printf( __( 'Результаты поиска: %s' ), '<span>«' . $_GET["s"] . '»</span>' ); ?>

Ещё более простой и правильный способ изменения поиска

function custom_search_query( $query ) {
	if ( !is_admin() && $query->is_search ) {

		remove_action( 'pre_get_posts', __FUNCTION__ ); // чтобы не было бесконечного цикла

		$search = get_posts( array(
			's' => get_query_var('s'),
			'posts_per_page' => -1,
			'fields' => 'ids',
			'post_type' => 'post',
			'category__not_in' => array(1, 35, 4, 59, 269)
		) );

		if (empty($search)){
			$query->set('meta_query', array(
				array(
					'key' => 'sku', 
					'value' => get_query_var('s'), 
					'compare' => 'LIKE'
				)
			));
			$query->set('s', ''); // обнуляем основной поиск, !обязательно в конце, т.к. мы его используем в meta_query
		}

		$query->set('category__not_in',array(1, 35, 4, 59, 269));
	    $query->set('post_type', 'post');

		return $query;

	};
}
add_filter( 'pre_get_posts', 'custom_search_query');
[site-socialshare]
  • Комментарии
  • Вложения

Добавить комментарий

Пока нет комментариев. Будь первым!

Расширение стандартного поиска
Локализация скрипта
Рекомендации для васЛокализация скриптаOpttour.ru
Спасибо! Наш менеджер свяжется с Вами в течении 5 минут.