Реализация расширенного поиска в WordPress
Я столкнулся с несколькими проблемами при создании собственной темы 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. Расширенный поиск с дополнительными параметрами
Я хочу осуществлять поиск по ключевым словам + категория + тег + мета-значение, примерно так:
Мне нужно устанавливать 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.

Если вы используете 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>

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

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

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

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

Похоже, у вас другая проблема. Возможно, будет лучше, если вы зададите новый вопрос и включите информацию о том, что делает функция 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..

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