Поиск Wordpress: полная подборка плагинов и сниппетов для кастомизации

480

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

Однако, по-умолчанию, WordPress производит его не сильно эффективно. Первое — система не всегда может найти то, что есть по факту. Например, «товар» и «товары» для неё разные вещи. Поиск также ничего не выдаст, если случайно изменена языковая раскладка клавиатуры. Например, если вместо слова вордпресс введено djhlghtcc.

Вторая проблема — вопрос релевантности. Даже если получено много результатов, они могут не всегда удовлетворять запрос пользователя. Это довольно глубокая проблема и во многом связана с тематикой сайта.

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

Поиск — полезная функция

Плагины

Прежде чем перейти к кодингу, коротко о существующих плагинах.

Relevansii (бесплатно)

Отличный плагин, который не использует облачный поисковый сервис, поэтому он может быть немного медленнее в зависимости от вашего хостинга. Но у вас будет максимальный контроль.

После установки плагина сначала необходимо создать индекс. Relevanssi заменяет поиск по умолчанию поиском с частичным совпадением, который сортирует результаты по релевантности. Он также индексирует комментарии и содержимое шорткодов. Есть несколько и других особенностей:

  • Поиск по комментариям, меткам, категориям и произвольным полям.
  • Предлагаются варианты, а-ля: «Вы имели в виду? …»
  • Исключение записей, страниц, тегов или категорий из поиска.
  • Поиск по части слова.

Вы можете изменить вес заголовков записей, текста комментариев, меток и категорий в зависимости от того, что считаете наиболее важным.

SearchWP (платно)

SearchWP — это мощный плагин пользовательского поиска для WordPress. Он очень прост в использовании, а результаты поиска более менее точны.

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

После активации плагин автоматически проиндексирует контент и заменит функцию поиска по умолчанию.

Swiftype Search (платно)

Swiftype — довольно новый поисковый сервис WordPress. Некоторые приятные функции включают:

  • Облачный сервис, который не напрягает серверы.
  • Очень релевантные результаты поиска.
  • Аналитика того, что ищут пользователи.
  • Функция автозаполнения.
  • Переопределение результатов поиска вручную.
  • Поиск приложений.

Плагин работает, отправляя индекс всего вашего контента на серверы разработчиков, поэтому ваш сервер не загромождается. Поскольку Swiftype вообще не использует MySQL, результаты поиска появляются намного быстрее. Для использования плагина необходимо создать учётную запись.

Сниппеты для фронтэнда

Однако, не всегда стоит бить «из пушки по воробьям». Если у вас простая задача, возможно, вам поможет использование несложного кода. Вот несколько полезных.

#1 Добавление формы поиска в меню

После добавления кода в файл function.php в меню вы увидите, что появился новый пункт — форма поиска. Обратите внимание, что вам необходимо установить свой идентификатор расположения меню $args->theme_location.  Обычно он указывается в функции wp_nav_menu, параметр theme_location.

add_filter( 'wp_nav_menu_items', 'cody_add_search_box_to_menu', 10, 2 );
function cody_add_search_box_to_menu( $items, $args ) {
    if( $args->theme_location == 'top' )
		$items .= '<li class="menu-item">' . get_search_form( false ) . '</li>';

    return $items;
}

#2 Подсветка искомых слов в результатах поиска

Данный сниппет подсветит слова из запроса в заголовках, основном контенте и цитатах.

add_filter( 'the_content', 'cody_search_results_hightlight' );
add_filter( 'the_title', 'cody_search_results_hightlight' );
add_filter( 'the_excerpt', 'cody_search_results_hightlight' );
function cody_search_results_hightlight( $text ){
	
	$colors = array( '', '#ffeb3b', '#CDDC39', '#7fdce8', '#edb5f7' );

	if ( ! is_search() || is_admin() ) return $text;

	$query_terms = get_query_var('search_terms');
	if( empty( $query_terms ) ) {
		$query_terms = (array)get_query_var( 's' );
	}
	
	if( empty( $query_terms ) ) {
		return $text;
	}

	$n = 0;
	foreach( $query_terms as $term ){
		$n++;

		$term = preg_quote( $term, '/' );
		$text = preg_replace_callback( "/$term/iu", function( $match ) use ( $colors, $n ){
			return '<span style="background-color: '. $colors[ $n ] .';">'. $match[0] .'</span>';
		}, $text );
	}

	return $text;
}

#3 Живой поиск без перезагрузки

Для реализации этой задачи сложно ограничиться кодом в несколько строк. Поэтому, этот раздел я перенёс в отдельную статью.

