Как создать многоуровневую пагинацию в WordPress с поддержкой AJAX

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

Что такое многоуровневая пагинация и зачем она нужна

Многоуровневая пагинация — это навигация, которая объединяет несколько видов переключателей страниц, например, классическую нумерацию, кнопки “Следующая”/“Предыдущая”, выбор количества отображаемых элементов и фильтрацию по категориям или тегам. Это удобно для сайтов с разнородным и объемным контентом, например, для блогов, магазинов или каталогов.

Стандартные функции WordPress, такие как paginate_links() или the_posts_pagination(), не поддерживают такой уровень кастомизации, а плагинов с готовой многоуровневой пагинацией не так много. Поэтому придется делать кастомное решение с использованием AJAX.

Подготовка темы и регистрация AJAX-обработчиков

Начнем с регистрации AJAX-обработчиков в файле functions.php вашей темы или в собственном плагине. Это позволит динамически подгружать записи без перезагрузки страницы.

add_action('wp_ajax_wptalk_load_posts', 'wptalk_load_posts_callback');
add_action('wp_ajax_nopriv_wptalk_load_posts', 'wptalk_load_posts_callback');

function wptalk_load_posts_callback() {
    $paged = isset($_POST['page']) ? intval($_POST['page']) : 1;
    $category = isset($_POST['category']) ? sanitize_text_field($_POST['category']) : '';
    $posts_per_page = isset($_POST['posts_per_page']) ? intval($_POST['posts_per_page']) : 5;

    $args = [
        'post_type' => 'post',
        'paged' => $paged,
        'posts_per_page' => $posts_per_page
    ];

    if ($category) {
        $args['category_name'] = $category;
    }

    $query = new WP_Query($args);

    if ($query->have_posts()) {
        ob_start();
        while ($query->have_posts()) {
            $query->the_post();
            ?>
            <article id="post-<?php the_ID(); ?>">
                <h2><?php the_title(); ?></h2>
                <div><?php the_excerpt(); ?></div>
            </article>
            <?php
        }
        wp_reset_postdata();
        $posts_html = ob_get_clean();
        wp_send_json_success(['posts' => $posts_html, 'max_page' => $query->max_num_pages]);
    } else {
        wp_send_json_error('Posts not found');
    }
    wp_die();
}

Этот обработчик принимает параметры страницы, категории и количества записей, формирует запрос и возвращает HTML постов и максимальное число страниц в формате JSON.

Создание интерфейса пагинации с фильтрами и выбором количества записей

Далее создадим HTML для пагинации с селектами для выбора категории и количества элементов на странице, а также контейнер для постов и навигационные кнопки.

<div id="wptalk-pagination-controls">
    <select id="wptalk-category-filter">
        <option value="">Все категории</option>
        <?php
        $categories = get_categories();
        foreach ($categories as $cat) {
            echo '<option value="' . esc_attr($cat->slug) . '">' . esc_html($cat->name) . '</option>';
        }
        ?>
    </select>

    <select id="wptalk-posts-per-page">
        <option value="5">5 записей</option>
        <option value="10">10 записей</option>
        <option value="20">20 записей</option>
    </select>
</div>

<div id="wptalk-posts-container"></div>

<div id="wptalk-pagination-buttons">
    <button id="wptalk-prev-page" disabled>Предыдущая</button>
    <span id="wptalk-current-page">1</span> / <span id="wptalk-max-page">1</span>
    <button id="wptalk-next-page" disabled>Следующая</button>
</div>

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

JavaScript: загрузка контента и управление пагинацией

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

