Создаем свой собственный поиск в 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, причем выдаваемые записи должны будут содержать поисковую фразу либо в своем заголовке, либо в контенте.
Самый простой способ создать свою собственную поисковую форму, предполагая, что вы хотите оставить стандартную форму в своем изначальном виде – это создать новый шаблон страницы с поисковой формой, закодированной под ваши требования, и привязать его к определенной странице.
Если же вы хотите обновить дефолтную поисковую форму – чтобы запустить поиск по фразам, к примеру – то в таком случае у вас есть два варианта, как поступить; в данном случае мы будем предполагать, что в вашем шаблоне поисковая форма не является жестко кодированной:
- Первый вариант – поместить произвольную поисковую форму в шаблон searchform.php. Всякий раз, когда функция get_search_form() будет вызвана, она в первую очередь будет использовать данный шаблон.
- Второй вариант – использовать фильтр 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;
}
Подсветка фразы реализована с помощью простого регулярного выражения.
Получение текста, содержащего поисковую фразу, оказалось не самым простым действием. Этому сильно поспособствовал тот факт, что контент каждого товара выводится в виде неупорядоченного списка с заголовком и описанием, однако попытка поиска соответствующего регулярного выражения не закончилась ничем, поэтому я решил обратиться к обработке строк.
Результат получился, тем не менее, достаточно хорошим:
Произвольные формы идеальны, когда вы хотите реализовать дополнительный поиск
Произвольные поисковые формы и функции идеальны в том случае, если вы хотите добавить дополнительную поисковую функцию, которая будет работать параллельно основной функции поиска и обладать некоторыми ограничениями.
В большинстве случаев вы сможете реализовать то, что вам нужно, путем использования произвольной поисковой формы, которая передает надлежащие параметры во встроенную функцию поиска. Вы можете легко протестировать использование параметров, добавив их к URL поиска.
Стоит заметить, что написание своей собственной функции поиска – не самая сложная задача. Вы можете воспользоваться дополнительными параметрами, чтобы управлять поведением поиска.
Источник: premium.wpmudev.org/blog
