Реализация расширенного поиска в WordPress

26 окт. 2016 г., 05:24:21
Просмотры: 1.05K
Голосов: 1

Я столкнулся с несколькими проблемами при создании собственной темы WordPress:

1. Как избежать жесткого кодирования URL поиска в файле searchform.php.

Типичный шаблон может выглядеть так:

<form class="search" method="get" action="<?php echo get_search_link(); ?>" role="search">
    <input class="search-input" type="search" name="s">
    <button class="search-submit" type="submit" role="button">Поиск</button>
</form>

Обратите внимание на action="<?php echo get_search_link(); ?> - URL жестко закодирован, он предполагает, что путь поиска будет http://homeurl/?s=xxx. Но что если плагин изменит путь поиска на что-то вроде http://homeurl/search?s=xxx?

2. Изменение URL поиска

Мне не нравится стандартный путь /?s=xxx для поиска, я хочу что-то вроде /search?s=xxx.

3. Расширенный поиск с дополнительными параметрами

Я хочу осуществлять поиск по ключевым словам + категория + тег + мета-значение, примерно так:

Пример интерфейса расширенного поиска в WordPress

Мне нужно устанавливать URL поиска для каждой ссылки в панели и выделять ее, если это текущий параметр запроса.

Возможно ли это?


(Обновленная проблема была опубликована в новом посте здесь)

Согласно ответу cybmeta, я внес следующие изменения:

add_action('pre_get_posts', 'include_any_post_type_in_search');
function include_any_post_type_in_search($query)
{
    if (!is_admin() && $query->is_search && $query->is_main_query()) {
        $tax_query = array(
            'relation' => 'AND'
        );

        if (isset($_REQUEST['c'])) {
            $cate = $_REQUEST['c'];
            array_push($tax_query, array(
                'taxonomy' => 'category',
                'terms' => sanitize_text_field($cate)
            ));
        }

        if (isset($_REQUEST['t'])) {
            $tag = $_REQUEST['t'];
            array_push($tax_query, array(
                'taxonomy' => 'post_tag',
                'terms' => sanitize_text_field($tag)
            ));
        }
        $query->set('tax_query', $tax_query);
    }
}

add_filter('query_vars', 'cyb_query_vars');
function cyb_query_vars($vars)
{
    array_push($vars, "t", "c");
    return $vars;
}

function my_get_search_url($key, $val)
{
    $query = array();
    $supported = array("c", "t", "k");
    foreach ($supported as $s) {
        if ($s == $key) {
            array_push($query, "$s=$val");
        } else {
            $old_val = get_query_var($s);
            if (isset($old_val) && !empty($old_val)) {
                array_push($query, "$s=$old_val");
            }
        }
    }
    return get_search_link(join("&", $query));
}

Затем используем это так:

<?php
$cates = get_categories();
foreach ($cates as $cate) { ?>
    <li>
        <a href="<?php echo my_get_search_url('c', $cate->term_id); ?>"><?php echo $cate->name; ?></a>
    </li>
<?php } ?>

Это генерирует URL типа: /search/c%3D9:

1. Параметр c=9 кодируется

2. Отображается главная страница вместо страницы результатов поиска.

При этом если я перейду по /?c=9&s=1, я получу результаты с ключевым словом 1 и категорией 9.

Для /?c=9 получаю главную страницу.

Для /search?c=9 получаю 404 ошибку.

Похоже, есть проблемы с rewrite rules.

1
Комментарии
  1. да, это возможно. 2. Вопросы должны быть о коде или основных концепциях, нет смысла задавать широкие теоретические вопросы, так как ответ обычно короткий и не очень полезный
Mark Kaplun Mark Kaplun
26 окт. 2016 г. 05:41:20
Все ответы на вопрос 1
7

Если вы используете get_search_link() и кто-то фильтрует URL поиска и изменяет его, get_search_link() вернет отфильтрованный URL; в этом и заключается прелесть нежестко заданных URL. Вы или сторонний плагин можете изменить URL, и он всегда будет возвращать корректное значение. Таким образом, проблемы 1 и 2, кажется, не существуют.

Проблема 3 имеет разные подходы:

1.- Использовать поля ввода в форме поиска с name, равным некоторому аргументу запроса, напрямую принимаемому WP_Query как строка запроса. Например, category_name:

