Постраничная навигация с асинхронной подгрузкой постов в WordPress. Бесконечная прокрутка постов.

Если на моём сайте вы перейдёте на страницу Блог или в какую-нибудь рубрику, то в самом низу страницы, наряду с обычной постраничной навигацией, вы увидите кнопку Загрузить ещё, которая позволяет подгружать следующие посты без обновления страницы.

Скажу прямо, на моём сайте используется в некоторой степени шаманский способ навигации по страницам — эту навигацию я разрабатывал давно и возможно в те времена ещё не был так хорош в PHP и jQuery. Теперь же я вам покажу более правильный и эффективный способ реализации постраничной навигации с возможностью асинхронной загрузки новых постов. То есть в код моего сайта можете не смотреть, а если у вас появятся вопросы, тогда поищите ответы на них в комментариях к этому посту или посмотрите виде.

Работать будем со стандартной темой TwentySeventeen, во-первых, эта тема довольно простая и будет нетрудно разобраться в коде, во-вторых, вы всегда можете установить её прямо из админки из репозитория тем WordPress.

Что мы попробуем сделать в этом посту?

  • Загрузку постов при нажатии на кнопку Загрузить ещё.
  • Бесконечную загрузку, т е посты и комментарии будут подгружаться автоматически при прокрутке страницы (да, как во вконтакте).
  • Сделаем так, чтобы подгрузка постов работала для любых архивов таксономий.

Шаг 1. Добавление кнопки «Загрузить ещё» 

Для начала нам надо найти файл, в котором добавляется постраничная навигация. В TwentySeventeen этот файл — прямо index.php. Если вы не понимаете, в каком файле надо искать в вашей теме, рекомендую взглянуть на этот туториал.

Если же вы решили использовать какую-то из стандартных тем (как я), то напоминаю, что для изменений желательно использовать дочерние темы (подробнее на видео в самом низу поста).

Найдите соответствующее место в шаблоне за пределами цикла while, то есть после того, как заканчивается вывод постов (в TwentySeventeen это место практически сразу после endwhile) и вставляем туда код:

<?php if (  $wp_query->max_num_pages > 1 ) : ?>
	<script>
	var ajaxurl = '<?php echo site_url() ?>/wp-admin/admin-ajax.php';
	var true_posts = '<?php echo serialize($wp_query->query_vars); ?>';
	var current_page = <?php echo (get_query_var('paged')) ? get_query_var('paged') : 1; ?>;
	var max_pages = '<?php echo $wp_query->max_num_pages; ?>';
	</script>
	<div id="true_loadmore">Загрузить ещё</div>
<?php endif; ?>
ajaxurl
Это обработчик AJAX-запросов в WordPress.
true_posts
Сериализованный массив, содержащий все необходимые параметры запроса, является свойством класса WP_Query.
current_page
Номер текущей страницы.

А теперь немного стилей, которые мы добавим на нашу кнопку, чтобы она круто выглядела (стили можно вставить в стандартный style.css в папке с темой).

#true_loadmore{
	background-color: #ddd; /* сервый фон */
    	border-radius: 2px; /* закругление углов */
    	display: block; /* блочный элемент, на случай, если захотите использовать <a> */
    	text-align: center; /* выравнивание текста по центру */
    	font-size: 14px; font-size: 0.875rem; /* размер шрифта */
    	font-weight: 800; /* начертание */
    	letter-spacing: 1px; /* межбуквенный интервал */
    	cursor: pointer; /* курсор мыши при наведении такой же, как при наведении на ссылку */
    	text-transform: uppercase;
    	padding: 10px 0; /* внутренние отступы сверху и снизу у кнопки */
    	transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, color 0.3s ease-in-out; /* CSS-анимация*/
}
#true_loadmore:hover{
	background-color: #767676;
	color: #fff;
}

Успешным выполнением первого шага будет считаться вот такая кнопка, которая должна будет появиться на странице всех ваших записей, но имейте ввиду, что если записей недостаточно для двух страниц, то кнопки не будет, для этого либо создайте больше записей, либо перейдите в Настройки > Чтение и измените количество отображаемых на странице записей там.

Кнопка асинхронной бесконечной загрузки постов

Самый легкий шаг позади.

Шаг 2. Подключение скриптов jQuery 

Документация функций wp_enqueue_script() и get_stylesheet_directory_uri() в помощь. Про подключение скриптов я писал часто и подробно, поэтому сейчас на этом останавливаться не будем, если есть проблемы — смотрите документацию. А этот код — в functions.php.

function true_loadmore_scripts() {
	wp_enqueue_script('jquery'); // скорее всего он уже будет подключен, это на всякий случай
 	wp_enqueue_script( 'true_loadmore', get_stylesheet_directory_uri() . '/loadmore.js', array('jquery') );
}
 
add_action( 'wp_enqueue_scripts', 'true_loadmore_scripts' );

Шаг 3. Скрипт асинхронной загрузки 

