WP_Query — один из самых мощных и часто используемых классов в WordPress для выборки записей из базы данных. Однако стандартный набор аргументов не всегда покрывает все задачи, особенно если нужна более сложная логика отбора. В таких случаях можно создавать кастомные условные аргументы и интегрировать их в WP_Query, расширяя возможности фильтрации.
Зачем создавать кастомные условные аргументы для WP_Query
Стандартный WP_Query умеет фильтровать по типу поста, таксономиям, статусу, дате, метаполям и многому другому. Но если нужно использовать уникальные условия, например, комбинировать несколько метаполей с особой логикой или создавать условные фильтры, которые не предусмотрены в ядре, — кастомные аргументы помогут сделать запросы более гибкими и удобочитаемыми.
Плюсы такого подхода:
- Чистый и понятный код запроса WP_Query;
- Повторное использование условий в разных частях сайта;
- Облегчение поддержки и масштабирования проекта;
- Возможность объединять сложные условия без дублирования кода.
Как реализовать кастомные условные аргументы для WP_Query
Для начала разберёмся, как WordPress обрабатывает аргументы WP_Query. Все аргументы передаются в SQL-запрос через фильтры. Чтобы добавить свои условия, можно воспользоваться фильтрами posts_where, posts_join, posts_groupby и posts_orderby.
Основная идея: перед запуском запроса добавить в аргументы специальные ключи, например wpquery_custom_flag, и затем в фильтре posts_where проверить наличие этого ключа и изменить SQL.
Пример создания кастомного аргумента: выбор записей с метаполем "rating" больше заданного значения
function wpquery_add_custom_where( $where, $query ) {
global $wpdb;
$custom_rating = $query->get( 'wpquery_min_rating' );
if ( $custom_rating ) {
$where .= $wpdb->prepare( " AND EXISTS (
SELECT 1 FROM {$wpdb->postmeta} pm
WHERE pm.post_id = {$wpdb->posts}.ID
AND pm.meta_key = 'rating'
AND pm.meta_value >= %d
)", intval( $custom_rating ) );
}
return $where;
}
add_filter( 'posts_where', 'wpquery_add_custom_where', 10, 2 );В этом примере мы добавили поддержку аргумента wpquery_min_rating, который позволяет фильтровать посты по метаполю rating с минимальным значением.
Пример использования в коде WP_Query:
$args = [
'post_type' => 'product',
'wpquery_min_rating' => 4,
'posts_per_page' => 10
];
$query = new WP_Query( $args );Такой подход позволяет расширять WP_Query практически без ограничений, создавая собственные фильтры для разных нужд.
Работа с JOIN: добавляем кастомные соединения таблиц
Если для реализации кастомных условий нужно подключить дополнительные таблицы, например, для сложных мета-запросов или связей с таксономиями, можно использовать фильтр posts_join. Ниже пример, как добавить JOIN по таблице постов метаданных для оптимизации запроса из предыдущего примера.
function wpquery_add_custom_join( $join, $query ) {
global $wpdb;
if ( $query->get( 'wpquery_min_rating' ) ) {
$join .= " INNER JOIN {$wpdb->postmeta} pm ON pm.post_id = {$wpdb->posts}.ID ";
}
return $join;
}
add_filter( 'posts_join', 'wpquery_add_custom_join', 10, 2 );Это ускорит выполнение запроса, так как мы явно укажем соединение с таблицей postmeta.
Обработка сортировки по кастомным аргументам
Если нужно сортировать по кастомным правилам, есть фильтр posts_orderby. Например, сортировка по метаполю rating:
function wpquery_add_custom_orderby( $orderby, $query ) {
global $wpdb;
if ( $query->get( 'wpquery_min_rating' ) ) {
$orderby = "CAST(pm.meta_value AS UNSIGNED) DESC";
}
return $orderby;
}
add_filter( 'posts_orderby', 'wpquery_add_custom_orderby', 10, 2 );Важно, чтобы этот фильтр работал вместе с posts_join, добавляющим JOIN к таблице postmeta.
Управление сложными условиями: пример фильтрации по нескольким метаполям
Частая задача — фильтрация по нескольким метаполям с логикой И/ИЛИ. Создадим кастомный аргумент wpquery_meta_conditions, принимающий массив условий:
function wpquery_add_complex_meta_where( $where, $query ) {
global $wpdb;
$meta_conditions = $query->get( 'wpquery_meta_conditions' );
if ( $meta_conditions && is_array( $meta_conditions ) ) {
$clauses = [];
foreach ( $meta_conditions as $condition ) {
$key = isset( $condition['key'] ) ? $condition['key'] : '';
$value = isset( $condition['value'] ) ? $condition['value'] : '';
$compare = isset( $condition['compare'] ) ? $condition['compare'] : '=';
if ( $key && $value !== '' ) {
$clauses[] = $wpdb->prepare(
"EXISTS (SELECT 1 FROM {$wpdb->postmeta} pm WHERE pm.post_id = {$wpdb->posts}.ID AND pm.meta_key = %s AND pm.meta_value {$compare} %s)",
$key,
$value
);
}
}
if ( $clauses ) {
$where .= ' AND (' . implode(' OR ', $clauses) . ')';
}
}
return $where;
}
add_filter( 'posts_where', 'wpquery_add_complex_meta_where', 10, 2 );Использование:
$args = [
'post_type' => 'post',
'wpquery_meta_conditions' => [
[ 'key' => 'color', 'value' => 'blue', 'compare' => '=' ],
[ 'key' => 'size', 'value' => 'large', 'compare' => '=' ]
],
'posts_per_page' => 5
];
$query = new WP_Query( $args );Этот запрос выберет посты, у которых метаполе color равно blue ИЛИ метаполе size равно large.
Практические советы и оптимизация
1. Всегда проверяйте SQL-запросы, которые формируются, с помощью echo $query->request; или плагинов для отладки запросов. Это помогает находить ошибки и узкие места.
2. Используйте индексы в базе данных на колонках meta_key и meta_value — это существенно ускорит мета-запросы.
3. Не добавляйте лишние JOIN и WHERE, если кастомные аргументы не используются — проверяйте наличие аргументов в фильтрах.
4. Для сложных фильтров с большим количеством условий лучше рассмотреть кэширование результатов, чтобы снизить нагрузку на базу.
Альтернативные решения: плагины и готовые инструменты
Если хочется не писать фильтры с нуля, обратите внимание на плагины, которые расширяют возможности WP_Query и мета-запросов:
- Clearfy Pro — содержит инструменты для оптимизации и расширения запросов;
- Expert Review — позволяет создавать сложные условия для выбора записей с отзывами;
- ACF (Advanced Custom Fields) совместим с WP_Query и позволяет добавлять метаполя для фильтрации.
Эти плагины помогут быстро внедрить сложную логику без глубокого погружения в SQL.
Итоги
Создание кастомных условных аргументов для WP_Query — мощный способ расширить стандартную выборку записей в WordPress. Используя фильтры posts_where, posts_join и posts_orderby, вы сможете реализовать практически любые задачи по фильтрации и сортировке. Главное — грамотно структурировать код, оптимизировать запросы и тестировать их на производительность.