AJAX поиск для WordPress

Вы обращали внимание на AJAX поиск на сайтах, которые Вы посещаете? А хотели бы добавить на свой сайт подобный поиск именно в том виде, в котором хотите именно Вы?

AJAX поиск предполагает выдачу результатов на основе данных поля ввода без перехода на страницу результатов поиска.

Кому-то это может показаться ненужным, но, на самом деле это облегчает навигацию для посетителя сайта, ему не нужно будет каждый раз переходить на страницу результатов, чтобы найти то что он ищет, достаточно просто менять поисковую фразу и результаты сразу будут высвечиваться.

Поиски статей на эту тему в интернете принесли неудовлетворительные результаты. Большинство предлагало использовать плагины, другие были слишком сложными, а третьи вообще незаконченными (работали не совсем корректно). Отсюда было решено описать мой вариант AJAX поиска.

Как это работает?

Ввиду того, что я решил перейти целиком и полностью на WordPress, то и AJAX поиск делать будем именно на нём. Это первая моя статья из цикла статей по WordPress, потому прошу извинить, если что-то неверно истолковываю.

Наш поиск будет срабатывать при вводе более 2-х символов и выводить результаты в соответствующий блок. При нажатии кнопки Enter, как и раньше, пользователь будет перемещаться на страницу результатов поиска.

Итак, в нужное место добавьте форму поиска:

<div class="search">
	<?php get_search_form(); ?>
</div>

В файле functions.php Вашей темы добавьте следующий фильтр, чтобы переопределить шаблон вывода формы:

add_filter('get_search_form', 'ba_search_form');
function ba_search_form($form) {
	$form = '
		<form role="search" method="get" id="searchform" action="' . home_url( '/' ) . '" >
			<input type="text" value="' . get_search_query() . '" name="s" class="search-input" id="s" placeholder="Поиск" />
		</form>
		<div class="result-search">
			<div class="preloader"><img src="' . get_bloginfo('template_directory') .'/images/loader.gif" class="loader" /></div>
			<div class="result-search-list"></div>
		</div>
	';
	return $form;
}

С помощью фильтра мы изменяем форму стандартного поиска WordPress так, как нужно именно нам. Здесь мы убрали кнопку поиска, оставив только поле ввода, а также добавили пустой блок, в который будем выводить результаты поиска.

Возможно Вы заметили, что внутри содержится еще изображение загрузчика, это позволит показать пользователю, что фраза отправлена и идет поиск. Об этом очень часто спрашивают, поэтому добавим его сразу, чтобы в дальнейшем не возникло вопросов. Если Вам не нужно изображение загрузчика, то просто удалите весь блок .preloader. Картинку подходящего для Вас загрузчика Вы можете найти в интернете.

Внешний вид

Теперь давайте добавим некоторое оформление, чтобы всё красиво смотрелось:

.search {
	position: relative;
}

.search .search-input {
	width: 300px;
}

.search .result-search {
	display: none;
}

.search .result-search {
	position: absolute;
	width: 100%;
	z-index: 5;
	display: none;
}

.search .result-search .preloader {
	width: 100%;
	display: none;
	background: #fff;
	border-top: none;
	border: 1px solid #eee;
}

.search .result-search .preloader .loader {
	width: 30px;
	height: 30px;
	margin: 0 auto;
	display: block;
}

.search .result-search .result-search-list {
	width: 100%;
	display: none;
	overflow-y: auto;
	padding: 10px;
	box-sizing: border-box;
	background: #fff;
	border-top: none;
	border: 1px solid #eee;
}

.search .result-search .result-search-list .result_item {
	line-height: 15px;
	width: 100%;
	display: block;
	box-sizing: border-box;
	border-bottom: 1px solid #eeeeee;
	padding-bottom: 10px;
	margin-top: 10px;
}

.search .result-search .result-search-list .result_item:first-child{
	margin-top: 0;
}

.search .result-search .result-search-list .result_item:last-child {
	padding-bottom: 0;
	border-bottom: none;
}

.search .result-search .result-search-list .result_item a {
	color: #7c83a0;
	margin-bottom: 5px;
	display: block;
}

