Не за#буйте с вашей пагинацией!!!

Почему не работает пагинация?

Один из самых популярных вопрос у разработчиков 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() ) {
		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 );

1 комментарий к “Не за#буйте с вашей пагинацией!!!”

  1. Огромное спасибо, блин, достаточно простой механизм однако, но из-за избытка корявых примеров на просторах сети нихера не работает. Название вашей статьи очень хорошо ложиться на моё состояние в котором я её нашел) Ещё раз спасибо, материал сохраню.

    Ответить

Добавить комментарий

%d такие блоггеры, как: