Создаем свой собственный поиск в WordPress

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

В данной статье мы посмотрим на то, как создать свой собственный поиск в WordPress, и заодно раскроем некоторые связанные с этим секреты.

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

Улучшаем поиск в WordPress путем добавления расширенной поисковой формы

За поиск WordPress отвечает класс WP_Query. Если вы раньше работали с произвольными циклами, то вы имеете представление о WP_Query.

WP_Query имеет массу возможных параметров, многие из которых могут быть легко определены в поисковой форме (или непосредственно в URL), что изменит поведение поиска.

К примеру, чтобы превратить обычный поиск в поиск по произвольному типу записей с названием product, достаточно ввести следующее:

http://www.yoursite.com/?s=football&post_type=product

В итоге мы получим результаты для записей с типом product, которые содержат в своем заголовке или контенте слово football.

Если вы пробежитесь по списку параметров WP_Query (он довольно обширный), то обнаружите много строковых и целочисленных параметров, которые вы можете легко закодировать в URL, чтобы изменить поведение поиска, начиная от добавления или исключения категорий и заканчивая добавлением поиска по таксономии и ограничением поиска по определенным авторам.

Помните, что для поиска важно включать параметр s в URL.

Существует также много дополнительных параметров, с помощью которых можно полностью изменить поведение, но которые, увы, не задокументированы в кодексе.

Поиск по фразе

По умолчанию WordPress совершает поиск по ключевому слову. Это означает, что если в поиск передан запрос «football boots», то WordPress формирует следующий код для условия WHERE:

((wp_posts.post_title LIKE '%football%') OR
(wp_posts.post_content LIKE '%football%')) 
AND
((wp_posts.post_title LIKE '%boots%') OR
(wp_posts.post_content LIKE '%boots%'))

Как вы можете видеть, здесь задан не поиск целой фразы, а поиск отдельных слов — «football» в заголовке или контенте и «boots» в заголовке или контенте. Таким образом, запись, содержащая слово «boot» в заголовке и «football» в контенте не будет, очевидно, соответствовать тому, что хотел получить пользователь, однако именно она будет выдана на экран.

Вы можете, правда, сделать так, чтобы WordPress искал фразы – для этого достаточно добавить sentence=1 в URL, что приведет к изменению условия WHERE:

((wp_posts.post_title LIKE '%football boots%') OR 
(wp_posts.post_content LIKE '%football boots%'))

Теперь поиск ведется по фразе, поэтому заголовок или контент материала должен фактически содержать оба слова (не обязательно подряд), чтобы быть найденным и выданным на экран. Попробуйте это сделать на своем собственном сайте. Запустите обычный поиск, после чего добавьте &sentence=1 к URL, и вы увидите, в чем состоит разница.

Поиск точного совпадения

Связанным с sentence, однако более специфичным является параметр exact. Добавление exact=1 к URL приведет к следующим изменениям в условии WHERE:

((wp_posts.post_title LIKE 'football boots') OR 
(wp_posts.post_content LIKE 'football boots'))

Вместо того чтобы разыскивать отличия, я сразу скажу вам, что единственная разница между условиях sentence и exact заключается в удалении % вокруг фразы в операторах LIKE. Такое удаление имеет большое значение, поскольку теперь заголовок или контент должен точно соответствовать поисковому запросу, а не просто включать его в себя.

То есть, если ни один продукт не имеет в заголовке фразы «football boots», то никаких результатов выдано не будет. Использовать exact нужно очень осторожно.

Изменение поисковой формы

Стандартная поисковая форма в WordPress довольно проста:

<form role="search" method="get" id="searchform" class="searchform" action="http://www.test.dev/">
<div>
<label class="screen-reader-text" for="s">Search for:</label>
<input type="text" value="" name="s" id="s" />
<input type="submit" id="searchsubmit" value="Search" />
</div>
</form>

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

<form role="search" method="get" id="searchform" action="http://www.test.dev/">
<div>
<label for="s">Search for:</label>
<input type="text" value="" name="s" id="s" />
<input type="hidden" value="1" name="sentence" />
<input type="hidden" value="product" name="post_type" />
<input type="submit" id="searchsubmit" value="Search" />
</div>
</form>

Эта поисковая форма при отправлении будет генерировать следующий URL:

http://www.test.dev/?s={query}&sentence=1&post_type=product

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

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

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

  1. Первый вариант – поместить произвольную поисковую форму в шаблон searchform.php. Всякий раз, когда функция get_search_form() будет вызвана, она в первую очередь будет использовать данный шаблон.
  2. Второй вариант – использовать фильтр get_search_form, что вынудит WordPress обратиться к вашей произвольной форме поиска.

Обе эти техники в деталях описаны в кодексе.

Когда произвольной формы недостаточно

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

Конкретный пример

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

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

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

Чтобы не трогать текущий поиск, была создана новая функция, которая:

  • Принуждала искать по фразе вместо поиска по ключевым словам
  • Ограничивала поиск по категориям журналов и буклетов
  • Выводила на экран и подсвечивала текст, содержащий соответствие поисковой фразе

