Как создать динамический фильтрованный список постов в WordPress с помощью WP_Query

В 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: фильтры должны быть понятны и отзывчивы, а результаты — выводиться быстро и корректно.

Оптимизация изображений в WordPress: лучшие решения для ускорения сайта
15.01.2026
Как создать автоматические снимки (thumbnail) для изображений в WordPress
30.03.2026
Как удалить варианты товаров WooCommerce с помощью кода
22.04.2026
Как удалить автоматически создаваемые категории в WordPress
03.04.2026
Как использовать WooCommerce Order Meta для дополнительных данных заказа
19.05.2026