Пагинация — важный элемент удобной навигации по контенту, особенно если речь идет о больших объемах данных. В WordPress классические темы и плагины обеспечивают пагинацию для стандартных циклов постов, но при создании кастомных блоков в редакторе Gutenberg возникает задача сделать пагинацию самостоятельно. В этой статье разберем, как добавить пагинацию в кастомный блок Gutenberg, используя React и WP REST API.
Почему нужна пагинация в кастомных блоках Gutenberg
В отличие от классических шаблонов, блоки Gutenberg работают на React и имеют собственный жизненный цикл. Если вы создаете блок для вывода списка постов, товаров или любых других записей, без пагинации пользователь будет видеть либо все записи, что неэффективно, либо ограниченное количество без возможности переключения страниц. Пагинация улучшает UX, ускоряет загрузку и снижает нагрузку на сервер.
Реализовать пагинацию в блоке можно через два основных подхода:
- Загрузка всех данных разом с последующей разбивкой на страницы на клиенте (React). Этот способ подходит для небольших объемов.
- Динамическая загрузка данных с сервера по страницам с помощью WP REST API и AJAX-запросов. Самый оптимальный и масштабируемый способ.
Создание кастомного блока с пагинацией — подготовка
Для примера сделаем блок, который выводит список постов с пагинацией. Предполагается, что вы знакомы с созданием кастомных блоков в Gutenberg и умеете работать с JavaScript и React.
Основные шаги:
- Создать блок с атрибутом для хранения текущей страницы.
- Сделать запрос к WP REST API для получения постов с параметрами
pageиper_page. - Отобразить посты и элементы управления пагинацией.
- Обработать переключение страниц с обновлением данных.
Пример кода JavaScript для блока с пагинацией
Используем ESNext, React hooks и wp.element. Для упрощения примера опустим часть регистрации блока и стили.
const { useState, useEffect } = wp.element;
const { registerBlockType } = wp.blocks;
registerBlockType('wppagenavi/post-list-paginated', {
title: 'Посты с пагинацией',
icon: 'list-view',
category: 'widgets',
edit: () => {
const [posts, setPosts] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const postsPerPage = 5;
useEffect(() => {
fetch(`/wp-json/wp/v2/posts?page=${currentPage}&per_page=${postsPerPage}`)
.then(response => {
setTotalPages(parseInt(response.headers.get('X-WP-TotalPages')));
return response.json();
})
.then(data => setPosts(data))
.catch(() => setPosts([]));
}, [currentPage]);
const onPrevClick = () => {
if (currentPage > 1) setCurrentPage(prev => prev - 1);
};
const onNextClick = () => {
if (currentPage < totalPages) setCurrentPage(prev => prev + 1);
};
return (
<div className="wppagenavi-post-list">
<ul>
{posts.map(post => (
<li key={post.id}>
<a href={post.link} target="_blank" rel="noopener noreferrer">{post.title.rendered}</a>
</li>
))}
</ul>
<div className="pagination-controls">
<button onClick={onPrevClick} disabled={currentPage === 1}>< Назад</button>
<span>Страница {currentPage} из {totalPages}</span>
<button onClick={onNextClick} disabled={currentPage === totalPages}>Вперед ></button>
</div>
</div>
);
},
save: () => {
return null; // Динамический блок, рендер на сервере
},
});
Рендеринг блока на сервере
Чтобы блок корректно отображался на фронтенде, полезно сделать серверный рендеринг. Это позволит поисковым системам видеть контент и улучшит SEO.
Добавим PHP-функцию для рендеринга блока, которая будет принимать атрибут page и возвращать HTML с постами.
function wppagenavi_render_post_list_paginated( $attributes ) {
$page = isset( $attributes['page'] ) ? intval( $attributes['page'] ) : 1;
$posts_per_page = 5;
$query = new WP_Query( array(
'post_type' => 'post',
'posts_per_page' => $posts_per_page,
'paged' => $page,
) );
if ( ! $query->have_posts() ) {
return '<p>Посты не найдены.</p>';
}
$output = '<ul>';
while ( $query->have_posts() ) {
$query->the_post();
$output .= '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
}
wp_reset_postdata();
$output .= '</ul>';
$output .= '<div class="pagination-controls">';
if ( $page > 1 ) {
$output .= '<button class="prev-page">< Назад</button>';
}
$output .= '<span>Страница ' . $page . ' из ' . $query->max_num_pages . '</span>';
if ( $page < $query->max_num_pages ) {
$output .= '<button class="next-page">Вперед ></button>';
}
$output .= '</div>';
return $output;
}
register_block_type( 'wppagenavi/post-list-paginated', array(
'render_callback' => 'wppagenavi_render_post_list_paginated',
) );
Как улучшить и расширить пагинацию в блоке
1. Добавить выбор количества постов на странице. Можно сделать настройку в атрибутах блока, которую пользователь задаёт в редакторе.
2. Добавить возможность фильтрации по категориям и меткам. В REST API для постов есть параметры categories и tags, их можно передавать и в JS, и в PHP.
3. Использовать кеширование. Для снижения нагрузки можно кэшировать результаты запросов через transients или сторонние кеш-плагины.
4. Поддержка AJAX для перехода по страницам без перезагрузки. В нашем примере React уже делает динамическую загрузку, но можно улучшить UX анимациями и состояниями загрузки.
Использование плагина ABC Pagination для кастомных блоков
Если вы предпочитаете готовые решения, плагин ABC Pagination отлично справляется с задачей добавления кастомной пагинации. Его можно интегрировать в блоки через REST API или PHP, используя хуки и фильтры.
Плагин позволяет легко настроить внешний вид и логику пагинации, поддерживает AJAX и кеширование, что значительно упрощает разработку.
Заключение
Добавление пагинации в кастомный блок Gutenberg — задача вполне решаемая, но требует понимания работы React, WP REST API и серверного рендеринга. Используя описанный подход, вы сможете сделать удобную, быструю и SEO-дружественную навигацию по вашим данным прямо в редакторе WordPress.
Для более глубокого погружения рекомендую посмотреть документацию Gutenberg и WP REST API, а также обратить внимание на современные плагины из WPSHOP, которые помогут ускорить разработку.