Не за#буйте с вашей пагинацией!!!
Решаем один из самых популярных вопросов у разработчиков WordPress: «Почему не работает пагинация?»
Так почему же?
Для начала нужно разобраться с тем, на какой странице вы хотите вывести пагинацию.
Существуют страницы постов (постов/страниц/кастомных типов постов(CPT)) или архивные страницы(архивные/терминов страницы и страница поиска).
Пагинация на странице постов
В целом пагинацию можно разбить на 3 небольших этапа:
- Делаем правильную выборку с помощью
WP_Query; - Выводим пагинацию;
- Выводим 404, когда это необходимо
WP_Query для пагинации
$current = absint(
max(
1,
get_query_var( 'paged' ) ? get_query_var( 'paged' ) : get_query_var( 'page' )
)
);
$posts_per_page = 3;
$query = new WP_Query(
[
'post_type' => 'post',
'posts_per_page' => $posts_per_page,
'paged' => $current,
]
);
Нужно обратить внимание на параметр paged в WP_Query, он говорит о том, какую страницу данного запроса вывести. С помощью функций get_query_var() мы получаем номер текущей страницы …/page/{# страницы}. В зависимости от типа страницы мы должны использовать get_query_var( 'paged' ) или get_query_var( 'page' ). Я решил написать универсальный вариант, который подойдет к любому типу страниц.
Вывод пагинации
Для вывода пагинации используем функцию paginate_links:
echo wp_kses_post(
paginate_links(
[
'total' => $query->max_num_pages,
'current' => $current,
]
)
);
В функцию paginate_links нужно передать два параметра: total — количество страниц и current — текущую страницу.
Так же можно использовать the_posts_pagination, но важно помнить, что данная функция работает только с глобальным wp_query и ее вызов выглядит примерно так:
global $wp_query;
$restore_wp_query = $wp_query;
$wp_query = $query;
the_posts_pagination();
$wp_query = $restore_wp_query;
Вывод 404 в случае, когда данных нет
if ( $query->have_posts() ) {
...
} else {
global $wp_query;
$wp_query->set_404();
status_header( 404 );
nocache_headers();
require get_404_template();
}
Устанавливаем 404 ответ в глобальный WP_Query. Ставим 404 статус ответа для сервера. nocache_headers — позволяет сбросить кеш для заголовков ответа во всех браузерах. И подключаем 404 страницу с помощью require get_404_template().
Важно, чтобы до вывода данных ф-ций ничего не выводилось на странице!
Результат
$current = absint(
max(
1,
get_query_var( 'paged' ) ? get_query_var( 'paged' ) : get_query_var( 'page' )
)
);
$posts_per_page = 3;
$query = new WP_Query(
[
'post_type' => 'post',
'posts_per_page' => $posts_per_page,
'paged' => $current,
]
);
if ( $query->have_posts() ) {
?>
<h1>Текущая страница <?php echo absint( $current ); ?></h1>
<?php
while ( $query->have_posts() ) {
$query->the_post();
the_title();
echo '<br>';
}
wp_reset_postdata();
echo wp_kses_post(
paginate_links(
[
'total' => $query->max_num_pages,
'current' => $current,
]
)
);
} else {
global $wp_query;
$wp_query->set_404();
status_header( 404 );
nocache_headers();
require get_404_template();
}
Пагинация на архивный страницах
Например я хочу сделать так, чтобы на странице поиска отображались записи только с конкретной категории. Тут важно понимать, что пагинация из примера выше работать не будет т.к. страница поиска является архивной страницей и имеет свою пагинацию. На архивных страницах можно изменить глобальный WP_Query с помощью хука pre_get_posts.
Пример страницы
if ( have_posts() ) {
while( have_posts() ) {
the_post();
the_title();
echo '<br>';
}
wp_reset_postdata();
}
Пагинация
Для архивных страниц можно использовать функцию the_posts_pagination.
if ( have_posts() ) {
while( have_posts() ) {
the_post();
the_title();
echo '<br>';
}
wp_reset_postdata();
the_posts_pagination();
}
Важно, что данная функция работает только с глобальным wp_query.
Изменяем результат запроса с помощью pre_get_posts
Добавляем в functions.php:
add_action( 'pre_get_posts', 'customize_search_query' );
function customize_search_query( WP_Query $wp_query ) {
if ( $wp_query->is_main_query() && ! $wp_query->is_admin() && $wp_query->is_search() ) {
$wp_query->set( 'cat', 10 );
}
}
С данным хуком нужно быть осторожным. Для начала нужно проверить, что данный запрос является основным с помощью метода is_main_query. Так же проверить, что данных запрос вызывается на фронте с помощью is_admin и то, что данный запрос является поиском is_search. Затем устанавливаем конкретную категорию set( 'cat', 10 );
Источник: WP Punk.


В процессе тестирования вашего кода на странице категорий, хотел вывеси посты с пагинацией этой категории. Создал 8 постов, применил указанный код из Результата. 1 и 2 страницы нормально посты отобразили (/category/uncategorized/page/2/), а вот нажимая на 3-ю ссылку редиректит на 404. Можете ли, как-то перепроверить код ? А то не работает( WP v 6.0.1
Проверьте
posts_per_pageПроверил, не работает. На самом деле, у меня немного иная задача. Мне необходимо сделать пагинацию для страницы на которой выводятся произвольные типы записи.
Вот так добавил тип записи в functions.php
add_action('init', function () { $labels = array( 'name' => 'News', 'singular_name' => 'News', 'add_new' => 'Add News', 'add_new_item' => 'Add News', 'edit_item' => 'Corrected news', 'new_item' => 'New news', 'all_items' => 'All news', 'search_items' => 'Search news', 'not_found' => 'News in these types were not found', 'not_found_in_trash' => 'No such news were found in the basket', 'menu_name' => 'News' ); $args = array( 'labels' => $labels, 'public' => true, 'publicly_queryable' => false, 'has_archive' => true, 'menu_icon' => 'dashicons-email-alt2', 'menu_position' => 5, 'supports' => array('title', 'editor', 'custom-fields', 'thumbnail'), 'taxonomies' => array('category', 'post_tag'), 'rewrite' => true, 'query_var' => true, ); register_post_type('news', $args); });Потом создал как описано в статье пагинацию на странице page-news.php
<div id="response" class="block_list"> <?php $current = absint( max( 1, get_query_var( 'paged' ) ? get_query_var( 'paged' ) : get_query_var( 'page' ) ) ); $query = new WP_Query( [ 'post_type' => 'news', 'posts_per_page' => '5', 'paged' => $current, ] ); if ($query->have_posts()) { while ($query->have_posts()) : $query->the_post(); $title = get_the_title(); $publication_arr = get_post_custom_values('publication_img'); if (is_null($publication_arr) || $publication_arr[0] == '0') { $publication_img_src = get_template_directory_uri() . '/images/no-image.jpg'; } else { $publication_img_src = ''; } echo '<div class="block_item"> <img class="block_item__img" src="' . $publication_img_src . '" alt="' . $title . '"> <a class="block_item__link" href="' . get_permalink() . '">' . $title . '</a> </div>'; endwhile; ?> <div class="category_pagination"> <?php echo paginate_links( array( 'base' => get_pagenum_link(1) . '%_%', 'format' => 'page/%#%/', 'total' => $query->max_num_pages, 'current' => $current, 'show_all' => false, 'end_size' => 1, 'mid_size' => 2, 'prev_next' => true, 'prev_text' => __('Previous', 'test'), 'next_text' => __('Next', 'test'), 'class' => '', ) ); ?> </div> <?php } wp_reset_postdata(); ?> <?php else : ?><p><?php esc_html_e('Missing posts with defined criteria', 'test'); ?></p><?php endif; ?> </div>Только расширил значения для функции paginate_links. Так вот ссылки пагинации отображает, а вот при нажатии на них редиректит на index.php Может есть совет, как решить эту задачу для произвольных типов записи?