Диагностика проблемы: почему пагинация не работает с несколькими WP_Query
Стандартная пагинация в WordPress построена вокруг глобального объекта $wp_query и параметра paged. При наличии на странице нескольких пользовательских запросов WP_Query часто возникают проблемы с пагинацией: ссылки ведут на 404, страницы не меняются, или показывается неправильный набор записей.
Обычно причины следующие:
- Все запросы используют одинаковое значение
pagedизget_query_var('paged'), поэтому переход по страницам работает только для одного из них. - Параметры пагинации конфликтуют, так как URL и параметры запроса не учитывают, какой именно запрос переключают.
- Отсутствует правильная обработка параметров пагинации для каждого запроса.
Пошаговое решение: как реализовать независимую пагинацию для двух и более WP_Query
1. Получение параметров paged для каждого запроса
Для каждого запроса нужно использовать уникальные GET-параметры, например, paged1 и paged2. Тогда каждый запрос будет читать свой параметр.
$paged1 = max( 1, get_query_var('paged1') ? intval(get_query_var('paged1')) : ( isset($_GET['paged1']) ? intval($_GET['paged1']) : 1 ) );
$paged2 = max( 1, get_query_var('paged2') ? intval(get_query_var('paged2')) : ( isset($_GET['paged2']) ? intval($_GET['paged2']) : 1 ) );2. Создание двух WP_Query с разными параметрами пагинации
$args1 = [
'post_type' => 'post',
'posts_per_page' => 5,
'paged' => $paged1
];
$query1 = new WP_Query($args1);
$args2 = [
'post_type' => 'product',
'posts_per_page' => 3,
'paged' => $paged2
];
$query2 = new WP_Query($args2);3. Вывод постов и пагинации с уникальными ссылками
Выводим посты каждого запроса и генерируем пагинацию вручную, используя функцию paginate_links() с параметром add_args для сохранения других параметров пагинации.
if ( $query1->have_posts() ) :
while ( $query1->have_posts() ) : $query1->the_post();
the_title('<h3>','</h3>');
endwhile;
echo paginate_links([
'base' => add_query_arg('paged1','%#%'),
'format' => '',
'current' => $paged1,
'total' => $query1->max_num_pages,
'add_args' => ['paged2' => $paged2],
]);
endif;
wp_reset_postdata();
if ( $query2->have_posts() ) :
while ( $query2->have_posts() ) : $query2->the_post();
the_title('<h4>','</h4>');
endwhile;
echo paginate_links([
'base' => add_query_arg('paged2','%#%'),
'format' => '',
'current' => $paged2,
'total' => $query2->max_num_pages,
'add_args' => ['paged1' => $paged1],
]);
endif;
wp_reset_postdata();Проверка результата после внедрения
Для проверки работы пагинации с несколькими запросами:
- Откройте страницу и убедитесь, что отображаются два списка с разным количеством постов.
- Нажимайте на ссылки пагинации каждого списка и проверяйте, что меняются только соответствующие записи, а второй список остаётся на той же странице.
- В URL должны появляться параметры
paged1иpaged2с разными значениями. - При смене страницы для одного запроса, другой не должен сбрасываться.
Частые ошибки и как их исправить
- Использование одного параметра paged для всех запросов. Решение: используйте отдельные параметры GET и обработку для каждого запроса.
- Не сбрасывается
postdataпосле каждого цикла. Это приводит к конфликтам с глобальными переменными. Используйтеwp_reset_postdata()после каждого цикла. - Пагинация не обновляет URL или ведёт на 404. Убедитесь, что ссылки пагинации формируются с помощью
paginate_links()с правильными базовыми параметрами и добавленными аргументами. - При использовании ЧПУ параметры пагинации не работают. В этом случае проще переключиться на использование параметров GET (
?paged1=2&paged2=1), либо реализовать дополнительную логику для перезаписи правил URL.
Практические советы по безопасности и производительности
- Всегда приводите параметры пагинации к целочисленному типу через
intval()и используйтеmax(1, ...), чтобы избежать отрицательных и нулевых значений. - Не забывайте вызывать
wp_reset_postdata()после каждого пользовательского запроса, чтобы очистить глобальные переменные WordPress. - Оптимизируйте запросы, устанавливая
posts_per_pageв адекватное количество, чтобы не перегружать сервер. - Если пагинация используется на страницах с большим количеством запросов, рассмотрите кеширование результатов через Transients API или сторонние плагины кеширования.
Сравнение подходов: плагины vs кастомный код vs компромисс
| Подход | Плюсы | Минусы | Когда использовать |
|---|---|---|---|
| Плагины для пагинации нескольких запросов | Быстрая реализация, готовый UI, поддержка обновлений | Могут быть тяжёлыми, не всегда гибкие, конфликтуют с кастомным кодом | Если нет времени на разработку, и требования стандартные |
| Кастомный код с разными параметрами paged | Полный контроль, оптимизированный под проект, без лишнего кода | Требует знаний, больше времени на отладку и поддержку | Для сложных кастомных сценариев и уникального UI |
| Компромисс: базовый плагин + кастомные доработки | Экономит время, позволяет расширять функционал под задачи | Требует интеграции и тестирования | Если нужна базовая функциональность с возможностью кастомизации |