Вы ещё не создали файл loadmore.js в папке с темой? Давайте создадим его и добавим туда следующий код:

jQuery(function($){
	$('#true_loadmore').click(function(){
		$(this).text('Загружаю...'); // изменяем текст кнопки, вы также можете добавить прелоадер
		var data = {
			'action': 'loadmore',
			'query': true_posts,
			'page' : current_page
		};
		$.ajax({
			url:ajaxurl, // обработчик
			data:data, // данные
			type:'POST', // тип запроса
			success:function(data){
				if( data ) { 
					$('#true_loadmore').text('Загрузить ещё').before(data); // вставляем новые посты
					current_page++; // увеличиваем номер страницы на единицу
					if (current_page == max_pages) $("#true_loadmore").remove(); // если последняя страница, удаляем кнопку
				} else {
					$('#true_loadmore').remove(); // если мы дошли до последней страницы постов, скроем кнопку
				}
			}
		});
	});
});

Я постарался сделать этот код максимально простым, дополнительными переменными усложнять его не стал. Если вы хотя бы немного разбираетесь в jQuery, то у вас не возникнет с ним никаких проблем. Даже если не разбираетесь, но сделаете всё по инструкции, то всё тоже будет ок.

Шаг 4. Обработчик PHP, вывод постов 

Этот код также отправляется в файл functions.php. Если он вам непонятен, читайте подробнее про WP_Query и query_posts().

<?php
function true_load_posts(){
 
	$args = unserialize( stripslashes( $_POST['query'] ) );
	$args['paged'] = $_POST['page'] + 1; // следующая страница
	$args['post_status'] = 'publish';
 
	// обычно лучше использовать WP_Query, но не здесь
	query_posts( $args );
	// если посты есть
	if( have_posts() ) :
 
		// запускаем цикл
		while( have_posts() ): the_post();
 
			get_template_part( 'template-parts/post/content', get_post_format() );
 
		endwhile;
 
	endif;
	die();
}
 
 
add_action('wp_ajax_loadmore', 'true_load_posts');
add_action('wp_ajax_nopriv_loadmore', 'true_load_posts');

Бесконечная загрузка постов при прокрутке страницы. 

Суть в том, что вы просто скроллите страницу вниз, а новые посты подгружаются по мере её прокрутки. Насколько я помню, впервые такая штука появилась у твиттера (могу ошибаться, поправьте, если я не прав), а потом уже все стянули её оттуда.

Скажу честно — заразная вещь. Те, кто сидят на сайте вконтакте, понимают это прекрасно. Так что, если у вас новостной сайт, тогда этот способ загрузки постов просто «must have».

Если вы сделали все предыдущие шаги из поста и дошли до этого момента — тогда отлично, добавим некоторые изменения для шагов 1 и 3.

Во-первых, кнопка Загрузить ещё нам больше не понадобится, поэтому немного изменим HTML-код:

<?php if (  $wp_query->max_num_pages > 1 ) : ?>
	<script id="true_loadmore">
	var ajaxurl = '<?php echo site_url() ?>/wp-admin/admin-ajax.php';
	var true_posts = '<?php echo serialize($wp_query->query_vars); ?>';
	var current_page = <?php echo (get_query_var('paged')) ? get_query_var('paged') : 1; ?>;
	</script>
<?php endif; ?>

Во-вторых, стили CSS нам тоже больше не нужны, если вы их добавляли, можете напрочь удалить.

В-третьих, содержимое файла loadmore.js изменится и будет следующим:

jQuery(function($){
	$(window).scroll(function(){
		var bottomOffset = 2000; // отступ от нижней границы сайта, до которого должен доскроллить пользователь, чтобы подгрузились новые посты
		var data = {
			'action': 'loadmore',
			'query': true_posts,
			'page' : current_page
		};
		if( $(document).scrollTop() > ($(document).height() - bottomOffset) && !$('body').hasClass('loading')){
			$.ajax({
				url:ajaxurl,
				data:data,
				type:'POST',
				beforeSend: function( xhr){
					$('body').addClass('loading');
				},
				success:function(data){
					if( data ) { 
						$('#true_loadmore').before(data);
						$('body').removeClass('loading');
						current_page++;
					}
				}
			});
		}
	});
});

Файл functions.php (это шаги 2 и 4) мы оставляем без изменений.

Надеюсь, что не запутал вас. Если возникнут трудности или какие-то вопросы, вот вам видео:

А чуть ниже можете почитать комментарии.

Миша Рудрастых Разработчик WordPress WooCommerce

Миша Рудрастых

Впервые познакомился с WordPress в 2009 году, и после двух лет мучений с Joomla и самописными движками это был просто бальзам на душу. С 2014 года меня можно встретить на WordCamp — официальной конфе по WP в Москве, иногда там выступаю. Также в настоящее время веду курсы по WordPress в Epic Skills в Питере.

Смотрите также