Wordpress.Поиск по категориям и дополнительным полям
По умолчанию WordPress ищет по заголовку и тексту записи, давайте попробуем научить его искать в определенной категории.
Поиск в категории.
Первым делом нужно добавить список категорий в форму поиска. Есть два способа, выбирайте который вам подходит:
- Создать шаблон формы поиска в папке с темой
- Переопределить вывод формы своей функцией.
Создание шаблона формы поиска.
Шаблон должен называться searchform.php
и содержать следующий код(с вашими поправками):
<?php
$dropdowncats = wp_dropdown_categories('echo=0&show_option_none=Все категории');
$form =
'<form id="searchform" role="search" method="get" action="' . home_url( '/' ) . '" >
<div>
<label for="s">Поиск</label>
<input name="s" id="s" type="text" value="' . get_search_query() . '" />' . $dropdowncats .
'<input type="submit" class="submit" name="submit" id="searchsubmit" value="Найти" />
</div>
</form>';
echo $form;
?>
Давайте разберем что тут такое.
Первым делом в переменную $dropdowncats
заносим список категорий в виде списка select
, потом в переменную $form
всю нашу форму и выводим ее echo $form;
Теперь вы можете вызвать эту форму в любом месте с помощью функции get_search_form()
Переопределение вывода формы своей функцией.
Почти то же самое.
<?php
function my_get_search_form() {
do_action( 'get_search_form' );
$dropdowncats = wp_dropdown_categories("echo=0&show_option_none=Все категории");
$form =
'<form id="searchform" role="search" method="get" action="' . home_url( '/' ) . '" >
<div>
<label for="s">Поиск</label>
<input name="s" id="s" type="text" value="' . get_search_query() . '" />' . $dropdowncats .
'<input type="submit" class="submit" name="submit" id="searchsubmit" value="Найти" />
</div>
</form>';
echo apply_filters('get_search_form', $form);
}
?>
И теперь можно вызывать ее в любом месте: my_get_search_form()
Ну вот, список категорий мы добавили:
Теперь сделаем чтобы оно работало. В файле function.php
пишем:
add_action('pre_get_posts', 'search_by_cat');
function search_by_cat() {
global $wp_query;
if (is_search()) {
$cat = intval($_GET['cat']);
if($cat<0) $cat='';
$wp_query->query_vars['cat'] = $cat;
}
}
Итак, мы пишем функцию, которая проверяет страница ли поиска это, и берет с глобальной переменной $_GET
категорию, так как пункт “Все категории” будет у нас иметь значение “-1″, то проверяем это дело и если никакая категория не выбрана, в $cat
ничего не пишем.
Далее мы эту нашу функцию вешаем на хук pre_get_posts
, которая выполняется до запроса в базу данных. Тем самым мы заставляем WordPress к запросу по умолчанию добавить еще один параметр – ID
категории из которой мы хотим произвести поиск.
Поиск по дополнительным полям.
Теперь давайте представим, что категории у нас – это список производителей автомобилей, типа: Mercedes, Nissan, Toyota и т.д. И у нас в дополнительных полях каждой записи есть ключ body и в нем может быть значения: sedan, coupe и т.д. Как же в этом случае? А в этом случае все так же, только одно отличие список нужно будет делать самому:
<select id="body" name="body">
<option value="sedan">Седан</option>
<option value="coupe">Купе</option>
<option value="etc">И т.д.</option>
</select>
ну или что-то в этом роде. Вставляете список в шаблон формы поиска, ну а функция немного изменится:
add_action('pre_get_posts', 'search_by_tag');
function search_by_tag() {
global $wp_query;
if (is_search()) {
$meta_key = ‘body’;
$meta_value = intval($_GET['body']);
$wp_query->query_vars['meta_key'] = $meta_key;
$wp_query->query_vars['meta_value'] = $meta_value;
}
}
То есть так же как и с категорией, только параметра два: имя ключа и его значение.
Сложный пример.
Перейдем к примеру посложнее. Окей, у нас в дополнительных полях будут цены 8-Q. И форма поиска у нас будет такая:
<?php
$dropdowncats = wp_dropdown_categories('echo=0&show_option_none=Select category');
$form =
'<form role="search" method="get" action="' . home_url( '/' ) . '" >
<div>
<label for="s">' . __('Search for:') . '</label>
<input type="text" value="' . get_search_query() . '" />' . $dropdowncats .
'<label for="pfrom">Цена от:</label><input id="pfrom">
<label for="pto">до:</label>
<input type="text">' . '<input id="searchsubmit" value="'. esc_attr__('Search') .'" />
</div>
</form>';
echo $form;
?>
И выглядеть она будет так:
И тут то нас поджидают неприятности(((, сделать как с категориями и доп.полями как выше мы не сможем(насколько я понял). Во-первых потому что дополнительные поля хранятся как текст, а во-вторых хотя и дополнительные поля можно сравнивать и есть даже у них параметр 'meta_compare' который может быть =
,!=
, >
, >=
, <
, или <=
, по умолчанию =
, но он не может делать то, что мы хотим: сравнивать от и до.
Ладно пойдем другим путем, более сложным, но не менее интересным.
Идем в файл function.php
и пишем функцию:
function is_price() {
if( isset($_GET['pfrom']) & isset($_GET['pto']) ) {
if( !empty($_GET['pfrom']) & !empty($_GET['pto']) )
return true;
}
return false;
}
Здесь мы проверяем установлены ли переменные и не пусты ли они. $pfrom
– это "от", а $pto
– это "до". Расшифровывается как price from, price to.
Далее пишем функцию и вешаем ее на posts_join
:
function search_meta_join($join) {
global $wpdb;
if( is_search() && is_price() ) {
$join .= " JOIN $wpdb->postmeta ON $wpdb->posts.ID = $wpdb->postmeta.post_id ";
}
return $join;
}
add_filter('posts_join', 'search_meta_join');
Тут мы проверяем правда ли это страница поиска и наши переменные, и… И говорим WordPress, что мы хотим к его запросу к базе добавить данные из таблицы postmeta. Ну и последняя функция:
function search_meta_where($where) {
global $wp_query, $wp_version, $wpdb;
if( !empty($wp_query->query_vars['s']) && is_price() ) {
$pfrom = $_GET['pfrom'];
$pto = $_GET['pto'];
$where .= " AND $wpdb->postmeta.meta_key = 'price' AND $wpdb->postmeta.meta_value >= $pfrom AND $wpdb->postmeta.meta_value <= $pto";
}
return $where;
}
add_filter('posts_where', 'search_meta_where');
Ну здесь мы опять проверяем поиск ли это, и установлены ли наши “от” и “до”. И указываем WordPress, какие нам именно данные из таблицы postmeta
нужны. То есть например если у нас “от 10 000 до 20 000”, то так и пишем, больше или равно и меньше или равно: $wpdb->postmeta.meta_value >= $pfrom AND $wpdb->postmeta.meta_value <= $pto"
И все у нас прекрасно работает! Естественно при реальном внедрении может быть понадобится намного больше времени и возни, но программу минимум мы выполнили и теперь знаем как делать такие вещи.