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

В современных проектах на WordPress часто возникает необходимость реализовать динамическую фильтрацию контента на страницах сайта. Это позволяет пользователям быстро находить нужные записи по заданным критериям, не перегружая сервер и не перегружая интерфейс. В этой статье мы подробно рассмотрим, как создать динамические фильтры в WordPress с использованием REST API и немного кастомного кода.

Почему REST API подходит для динамических фильтров

WordPress REST API — мощный инструмент, который позволяет обращаться к данным сайта через HTTP-запросы. Это значит, что можно подгружать данные асинхронно, без перезагрузки страницы, что улучшает пользовательский опыт и снижает нагрузку на сервер.

Используя REST API, мы можем создавать собственные маршруты или расширять существующие endpoint’ы для фильтрации записей по произвольным параметрам, например, категориям, таксономиям, метаданным и т.д.

В итоге мы получаем удобный и гибкий механизм фильтрации, который легко интегрируется с фронтенд-фреймворками или обычным JavaScript.

Создаем кастомный REST API endpoint для фильтрации постов

Для начала создадим собственный endpoint, который будет принимать параметры фильтрации и возвращать отфильтрованные записи. Добавьте следующий код в файл functions.php вашей темы или в отдельный плагин:

add_action('rest_api_init', function () {
    register_rest_route('wpfind/v1', '/filter-posts', array(
        'methods' => 'GET',
        'callback' => 'wpfind_filter_posts_callback',
        'permission_callback' => '__return_true',
    ));
});

function wpfind_filter_posts_callback(WP_REST_Request $request) {
    $args = array(
        'post_type' => 'post',
        'posts_per_page' => 10,
        'paged' => $request->get_param('page') ?: 1,
    );

    // Фильтрация по категории
    if ($category = $request->get_param('category')) {
        $args['category_name'] = sanitize_text_field($category);
    }

    // Фильтрация по произвольному метаполю
    if ($meta_key = $request->get_param('meta_key') && $meta_value = $request->get_param('meta_value')) {
        $args['meta_query'] = array(
            array(
                'key' => sanitize_text_field($meta_key),
                'value' => sanitize_text_field($meta_value),
                'compare' => '=',
            ),
        );
    }

    $query = new WP_Query($args);

    $posts = array();
    if ($query->have_posts()) {
        while ($query->have_posts()) {
            $query->the_post();
            $posts[] = array(
                'id' => get_the_ID(),
                'title' => get_the_title(),
                'excerpt' => get_the_excerpt(),
                'link' => get_permalink(),
            );
        }
        wp_reset_postdata();
    }

    return rest_ensure_response(array(
        'posts' => $posts,
        'total' => (int) $query->found_posts,
        'pages' => (int) $query->max_num_pages,
    ));
}

Этот код регистрирует новый маршрут /wpfind/v1/filter-posts, который позволяет передавать параметры category, meta_key, meta_value и page для пагинации. В ответе мы получим отфильтрованные записи в удобном формате JSON.

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

Теперь, когда REST API endpoint готов, можно подключить к нему JavaScript для динамической подгрузки отфильтрованных постов. Рассмотрим простой пример с использованием Fetch API:

const filterForm = document.getElementById('filter-form');
const postsContainer = document.getElementById('posts-container');

filterForm.addEventListener('submit', function(e) {
    e.preventDefault();

    const category = document.getElementById('category').value;
    const metaKey = document.getElementById('meta_key').value;
    const metaValue = document.getElementById('meta_value').value;

    let url = `/wp-json/wpfind/v1/filter-posts?`;
    if(category) url += `category=${encodeURIComponent(category)}&`;
    if(metaKey && metaValue) url += `meta_key=${encodeURIComponent(metaKey)}&meta_value=${encodeURIComponent(metaValue)}&`;

    fetch(url)
        .then(response => response.json())
        .then(data => {
            postsContainer.innerHTML = '';
            if(data.posts.length === 0) {
                postsContainer.innerHTML = '<p>Посты не найдены</p>';
                return;
            }
            data.posts.forEach(post => {
                const postElem = document.createElement('div');
                postElem.innerHTML = `<h3><a href="${post.link}">${post.title}</a></h3><p>${post.excerpt}</p>`;
                postsContainer.appendChild(postElem);
            });
        });
});

HTML форма фильтров может выглядеть так:

<form id="filter-form">
    <label>Категория:
        <input type="text" id="category" name="category" />
    </label>
    <label>Meta Key:
        <input type="text" id="meta_key" name="meta_key" />
    </label>
    <label>Meta Value:
        <input type="text" id="meta_value" name="meta_value" />
    </label>
    <button type="submit">Фильтровать</button>
