Фильтрация записей по мета полям — одна из востребованных задач при разработке сложных сайтов на WordPress. Особенно когда нужно дать пользователям возможность выбирать записи по произвольным параметрам, например, по цене, рейтингу, дате или другим пользовательским данным.
Почему важна динамическая фильтрация по мета полям в WordPress
Стандартный WP_Query позволяет легко фильтровать записи по мета полям, но если нужно создавать универсальный фильтр, который будет обрабатывать разные поля и значения на лету, приходится писать собственные динамические функции. Это особенно актуально для каталогов, интернет-магазинов и сайтов с большим количеством кастомных данных.
Динамическая функция позволяет не дублировать код, уменьшает вероятность ошибок и упрощает поддержку кода.
В этой статье мы создадим универсальную функцию фильтрации, которую можно использовать в темах и плагинах, а также рассмотрим примеры расширения с AJAX и интеграцией с плагинами.
Основы фильтрации по мета полям в WP_Query
Для начала напомню, что фильтрация по мета полям осуществляется через параметр meta_query в WP_Query. Пример базового запроса:
$args = [
'post_type' => 'product',
'meta_query' => [
[
'key' => 'price',
'value' => 1000,
'compare' => '>=',
'type' => 'NUMERIC'
]
]
];
$query = new WP_Query($args);Этот запрос выведет все товары с ценой больше или равной 1000. Но если у нас много полей и разные условия, то хочется обобщить это в функцию.
Создание динамической функции фильтра по мета полям
Рассмотрим пример функции wpmy_filter_by_meta, которая принимает массив фильтров и возвращает результаты:
function wpmy_filter_by_meta($post_type, $filters = []) {
$meta_query = ['relation' => 'AND'];
foreach ($filters as $filter) {
if (empty($filter['key']) || !isset($filter['value'])) {
continue;
}
$meta_query[] = [
'key' => $filter['key'],
'value' => $filter['value'],
'compare' => $filter['compare'] ?? '=',
'type' => $filter['type'] ?? 'CHAR'
];
}
$args = [
'post_type' => $post_type,
'meta_query' => $meta_query,
'posts_per_page' => $filters['posts_per_page'] ?? 10
];
return new WP_Query($args);
}Функция принимает название типа записей и массив фильтров, где каждый фильтр это ассоциативный массив с ключами key, value, compare и type. Это позволяет гибко настраивать условия.
Пример вызова:
$filters = [
[
'key' => 'price',
'value' => 500,
'compare' => '>=',
'type' => 'NUMERIC'
],
[
'key' => 'color',
'value' => 'red',
'compare' => '='
]
];
$query = wpmy_filter_by_meta('product', $filters);
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
echo '<h2>' . get_the_title() . '</h2>';
echo '<p>Цена: ' . get_post_meta(get_the_ID(), 'price', true) . '</p>';
}
wp_reset_postdata();
}Расширение фильтра: поддержка диапазонов и множественных значений
Для более сложных задач часто нужны фильтры с диапазонами, например, цены от и до, или выбор из нескольких значений. Расширим функцию, чтобы поддерживать такие случаи.
Добавим поддержку ключей value_min и value_max для диапазонов, а также value_in для множественного выбора:
function wpmy_filter_by_meta_extended($post_type, $filters = []) {
$meta_query = ['relation' => 'AND'];
foreach ($filters as $filter) {
if (empty($filter['key'])) {
continue;
}
if (isset($filter['value_min']) && isset($filter['value_max'])) {
$meta_query[] = [
'key' => $filter['key'],
'value' => [$filter['value_min'], $filter['value_max']],
'compare' => 'BETWEEN',
'type' => $filter['type'] ?? 'NUMERIC'
];
} elseif (isset($filter['value_in']) && is_array($filter['value_in'])) {
$meta_query[] = [
'key' => $filter['key'],
'value' => $filter['value_in'],
'compare' => 'IN',
'type' => $filter['type'] ?? 'CHAR'
];
} elseif (isset($filter['value'])) {
$meta_query[] = [
'key' => $filter['key'],
'value' => $filter['value'],
'compare' => $filter['compare'] ?? '=',
'type' => $filter['type'] ?? 'CHAR'
];
}
}
$args = [
'post_type' => $post_type,
'meta_query' => $meta_query,
'posts_per_page' => $filters['posts_per_page'] ?? 10
];
return new WP_Query($args);
}Теперь можно фильтровать, например, так:
$filters = [
[
'key' => 'price',
'value_min' => 1000,
'value_max' => 5000
],
[
'key' => 'color',
'value_in' => ['red', 'blue', 'green']
]
];
$query = wpmy_filter_by_meta_extended('product', $filters);Практические советы по оптимизации запросов
Фильтрация по мета полям может быть ресурсоёмкой, особенно при большом объёме данных. Чтобы ускорить запросы, рекомендуется:
- Добавлять индексы на таблицу мета данных в базе данных (wp_postmeta).
- Использовать кэширование результатов через Transients API или внешние системы кэширования.
- Минимизировать количество условий в
meta_query, объединять их, если возможно. - Стараться использовать числовые типы и сравнения для оптимизации.
Интеграция динамического фильтра с AJAX для улучшения UX
Чтобы пользователи могли динамически фильтровать записи без перезагрузки страницы, удобно использовать AJAX-запросы. Рассмотрим базовый пример интеграции.
1. JavaScript код для отправки запроса с фильтрами:
jQuery(document).ready(function($) {
$('#filter-form').on('submit', function(e) {
e.preventDefault();
var data = $(this).serialize();
$.ajax({
url: wpmy_ajax.ajax_url,
method: 'POST',
data: data + '&action=wpmy_filter',
success: function(response) {
$('#filter-results').html(response);
}
});
});
});2. PHP обработчик AJAX в functions.php или плагине:
add_action('wp_ajax_wpmy_filter', 'wpmy_ajax_filter_handler');
add_action('wp_ajax_nopriv_wpmy_filter', 'wpmy_ajax_filter_handler');
function wpmy_ajax_filter_handler() {
$filters = [];
if (!empty($_POST['price_min'])) {
$filters[] = [
'key' => 'price',
'value_min' => intval($_POST['price_min'])
];
}
if (!empty($_POST['price_max'])) {
if (isset($filters[0])) {
$filters[0]['value_max'] = intval($_POST['price_max']);
} else {
$filters[] = [
'key' => 'price',
'value_max' => intval($_POST['price_max'])
];
}
}
if (!empty($_POST['color'])) {
$filters[] = [
'key' => 'color',
'value_in' => explode(',', sanitize_text_field($_POST['color']))
];
}
$query = wpmy_filter_by_meta_extended('product', $filters);
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
echo '<div><h3>' . get_the_title() . '</h3>';
echo '<p>Цена: ' . get_post_meta(get_the_ID(), 'price', true) . '</p></div>';
}
wp_reset_postdata();
} else {
echo '<p>Результаты не найдены.</p>';
}
wp_die();
}3. Передача локализации скрипта в PHP для корректной работы AJAX:
function wpmy_enqueue_scripts() {
wp_enqueue_script('wpmy-filter', get_template_directory_uri() . '/js/filter.js', ['jquery'], null, true);
wp_localize_script('wpmy-filter', 'wpmy_ajax', [
'ajax_url' => admin_url('admin-ajax.php')
]);
}
add_action('wp_enqueue_scripts', 'wpmy_enqueue_scripts');Полезные плагины для работы с мета полями и фильтрами
Если хочется готовых решений с визуальным конструктором фильтров, можно обратить внимание на плагины:
- Clearfy Pro — оптимизация и управление мета данными, есть расширения для фильтрации.
- ABC Pagination — удобная навигация для фильтрованных списков.
- WPRemark — расширение комментариев, которое можно интегрировать с фильтрами по пользовательским данным.
Однако для точечного и лёгкого фильтра лучше писать свой код, как показано выше — это даёт максимальную гибкость и контроль.
Заключение по созданию динамической функции фильтра по мета полям
Динамическая фильтрация по мета полям — мощный инструмент для улучшения UX и функционала сайта на WordPress. Правильно написанная универсальная функция с поддержкой разных операторов и AJAX значительно упростит разработку и расширение проекта.
Не забывайте тестировать производительность и использовать кэширование при необходимости, а также встраивать фильтр в удобный интерфейс.