Первые два требования можно было фактически реализовать с помощью произвольной поисковой формы:

<form role="search" method="get" id="searchform" action="http://www.test.dev/">
<div>
<label for="s">Search for:</label>
<input type="text" value="" name="s" id="s" />
<input type="hidden" value="1" name="sentence" />
<input type="hidden" value="product" name="post_type" />
<input type="hidden" value="product_cat" name="magazines,books" />
<input type="submit" id="searchsubmit" value="Search" />
</div>
</form>

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

Вот основная логика шаблона:

<div id="content" class="col-full">
    	
	<section id="main" class="col-left">
		
	<!-- begin search form -->
    	<form action="/library" method="post">
    			
		<p>
			<label for="query"><?php _e( 'Search', 'woothemes' ); ?></label>
			<input type="text" name="query" id="query" value="<?php echo esc_attr( $query ); ?>" />
		</p>
		<p>
			<input type="submit" id="searchsubmit" value="<?php _e( 'Search', 'woothemes' ); ?>" />
		</p>
 
    	</form>
    	<!-- end search form -->   	
    	
    	<?php 
    	
    	if( !empty( $query ) ) : 
 
        	$product_cats = 'books, renew, sanctuary';
  
  		$args = array(
  			'posts_per_page' => -1,
  			'post_type' => 'product',
			'orderby' => 'date menu_order', 
			'order' => 'DESC',
			's' => $query,
			'sentence' => 1,
			'product_cat' => $product_cats,
			
		);
  
         	// perform the search
        	$posts = new WP_Query( $args );
 
      		if( ( $posts->have_posts() ) ) : 
      		
      		?>
 
        		<header class="page-header">
          			<h1 class="page-title"><?php printf( __( 'Library Search Results for: %s', 'woothemes' ), $query ); ?></h1>
        		</header>
 
        		<?php /* The loop */ ?>
        		
        			<ul style="list-style: none">
        		
        		<?php  
        		      
        		while ( $posts->have_posts() ): $posts->the_post(); 
        		?>
          			<li style="display: block; margin-bottom: 50px">
							
					<div style="float: left; width: 110px;">	
					
						<a href="<?php echo get_permalink(); ?>">
							<?php echo get_the_post_thumbnail( $post->ID, array( 175, 175 ) ); ?>
						</a>
							
					</div>
 
					<div style="float:left; margin-left: 20px; width: 500px">
							
						<h2 style="margin-top: -10px; padding-top: 0px;">		
							<a href="<?php echo get_permalink(); ?>"	
								<?php echo apply_highlight( get_the_title() , $query ) ?>
							</a>
						</h2>
							
						<div><?php echo apply_highlight( get_snippet( get_the_content() , $query ) , $query ) ?></div>
								
					</div>
							
					<div style="clear:both"></div>
          				
          			</li>
          		<?php
        		endwhile; 
        		
        		?>
        			</ul>
        		<?php
 
        		wp_reset_postdata();
        		
        		?>
 
 
      		<?php 
      		
      		else : 
      		
      		?>
				
				<h1 class="page-title"><?php printf( __( 'Sorry, no matches found for "' . $query .'"', 'woothemes' )  ); ?></h1>
 
				<h4>Search Suggestions:</h4>
				<ul>
					<li>Check your spelling</li>
					<li>Try more general words</li>
					<li>Try different words that mean the same thing</li>
				</ul>
					
				<h1 class="page-title">Or, perhaps these might be of interest...</h1>
					
				<?php
								
						echo do_shortcode('[product_category per_page="3" columns="3" orderby="date" order="desc" category="books"]'); 
													
						echo do_shortcode('[product_category per_page="3" columns="3" orderby="date" order="desc" category="renew"]'); 
 
						echo do_shortcode('[product_category per_page="3" columns="3" orderby="date" order="desc" category="sanctuary"]'); 				
				
			endif; // !(empty ( $posts ))
 
		endif; // !(empty ( $query ))
		
		?>
                
        </section><!-- /#main -->
 
</div><!-- /#content -->

Как вы можете видеть, форма поиска напоминает стандартную поисковую форму в WordPress, поскольку все манипуляции с вызовом WP_Query выполняются через код, где:

  • post_type задается как product
  • sentence задается в 1 для инициирования поиска по фразе
  • добавляется параметр таксономии для ограничения поиска по трем выбранным категориям товаров
  • упорядочивание задается по дате, menu_order – по убыванию
  • все записи должны быть возвращены

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

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

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

function apply_highlight( $the_content , $the_query) {
 
	return preg_replace( '/' . $the_query . '/i' , '<span style="background-color: #00FF00">$0</span>' , $the_content );
 
}
 