#4 Поиск только по точному вхождению фразы

По умолчанию WordPress разбивает поисковую строку на части. Давайте отключим эту функцию и будем производить поиск только по точному совпадению.

add_action( 'pre_get_posts', 'cody_search_filter' );
function cody_search_filter( $query ){
	if( ! is_admin() && $query->is_main_query() ){
		if( $query->is_search ){
			$query->set( 'sentence', 1 );
		}
	}
}

#5 Поиск только по подзаголовку

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

add_filter( 'posts_search', 'cody_search_only_in_title', 500, 2 );
function cody_search_only_in_title( $search, $wp_query ) {
    global $wpdb;
    if (empty($search))
        return $search;
    $q = $wp_query->query_vars;
    $n = !empty($q['exact']) ? '' : '%';
    $search = $searchand = '';
    foreach ((array) $q['search_terms'] as $term) {
        $term = esc_sql( $wpdb->esc_like( $term ) );
        $search .= "{$searchand}($wpdb->posts.post_title LIKE '{$n}{$term}{$n}')";
        $searchand = ' AND ';
    }
    if (!empty($search)) {
        $search = " AND ({$search}) ";
        if (!is_user_logged_in())
            $search .= " AND ($wpdb->posts.post_password = '') ";
    }
    return $search;
}

#6 Перенаправление на единственную страницу-результат

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

add_action( 'template_redirect', 'cody_redirect_single_post' );
function cody_redirect_single_post() {
	if ( !is_search() ) return;
	
	global $wp_query;
	if ( $wp_query->post_count == 1 ) {
		wp_redirect( get_permalink( $wp_query->posts['0']->ID ) );
	}
}

#7 Поиск при неправильной раскладке клавиатуры

Пожалуй, этот сниппет — один из самых интересных, и применимых почти для всех русскоязычных сайтов. Он позволяет производить поиск, если пользователь забыл переключиться на русскую раскладку. Например, если он ввёл djhlghtcc вместо необходимого вордпресс.

Для реализации этой задачи, давайте напишем свою функцию. Если WordPress не получил ни одного результата, будем считать, что теоретически была использована неверная раскладка. Нам необходимо вмешаться в текущий запрос WP_Query. Для  этого вполне подойдёт фильтр posts_results. В начале мы заменяем латинские символы на подходящие кириллицей.

Так как по старому запросу мы ничего не нашли, снова производим выборку записей через метод $wpdb->get_results. При этом нам не нужно беспокоиться о составлении SQL запроса. WP фактически уже это сделал за нас, достаточно обратиться к $query->request. Нам остаётся лишь заменить старый поисковый запрос на новый. Результатом нового SQL запроса станет новый массив, содержащий ID найденных постов.

add_filter( 'posts_results', 'cody_search_cir_lat', 10, 2 );
function cody_search_cir_lat( $posts, $query ) {
	
	if ( is_admin() || !$query->is_search ) return $posts;
	
	global $wp_query;

	if ( $wp_query->found_posts == 0 ) {
		
		// замена латиницы на кириллицу
		$letters = array( 'f' => 'а', ',' => 'б', 'd' => 'в', 'u' => 'г', 'l' => 'д', 't' => 'е', '`' => 'ё', ';' => 'ж', 'p' => 'з', 'b' => 'и', 'q' => 'й', 'r' => 'к', 'k' => 'л', 'v' => 'м', 'y' => 'н', 'j' => 'о', 'g' => 'п', 'h' => 'р', 'c' => 'с', 'n' => 'т', 'e' => 'у', 'a' => 'ф', '[' => 'х', 'w' => 'ц', 'x' => 'ч', 'i' => 'ш', 'o' => 'щ', ']' => 'ъ', 's' => 'ы', 'm' => 'ь', '\'' => 'э', '.' => 'ю', 'z' => 'я' );
		
		$cir = array( 'а', 'б', 'в', 'г', 'д', 'е', 'ё', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я', 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я' );
		$lat = array( 'f', ',', 'd', 'u', 'l', 't', '`', ';', 'p', 'b', 'q', 'r', 'k', 'v', 'y', 'j', 'g', 'h', 'c', 'n', 'e', 'a', '[', 'w', 'x', 'i', 'o', ']', 's', 'm', '\'', '.', 'z', 'F', ',', 'D', 'U', 'L', 'T', '`', ';', 'P', 'B', 'Q', 'R', 'K', 'V', 'Y', 'J', 'G', 'H', 'C', 'N', 'E', 'A', '[', 'W', 'X', 'I', 'O', ']', 'S', 'M', '\'', '.', 'Z' );
		$new_search = str_replace( $lat, $cir, $wp_query->query_vars['s'] );
		
		// производим выборку из базы данных
		global $wpdb;
		$request = $wpdb->get_results( str_replace( $wp_query->query_vars['s'], $new_search, $query->request ) );
		
		if ( $request ) {
			$new_posts = array();
			foreach ( $request as $post ) {
				$new_posts[] = get_post( $post->ID );
			}
			if ( count( $new_posts ) > 0 ) {
				$posts = $new_posts;
			} 
		}
	}
	// возвращаем массив найденных постов
	return $posts;
}