<form class="search" method="get" action="<?php echo get_search_link(); ?>" role="search">
    <input class="search-input" type="search" name="s">
   <select name="category_name">
        <option value="">Все категории</option>
        <option value="politics">Политика</option>
        <option value="economy">Экономика</option>
    </select>
    <button class="search-submit" type="submit" role="button">Поиск</button>
</form>

2.- Использовать любую строку запроса и подключить WP_Query к запросу поиска в действии pre_get_posts:

HTML:

<form class="search" method="get" action="<?php echo get_search_link(); ?>" role="search">
    <input class="search-input" type="search" name="s">
   <select name="a_search_filter">
        <option value="">Все категории</option>
        <option value="politics">Политика</option>
        <option value="economy">Экономика</option>
    </select>
    <button class="search-submit" type="submit" role="button">Поиск</button>
</form>

И действие:

add_action( 'pre_get_posts', 'cyb_advanced_search' );
function cyb_advanced_search( $query ) {

    if ( ! is_admin() && $query->is_search && $query->is_main_query() ) {

        // Установите необходимые параметры запроса
        // Например
        $search_filter = $_REQUEST[ 'a_search_filter' ];
        $tax_query = [
            'taxonomy' => 'news',
            'field'    => 'slug',
            'terms'    =>  sanitize_text_field( $search_filter ),
        ];
        $query->set( 'tax_query', $tax_query );

    }
}

Я бы добавил строку запроса в систему WP Rewrite:

add_filter( 'query_vars', 'cyb_query_vars' );
function cyb_query_vars( $vars ) {
  $vars[] = 'a_search_filter';
  return $vars;
}

Теперь вы используете get_query_var() для получения значения пользовательской переменной запроса:

add_action( 'pre_get_posts', 'cyb_advanced_search' );
function cyb_advanced_search( $query ) {

    if ( ! is_admin() && $query->is_search && $query->is_main_query() ) {

        // Установите необходимые параметры запроса
        // Например
        $search_filter = get_query_var( 'a_search_filter' );
        $tax_query = [
            'taxonomy' => 'news',
            'field'    => 'slug',
            'terms'    =>  sanitize_text_field( $search_filter ),
        ];
        $query->set( 'tax_query', $tax_query );

    }
}

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

if( get_query_var(  'a_search_filter' ) ==  'category1' ) {
    $class = 'selected';
}

<a href="..." class=".<?php esc_attr_e( $class ); ?>.">Категория 1</a>
26 окт. 2016 г. 05:53:21
Комментарии

Спасибо за подробный ответ. И вы имеете в виду, что все принятые аргументы запроса можно использовать прямо в URL поиска как переменные запроса, такие как category_name? Я даже не знал об этом :(

hguser hguser
26 окт. 2016 г. 06:17:38

Не все аргументы запроса, только те, которые принимаются как строка запроса. Например, вы можете использовать https://example.com/?s=keyword&category_name=politics, и результаты поиска будут искать keyword в статьях, принадлежащих категории politics. К сожалению, я не знаю точного списка аргументов, которые можно использовать напрямую как строку запроса, но аргументы, которые вы видите в документации в формате key=value, должны работать, включая post_type, author и многие другие.

cybmeta cybmeta
26 окт. 2016 г. 06:40:33

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

hguser hguser
26 окт. 2016 г. 06:49:33

Конечно, я не тестировал это, просто написал здесь. Исправлено.

cybmeta cybmeta
26 окт. 2016 г. 06:58:23

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

hguser hguser
26 окт. 2016 г. 07:12:17

Похоже, у вас другая проблема. Возможно, будет лучше, если вы зададите новый вопрос и включите информацию о том, что делает функция my_get_search_url() и какой результат вы ожидаете. /?c=9 загружает индекс, а /search?c=9 выдает 404 ошибку, что кажется мне правильным поведением, если вы не запрограммировали другое поведение для таких URL; по умолчанию WordPress распознает поисковый запрос (is_search() возвращает true) только если установлена query var s (см. строку 1646 (WP 4.6) в wp-includes/query.php..

cybmeta cybmeta
26 окт. 2016 г. 10:59:06

Я создаю новую запись:http://wordpress.stackexchange.com/q/244088/104900

hguser hguser
27 окт. 2016 г. 00:47:14
Показать остальные 2 комментариев