function get_snippet( $the_content , $the_query ) {
 
	preg_match( '/' . $the_query . '/i' , $the_content , $matches, PREG_OFFSET_CAPTURE );
	
	$snippet = '<ul>';
	
	foreach ($matches as $match):
 
		$cutoff = substr( $the_content, 0 , $match[1] );
		
		$start = strripos( $cutoff, '<li>' );
		$end = strpos( $the_content, '</li>' , $match[1] );
		
		$snippet .= substr( $the_content, $start, ( $end - $start ) + 4 );
		
		//$snippet .= $match[0] . ' - ' . $match[1];
 
	endforeach;
 
	$snippet .= '</ul>';
	
	return $snippet;
}

Подсветка фразы реализована с помощью простого регулярного выражения.

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

Результат получился, тем не менее, достаточно хорошим:

custom_search

Произвольные формы идеальны, когда вы хотите реализовать дополнительный поиск

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

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

Стоит заметить, что написание своей собственной функции поиска – не самая сложная задача. Вы можете воспользоваться дополнительными параметрами, чтобы управлять поведением поиска.

Источник: premium.wpmudev.org/blog

Блог про WordPress
Комментарии: 16
  1. Otshelnik-fm

    вопрос: &exact=1 — у вас работает?

    У меня никак не получилось заставить работать этот вызов. Хотя в файле вордпресса query.php есть вызов $n = !empty($q[‘exact’]) ? » : ‘%’; -так что должно работать, а не хочет. Спрошу еще и у источника

    А &sentence=1 -да это крутая штука. И она работает

  2. Otshelnik-fm

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

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

    1. Дмитрий (автор)

      Да, тоже замечал это. Никаких уведомлений не присылают, просто перезагружают страницу, я в итоге забил на оставление комментариев. Про exact, к сожалению, не в курсе — этот параметр не задокументирован в кодексе, но имеется в query.php, как вы и привели выше, поэтому, в принципе, должен работать.

  3. Anton

    ужасный баннер

    1. Дмитрий (автор)

      Какой баннер?

  4. Катя

    У меня поиск на сайте ограничивается поиском по заголовкам и словам в текстах. Как организовать код, чтобы поиск велся по всему: категориям, меткам, заголовкам?

    1. Наталья

      Катя, вы решили вопрос с поиском?

  5. Дмитрий (автор)

    Прекрасная замена стандартного поиска — https://wordpress.org/plugins/search-filter/. Умеет искать по разным таксономиям и т.д.

  6. Анатолий

    Как раз пытаюсь написать свой поиск по сайту на вордпресс. У меня поиск должен работать не по постам а по таблице с данными кирпичей — она создана с помощью отдельного самописного поиска.
    Ваш материал по поиску мне очень помог.
    Спасибо

  7. Данил

    Добрый день , что мне нужно сделать, чтобы получить «Поиск точного совпадения», я нашел файл query.php, но так и не понял что делать в нем. Либо не в нем? Помогите пожалуйста. Мне необходимо сделать поиск по меткам так чтобы искало , например «большая футболка», а не «большая» и «футболка»

  8. Артем

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

  9. Олег

    Добрый день. Возникла ситуация делаю сайт на wp это 4 сайт. На данном сайте необходимо:

    Поиск: вывести в алфавитный указатель.

    Алфавит:

    при клике на букву переходим на страницу с алфавитным указателем и продукцией выстроенной по алфавиту внутри групп. Если в группе на эту букву нет продукции, группа не выводится.
    Сортировать статьи по алфавиту — этой функции на сайте нет. Необходимо ее добавить.
    Задача:
    1 сортировка по алфавиту должна быть таким образом, чтобы сортировалось именно по типу продукции, Например: если у статьи заголовок H1 производство болтов. Данная статья должна отображаться по буквой Б.
    Сохранить уникальный заголовок H1 в статье нам необходимо для сео, чтобы не писать: Болты. Производство болтов.
    Это тз . У меня получается что выводятся только категории. без записей и выводит по первой букве Категории. Немного не понимаю от чего оттолкнуться. Если возможно помогите. Заранее спасибо!

    1. Дмитрий (автор)

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

      Проще поставить метку «Болты» у статьи и потом вывести по метке, чем так возиться.

  10. Сергей Нестеровский

    Я написал свой шаблон и подключил его в WordPress. В шапке шаблона у меня стоит форма поиска, форма нормально работает только на главной странице. Если перейти на любую другую страницу, например /about и ввести любую поисковую фразу, то WP редиректит на 404 страницу, потому, что подставляет в url /about/?s=ключевая%20фраза
    вместо /?s=ключевая%20фраза . Подскажите в чём проблема?

    1. Дмитрий (автор)

      Нужно смотреть, как именно сделана эта форма — плагинами или сама тема добавляет форму поиска.
      Есть ли файл searchform.php в теме? Если да, копайте в него.
      Если нет, то смотрите в functions.php. Там должен быть код для хука get_search_form.

  11. Андрей

    Как сделать поиск по 3м полям откуда-куда-дата(интервал) ? Данные есть в подгруженной базе и в постах. Нигде не видел плагинов или объяснений

Добавить комментарий для Дмитрий Отменить ответ

Получать новые комментарии по электронной почте.