Wordpress.Поиск по категориям и дополнительным полям

По умолчанию WordPress ищет по заголовку и тексту записи, давайте попробуем научить его искать в определенной категории.

Поиск в категории.

Первым делом нужно добавить список категорий в форму поиска. Есть два способа, выбирайте который вам подходит:

  1. Создать шаблон формы поиска в папке с темой
  2. Переопределить вывод формы своей функцией.

Создание шаблона формы поиска.

Шаблон должен называться 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()

Ну вот, список категорий мы добавили:

Wordpress.Поиск по категориям и дополнительным полям

Теперь сделаем чтобы оно работало. В файле 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;
?>

И выглядеть она будет так:

Wordpress.Поиск по категориям и дополнительным полям

И тут то нас поджидают неприятности(((, сделать как с категориями и доп.полями как выше мы не сможем(насколько я понял). Во-первых потому что дополнительные поля хранятся как текст, а во-вторых хотя и дополнительные поля можно сравнивать и есть даже у них параметр '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"

И все у нас прекрасно работает! Естественно при реальном внедрении может быть понадобится намного больше времени и возни, но программу минимум мы выполнили и теперь знаем как делать такие вещи.