document.addEventListener('DOMContentLoaded', function () {
    const postsContainer = document.getElementById('wptalk-posts-container');
    const categoryFilter = document.getElementById('wptalk-category-filter');
    const postsPerPageSelect = document.getElementById('wptalk-posts-per-page');
    const prevBtn = document.getElementById('wptalk-prev-page');
    const nextBtn = document.getElementById('wptalk-next-page');
    const currentPageSpan = document.getElementById('wptalk-current-page');
    const maxPageSpan = document.getElementById('wptalk-max-page');

    let currentPage = 1;
    let maxPage = 1;

    function wptalkLoadPosts() {
        const data = new FormData();
        data.append('action', 'wptalk_load_posts');
        data.append('page', currentPage);
        data.append('category', categoryFilter.value);
        data.append('posts_per_page', postsPerPageSelect.value);

        fetch(wptalk_ajax_object.ajax_url, {
            method: 'POST',
            credentials: 'same-origin',
            body: data
        })
        .then(response => response.json())
        .then(result => {
            if (result.success) {
                postsContainer.innerHTML = result.data.posts;
                maxPage = result.data.max_page;
                currentPageSpan.textContent = currentPage;
                maxPageSpan.textContent = maxPage;

                prevBtn.disabled = currentPage <= 1;
                nextBtn.disabled = currentPage >= maxPage;
            } else {
                postsContainer.innerHTML = '<p>Нет записей для отображения.</p>';
            }
        })
        .catch(() => {
            postsContainer.innerHTML = '<p>Произошла ошибка при загрузке.</p>';
        });
    }

    categoryFilter.addEventListener('change', function () {
        currentPage = 1;
        wptalkLoadPosts();
    });

    postsPerPageSelect.addEventListener('change', function () {
        currentPage = 1;
        wptalkLoadPosts();
    });

    prevBtn.addEventListener('click', function () {
        if (currentPage > 1) {
            currentPage--;
            wptalkLoadPosts();
        }
    });

    nextBtn.addEventListener('click', function () {
        if (currentPage < maxPage) {
            currentPage++;
            wptalkLoadPosts();
        }
    });

    // Инициализация
    wptalkLoadPosts();
});

Не забудьте подключить этот скрипт и передать URL AJAX-запроса из PHP:

function wptalk_enqueue_scripts() {
    wp_enqueue_script('wptalk-pagination', get_template_directory_uri() . '/js/wptalk-pagination.js', ['jquery'], null, true);
    wp_localize_script('wptalk-pagination', 'wptalk_ajax_object', [
        'ajax_url' => admin_url('admin-ajax.php')
    ]);
}
add_action('wp_enqueue_scripts', 'wptalk_enqueue_scripts');

Советы по улучшению и расширению пагинации

Для повышения удобства и производительности можно добавить индикатор загрузки, кэширование запросов на клиенте, а также поддержку бесконечной прокрутки вместо кнопок “Следующая”/“Предыдущая”.

Если вы используете плагин Clearfy Pro, обратите внимание, что он умеет оптимизировать AJAX-запросы и уменьшать нагрузку на базу данных, что может быть полезно при реализации такой пагинации.

Кроме того, для магазинов на WooCommerce возможно расширить пагинацию фильтрами по атрибутам товаров, интегрируя AJAX-запросы с параметрами фильтрации.

Итоги и рекомендации

Создание многоуровневой пагинации с поддержкой AJAX требует базовых знаний о WordPress AJAX API, JavaScript и WP_Query. Наш пример позволяет гибко управлять выводом записей, фильтровать по категориям и менять количество элементов на странице без перезагрузки. Это значительно улучшает UX и производительность сайта.

Для более сложных задач рекомендую рассмотреть кастомные WP REST API эндпоинты и использование популярных JS-фреймворков, например React или Vue, но для большинства проектов приведенное решение будет достаточно.

Если хотите ускорить разработку и получить дополнительные опции оптимизации, обратите внимание на плагины из WPSHOP.ru.

Отложенная публикация постов в WordPress: практическое руководство
09.01.2026
Как избежать конфликтов между WooCommerce и другими плагинами WordPress
23.04.2026
Как добавить автоматическую настройку изображений в WordPress для ускорения сайта
06.03.2026
Автоматический импорт контента из Instagram в WordPress
16.03.2026
Как избежать проблем с кэшированием в WordPress: практические советы
01.03.2026