#8 Поиск по категориям с выпадающим списком

Ещё одна возможность — позволить читателям фильтровать результаты поиска, ориентируясь на определенную категорию. Это можно реализовать с помощью простого раскрывающегося списка, содержащего все названия категорий. Всё, что вам нужно сделать — заменить стандартную форму поиска (обычно он находится в файле searchform.php) на фрагмент ниже:

<form role="search" method="get" id="searchform" action="<?php bloginfo('siteurl'); ?>">
	<div>
		<label class="screen-reader-text" for="s">Search for:</label>
		<input type="text" value="" name="s" id="s" /> 
		in <?php wp_dropdown_categories( 'show_option_all=All Categories' ); ?> 
		<input type="submit" id="searchsubmit" value="Search" />
	</div>
</form>

Сниппеты для админки

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

#1 Поиск записей в админке на ajax (без перезагрузки)

add_action( 'admin_print_footer_scripts', 'cody_search_posts_in_admin' );
function cody_search_posts_in_admin() {
	?>
	<script type="text/javascript">
	jQuery(document).ready(function($) {
		function cody_ajax_admin_search_update_search() {
			s = a.val().replace(' ', '+');
			var url = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
			for (var i = 0; i < url.length; i++) {
				if (/(^s$)|(\bs=.*\b)|(\bs=)/g.test(url[i]) === true || /http.*/g.test(url[i]) === true) y = i;
			}
			if (typeof y === 'undefined') url.unshift('s=' + s);
			else url[y] = 's=' + s;
			url = url.join('&');
			url = window.location.pathname + '?' + url;
			$.get(url, {}, function(data) {
				var r = $('<div />').html(data);
				var table = r.find(z);
				var tablenav_top = r.find(tnt);
				var tablenav_bottom = r.find(tnb);
				$(z).html(table);
				$(tnt).html(tablenav_top);
				$(tnb).html(tablenav_bottom);
			}, 'html');
			$(document).ajaxStop(function() {
				if (s.length) {
					history.pushState({}, "after search", url);
				} else {
					history.pushState({}, "empty search", url);
				}
			});
		}
		$(function() {
			a = $('input[type="search"]');
			t = a.closest('form').find('table');
			if (!t.length) t = a.closest('div').find('table');
			if (!t.length) return;
			z = '.' + t.attr('class').replace(/\s/g, '.');
			tn = '.top .displaying-num';
			bn = '.bottom .displaying-num';
			tpl = '.top span.pagination-links';
			bpl = '.bottom span.pagination-links';
			tnt = '.tablenav.top';
			tnb = '.tablenav.bottom';
			var timer;
			a.on('keyup', function(event) {
				if (timer) clearTimeout(timer);
				timer = setTimeout(cody_ajax_admin_search_update_search, 300);
			});
		});
	});
	</script>
	<?php
}

#2 Создание поисковой строки в списках категорий

Было — стало
add_action( 'admin_print_scripts', 'cody_admin_category_filter', 99 );
function cody_admin_category_filter() {
	
	$screen = get_current_screen();
	if( 'post' !== $screen->base ) return;
	
	?>
	<script>
	jQuery( document ).ready( function( $ ){
		var $div = $( '.categorydiv' );
		$div.prepend( '<input type="search" class="fc-search-field" placeholder="<?php _e( 'Фильтр', 'theme' ); ?>" style="width:100%" />' );
		$div.on( 'keyup search', '.fc-search-field', function ( event ) {
			var searchTerm = event.target.value,
				$listItems = $( this ).parent().find( '.categorychecklist li' );

			if( $.trim( searchTerm ) ){
				$listItems.hide().filter( function () {
					return $( this ).text().toLowerCase().indexOf( searchTerm.toLowerCase() ) !== -1;
				} ).show();
			} else {
				$listItems.show();
			}
		} );
	} );
	</script>
	<?php
}

У нас получилась неплохая подборка. Если у вас есть ещё идеи, пишите в комментариях.

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

Made with by WP Store