.search .result-search .result-search-list .result_item span {
	height: 100%;
	float: left;
	min-height: 100px;
}

.search .result-search .result-search-list .result_item p {
	line-height: 13px;
	font-size: 13px;
	color: #7c83a0;
	font-style: italic;
	background-color: white;
}

.search .result-search .result-search-list .result_item img {
	width: 60px;
	float: left;
	border: 1px solid #eeeeee;
	background-color: #eeeeee;
	margin: 0 5px 5px 0;
}

Обратите внимание на блок, который оборачивает весь наш поиск, он имеет свойство position: relative; а сам блок результатов — абсолютное позиционирование. В основном всё оформление зависит исключительно от Вас, главное обратите внимание на позиционирование и на то, какие блоки скрыты.

Отправка данных с помощью AJAX

Создайте файл search.js и добавьте в него следующий скрипт:

jQuery(function($){
	var searchTerm = '';
	
	$('.search-input').keydown(function(){
		searchTerm = $.trim($(this).val());
	});
		
	$('.search-input').keyup(function(){
		if ($.trim($(this).val()) != searchTerm) { // Если новое значение не равно старому, идем дальше
			searchTerm = $.trim($(this).val());
			if(searchTerm.length > 2){ // Если введено больше 2-х символов, идем дальше
				$.ajax({
					url : '/wp-admin/admin-ajax.php', // Ссылка на AJAX обработчик WP
					type: 'POST', // Отправляем данные методом POST
					data: {
						'action' : 'ba_ajax_search', // Вызываемое действие, которое мы описали в functions.php
						'term' : searchTerm // Отправляемые данные поля ввода
					},
					beforeSend: function() { // Перед отправкой данных
						$('.result-search .result-search-list').fadeOut(); // Скроем блок результатов
						$('.result-search .result-search-list').empty(); // Очистим блок результатов
						$('.result-search .preloader').show(); // Покажем загрузчик
					},
					success: function(result) { // После выполнения поиска
						$('.result-search .preloader').hide(); // Скроем загрузчик
						$('.result-search .result-search-list').fadeIn().html(result); // Покажем блок результатов и добавим в него полученные данные
					}
				});
			}
		}
	});
	
	$('.search-input').focusin(function() {
		$('.result-search').fadeIn();
	})
	
	$(document).mouseup(function(e) {
		if ((!$('.result-search').is(e.target) && $('.result-search').has(e.target).length === 0) && (!$('.search-input').is(e.target) && $('.search-input').has(e.target).length === 0)) {
			$('.result-search').fadeOut();
		}
	});
});

Здесь несколько функций, при нажатии клавиши в поле поиска мы получаем значение поля, т.е. это будет старое значение, потом после того, как клавишу отпустили, мы снова получаем значение поля поиска и сравниваем со старым, если значение изменилось, то заносим значение поля в переменную и идем дальше. Это сделано для того, чтобы функция не срабатывала каждый раз при нажатии непонятных клавиш, типа CTRL, ALT и т.д., Вы можете использовать свои методы отсеивания этих клавиш.

После этого мы проверяем, чтобы в поле поиска было более 2-х символов. Функция $.trim(); позволяет нам удалить пробелы вначале и конце строки, что опять таки позволит предотвратить отправку формы, если пользователь просто ввел много пробелов.

Далее у нас еще есть функция, срабатывающая при нажатии (фокусировке) в поле поиска, покажем блок результатов поиска, если они уже есть, вдруг пользователь промахнулся и результаты закрылись, а он хочет их снова просмотреть. И ниже функция скрытия блока результатов, если пользователь нажал мышью вне блока результатов поиска и вне самого поля поиска.

Остальной код прокомментирован, так что останавливаться не будем.

Теперь необходимо подключить наш файл скрипта, Вы можете сделать это любым удобным для Вас способом, лично я предпочитаю осуществлять подключение в файле functions.php

function ba_jquery_scripts() {
	wp_enqueue_script('jquery');
	wp_enqueue_script('search', get_template_directory_uri() . '/js/search.js', array('jquery'), false, true);
}
add_action('wp_enqueue_scripts', 'ba_jquery_scripts');

Обратите внимание, что скрипт у нас работает на основе библиотеки jQuery, поэтому не забудьте подключить её тоже.