</form>
<div id="posts-container"></div>

Расширение функционала фильтров: работа с таксономиями и сложными метазапросами

В реальных проектах часто требуется фильтрация по нескольким таксономиям одновременно или сложные запросы с несколькими условиями для метаданных. Рассмотрим, как расширить наш endpoint для поддержки таких сценариев.

Добавим поддержку нескольких категорий и кастомных таксономий через параметр массива. Для метазапросов — поддержим несколько условий с логическими операциями.

function wpfind_filter_posts_callback(WP_REST_Request $request) {
    $args = array(
        'post_type' => 'post',
        'posts_per_page' => 10,
        'paged' => $request->get_param('page') ?: 1,
    );

    // Таксономии
    $tax_query = array('relation' => 'AND');

    if ($categories = $request->get_param('categories')) { // ожидаем массив
        $tax_query[] = array(
            'taxonomy' => 'category',
            'field' => 'slug',
            'terms' => array_map('sanitize_text_field', (array) $categories),
            'operator' => 'IN',
        );
    }

    if ($custom_tax = $request->get_param('custom_tax')) {
        // custom_tax ожидается в формате ['taxonomy' => 'taxonomy_slug', 'terms' => ['term1','term2']]
        if (isset($custom_tax['taxonomy'], $custom_tax['terms']) && is_array($custom_tax['terms'])) {
            $tax_query[] = array(
                'taxonomy' => sanitize_text_field($custom_tax['taxonomy']),
                'field' => 'slug',
                'terms' => array_map('sanitize_text_field', $custom_tax['terms']),
                'operator' => 'IN',
            );
        }
    }

    if (count($tax_query) > 1) {
        $args['tax_query'] = $tax_query;
    }

    // Метазапрос
    $meta_query = array('relation' => 'AND');
    $meta_filters = $request->get_param('meta_filters');
    if ($meta_filters && is_array($meta_filters)) {
        foreach ($meta_filters as $filter) {
            if (isset($filter['key'], $filter['value'], $filter['compare'])) {
                $meta_query[] = array(
                    'key' => sanitize_text_field($filter['key']),
                    'value' => sanitize_text_field($filter['value']),
                    'compare' => sanitize_text_field($filter['compare']),
                );
            }
        }
    }
    if (count($meta_query) > 1) {
        $args['meta_query'] = $meta_query;
    }

    $query = new WP_Query($args);

    $posts = array();
    if ($query->have_posts()) {
        while ($query->have_posts()) {
            $query->the_post();
            $posts[] = array(
                'id' => get_the_ID(),
                'title' => get_the_title(),
                'excerpt' => get_the_excerpt(),
                'link' => get_permalink(),
            );
        }
        wp_reset_postdata();
    }

    return rest_ensure_response(array(
        'posts' => $posts,
        'total' => (int) $query->found_posts,
        'pages' => (int) $query->max_num_pages,
    ));
}

Такой подход позволит гибко комбинировать фильтры и строить сложные запросы к базе.

Практические рекомендации и полезные плагины

Для упрощения работы с REST API и фильтрами можно использовать готовые плагины. Например, Clearfy Pro имеет расширенные возможности по оптимизации и управлению REST API, что позволяет улучшить безопасность и производительность.

Еще один полезный плагин — ABC Pagination, который поможет реализовать удобную пагинацию для асинхронно подгружаемых записей.

Если вы хотите добавить визуальные фильтры и виджеты, обратите внимание на плагины с поддержкой AJAX фильтрации, например, FacetWP или JetSmartFilters (хотя они коммерческие и могут быть тяжелее для простых проектов).

Оптимизация и безопасность при работе с REST API фильтрами

При создании кастомных фильтров важно соблюдать меры безопасности. Никогда не забывайте санитизировать входящие параметры, чтобы избежать SQL-инъекций и других уязвимостей.

Также стоит ограничить количество возвращаемых записей и использовать пагинацию, чтобы не допустить перегрузки сервера.

Для повышения производительности можно кэшировать результаты запросов с помощью Transients API или внешних систем кеширования.

И, конечно, тщательно тестируйте фильтры на больших объемах данных, особенно если используются сложные метазапросы и таксономии.

Как удалить пустые категории в WordPress с помощью кода
16.02.2026
Обновление WordPress без проблем и сбоев
05.02.2026
Как автоматизировать создание изображений в WordPress при загрузке
23.03.2026
Как удалить все комментарии от определённого автора в WordPress
23.11.2025
Как избежать проблем с проверкой лицензий в WordPress плагинах
31.01.2026

Сайт в разработке, скоро здесь будет портал о WordPress.