В WordPress часто возникает задача вывести посты, сгруппированные не только по одной категории, но по логическим связям между категориями. Например, показать посты, которые принадлежат одновременно к двум и более категориям, или исключить определённые категории из выборки с пагинацией. Стандартные способы пагинации при этом не всегда работают корректно, особенно при сложных запросах. В этой статье мы разберём, как реализовать пагинацию для постов в логических категориях с помощью WP_Query, а также рассмотрим примеры решения с использованием плагинов и кода.
Почему стандартная пагинация не подходит для логических категорий
WordPress по умолчанию позволяет использовать пагинацию для обычных категорий через архивы или WP_Query с параметром 'cat'. Но если нужно вывести посты, которые удовлетворяют сложным условиям — например, принадлежат к категории А и категории B, или принадлежат к категории А, но не принадлежат к категории B, — стандартная пагинация часто ломается. Это связано с тем, что параметры WP_Query для таксономий не всегда позволяют корректно формировать условия И/ИЛИ/НЕ, а также с особенностями подсчёта общего количества страниц.
В результате пагинация может показывать некорректное число страниц, вести на несуществующие страницы или повторять одни и те же записи.
Для решения этой задачи нам понадобится писать свой запрос с точным условием и вручную рассчитывать параметры пагинации.
Использование WP_Query для пагинации по логическим категориям
Начнём с разбора параметров WP_Query, которые позволяют составлять логические условия по таксономиям. Для этого используется параметр tax_query. Внутри него можно задавать массивы условий с операторами IN, NOT IN, AND и логическими отношениями relation.
Пример запроса, который выведет посты, относящиеся одновременно к категориям с ID 3 и 7 (логическое И):
function wppagenavi_get_posts_logical_categories($paged = 1, $posts_per_page = 10) {
$args = [
'post_type' => 'post',
'posts_per_page' => $posts_per_page,
'paged' => $paged,
'tax_query' => [
'relation' => 'AND',
[
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => 3,
'operator' => 'IN',
],
[
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => 7,
'operator' => 'IN',
],
],
];
return new WP_Query($args);
}
В этом примере мы используем relation => 'AND' для того, чтобы получить посты, принадлежащие обеим категориям сразу.
Далее нужно вывести пагинацию. Здесь важно корректно посчитать общее число страниц, учитывая сложный запрос. WP_Query сам это делает, но могут быть нюансы с подсчётом при сложных tax_query.
Пример вывода пагинации для логических категорий
После получения объекта WP_Query с нужными постами вы можете вывести посты и пагинацию следующим образом:
$paged = get_query_var('paged') ? get_query_var('paged') : 1;
$query = wppagenavi_get_posts_logical_categories($paged, 5);
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
echo '<h2>' . get_the_title() . '</h2>';
echo get_the_excerpt();
}
// Пагинация
$big = 999999999; // уникальное число для замены
echo paginate_links([
'base' => str_replace($big, '%#%', esc_url(get_pagenum_link($big))),
'format' => '?paged=%#%',
'current' => max(1, $paged),
'total' => $query->max_num_pages,
'prev_text' => '« Назад',
'next_text' => 'Вперед »',
]);
} else {
echo '<p>Посты не найдены.</p>';
}
wp_reset_postdata();
Обратите внимание, что paginate_links корректно работает, если передать правильное количество страниц из объекта WP_Query.
Исключение категорий из пагинации: пример с логикой «НЕ»
Если нужно вывести посты, которые принадлежат к категории 3, но не принадлежат к категории 7, то можно использовать оператор NOT IN в tax_query:
$args = [
'post_type' => 'post',
'posts_per_page' => 10,
'paged' => get_query_var('paged') ?: 1,
'tax_query' => [
[
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => 3,
'operator' => 'IN',
],
[
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => 7,
'operator' => 'NOT IN',
],
],
];
$query = new WP_Query($args);
Такой запрос позволяет гибко формировать выборку и одновременно использовать пагинацию.
Решение типичных проблем пагинации при сложных запросах
При сложных tax_query иногда возникают следующие проблемы:
- Пагинация показывает неправильное число страниц. Это связано с тем, что WP_Query считает общее количество через отдельный запрос, который может игнорировать часть условий.
- Переходы по страницам ведут на пустые страницы. Такое бывает, если параметры запроса не учитываются в ссылках пагинации.
- Дублирование постов на разных страницах. Обычно происходит из-за некорректно переданного параметра
pagedили фильтрации.
Чтобы решить эти проблемы, рекомендуем:
- Всегда использовать параметр
pagedизget_query_var('paged'). - Генерировать ссылки пагинации через функцию
paginate_linksс корректным параметромbase. - Использовать правильную структуру
tax_queryс параметромrelation. - Если пагинация всё равно даёт сбои, можно добавить фильтр
found_posts, чтобы вручную скорректировать общее число постов.
Пример фильтра для корректировки подсчёта постов
Если вы замечаете, что общее количество постов в пагинации неверно, можно переопределить его так:
add_filter('found_posts', 'wppagenavi_correct_found_posts', 10, 2);
function wppagenavi_correct_found_posts($found_posts, $query) {
// Проверяем, что это наш сложный запрос
if ($query->is_main_query() && !is_admin() && isset($query->query_vars['tax_query'])) {
global $wpdb;
$tax_query = new WP_Tax_Query($query->query_vars['tax_query']);
$tax_sql = $tax_query->get_sql($wpdb->posts, 'ID', 'term_taxonomy_id');
// Собираем SQL для подсчёта
$count_sql = "SELECT COUNT(DISTINCT {$wpdb->posts}.ID) FROM {$wpdb->posts} ";
$count_sql .= $tax_sql['join'];
$count_sql .= ' WHERE 1=1 ' . $tax_sql['where'];
$count = $wpdb->get_var($count_sql);
return $count ?: $found_posts;
}
return $found_posts;
}
Этот код выполняет точный подсчёт количества постов для сложного tax_query и возвращает корректное число для пагинации.
Плагины, которые помогают с пагинацией и логическими категориями
Для упрощения задач с пагинацией при сложных условиях можно использовать плагины:
- WP-PageNavi — расширяет стандартную пагинацию WordPress удобными стилями и настройками. Хорошо интегрируется с кастомными WP_Query.
- Clearfy Pro — оптимизационный плагин, который улучшает производительность запросов и пагинации, в том числе с таксономиями. Подробнее: https://wpshop.ru/plugins/clearfy-pro/
- Expert Review — помогает создавать сложные запросы и выводить посты с пагинацией, удобно для кастомных условий. Подробнее: https://wpshop.ru/plugins/expert-review/
Использование этих плагинов позволяет уменьшить количество кода и упростить поддержку сложной пагинации.
Итоговые рекомендации по созданию пагинации для постов в логических категориях
Подводя итог, можно выделить основные моменты:
- Используйте
tax_queryс правильнымrelationи операторамиIN,NOT IN,ANDдля создания логики категорий. - Передавайте параметр
pagedв WP_Query, чтобы пагинация работала корректно. - Для вывода пагинации используйте функцию
paginate_linksс корректными параметрами. - Если возникают проблемы с подсчётом общего количества постов, применяйте фильтр
found_postsс ручным подсчётом. - Рассмотрите возможность использования плагинов, например, WP-PageNavi или Clearfy Pro, для упрощения задачи.
- Тестируйте пагинацию на разных страницах и с разными условиями, чтобы исключить дубли и пустые страницы.
Такой подход позволит создавать сложные выборки постов с логическими связями категорий и корректной пагинацией без сбоев и ошибок.