В современных проектах на WordPress часто требуется интегрировать пагинацию прямо в кастомные блоки редактора Gutenberg. Особенно актуально это, если блок выводит списки постов или кастомных записей и нужно обеспечить плавную навигацию без перезагрузки страницы. В этой статье мы подробно разберём, как реализовать такую пагинацию с помощью AJAX, чтобы улучшить UX и снизить нагрузку на сервер.
Почему нужна AJAX пагинация в Gutenberg блоках
Стандартные подходы к пагинации, которые перезагружают страницу, плохо вписываются в концепцию динамичных Gutenberg блоков. Пользователь ожидает быстрый отклик и плавную смену содержимого. AJAX пагинация позволяет подгружать новые данные на лету, не перезагружая весь сайт.
Такой подход повышает скорость работы, снижает потребление ресурсов и улучшает взаимодействие с пользователем, особенно на мобильных устройствах.
Реализовать это можно через REST API WordPress или через собственные AJAX обработчики.
Создание кастомного Gutenberg блока с пагинацией
Для начала создадим базовый блок, который будет выводить посты с пагинацией. Предположим, блок будет использовать REST API для получения данных.
В файле block.js в редакторе:
const { registerBlockType } = wp.blocks;
const { useState, useEffect } = wp.element;
registerBlockType('wppagenavi/custom-posts-pagination', {
title: 'Посты с пагинацией AJAX',
icon: 'list-view',
category: 'widgets',
edit: () => {
const [posts, setPosts] = useState([]);
const [page, setPage] = useState(1);
const [maxPages, setMaxPages] = useState(1);
useEffect(() => {
fetch(`/wp-json/wp/v2/posts?per_page=5&page=${page}`)
.then(res => {
setMaxPages(parseInt(res.headers.get('X-WP-TotalPages')));
return res.json();
})
.then(data => setPosts(data));
}, [page]);
return (
<div>
<ul>
{posts.map(post => <li key={post.id}>{post.title.rendered}</li>)}
</ul>
<div className="pagination-controls">
<button onClick={() => setPage(p => Math.max(p - 1, 1))} disabled={page === 1}>Назад</button>
<span>Страница {page} из {maxPages}</span>
<button onClick={() => setPage(p => Math.min(p + 1, maxPages))} disabled={page === maxPages}>Вперед</button>
</div>
</div>
);
},
save: () => {
return null; // Динамический блок
},
});
Этот блок использует WP REST API для получения постов по 5 штук на страницу. Хедер X-WP-TotalPages позволяет узнать общее число страниц.
Добавление серверной поддержки динамического блока
Так как блок динамический, нужно зарегистрировать его на PHP стороне. Добавим код в functions.php или в файл плагина:
function wppagenavi_register_custom_posts_block() {
register_block_type('wppagenavi/custom-posts-pagination', [
'render_callback' => 'wppagenavi_render_custom_posts_block',
]);
}
add_action('init', 'wppagenavi_register_custom_posts_block');
function wppagenavi_render_custom_posts_block($attributes) {
// Контент рендерится на фронте через JS и REST API
return '<div id="wppagenavi-custom-posts-pagination"></div>';
}
Этот код регистрирует блок и выводит контейнер, куда JS подгружает содержимое.
Как расширить функциональность: фильтры и кастомные типы записей
Если нужно выводить не только посты, но и кастомные типы записей, можно расширить запросы REST API с параметрами. Например, добавить атрибут postType в блок:
const [postType, setPostType] = useState('post');
// Изменить URL запроса
fetch(`/wp-json/wp/v2/${postType}?per_page=5&page=${page}`)
Для фильтрации по таксономиям можно добавить параметры в URL, например categories или tag.
Также можно создать собственный REST API endpoint, если стандартный не подходит. Пример регистрации:
add_action('rest_api_init', function () {
register_rest_route('wppagenavi/v1', '/posts/', [
'methods' => 'GET',
'callback' => 'wppagenavi_get_posts',
'permission_callback' => '__return_true',
]);
});
function wppagenavi_get_posts(WP_REST_Request $request) {
$params = $request->get_params();
$paged = isset($params['page']) ? intval($params['page']) : 1;
$post_type = isset($params['post_type']) ? sanitize_text_field($params['post_type']) : 'post';
$query = new WP_Query([
'post_type' => $post_type,
'posts_per_page' => 5,
'paged' => $paged,
]);
$posts = [];
foreach($query->posts as $post) {
$posts[] = [
'id' => $post->ID,
'title' => get_the_title($post),
'link' => get_permalink($post),
];
}
return [
'posts' => $posts,
'max_pages' => $query->max_num_pages,
];
}
Такой endpoint можно использовать в JS:
fetch(`/wp-json/wppagenavi/v1/posts/?page=${page}&post_type=${postType}`)
Использование плагинов для улучшения пагинации в Gutenberg
Если хочется ускорить разработку, можно использовать готовые решения. Например, плагин WP-PageNavi позволяет легко подключить красивую пагинацию и поддерживает AJAX.
Для Gutenberg блоков можно разработать обёртку над WP-PageNavi, которая будет работать как динамический блок с AJAX.
Пример интеграции WP-PageNavi с AJAX в Gutenberg блоке
Основная идея — использовать WP-PageNavi для генерации разметки пагинации на сервере и ловить клик на кнопках в JS, чтобы делать AJAX запросы и обновлять содержимое блока.
На PHP стороне:
function wppagenavi_render_paginated_posts() {
$paged = isset($_GET['paged']) ? intval($_GET['paged']) : 1;
$query = new WP_Query([
'posts_per_page' => 5,
'paged' => $paged,
]);
ob_start();
if ($query->have_posts()) {
echo '<ul>';
while ($query->have_posts()) {
$query->the_post();
echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
}
echo '</ul>';
}
wp_pagenavi(['query' => $query]);
wp_reset_postdata();
return ob_get_clean();
}
В JS блоке — ловим клики и подгружаем содержимое через AJAX без перезагрузки.
Заключение по реализации
Реализация AJAX пагинации в кастомных Gutenberg блоках — задача, требующая понимания как фронтенд-части с React, так и серверной логики WordPress. Использование REST API упрощает процесс, но иногда нужен собственный endpoint для тонкой настройки.
Подключение готовых решений, таких как WP-PageNavi, помогает ускорить разработку и улучшить внешний вид пагинации.
Такой подход позволит сделать сайт более интерактивным, повысит удобство пользователей и улучшит производительность.