Если сейчас попытаться ввести поисковую фразу, то в консоли будут ошибки работы скрипта, а всё потому, что у нас еще нет конечного обработчика.

Основной обработчик

Откройте файл functions.php и добавьте следующий код:

function ba_ajax_search(){
	$args = array(
		's' => $_POST['term'],
		'posts_per_page' => 5
	);
	$the_query = new WP_Query($args);
	if ($the_query->have_posts()) {
		while ($the_query->have_posts()) {
			$the_query->the_post();
?>
			<div class="result_item clear">
				<?php
					if(has_post_thumbnail()) {
						the_post_thumbnail(array('class'=>'post_thumbnail'));
					} else {
				?>
						<img src="<?php bloginfo('template_directory'); ?>/images/noimage.png" />
				<?php } ?>
				<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
				<?php the_excerpt();?>
			</div>
<?php
		}
	} else {
?>
	<div class="result_item">
		<span class="not_found">Ничего не найдено, попробуйте другой запрос</span>
	</div>
<?php
	}
	exit;
}
add_action('wp_ajax_nopriv_ba_ajax_search','ba_ajax_search');
add_action('wp_ajax_ba_ajax_search','ba_ajax_search');

Здесь мы описали стандартную функцию WordPress WP_Query(), о которой Вы можете найти множество статей в интернете. В качестве аргумента поиска «s» мы передаем полученное значение переменной term, которую отправили с помощью AJAX.

В описанной функции Вы можете формировать и выводить данные так, как Вам хочется. В моём случае для примера я показываю миниатюру, заголовок и вводный текст.

Вот и всё, ничего сложного. Если у Вас остались вопросы, оставляйте их в комментариях.

Комментарии

  • Евгений
    Добрый день. Подскажите как вывести в Блоге один вариант а в пользовательском post-type другой вариант поиска в ba_ajax_search()
    • Blog About
      Добрый день, Вы можете прямо внутри функции добавить проверку и сделать нужные запросы для каждого из вариантов:

      function ba_ajax_search(){
      if (is_post_type_archive('ВАШ_POST_TYPE')) {
      // вариант для пользовательского post_type
      } else {
      // вариант для блога
      }
      exit;
      }
  • Дмитрий
    Отлично работает, но как прикрутить этот код к нескольким разным формам на сайте?
  • Alex
    Кстати, а что Вы думаете по поводу кеширования запросов поиска функцией set_transient()? Она позволит даже не дергать new WP_Query($args); если запрос уже делался.
    • Blog About
      Добрый день. Статья в основном предусматривает именно реализацию поиска через Ajax, соответственно в конечном запросе по формированию выборки Вы в праве делать что угодно и как угодно. Саму функцию set_transient() не рассматривал и в принципе никогда не сталкивался, если Вы знаете как ей пользоваться, то да, почему бы ее не использовать, ведь чем быстрее работает сайт, тем лучше.
  • Alex
    Спасибо, очень помогло!
  • Тимур
    Вообще не работает, никак.
    Помимо этого у меня установлен плагин Ajax Search Lite, может ли он быть причиной конфликта и невозможности работы самописного скрипта ?)
    • Blog About
      Добрый день. Не уверен, что они будут конфликтовать. В консоли браузера есть какие-нибудь ошибки? Если есть, то их необходимо устранить.
      В коде страницы проверьте, что файл скрипта с поиском действительно подключается (в статье это файл search.js) и он идет после подключения библиотеки jquery. Если в functions.php происходит переподключение библиотеки jQuery (например, вместо стандартной подключаете с CDN), то скрипт может не сработать.
      Если сайт в общем доступе, скиньте ссылку, посмотрю.
  • Анна
    Добрый день. У меня выводится только один объект, хотя по факту их должно быть больше. Код несколько раз перепроверила. В чем может быть проблема?
  • Виталий
    Здравствуйте. Использовал Ваш метод. Он мне очень подошел.
    После экшена выводит единицу. Вот не могу разобраться из-за чего он выводит. Не подскажите как убрать единицу?
    Скрин (уберите пробелы): http :// joxi.ru/vAWdK9vUglNj7r

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