Диагностика: почему стандартные запросы не подходят для сложной фильтрации
В WordPress стандартные запросы WP_Query часто не позволяют гибко и эффективно фильтровать записи по сложным условиям, например, исключить определённые категории, добавить мета-запросы или изменить вывод на страницах архива и главной. Многие разработчики пытаются модифицировать запросы, используя параметры в шаблонах, но это не всегда удобно и ведёт к дублированию кода.
Для решения таких задач существует хук pre_get_posts, который позволяет изменять объект запроса до его выполнения. Однако неправильное использование этого хука может привести к проблемам, таким как изменение запросов в админке или на страницах, где этого не нужно.
Пошаговое решение: корректное применение pre_get_posts
1. Определяем, где нужно изменить запрос
Чтобы избежать влияния на админ-панель и другие запросы, обязательно проверяем параметры запроса:
function my_custom_filter( $query ) {
// Проверяем, что это основной запрос и не админка
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
// Пример: изменить запрос только на главной странице
if ( $query->is_home() ) {
// Добавляем условие фильтрации
}
}
add_action( 'pre_get_posts', 'my_custom_filter' );2. Добавляем условия фильтрации
Например, исключим из главной страницы записи из категории с ID 5 и добавим мета-запрос, чтобы выводить только опубликованные товары с метаполем in_stock равным 1.
function my_custom_filter( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( $query->is_home() ) {
// Исключаем категорию с ID 5
$query->set( 'cat', '-5' );
// Добавляем мета-запрос
$meta_query = array(
array(
'key' => 'in_stock',
'value' => '1',
'compare' => '=',
),
);
$query->set( 'meta_query', $meta_query );
}
}
add_action( 'pre_get_posts', 'my_custom_filter' );3. Обработка кастомных типов записей и таксономий
Если нужно фильтровать архив кастомного типа записей или таксономии, проверяем соответствующие условные теги и меняем параметры:
function my_custom_post_type_filter( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( $query->is_post_type_archive( 'product' ) ) {
// Выводим только опубликованные товары с ценой больше 1000
$meta_query = array(
array(
'key' => 'price',
'value' => 1000,
'compare' => '>',
'type' => 'NUMERIC',
),
);
$query->set( 'meta_query', $meta_query );
}
}
add_action( 'pre_get_posts', 'my_custom_post_type_filter' );Проверка результата после внедрения
- Очистите кеш сайта и браузера, чтобы изменения запроса вступили в силу.
- Откройте фронтенд страницы, где вы изменяли запрос (например, главную или архив кастомного типа).
- Проверьте, что записи отфильтрованы согласно заданным условиям (например, отсутствуют записи из исключённой категории или отображаются товары с метаполем
in_stock= 1). - Для детальной отладки можно временно добавить вывод SQL-запроса:
add_action( 'pre_get_posts', function( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
// Ваша логика
add_filter( 'posts_request', function( $sql ) {
error_log( $sql ); // Запишет запрос в error_log
return $sql;
} );
} );Частые ошибки и как их исправить
- Изменение запросов в админке: забыли проверить
is_admin(), из-за чего ломаются запросы в административной панели. Решение: всегда добавляйте проверкуif ( is_admin() ) return;. - Не проверяется основной запрос: изменения применяются ко всем WP_Query, включая вложенные запросы (например, в виджетах). Решение: используйте
$query->is_main_query()для попадания только в главный запрос. - Неправильный синтаксис мета-запросов: не указываете тип данных или используете неправильный ключ. Решение: всегда задавайте
typeв мета-запросах, особенно для чисел.
Практические советы по безопасности и производительности
- Не используйте
pre_get_postsдля сложных выборок с большими мета-запросами без индексации — это сильно нагружает базу данных. - При необходимости кэшируйте результаты запросов с помощью Transients API или плагинов кеширования.
- Избегайте дублирования логики фильтрации в шаблонах и хуках — централизуйте её в
pre_get_posts.
Сравнение способов фильтрации записей
| Метод | Плюсы | Минусы |
|---|---|---|
Использование pre_get_posts | Гибкая фильтрация, применяется до выполнения запроса, не требует кастомных запросов в шаблонах | Требует аккуратности, можно сломать админку без проверок |
| Создание кастомного WP_Query в шаблоне | Локальный контроль над выборкой, меньше риска повлиять на другие части сайта | Дублирование кода, хуже поддерживаемость |
| Использование плагинов фильтрации | Упрощение для неразработчиков, готовые интерфейсы | Может быть перегружено, меньше гибкости, влияет на производительность |