В WordPress хук pre_get_posts — один из самых мощных инструментов для изменения основного запроса на вывод записей. Он позволяет гибко настраивать выборку постов на страницах архива, главной, в поиске и других местах без необходимости создавать собственные запросы с нуля.
Что такое pre_get_posts и зачем его использовать для фильтров
Хук pre_get_posts срабатывает до выполнения запроса WP_Query, поэтому именно в нем можно изменить параметры выборки. Это гораздо удобнее и оптимальнее, чем после получения результата фильтровать записи вручную.
Например, если вам нужно реализовать сложные фильтры по нескольким таксономиям и метаполям, или исключить из выборки определённые записи, вы можете сделать это централизованно через этот хук.
Важно помнить, что pre_get_posts срабатывает везде, где используется WP_Query, поэтому нужно обязательно проверять, что вы меняете именно нужный запрос — например, основной запрос на странице архива.
Пример: создание сложного AJAX-фильтра с таксономиями и метаполями
Рассмотрим практический пример, как с помощью pre_get_posts реализовать фильтр записей по нескольким параметрам — категориям, тегам и кастомному метаполю «цена».
Для начала добавим обработчик в functions.php вашей темы или плагина:
function wplessons_pre_get_posts_filter(\WP_Query $query) {
// Проверяем, что это не админка и основной запрос
if (is_admin() || !$query->is_main_query()) {
return;
}
// Пример: применяем фильтр только на главной странице архива записей
if (is_post_type_archive('post') || is_home()) {
$tax_query = [];
$meta_query = [];
// Фильтр по категориям, переданным в URL, например ?cat_filter=5,7
if (!empty($_GET['cat_filter'])) {
$cats = array_map('intval', explode(',', $_GET['cat_filter']));
$tax_query[] = [
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => $cats,
'operator' => 'IN',
];
}
// Фильтр по тегам, например ?tag_filter=wordpress,php
if (!empty($_GET['tag_filter'])) {
$tags = array_map('sanitize_text_field', explode(',', $_GET['tag_filter']));
$tax_query[] = [
'taxonomy' => 'post_tag',
'field' => 'slug',
'terms' => $tags,
'operator' => 'IN',
];
}
// Фильтр по метаполю 'price', например ?price_min=100&price_max=500
$price_min = isset($_GET['price_min']) ? (float)$_GET['price_min'] : 0;
$price_max = isset($_GET['price_max']) ? (float)$_GET['price_max'] : 0;
if ($price_min || $price_max) {
$meta_query[] = [
'key' => 'price',
'value' => [$price_min, $price_max],
'compare' => 'BETWEEN',
'type' => 'NUMERIC',
];
}
if ($tax_query) {
$query->set('tax_query', $tax_query);
}
if ($meta_query) {
$query->set('meta_query', $meta_query);
}
// Дополнительные настройки сортировки
if (!empty($_GET['orderby'])) {
$orderby = sanitize_text_field($_GET['orderby']);
if ($orderby === 'price') {
$query->set('orderby', 'meta_value_num');
$query->set('meta_key', 'price');
$query->set('order', 'ASC');
} elseif ($orderby === 'date') {
$query->set('orderby', 'date');
$query->set('order', 'DESC');
}
}
}
}
add_action('pre_get_posts', 'wplessons_pre_get_posts_filter');В этом коде мы строим два массива tax_query и meta_query в зависимости от параметров GET, переданных в URL. Это позволяет динамически менять выборку без создания дополнительных WP_Query.
Пояснение к параметрам фильтрации
- cat_filter — список ID категорий, по которым нужно отфильтровать посты
- tag_filter — список слуг тегов для фильтрации
- price_min и price_max — диапазон для числового метаполя «price»
- orderby — сортировка по цене или дате
Как использовать фильтр на фронтенде с AJAX
Для удобства пользователей фильтр часто делают AJAX-формой, чтобы при выборе параметров страница не перезагружалась. В этом случае нужно отправлять параметры на сервер и перезаписывать содержимое списка записей.
Например, используя jQuery, можно сделать примерно так:
jQuery(document).ready(function($) {
$('#filter-form').on('change', 'select, input', function() {
var data = $('#filter-form').serialize();
$.ajax({
url: window.location.href,
data: data,
type: 'GET',
success: function(response) {
var newContent = $(response).find('#posts-container').html();
$('#posts-container').html(newContent);
}
});
});
});Здесь #filter-form — форма с фильтрами, а #posts-container — контейнер с выводом записей. AJAX-запрос обновляет этот блок без полной перезагрузки.
Оптимизация и тонкости работы с pre_get_posts
Несмотря на мощь pre_get_posts, важно помнить о нескольких моментах:
- Обязательно проверяйте
is_main_query(), чтобы не менять запросы в админке или вспомогательные WP_Query. - Если используете
tax_queryиmeta_query— помните, что их сложные комбинации могут замедлить запросы. Важно тестировать производительность. - Для сложных фильтров с большим количеством параметров стоит рассмотреть кэширование результатов или использование плагинов оптимизации.
Также для визуализации фильтров на сайте можно использовать специализированные плагины, например, ABC Pagination — отличный инструмент для улучшения навигации по фильтрованным постам.
Заключение
Использование pre_get_posts — это самый правильный способ реализовать сложное фильтрование записей в WordPress без прямого вмешательства в SQL-запросы. Применяйте проверку условий, комбинируйте таксономии и метаполя, и не забывайте про оптимизацию.
Если хотите автоматизировать создание контента с фильтрами или улучшить UX, обратите внимание на плагины из каталога WPSHOP, которые помогут сделать ваш сайт ещё удобнее и функциональнее.