В WordPress часто возникает задача вывести список постов, которые можно фильтровать по различным параметрам — категориям, меткам, пользовательским полям, датам и т.д. В этой статье мы рассмотрим, как создать динамический фильтрованный список постов с помощью стандартного класса WP_Query. Такой подход позволит реализовать удобный интерфейс для посетителей сайта и при этом сохранить производительность.
Основы работы с WP_Query: что это и как использовать
WP_Query — это мощный класс WordPress, который позволяет выполнять сложные запросы к базе данных для получения постов по нужным параметрам. Он поддерживает фильтрацию по стандартным полям (категории, теги, автор, дата) и метаполям, а также сортировку и пагинацию.
Для создания фильтруемого списка нам нужно динамически формировать массив аргументов для WP_Query на основании переданных пользователем параметров. Например, если пользователь выбрал категорию и дату публикации — мы передадим это в запрос.
Простейший пример запроса:
$args = [
'post_type' => 'post',
'category_name' => 'novosti',
'posts_per_page' => 10,
];
$query = new WP_Query($args);
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
the_title('<h3>','</h3>');
}
wp_reset_postdata();
}Этот код выведет последние 10 постов из категории «novosti».
Создание формы фильтрации и получение параметров
Для начала создадим HTML-форму, в которой пользователь сможет выбрать параметры фильтрации. Например, категории и даты.
<form method="GET" id="wpboard_filter_form">
<select name="category">
<option value="">Все категории</option>
<?php
$categories = get_categories();
foreach ($categories as $cat) {
printf('<option value="%s" %s>%s</option>', esc_attr($cat->slug), selected($_GET['category'] ?? '', $cat->slug, false), esc_html($cat->name));
}
?>
</select>
<select name="year">
<option value="">Все годы</option>
<?php
$years = $wpdb->get_col("SELECT DISTINCT YEAR(post_date) FROM {$wpdb->posts} WHERE post_type = 'post' AND post_status = 'publish' ORDER BY post_date DESC");
foreach ($years as $year) {
printf('<option value="%d" %s>%d</option>', $year, selected($_GET['year'] ?? '', $year, false), $year);
}
?>
</select>
<button type="submit">Фильтровать</button>
</form>Форма отправляется методом GET, чтобы параметры отображались в URL и можно было сохранять и делиться ссылками. Теперь в шаблоне или в кастомном плагине обрабатываем эти параметры и строим запрос.
Динамический WP_Query с учетом фильтров
Создадим функцию wpboard_get_filtered_posts_query, которая формирует и возвращает объект WP_Query по параметрам фильтра.
function wpboard_get_filtered_posts_query() {
$args = [
'post_type' => 'post',
'posts_per_page' => 10,
'paged' => get_query_var('paged') ? get_query_var('paged') : 1,
];
if (!empty($_GET['category'])) {
$args['category_name'] = sanitize_text_field($_GET['category']);
}
if (!empty($_GET['year'])) {
$year = intval($_GET['year']);
$args['date_query'] = [
[
'year' => $year,
],
];
}
return new WP_Query($args);
}Далее выводим посты с пагинацией:
$query = wpboard_get_filtered_posts_query();
if ($query->have_posts()) {
echo '<div class="wpboard-posts-list">';
while ($query->have_posts()) {
$query->the_post();
echo '<article>';
the_title('<h2>','</h2>');
the_excerpt();
echo '</article>';
}
echo '</div>';
// Пагинация
echo paginate_links([
'total' => $query->max_num_pages,
'current' => max(1, get_query_var('paged')),
'format' => '?paged=%#%',
'add_args' => [
'category' => $_GET['category'] ?? '',
'year' => $_GET['year'] ?? '',
],
]);
} else {
echo '<p>Посты не найдены по заданным параметрам.</p>';
}
wp_reset_postdata();Расширение фильтрации: пользовательские поля и таксономии
Часто фильтрация требуется не только по стандартным категориям, но и по кастомным таксономиям или метаполям. Например, вывод товаров по цвету или цене.
Для фильтрации по таксономии добавим в форму новый выпадающий список, а в запрос — параметр tax_query. Для метаполей — параметр meta_query.
Пример добавления фильтра по таксономии product_color:
<select name="color">
<option value="">Все цвета</option>
<?php
$colors = get_terms(['taxonomy' => 'product_color', 'hide_empty' => false]);
foreach ($colors as $color) {
printf('<option value="%s" %s>%s</option>', esc_attr($color->slug), selected($_GET['color'] ?? '', $color->slug, false), esc_html($color->name));
}
?>
</select>В функцию запроса добавим:
if (!empty($_GET['color'])) {
$args['tax_query'][] = [
'taxonomy' => 'product_color',
'field' => 'slug',
'terms' => sanitize_text_field($_GET['color']),
];
}Для метаполей, например, цена больше 1000:
if (!empty($_GET['min_price'])) {
$args['meta_query'][] = [
'key' => 'price',
'value' => intval($_GET['min_price']),
'compare' => '>=',
'type' => 'NUMERIC',
];
}Такой подход позволяет создавать гибкие и многоуровневые фильтры.
Оптимизация фильтров и использование кэширования
Фильтрация с WP_Query может создавать нагрузку на базу, особенно если используется много метаполей. Чтобы ускорить работу, можно использовать кэширование результатов с помощью transient API.
Пример сохранения результата запроса в transient с уникальным ключом по параметрам фильтра:
function wpboard_get_filtered_posts_query() {
$args = [...]; // формируем аргументы
$cache_key = 'wpboard_filtered_posts_' . md5(serialize($args));
$cached = get_transient($cache_key);
if ($cached !== false) {
return $cached;
}
$query = new WP_Query($args);
set_transient($cache_key, $query, HOUR_IN_SECONDS);
return $query;
}Также рекомендуется использовать индексы в базе данных для метаполей, если фильтров много и они влияют на скорость.
Примеры полезных плагинов для расширения фильтрации
Если хочется не писать код, а использовать готовые решения, обратите внимание на плагины:
- WPExpert Review — хороший плагин для расширенной работы с кастомными типами постов и таксономиями.
- ABC Pagination — удобный инструмент для красивой пагинации с сохранением фильтров.
Эти плагины помогут быстрее получить желаемый функционал и сэкономят время.
Выводы и рекомендации по созданию фильтров
Динамическая фильтрация с использованием WP_Query — мощный способ создавать удобные списки постов с возможностью выбора пользователем нужных параметров. Важно грамотно строить запросы, избегать избыточных метаполей, использовать кэширование и оптимизировать базу данных.
Также следует уделять внимание UX: фильтры должны быть понятны и отзывчивы, а результаты — выводиться быстро и корректно.