В этой статье рассмотрим, как создать уникальный и гибкий фильтрованный список постов в WordPress. Мы разберём, как построить кастомный WP_Query с несколькими параметрами, как добавить AJAX-подгрузку, чтобы улучшить взаимодействие пользователя, и приведём примеры кода для быстрой интеграции.
Понимание WP_Query и фильтрация по метаданным и таксономиям
Для начала важно понять, что WP_Query — это мощный класс WordPress, который позволяет получать записи из базы данных с учётом различных параметров. Вы можете фильтровать посты по категориям, меткам, произвольным таксономиям, пользовательским полям (custom fields) и другим критериям.
Допустим, нам нужно вывести записи определённого типа с фильтрацией по нескольким таксономиям и пользовательским полям. Для этого используем параметры tax_query и meta_query.
Пример базового запроса с фильтрацией по категории и произвольному полю:
$args = [
'post_type' => 'post',
'tax_query' => [
[
'taxonomy' => 'category',
'field' => 'slug',
'terms' => 'novosti',
],
],
'meta_query' => [
[
'key' => 'author_rating',
'value' => 4,
'compare' => '>=',
'type' => 'NUMERIC',
],
],
];
$query = new WP_Query($args);Здесь мы получаем посты из категории «novosti», у которых значение метаполя author_rating не меньше 4.
Создание формы фильтрации и обработка пользовательского ввода
Чтобы пользователи могли выбирать параметры фильтра, создадим HTML-форму с нужными полями. Например, выпадающий список категорий и радиокнопки для рейтинга:
<form id="filter-form">
<select name="category" id="filter-category">
<option value="">Все категории</option>
<option value="novosti">Новости</option>
<option value="stati">Статьи</option>
</select>
<label>
<input type="radio" name="rating" value="3"> От 3
</label>
<label>
<input type="radio" name="rating" value="4"> От 4
</label>
<button type="submit">Применить</button>
</form>
<div id="posts-container"></div>Форма отправляет данные на сервер, и мы обновляем список постов динамически с помощью AJAX.
Реализация AJAX-подгрузки фильтрованных постов
Добавим JavaScript для перехвата отправки формы и выполнения AJAX-запроса:
jQuery(document).ready(function($) {
$('#filter-form').on('submit', function(e) {
e.preventDefault();
var data = {
action: '2wp_filter_posts',
category: $('#filter-category').val(),
rating: $('input[name="rating"]:checked').val(),
nonce: filter_vars.nonce
};
$.post(filter_vars.ajaxurl, data, function(response) {
$('#posts-container').html(response);
});
});
});Теперь создадим PHP-функцию для обработки AJAX-запроса. В functions.php темы или в плагине добавим:
add_action('wp_ajax_2wp_filter_posts', 'twop_ru_filter_posts_callback');
add_action('wp_ajax_nopriv_2wp_filter_posts', 'twop_ru_filter_posts_callback');
function twop_ru_filter_posts_callback() {
check_ajax_referer('2wp_filter_nonce', 'nonce');
$category = sanitize_text_field($_POST['category'] ?? '');
$rating = intval($_POST['rating'] ?? 0);
$args = [
'post_type' => 'post',
'posts_per_page' => 10,
];
if ($category) {
$args['tax_query'] = [[
'taxonomy' => 'category',
'field' => 'slug',
'terms' => $category,
]];
}
if ($rating > 0) {
$args['meta_query'] = [[
'key' => 'author_rating',
'value' => $rating,
'compare' => '>=',
'type' => 'NUMERIC',
]];
}
$query = new WP_Query($args);
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
echo '<h3><a href="' . get_permalink() . '">' . get_the_title() . '</a></h3>';
echo '<p>' . get_the_excerpt() . '</p>';
}
} else {
echo '<p>Посты не найдены.</p>';
}
wp_reset_postdata();
wp_die();
}Не забудьте локализовать скрипт и передать ajaxurl и nonce:
function twop_ru_enqueue_scripts() {
wp_enqueue_script('twop-ajax-filter', get_template_directory_uri() . '/js/filter.js', ['jquery'], null, true);
wp_localize_script('twop-ajax-filter', 'filter_vars', [
'ajaxurl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('2wp_filter_nonce'),
]);
}
add_action('wp_enqueue_scripts', 'twop_ru_enqueue_scripts');Расширение фильтрации: добавление кастомных типов записей и сложных условий
Фильтр можно легко расширить для поддержки кастомных типов записей, например, если у вас есть тип product или portfolio. Для этого добавьте параметр post_type из формы и учитывайте его в запросе.
Также возможна сложная логика с relation в meta_query или tax_query, например:
$args['meta_query'] = [
'relation' => 'AND',
[
'key' => 'price',
'value' => 1000,
'compare' => '<',
'type' => 'NUMERIC',
],
[
'key' => 'in_stock',
'value' => '1',
'compare' => '=',
],
];Это позволит отфильтровать товары, у которых цена меньше 1000 и которые есть в наличии.
Как использовать плагины для создания фильтров без кода
Если вы хотите быстрее получить фильтры без написания кода, обратите внимание на плагины из каталога на wpshop.ru. Например:
- Clearfy Pro — оптимизация и расширение функционала, включая улучшенную фильтрацию.
- ABC Pagination — гибкая постраничная навигация, которая отлично работает с кастомными запросами.
- Expert Review — если важны рейтинги и отзывы, можно интегрировать их в фильтрацию.
С этими плагинами вы сможете создать удобный интерфейс фильтрации с минимальными усилиями, при этом сохранив гибкость и производительность.
Советы по оптимизации производительности фильтров
При работе с фильтрами на больших сайтах важно учитывать оптимизацию запросов, чтобы не нагружать базу данных.
- Используйте индексы для метаполей, по которым фильтруете.
- Кэшируйте результаты фильтрации с помощью Transients API или плагинов кеширования.
- Ограничивайте количество выводимых постов и используйте пагинацию.
- Избегайте избыточного количества условий в
meta_queryиtax_query, старайтесь объединять параметры.
Например, можно кэшировать результат AJAX-запроса так:
function twop_ru_get_filtered_posts_cached($args) {
$cache_key = 'twop_filtered_' . md5(serialize($args));
$posts_html = get_transient($cache_key);
if (!$posts_html) {
$query = new WP_Query($args);
ob_start();
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
echo '<h3><a href="' . get_permalink() . '">' . get_the_title() . '</a></h3>';
echo '<p>' . get_the_excerpt() . '</p>';
}
} else {
echo '<p>Посты не найдены.</p>';
}
wp_reset_postdata();
$posts_html = ob_get_clean();
set_transient($cache_key, $posts_html, HOUR_IN_SECONDS);
}
return $posts_html;
}Это снизит нагрузку на сервер при повторных запросах с одинаковыми параметрами.