В этой статье разберём, как реализовать пагинацию для сложных запросов WordPress, которые используют одновременно таксономии и meta-записи. Такие запросы часто встречаются при создании фильтров по пользовательским критериям, например, для каталогов товаров, портфолио или новостных сайтов с расширенной фильтрацией. Стандартные функции пагинации иногда работают некорректно с подобными запросами, поэтому важно правильно построить WP_Query и вывести пагинацию.
Почему стандартная пагинация не подходит для комплексных запросов
Стандартный механизм пагинации WordPress ориентирован на простые запросы — посты без сложных фильтров. Когда добавляются фильтры по таксономиям или meta-записям, WP_Query меняет SQL-запрос, и подсчёт общего количества страниц может искажаться. В итоге пагинация выводится неправильно, например, страниц слишком много или слишком мало, ссылки ведут на пустые страницы.
Причина — WP_Query умеет считать общее количество записей через found_posts, но при сложных запросах с JOIN в таблицах таксономий и meta-данных необходимо правильно использовать аргумент no_found_rows и иногда вручную корректировать запрос.
Также пагинация должна учитывать, что фильтрация по нескольким таксономиям и meta-данным усложняет формирование ссылок на страницы с правильными параметрами.
Создание WP_Query для комплексных запросов с пагинацией
Рассмотрим пример, где мы выводим товары с двумя таксономиями (например, категория и бренд) и фильтрацией по цене (meta-запись). Важный момент — включить в запрос параметр paged для корректной работы пагинации.
$paged = max( 1, get_query_var('paged') );
$args = [
'post_type' => 'product',
'posts_per_page' => 10,
'paged' => $paged,
'tax_query' => [
'relation' => 'AND',
[
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => 'electronics',
],
[
'taxonomy' => 'brand',
'field' => 'slug',
'terms' => 'sony',
],
],
'meta_query' => [
[
'key' => 'price',
'value' => [10000, 50000],
'compare' => 'BETWEEN',
'type' => 'NUMERIC',
],
],
'no_found_rows' => false, // важно для подсчёта пагинации
];
$query = new WP_Query($args);
Обратите внимание, что no_found_rows выставлен в false — это нужно, чтобы WP_Query вычислил общее количество подходящих записей и пагинация работала корректно.
Вывод пагинации с WP-PageNavi и кастомной навигацией
Для вывода пагинации удобно использовать плагин WP-PageNavi. Он легко настраивается и поддерживает кастомные запросы.
Пример вывода пагинации после цикла:
if ( $query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
// выводим пост
endwhile;
if ( function_exists('wp_pagenavi') ) {
wp_pagenavi( [ 'query' => $query ] );
}
wp_reset_postdata();
else :
echo '<p>По вашему запросу ничего не найдено.</p>';
endif;
Ключевой момент — передать в функцию wp_pagenavi параметр query с нашим объектом WP_Query, чтобы пагинация строилась по правильному числу страниц.
Кастомная пагинация без плагинов
Если вы хотите сделать свою пагинацию, можно использовать функцию paginate_links:
$big = 999999999; // уникальное число
$pagination_links = paginate_links([
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link($big) ) ),
'format' => '?paged=%#%',
'current' => $paged,
'total' => $query->max_num_pages,
'prev_text' => '« Назад',
'next_text' => 'Вперёд »',
]);
echo '<nav class="custom-pagination">' . $pagination_links . '</nav>';
Важно передавать параметр total — общее количество страниц из WP_Query.
Сохранение фильтров в URL и пагинации
При фильтрации по таксономиям и meta-записям часто используются GET-параметры для передачи значений фильтра. Чтобы при переключении страниц пагинация не сбрасывала фильтры, нужно их сохранять в ссылках пагинации.
Если вы используете стандартный paged в URL, то фильтры можно добавить в базу пагинации через add_query_arg или вручную дописывать параметры в ссылку.
$current_page = max(1, get_query_var('paged'));
$base = get_pagenum_link(1);
// Допустим, фильтры передаются через $_GET
$filter_args = [];
if (!empty($_GET['brand'])) {
$filter_args['brand'] = sanitize_text_field($_GET['brand']);
}
if (!empty($_GET['min_price'])) {
$filter_args['min_price'] = intval($_GET['min_price']);
}
$pagination = paginate_links([
'base' => add_query_arg($filter_args, $base) . '%_%',
'format' => 'page/%#%/',
'current' => $current_page,
'total' => $query->max_num_pages,
]);
echo '<nav>' . $pagination . '</nav>';
Это гарантирует, что при переходе по страницам фильтры останутся в URL и будут учтены в новом запросе.
Оптимизация запросов и кеширование пагинации
Сложные запросы с несколькими JOIN и фильтрами могут нагружать базу данных. Чтобы улучшить производительность, стоит применять кеширование результатов WP_Query и готовых HTML-пагинаций.
Например, можно использовать встроенный объектный кеш WordPress или плагины кеширования. Также плагин Clearfy Pro поможет оптимизировать общие настройки сайта и улучшить скорость.
Полезные советы и рекомендации
- Всегда проверяйте, что
pagedкорректно передается в WP_Query. - Используйте
no_found_rows => falseдля подсчёта общего количества страниц. - Передавайте объект WP_Query в функции пагинации, особенно для плагина WP-PageNavi.
- Сохраняйте параметры фильтров в URL и пагинации, чтобы пользователь не терял применённые фильтры при переходе по страницам.
- Рассмотрите кеширование сложных запросов для снижения нагрузки на базу данных.
- Используйте хуки и фильтры WordPress для гибкой настройки запросов и навигации.