Постраничная навигация с асинхронной подгрузкой постов в 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 в 2009 году. С 2014 года меня можно встретить на WordCamp — официальной конфе по WordPress, иногда там выступаю. Также в настоящее время веду курсы по WordPress в Epic Skills.

Если вам нужна помощь с вашим сайтом или может даже разработка с нуля — пишите мне.

Комментарии 301

  • Эльдар:

    Спасибо!! Очень ждал этого поста)))

    А этим способом можно сделать подгрузку сразу для 3 циклов на одной странице?

    • Миша:

      да, конечно) немного доработав. Тут главное учесть, что элементов с одинаковыми HTML-атрибутами id не должно быть на странице.

    • Алексей:

      Люди, кто уже пытался реализовать несколько циклов на одной странице? Подскажите как это сделать?

      • Миша:

        Изменить название переменных, ID кнопки поменять на класс.. 🙂

        • Алексей:

          Изменил, теперь циклы работают одновременно и выводятся одинаковые посты с категории последнего цикла 🙁

          • Миша:

            Ну смотрите, на самом деле тут больших сложностей быть не должно, поэтому я постараюсь объяснить.

            Когда у нас была только одна подгрузка на странице, то всё было просто, было несколько переменных и кнопка с определенным ID, код к ним обращался и всё ок.

            Если же нужно сделать несколько подгрузок, то тут два варианта, либо скопировать полностью весь код и заменить названия всех переменных и ID кнопок сменить. Это простой способ. Он плох тем, что если нужно будет третью подгрузку сделать, то по новой всё копировать.

            Хороший же вариант, сделать всё по классам и по относительным обращениям к элементам (слова русские, смысл непонятен 🙂

            В шаге 1 например перменную ajaxurl не трогаем, она остается одинаковой, зато другие перменные лучше попробовать затолкать в атрибуты кнопки, например data-posts, data-current-page — в итоге мы будем обращаться к ним через $(this), а значит относительно.

            В третьем же шаге, нужно сделать так, чтобы можно было нажать любую кнопку и получить один результат, для этого мы добавляем кнопкам одинаковый класс и обращаемся по нему. Затем в функции надо сделать замены вот такого типа, например меняем:

            'page' : current_page

            на

            'page' : $(this).attr('data-current-page')
      • Миша:

        Как реализовать несколько кнопок «Загрузить ещё» на одной странице

        Прежде всего, давайте условимся следующим:

        1. Дополнительные циклы на странице мы будем задавать при помощи WP_Query.
        2. Подгрузка постов будет начинаться только с 1-й страницы — конечно все эти моменты вы сами сможете потом доработать, но давайте начнём с простого?

        Допустим вы уже поставили одну кнопку подгрузки постов и она у вас заработала — отлично! Остальные изменения будут касаться только Шагов 1 и 3.

        Изменения в шаге 1

        Для начала вынесем эти переменные куда-нибудь отдельно, например в <head> сайта:

        <script>
        	var ajaxurl = '<?php echo site_url() ?>/wp-admin/admin-ajax.php';
        	var current_page = 1;
        </script>

        Как я уже говорил, посты будут начинаться всегда с первой страницы, поэтому изменённый код будет выглядеть следующим образом:

        <?php if (  $wp_query->max_num_pages > 1 ) : ?>
        	<div class='true_loadmore' data-true-posts='<?php echo serialize($wp_query->query_vars); ?>' data-max-pages='<?php echo $wp_query->max_num_pages; ?>'>Загрузить ещё</div>
        <?php endif; ?>

        Этот код кнопки нужно добавить после каждого цикла! Предпочтительно перед endif;. Конечно, если дело касается дополнительных циклов, вам следует заменить $wp_query на название соответствующего объекта WP_Query.

        Изменение в шаге 3

        Тут всё просто — всё, что вам нужно, это заменить код в .js-файле на следующий:

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

    Хорошая статья, только я передавал у себя не запрос, а конкретные данные к запросу, когда писал шаблоны)

    Еще, для чего использовать эту конструкцию?

    $q->post->ID

    Функия the_post() автоматом строит переменную $post или я ошибаюсь?

  • Александр:

    Все это круто, но я отказался от бесконечного скроллинга в силу того, что большинство юзеров открывают пост на этой же странице и, возвращаясь назад, попадают в начало. Здесь та же тема. Например, я нажал на 4 страницу, а потом подгрузил еще три, открыл пост на седьмой и по кнопке "назад" меня перекинуло опять на четвертую.

  • Jason:

    Спасибо, забрал себе) Смущает только то, что с индексацией такого контента будут траблы.
    А как это дело немного припрятать от посторонних глаз? Пробовал во внешний файл, но тогда не работает..

  • Иван:

    Здравствуйте, я использую в цикле the_loop для вставки миниатюр в background такой код:
    if (have_posts()) : while (have_posts()) : the_post();
    $id = get_post_thumbnail_id( );
    $background_url = wp_get_attachment_image_src( $id );?>
    ....
    <div style="background-image: url('');">
    Но когда я вставил его в 4 пунк:
    ....
    $q = new WP_Query($args);
    if( $q->have_posts() ): while($q->have_posts()): $q->the_post();
    $id = get_post_thumbnail_id( );
    $background_url = wp_get_attachment_image_src( $id );?>
    ....
    <div style="background-image: url('');">

    То он перестал работать. Посты выводятся, а background'а нет. Как решить эту проблему?

  • Иван:

    В url('') находится .
    Не напечаталось почему то.

  • Иван:

    Извиняюсь. Код внезапно заработал.

  • Илья:

    Зачем так путать? У меня проблемы начались на моменте когда второй раз добавляю код в functions.php . Тупо белый экран.

  • Илья:

    Вообщем, скрипт настроил пашет, но не так как нужно. У меня на страницах миниатюры записей идут но когда пролистываешь, внизу появляются полные записи а нужно чтобы так же выводились анонсы.
    Подгруженные посты появляются сразу, у поользователя нет выбора и шанса увидеть подвал сайта. Как можно исправить? Заранее большое человеческое благодарю.

  • laki:

    а сортировка, опубликованные и не опубликованные посты разве не нужна?)

  • lakispy:

    Просто в конкретно моем случае, за отображение и скрытие постов в категориях, архивах и на главной отвечает плагин Advanced Category Excluder, а он никак не связан с дальнейшей подгрузкой постов на странице.

  • lakispy:

    или не в нем проблема, в общем:
    1) подгружаются черновики
    2) при первом нажатии подгрузки выводятся новые записи+3 старые, то есть на странице 10 записей, а он подгружает 7 новых и 3 старых. В последующем цикле подгрузки все ок.

    • Миша:

      Ваши обе проблемы связаны с подгрузкой черновиков. По идее все параметры уже должны были быть включены в переменную true_posts.

      Также вы можете попробовать обновить участок кода:

      1
      2
      3
      4
      5
      
      <?php
      function true_load_posts(){
      	$args = unserialize(stripslashes($_POST['query']));
      	$args['paged'] = $_POST['page'] + 1; // следующая страница
      	$args['post_status'] = 'publish';
      • lakispy:

        Извиняюсь, не ответил. Проблему черновиков это конечно решило, но главная проблема в подгружаемых старых записях. Честно говоря, надоело искать решения и решил пойти методом тыка по плагинам. И наткнулся на "лекарство от головной боли", плагин Infinite Scroll, он привязывается к css, подменяя пагинацию на сайте. То есть двойной плюс, на сайте сохраняется постраничная навигация, что в принципе полезно для SEO и у него есть любой вариант подгрузки включая и кнопкой (manual trigger), НО именно вариант с кнопкой адаптировали только для стандартных шаблонов. На github разжевывают настройку, которой естественно нет в русифицированном виде. Не желаете ли русифицированное FAQ сделать, думаю это актуально?)

        • Миша:

          но главная проблема в подгружаемых старых записях.

          Расскажите пожалуйста про эту проблему, это важно.

          плагин Infinite Scroll

          Возможно когда-нибудь я напишу обзор этого плагина... 🙂

          • lakispy:

            Изначально я код удалил, после нескольких попыток не увенчавшихся успехом. Сейчас поставил по новой и все работает. Может кому пригодится, вот код разделения в две колонки:

            Ниже новый код, вместо ранее добавленного в functions.php

            function true_load_posts(){
            	$args = unserialize(stripslashes($_POST['query']));
            	$args['paged'] = $_POST['page'] + 1;
            	$args['post_status'] = 'publish';
            	$q = new WP_Query($args);
            	if( $q->have_posts() ): $first = true;  ?>
             
            		<ul class="post-list">
             
            		<?php while($q->have_posts()): $q->the_post();
            			if($first) $class = "post first-in-row";
            			else $class="post";
            			$first = !$first;
            		?>
            			<!-- Start: Post -->
             
            		<li id="post-<?php echo $q->post->ID ?>" <?php post_class($class); ?>>
            <!-- Тут блок одного поста -->
            </li>
            <!-- End: Post -->
            			<?php
            		endwhile; ?>
            <div class="clear"></div></ul>
            <?php endif;
            	wp_reset_postdata();
            	die();
            }

            Это в CSS:

            .post-list {overflow: hidden;list-style: none;width: 650px;display: inline;}
            .post-list li.post {overflow: hidden;margin: 0 40px 16pt 0;width: 300px;float: left;}
            .post-list li.first-in-row {clear: left;}
            .clear {height: 0;margin: 0;padding: 0;clear: both;float: none;overflow: hidden;border: none;}

            Чтобы все адекватно выглядело, естественно нужно переделать и основной шаблон под отображение в две колонки.

            Кстати, Михаил у вас подписка на сообщения с ошибкой в ссылке: "Anchor/comment-2760truemisha.ru/blog/wordpress/ajax-pagination.html"

  • Леонид:

    Мне непонравился момент, где на страничку добавляется стиль, который скрывает кнопку для загрузки дальнейшего контента. Я сделал немного по-другому:

    В скрипте, где мы получаем ajax url и другие параметры можно добавить переменную "maxPages", с которой мы в дальнейшем сравним "currentPage" и удлим кнопку, если страницы совпадают.

    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; ?>';
    $.ajax({
        url: ajaxurl, 
        data: data,
        type: "POST", 
        success: function(data){
          if( data ) { 
            $("#true_loadmore").before(data); 
            currentPage++; 
            if (currentPage == maxPages) { $("#true_loadmore").remove();  }
          } else {
            $("#true_loadmore").remove(); 
          }
        }
      });
  • Юра:

    А как задать количество подгружаемых постов в этом примере?

  • bvv:

    Поставил и настроил скрипт - все работает.
    Была та же проблема, что и у lakispy - выводились повторные записи.
    Применил предложенное решение - помогло.

    Теперь то ли в конце загруженной страницы (начиная со второй), то ли в начале (начиная с третьей) откуда-то стал выводиться 0.
    Причем если прокрутить до конца (записей больше нет), то эти нули в последней строке начинают плодиться.

  • Роман Яковлев:

    Спасибо за пост.
    В файле functions после

    while($q->have_posts()): $q->the_post();

    необходимо прописать

    global $post; $cvalue =get_post_meta($post->ID, $page_value, true);

    .
    После этого внутри можно разместить любые пользовательские функции . Без этого пользовательские функции не отображаются.

  • Алексей:

    Доброго времени суток! Статья очень помогла, но есть проблема. У меня подгружаются дополнительные данные из плагина, эти данные я вставляю при помощи shortcode:

    К сожалению, вместо того чтобы вывести результат обработки shortcode, мне выводится сам шорткод [site_show_price] . Помогите пожалуйста разобраться с этой проблемой.

  • Ильдар Хакимов:

    Бесит такая штука в контакте, когда хочешь в подвал, чтобы перейти по ссылке "Разработчика", а тебя все не пускает и не пускает, приходиться заходить в "Документы", а оттуда в подвал. Хотя для задержания крутая тема, жаль по нажатию на ESC функция не отключается.

  • Ильдар Хакимов:

    И мне хотелось бы такую функцию к странице, которая разбита на 200 подстраниц, а не к категориям.

  • deSiter:

    Чувак, спасибо! Пол дня сладить пытался, а по твоей инструкции за 20 минут заработало!

  • Витя mateas:

    А как сделать чтобы и постраничная навигация оставалась и кнопка загрузить еще работала, как у вас в блоге?

  • Рома:

    Привет, у меня ничего не работает. Использовал в теме Twenty Twelve, но никаких действий нет. Если нужно изменить html код в php обработчике на код шаблона из Twenty Twelve, то какой?

  • Рома:

    кнопка не работает. никаких действий не происходит. сделал все по уроку, кнопка есть, но погрузки постов нет.

  • Рома:

    и вдруг всё чудесным образом заработало)

  • Дмитрий:

    Пожалуйста, помогите решить проблему: после того как добавляю код с подключением jquery и loadmore.js - при обновлении страницы весь текст на странице превращается в иероглифы, картинки растягиваются на аномально большую высоту. Как исправить?

  • Дмитрий:

    Не подскажите, как сделать чтобы подгружались посты только из определенной категории?

  • Radnk:

    При быстром многократном нажатии загружается одна страница много раз, как исправить?

    И как убрать вот это (script): http://ssmaker.ru/c02ea7d7.png

    у вас например в исходном коде такого нет

    • Миша:

      1) Можно в самом начале AJAX-запроса добавлять класс (к body или к кнопке), после выполнения запроса удалять его. Соответственно перед нажатием кнопки будет проверять наличие класса. Если класс есть (т.е. предыдущий запрос не выполнен до конца), то ничего не делаем.

      2) Имеете ввиду скрипт с параметрами? Можете просунуть их в атрибуты кнопки.

      • Radnk:

        А не поможете кодом?

        я уже как только не крутил: http://ssmaker.ru/054036d2.png

      • Radnk:

        Все работает:

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

        Но правильно ли это?

        • Radnk:

          Вот:

          jQuery(function($) {
          	$('#true_loadmore').click(function(){
           
              	var $el = $(this),
                  	$preloader = $('.preloader');
          		var data = {
          			'action': 'loadmore',
          			'query': true_posts,
          			'page': current_page
          		};
           
          		$.ajax({
          			url: 'http://pro100-minecraft.ru/wp-admin/admin-ajax.php', // Обработчик
          			type: 'POST', // Тип запроса
          			data: data, // Данные
          			cache: false, // Кэширование
          			beforeSend: function( ) { // Действия, которые будут выполнены перед выполнением ajax-запроса
          				$el.hide(); 
          				$preloader.show();
          			},
          			success: function(data){
          				if( data ) { 
          					$el.before(data); // Вставляем новые посты
          					current_page++; // Увеличиваем номер страницы на единицу
          					if (current_page == max_pages) {
          						$el.remove();
          					}
          				} else {
          					$el.remove(); // Если мы дошли до последней страницы постов, скроем кнопку
          				}
          			}           
          		})
           
          		.complete(function() { // Действия, которые будут выполнены после завершения ajax-запроса
          			$preloader.hide();
          			$el.show();
          		});
          	});
          });

          И не работал:

          if (currentPage == maxPages) { $el.remove(); }

          Поменял на:

          if (current_page == max_pages) { $el.remove(); }

          Правильно как?

  • Александр:

    После кнопки у меня идет самодельная пагинация. Все работает, только после подгрузки не обновляется номер текущей страницы. Помогите связать ее с Вашим кодом.

    	function paginator() {  
    	global $wp_query;  
    	$pages = '';  
    	$max = $wp_query->max_num_pages;  
    	if (!$current_page = get_query_var('paged')) $current_page = 1;  
    	$a['base'] = str_replace(999999999, '%#%', get_pagenum_link(999999999));  
    	$a['total'] = $max;  
    	$a['current_page'] = $current_page;  
     
    	$a['mid_size'] = 3; //сколько ссылок показывать слева и справа от текущей  
    	$a['end_size'] = 1; //сколько ссылок показывать в начале и в конце  
     
    	if ($max > 1) echo '<div class="b-pager">';  
    	echo $pages . paginate_links($a);  
    	if ($max > 1) echo '</div>';  
    	}
  • Лев:

    Все отлично, но есть проблема. У меня многие шорткоды созданы по инструкции http://scribu.net/wordpress/optimal-script-loading.html . Суть состоит в том, что для многих шорткодов нужны js скрипты, они подгружаются в футере только один раз на страницу и только на тех страницах, на которых это действительно надо. При использовании ajax пагинации сами шорткоды исполняются, а вот js коды в футере не исполняются. Что можно сделать?

  • Max:

    Спасибо все работает но есть проблемка после нажатия выводит всю статью
    подскажите как исправить что бы выводил только анонс с миниатюрой ( вот пример http://tehnew.ts9.ru/ )

  • Павел:

    У меня стоит ограничение на вывод не больше 5 постов, нужно что бы при нажатии загрузить еще подгружались не 5, а 20 постов. Я так понял сколько стоит ограничение по столько и будет подгружать, можно это изменить?

  • boris_:

    Никак не могу победить проблему с выводом нулей в конце страницы. Die() в конце functions.php есть, но проблему это не решает.

  • Роман:

    Миша привет, спасибо за пост, очень помог,но всё атки не получается нормально выводить несколько постов, меняю кол-во выводимых постов и они выводятся но некорректно, в коде отображается один, а остальне просто друг на друге появляются и в коде их нет, куда капать? Подскажи пожалуйста!

  • Константин:

    Михаил, приветствую!!!! А как можно сделать ajax подгрузку постов по клику, например на cтрелки вперед-назад , из определенной категории типа такой https://yadi.sk/i/7Tyq2Lm9gEkYQ ? Благодарю за ответ

  • Стас:

    Привет! Спасибо большое за материал. Давно хотел реализовать что-то подобное. В целом, удалось реализовать и автоматическую подгрузку и подгрузку через нажатие кнопки. Однако не могу разобраться с оформлением выводимых постов - по ходу его просто нет (см. пожалуйста скриншот http://joxi.ru/jKM-VYwyTJDLMYpkOZI). Подозреваю, что проблема в этом get_template_part( 'content', 'excerpt' ); - т.е. часть кода подгружается с других файлов. Возможно ошибаюсь, поскольку не силен во всем этом. Надеюсь подскажите, как придать постам нормальный (стандартный) вид.

  • Aleksander:

    Добрый день.
    У меня к вам вопрос: получилось сделать динамическую подгрузку данных на страницу, но раньше была миниатюра записи, когда ты её открывал, открывался и пост полностью, а сейчас, когда прогружаются новости, открывается и новость полностью, подскажите пожалуйста, как я могу сделать так, что бы подгружались только миниатюры, а не пост целиком?
    Надеюсь, я все понятно объяснил)
    Спасибо большое!!!

  • andrew:

    Добрый день.
    Интересует вопрос безопасности.
    Пользователь, изменяя переменную true_posts, изменит wp_query?

    • Миша:

      Добрый день!
      Разумеется, если изменить true_posts, то изменится WP_Query, только в чем тут опасность, то, что он посты из другой рубрики сможет подгрузить?)

  • andrew:

    Пользователь сможет выполнять любые нужные ему (но совсем не нужные вам) запросы к БД.

  • Игорь:

    Здравствуйте! спасибо за код очень помог! но есть пару нюансов:
    1. Если всего 1 запись то почему то он ее не выводит , делаю подгружение без кнопки. ( подскажите в чем может быть проблема ?)

    2. Если прописать в functions $args['posts_per_page'] = '1'; скрипт перестает работать и не вводит посты , в консоле пишет - http://prntscr.com/7896o2 , но если в админке выставить чтение 1 запись , то все отлично , если выставить 2 записи то снова пустота , помогите пожалуйста))

  • Миша:

    Здравствуйте!
    У вас просто не выполняется условие if ( $wp_query->max_num_pages > 1 ) :, это значит, что в настройках чтениях либо где-то еще определено такое количество постов, которое помещается на одной странице.

  • Александр:

    Привет, Михаил!
    Использую Ваш метод "бесконечная загрузка постов при прокрутке страницы"
    Есть один нюанс...
    У меня также установлен плагин "Pods" для WP и он в своем шаблоне категории произ.типов постов выводит дополнительные поля с помощью конструкции:

    <?php echo get_post_meta( $post->ID, 'client_name', true ); ?>

    Вставляю данный код в кусок шаблона в functions.php (там где необходимо привести код моего шаблона поста) и на сайте вижу, что на вновь загруженных постах, вместо данного доп поля из PODS пусто. Привожу кусок кода шаблона поста:

    <?php // ВЫВОД ПРОЕКТА ИЗ ПОРТФОЛИО ?>
    	<div class="col-lg-3 col-md-3 col-sm-6 col-xs-12">
    		<div class="one-block">
    				<a href="<?php the_permalink(); ?>" class="company"><?php echo get_post_meta( $post->ID, 'client_name', true ); ?><span class="arr_ico"></span></a>
     
    				<div class="date"><?php the_time('j F Y'); ?></div>
     
    				<a href="<?php the_permalink(); ?>" class="title"><?php the_title(); ?></a>
     
    				<a href="<?php the_permalink(); ?>" class="prev_img">
    					<div><?php if ( has_post_thumbnail() ) the_post_thumbnail(); // выводим миниатюру поста, если есть ?></div>
    				</a>
     
    				<ul>
    					<li title="Комментарии"><a href="<?php the_permalink(); ?>#comments" class="comments_link"><i class="fa fa-comments"></i>&nbsp;&nbsp;<?php echo get_comments_number(); ?></a></li>
    					<li><?php if( function_exists('zilla_likes') ) zilla_likes(); ?></li>
    				</ul>
    		</div>
    	</div>
      <?php // ВЫВОД ПРОЕКТА ИЗ ПОРТФОЛИО ?>

    Натолкните на мысль, что и где нужно добавить, чтобы доп. поля отрабатывали для вновь загруженных аяксом постов. Обращаю внимание, что лайки из дополнительного плагина "zilla_likes" для подгружаемых постов работают и отображаются на странице верно. Заранее спасибо!

    • Миша:

      Привет!
      Вам нужно изменить первый параметр функции get_post_meta() — с $post->ID на $q->post->ID.

      • Александр:

        Бесконечно благодарен, а анимацию как-нибудь без кнопки, но все же всплывающую при подгрузке реально плавно реально допилить? Как я понял для этого в loadmore.js и добавляется класс ".loading" ?
        А что касается сеошного вопроса, что если просто добавить пагинацию обычную вордпрессовскую и скрыть на css "display:none;"? тогда индексироваться будут корректно все записи?

  • Aleksander:

    Добрый день.
    Столкнулся со следующей проблемой: поставил бесконечную подгрузку постов, все работает на компьютере замечательно, захожу с телефона, и оно не работает, вместо того, чтобы загружать посты, оно в конце страницы, открывает последнюю новость, если допустим в самом низу новость 7, то оно не будет подгружать новость 6 и т.д., оно откроет новость 7.
    Как можно решить данную проблему?
    Спасибо большое!!!

  • Александр:

    Миша, а вы не покажете способ, как допилить код, чтобы при первом нажатии "Загрузить еще" пагинатор скрывался. Как сделано здесь http://siliconrus.com/ Очень удачное решение.

  • Aleksander:

    Добрый день.
    Скажите пожалуйста, как вывести бесконечную загрузку на главную страницу? я вывел новости на главную и теперь не могу добавить загрузку.
    Большое спасибо!

  • Александр:

    Добрый день.
    Подскажите пожалуйста, я поставил на сайте бесконечную загрузку, когда захожу на сайт через UC Browser сталкиваюсь со следующей проблемой: когда дохожу до конца страницы оно пишет "Preloading" и открывает последний пост внизу, то есть, появляется под страницей новостей еще одна страница, в которой открыта последняя новость, смотрится это мягко говоря, не очень хорошо. На других браузерах с таким не встречался. Может кто знает решение проблемы?
    Заранее большое спасибо!

    • Миша:

      Добрый день!
      Если такая серьезная проблема и на других браузерах её нет, то, извините за банальный совет, но вы кэш чистили?

      • Александр:

        Добрый день.
        В том то и дело, что все чистил, не помогает, даже не знаю, что делать. Скажите пожалуйста, а вы проверяли этот код в этом браузере? Скорее всего глупая мысль, но может браузер как-то неправильно воспринимает этот код?)

  • Александр:

    На обычных постах работает, а как сделать аjax пагинацию для произвольных типов записей? Где нужно скорректировать код, подскажите пожалуйста.

    • Миша:

      По идее добавить в PHP-обработчик параметр $args['post_type']. Вы на какой странице это делаете? Архивы типов записей?

      • Александр:

        Я сделал страницу шаблон - галерея. Где вывожу все произвольные записи 'gallery'. И к этой же странице шаблону, хочу подгрузить вашу ajax-пагинацию.

        Проблема еще в том, что я уже использую вашу ajax-пагинацию для обычных постов. )) Если я начну изменять код $args['post_type'], то пагинация для обычных постов перестанет работать. Прошу вашего совета)

      • Александр:

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

  • Олег:

    Миша подскажите пожалуйста как сделать вывод постов по средствам masonry.js ?

  • Олег:

    Как то нжуно использовать метод append http://desandro.github.io/masonry/docs/methods.html но что-то у меня не получается может подскажете. Посты выводятся поверх.

    • Миша:

      Во-первых, у вас должен быть отдельный контейнер для блоков, например #posts.
      Во-вторых, вам нужно в этот контейнер вставлять результат ajax через append (а не как у меня через before перед кнопкой).
      В-третьих, кнопку нужно вынести за пределы контейнера.

      $('#posts').append( data ).masonry( 'appended', data );

      Ну в общем вам надо капитально над структурой поработать.

  • Александр:

    Миша подскажите, пожалуйста. Я сделал загрузку аjax постов для новостей через кнопку. И я также сделал загрузку аjax постов для произвольного типа записи без кнопки, но при прокрутке. По отдельности они работают, если будет только ajax загрузка для новстей или если только будет ajax загрузка для произвольного типа записи. Но чтобы было и то и то не получается, работает криво. По сути он берет только один обработчик первый, а второй как бы не видит.

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

    add_action('wp_ajax_loadmore', 'true_load_posts');
    add_action('wp_ajax_nopriv_loadmore', 'true_load_posts');
     
    add_action('wp_ajax_loadmore', 'true_load_posts_scroll');
    add_action('wp_ajax_nopriv_loadmore', 'true_load_posts_scroll');

    Вот внутренности двух скриптов

    jQuery(function($){
    	$(window).scroll(function(){
    		var bottomOffset = 4000; // отступ от нижней границы сайта, до которого должен доскроллить пользователь, чтобы подгрузились новые посты
    		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_1').before(data);
    						$('body').removeClass('loading');
    						current_page++;
    					}
    				}
    			});
    		}
    	});
    });
    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('Ещё').append('<span></span>').before(data); // вставляем новые посты
    					current_page++; // увеличиваем номер страницы на единицу
    					if (current_page == max_pages) $("#true_loadmore").remove(); // если последняя страница, удаляем кнопку
    				} else {
    					$('#true_loadmore').remove(); // если мы дошли до последней страницы постов, скроем кнопку
    				}
    			}
    		});
    	});
    });

    может быть здесь должно быть отличие?

    		var data = {
    			'action': 'loadmore',
    			'query': true_posts,
    			'page' : current_page
    		};
    • Миша:

      Да, отличие должно быть в параметре action.

      var data = {
      			'action': 'loadmore', // и для второго скрипта например loadmore2

      Тогда:

      add_action('wp_ajax_loadmore', 'true_load_posts');
      add_action('wp_ajax_nopriv_loadmore', 'true_load_posts');
       
      add_action('wp_ajax_loadmore2', 'true_load_posts_scroll'); // тут тоже меняем
      add_action('wp_ajax_nopriv_loadmore2', 'true_load_posts_scroll'); // тут тоже

      Вот тут больше инфы об этом.

  • Александр:

    Добрый день.
    Подскажите пожалуйста, как бесконечную загрузку сделать на главной странице?
    Спасибо большое!

  • Александр:

    Спасибо за отличный пост!
    Не подскажете, как изменить код, чтобы при нажатии на кнопку новые посты отображались не внизу, а на месте старых. То есть чтобы уже отображенные посты просто заменялись новыми. Заранее спасибо!

  • alex:

    Попробовал всё сделать как вы описали, но у меня не срабатывает бесконечная подгрузка постов.
    первый вариант с кнопкой работает, но если заменяю на

    <?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; ?>

    бусконечная подгрузка не срабатывает.
    если же оставить

    <div id="true_loadmore">Загрузить ещё</div>

    тогда бесконечная подгрузка работает но + еще кнопка всегда присутствует.

    Возможно проблема в

    <script id="true_loadmore">

    ??

    Также есть еще нюанс, при загрузке страницы список постов не появляется, а только после нажатия на кнопку "Загрузить еще" подгружаются первые 5 постов. Подскажите как сделать по умолчанию загрузку первой партиии постов?

    • Миша:

      Ну вы оставьте кнопку, только текст можете убрать или скрыть её вовсе через CSS:

      <div id="true_loadmore"></div>

      Этот код расчитан, что только новые посты подгружаются асинхронно. Если вам нужно, чтобы он срабатывал для всех постов, даже тех, которые показываюстя при загрузке страницы, запускайте код сразу же, тогда переменная current_page будет равна 0 получается.

  • most_wanted:

    Если я вывожу кастомный тип поста

     $property_types = array('property','land', 'commercial', 'business', 'commercial_land' , 'location_profile','rural');
    	$args = unserialize(stripslashes($_POST['query']));
    	$args['paged'] = $_POST['page'] + 1; // следующая страница
    	$args['post_status'] = 'publish';
     
            $args['post_type'] = $property_types;

    то кнопка "загрузить еще" не пропадает при загрузке последней страницы с записями, на неё нужно еще раз нажать и тогда она пропадает, хотя посты уже больше не загружаются.
    если же снова ставлю post_type="page", то работает как положено - с последнейзагрузкой постов кнопка пропадает. Почему так?

  • Сергей:

    Добрый день!
    Сделал все как описано у вас в статье.
    Отладчик браузера выдает ошибку
    Uncaught ReferenceError: true_posts is not defined

  • most_wanted:

    скажите зачем мы передаём сериализованные данные а потом снова их извлекаем?

    var true_posts = '<?php echo serialize($wp_query->query_vars); ?>';

    и потом:

    $args = unserialize(stripslashes($_POST['query']));
  • Mariel:

    Миша привет. Спс за статью. Скажите пожалуйста... как вместе текста "Загружаю", как поставить картинку GIF...

  • Игорь Фёдоров:

    Миша, привет! Можешь помочь? Как обновлять текущий элемент в стандартной пагинации ВП, если она используется вместе с Ajax подгрузкой?

  • WebNatrix:

    Нашел баг, вы все через админку проверяете скрипт, но попробуйте под гостем зайти или простым пользователем, у вас admin-ajax.php не даст подгрузить. Что делать?

    • Миша:

      Оба использовали?

      add_action('wp_ajax_loadmore', 'true_load_posts');
      add_action('wp_ajax_nopriv_loadmore', 'true_load_posts');
      • WebNatrix:

        ага, прям как у вас там.

        • Миша:

          Проблема, решена, заключалась в конфликте с другим плагином пользователя.

          • Иван:

            А как решена, Миша? У меня такая же проблема - работает только когда я залогинен на сайте!!! то есть конфликт? а как определить с чем конфликтует дайте пожалуйста наметки! Спасибо!

            • Миша:

              Да без понятия, это было давно 🙂

              Окей, алгоритм:

              • Убедиться, что используются оба хука
              • Убедиться, что файл /wp-admin/admin-ajax.php не заблокирован через .htaccess
              • Если не помогло — отключаем все текущие плагины и смотрим, не изменилось, ли что.
              • Иван:

                Я не могу отключить некоторые плагины (easy vk connekt и true instagram), там настройки я настраивал долго! как обойти вариант с отключением плагинов? htaccess проверил - чисто, только в папках wp-admin стоят вот такие записи:

                <IfModule mod_rewrite.c>
                RewriteEngine On
                RewriteBase /exactly/
                RewriteRule ^index\.php$ - [L]
                RewriteCond %{REQUEST_FILENAME} !-f
                RewriteCond %{REQUEST_FILENAME} !-d
                RewriteRule . /exactly/index.php [L]
                </IfModule>

                Оба хука используются

                • Иван:

                  Короче наверно не судьба? я много намутил с защитой блога, теперь уже не помню где что защищал, вот видимо эта защита и работает)) Миша, а можно ли вывести этот ajax как то в отдельный файл что-ли в обход авторизации чтобы работал он?

                  • Миша:

                    А вы попробуйте удалить временно .htaccess из админки и быстро проверить, а потом сразу Ctrl+Z 🙂

                    Можно создать прямо в папке сайта файл ajax.php (например) и в него вставить:

                    require_once( dirname(__FILE__) . '/wp-admin/admin-ajax.php' );

                    Только в AJAX запросах не забудьте URL сменить.

                    • Иван:

                      Миша в общем я нашел решение проблемы..
                      Я же говорил, что безопасность)) В общем у меня была функция которая блокирует доступ к области администратора. То есть в панель администрирования могут только админы заходить. И если пользователь не админ, то происходит редирект на главную
                      Вот сама ф-ция

                      function restrict_admin()
                      {
                      	if ( ! current_user_can( 'manage_options' ) && '/wp-admin/admin-ajax.php' != $_SERVER['PHP_SELF'] ) {
                                      wp_redirect( site_url() );
                      	}
                      }
                      add_action( 'admin_init', 'restrict_admin', 1 );

                      А теперь вопрос к Вам Миша, есть ли аналог этой функции но чтобы не блочил ajax? Спасибо!

                    • Миша:

                      Есть условие проверки, что выполняется AJAX:

                      if( defined( 'DOING_AJAX' ) && DOING_AJAX )
  • Александр:

    Добры день, Коллеги, кто может дать совет как в подгрузке постов задать разные шаблоны использования. Я хочу реализовать подкрузку постов на разных страницах. На каждой странице разный шаблон отображения. как можно задать условие, что бы автоматически подгружались шаблоны нужной страницы. Не преписывать же все скрипты отдельно для каждой страницы?

  • Олег:

    Уважаемый люди, помогите реализовать, не получается у меня почему-то,
    Запутался во всем уже, смотрите первое что я сделал это установил кнопку в место где мне это необходимо в моем случае это index.php следующее добавил стили но это мелочи по сути это я понял, вот дальше functions.php вставил данный код, потом создал файл loadmore.js закинул туда код и залил в папку с темой, вот тут с Обработчик PHP я чет не очень понял как его и куда конкретно вставлять вставил в в самый верх, и все ровно кнопка бездействует ( вот я еще не совсем понял какую конкретно часть кода надо вставить в admin-ajax.php так как он подключен к функционалу кнопки. помогите пожалуйста реализовать, голова уже дымится не знаю что уже делать.

  • Сергей:

    Здравствуйте, Михаил!
    Только начинаю использовать WordPress и не могу "заставить" работать AJAX.
    Взял пример из Вашей статьи для решения своей задачи.

    У меня задача - разработать страницу соревнований. У каждого соревнования несколько вкладок с информацией. Мне бы хотелось, чтобы информация из каждой вкладки погружалась с помощью AJAX по клику на нее.

    Как я понял реализация этой идеи должна происходить таким образом:

    1. Создаю функцию в файле functions.php, которая будет возвращать мне данные о соревновании, предположим, что это будет контент поста;

    <?php function my_function(){?>
                <p>Контент: <?php the_content(); ?></p>
      <?php die();
    }
    add_action('wp_ajax_myaction', 'my_function'); 
    add_action('wp_ajax_nopriv_myaction', 'my_function'); 
    ?>

    2. Создаю скрипт который при нажатии на кнопку с классом .btn делает запрос на обработку и возвращает ответ в результате работы функции, прикрепленной на хук myaction в контейнер c id #container.

    jQuery(function($){
        $('.btn').click(function(){
          $.ajax({
            type:'POST',
            url:'<?php echo site_url() ?>/wp-admin/admin-ajax.php', // обработчик
            data:{ action: 'myaction'}, 
            success:function(response){
                $('#container').html(response);
            }
          });
        });
      });

    3. Как я понял - все должно выглядеть примерно так, но при нажатии на кнопку .btn я получаю только текст: "Контент:" .

    При этом цикл вывода статьи уже заранее помещен на страницу соревнования и если я вызываю эту же функцию с помощью

    <?php if(function_exists('my_function')) {
              my_function();
          } ?>

    то содержимое поста выводится.
    Никак не пойму в чем ошибка. Уже несколько дней пытаюсь разобраться и без результатов. Буду рад Вашей помощи!

    • Миша:

      Здравствуйте!
      У вас всё правильно, за исключением одной мелочи — функция the_content() не получает значение ID/объекта поста.

      Я предлагаю в параметры AJAX-запроса добавить ID поста, а в самом обработчике также получить объект его при помощи get_post().

      Если непонятно объяснил, пожалуйста, переспрашивайте.

      • Сергей:

        Спасибо за ответ! Как только появилось время, стал разбираться:

        1. Переделал функцию так, чтобы она использовала id поста, передаваемого через JavaScript.

        <?php 
            function my_function(){
            $my_post = get_post($_REQUEST['postID']); ?> //передал значение id поста
         
           <h1>Заголовок:<?php echo $my_post->post_title; ?></h1> // Вывел заголовок поста
           <p>Контент поста:<?php echo $my_post->post_content; ?></p> //Вывел контент поста
         
           /* У меня получилось вывести стандартные данные поста. После этого у меня возникла новая задача - мне необходимо вывести содержимое кастомных полей, созданных с помощью плагина ACF... сначала немного запаниковал, но документация плагина в помощь и я с легкостью вывожу содержимое кастомного поля, добавляя в качестве второго аргумента id своего поста! (пример ниже); */
         
           <p>Содержимое кастомного поля: <?php the_field('custom_article_text_field',$_REQUEST['postID']); ?></p>
         
        <?php 
            die();
        }
        add_action('wp_ajax_myaction', 'my_function'); 
        add_action('wp_ajax_nopriv_myaction', 'my_function'); 
        ?>

        2. Немного переделал скрипт таким образом, чтобы он брал id выводимого поста и отправлял его с AJAX-запросом:

        jQuery(function($){
            $('.btn').click(function(){
              $.ajax({
                type:'POST',
                url:'<?php echo site_url() ?>/wp-admin/admin-ajax.php', // задаю путь к обработчику
                data:{ 
                  action: 'myaction', 
                 'postID': '<?php the_ID(); ?>'}, // прикрепляю к ключу 'postID' значение id текущего поста
                success:function(response) {
                    $('#container').html(response);
                }
              });
            });
          });

        И... все работает! Получилось достать все данные поста!

        Спасибо огромное за помощь! Даже не знаю, как долго я бы еще пытался найти решение своей задачи без Вашей помощи!

        P.S. Если, вдруг, есть какие-то ошибки, которые я допустил или советы по оптимизации, то буду рад услышать!

  • Egor:

    Функция с бесконечной прокруткой страницы перестала работать на wordpress 4.4

    Перестала работать на основном сайте после обновления. Я собрал заново все решение на тестовом сайте с wp 4.3 - все работает, обновляю сайт - ошибка.

    Ошибка - При бесконечной прокрутке посты начинают грузится сначала. Т.е., например, на странице есть посты с 100-ого по 90-ый. При прокрутке появляются опять опять те же посты с 100-ого по 90-ый, а не с 90-ого по 80-ый и т.д.

    Не знаете, как бы можно было исправить?

  • Иван:

    Вечер добрый! Все работает прекрасно, но столкнулся с одним моментом. На главной всё подгружается прекрасно, но когда выбираешь отдельную рубрику, подгружаемые посты игнорируют фильтрацию по рубрике, т.е. подгружается все подряд. Как это исправить? Т.е. чтобы на главной подгружались все посты, а в разных категориях только определенные.

  • Иван:
    <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>
  • Valeriy:

    Если у меня задается сортировка в цикле WP_Query, да еще не простая, а по значению произвольного поля.. подгружаемые посты уже получаются не отсортированные. Возможно что то придумать в таком случае ?

  • Дмитрий:

    добрый день, хочу спросить. А реально реализвать так, при кнопке далее, навые посты подгружаются за мест страрых. Чтобы посты не вниз уходили, а просто заменялись новыми, но асинхронно

  • Михаил:

    Доброй ночи, возникла задачи выводить контент динамически, нашел ваш пост, работает. У меня возник вопрос, можно ли как-то поставить проверку в php обработчике, имеется две рубрики которые выводятся на разные шаблоны и визуально у них разные стили, когда идет загрузка новостей в эти рубрики структура загрузившихся постов и стили одинаковые, возможно ли поставить проверку в обработчике в файле functions.php :

    <?php if ( in_category(array('6','4','5','7'))){}?>

    , что бы для разных рубрик была разная структура и соответсвенно стили, не понимаю как это сделать, возможно подтолкнете на мысль и поделитесь соображениями.

    • Миша:

      Здравствуйте!
      Вообще тут два варианта:

      1. Добавлять CSS-класс в виде ярлыка рубрики (так как рубрики разные, то и стилизовать можно по-разному будет). Чаще всего используется именно этот способ.
      2. Предложенная вами функция in_category(), только не забывайте про второй параметр, в данном случае я считаю он необходим.
  • Amira:

    Добрый вечер. Отличная статья, очень помогла, но у меня проблема, дублируются посты.

    Этот код в index.php

                    <div class="row">
                      <?php query_posts(array('orderby'=> 'rand','paged' => get_query_var('paged'))); ?>
                      <?php if (have_posts()) : while (have_posts()) : the_post(); ?> 
                      <div id="block-<?php echo $post->ID ?>" class="col-md-3 sell-<?php echo $post->ID ?>">
                            <a href="<?php the_permalink(); ?>" class="href">
                            <div class="sell">
                            <?php $sale = get_post_meta($post->ID, 'sale_number', true); if ($sale) { ?>
                                <div class="discount ic"><span class="num">-<?php the_field('sale_number'); ?>%</span></div>
                                <div class="discount ln s"><img src="http://skidka.kg/assets/css/images/skidka.png" alt="" class="src"></div>
                            <?php } else { ?>
                                <div class="discount line"><span class="num"><?php the_field('price_number'); ?></span></div>
                                <div class="discount ln s"><img src="http://skidka.kg/assets/css/images/ac.png" alt="" class="src"></div><?php } ?>
                                <div class="thumb">
                                    <img src="<?php the_field('slide_1'); ?>"  title="<?php the_title(); ?> изображение" alt="<?php the_title(); ?> в Бишкеке" class="src sale">
                                    <?php $sale = get_post_meta($post->ID, 'sale_number', true); if ($sale) { ?>
                                        <?php $price = get_post_meta($post->ID, 'price_old', true); if ($price) { ?>
                                        <div class="price"><span class="old"><?php the_field('price_old'); ?></span> - <span class="new"><?php the_field('price_new'); ?></span></div>
                                        <?php } else { ?><?php } ?>
                                    <?php } else { ?><?php } ?>
                                </div>
                                <h5><?php the_title(); ?></h5>
                            </div>
                            </a>
                        </div>
                        <?php endwhile; endif; ?>
                        <?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="load">Загрузить ещё</div>
    <?php endif; ?>
                    </div>
  • Amira:

    Это из function.php

    <?php
    function true_load_posts(){
    	$args = unserialize(stripslashes($_POST['query']));
    	$args['paged'] = $_POST['page'] + 1; // следующая страница
    	$args['post_status'] = 'publish';
    	$q = new WP_Query($args);
    	if( $q->have_posts() ):
    		while($q->have_posts()): $q->the_post();
    			/*
    			 * Со строчки 13 по 27 идет HTML шаблон поста, максимально приближенный к теме TwentyTen.
    			 * Для своей темы вы конечно же можете использовать другой код HTML.
    			 */
    			?>
    			<div id="block-<?php echo $q->post->ID ?>" class="col-md-3 sell-<?php echo $q->post->ID ?>">
                            <a href="<?php the_permalink(); ?>" class="href">
                            <div class="sell">
                            <?php $sale = get_post_meta($q->post->ID, 'sale_number', true); if ($sale) { ?>
                                <div class="discount ic"><span class="num">-<?php the_field('sale_number'); ?>%</span></div>
                                <div class="discount ln s"><img src="http://skidka.kg/assets/css/images/skidka.png" alt="" class="src"></div>
                            <?php } else { ?>
                                <div class="discount line"><span class="num"><?php the_field('price_number'); ?></span></div>
                                <div class="discount ln s"><img src="http://skidka.kg/assets/css/images/ac.png" alt="" class="src"></div><?php } ?>
                                <div class="thumb">
                                    <img src="<?php the_field('slide_1'); ?>"  title="<?php the_title(); ?> изображение" alt="<?php the_title(); ?> в Бишкеке" class="src sale">
                                    <?php $sale = get_post_meta($q->post->ID, 'sale_number', true); if ($sale) { ?>
                                        <?php $price = get_post_meta($q->post->ID, 'price_old', true); if ($price) { ?>
                                        <div class="price"><span class="old"><?php the_field('price_old'); ?></span> - <span class="new"><?php the_field('price_new'); ?></span></div>
                                        <?php } else { ?><?php } ?>
                                    <?php } else { ?><?php } ?>
                                </div>
                                <h5><?php the_title(); ?></h5>
                            </div>
                            </a>
                        </div>
    			<?php
    		endwhile;
    	endif;
    	wp_reset_postdata();
    	die();
    }
    add_action('wp_ajax_loadmore', 'true_load_posts');
    add_action('wp_ajax_nopriv_loadmore', 'true_load_posts');
    ?>
  • Amira:

    Это из браузера, всего около 29 постов есть, по умолчанию отображается 12 постов.

    <div id="block-88" class="col-md-3 sell-88">Контент вырезан</div>
    <div id="block-479" class="col-md-3 sell-479">Контент вырезан</div>
    <div id="block-69" class="col-md-3 sell-69">Контент вырезан</div>
    <div id="block-341" class="col-md-3 sell-341">Контент вырезан</div>
    <div id="block-302" class="col-md-3 sell-302">Контент вырезан</div>
    <div id="block-318" class="col-md-3 sell-318">Контент вырезан</div>
    <div id="block-327" class="col-md-3 sell-327">Контент вырезан</div>
    <div id="block-258" class="col-md-3 sell-258">Контент вырезан</div>
    <div id="block-167" class="col-md-3 sell-167">Контент вырезан</div>
    <div id="block-35" class="col-md-3 sell-35">Контент вырезан</div>
    <div id="block-334" class="col-md-3 sell-334">Контент вырезан</div>
    <div id="block-406" class="col-md-3 sell-406">Контент вырезан</div>
    <script>Тут ваш сприпт</script>
    <div id="block-35" class="col-md-3 sell-35">Контент вырезан</div>
    <div id="block-206" class="col-md-3 sell-206">Контент вырезан</div>
    <div id="block-479" class="col-md-3 sell-479">Контент вырезан</div>
    <div id="block-143" class="col-md-3 sell-143">Контент вырезан</div>
    <div id="block-69" class="col-md-3 sell-69">Контент вырезан</div>
    <div id="block-189" class="col-md-3 sell-189">Контент вырезан</div>
    <div id="block-88" class="col-md-3 sell-88">Контент вырезан</div>
    <div id="block-293" class="col-md-3 sell-293">Контент вырезан</div>
    <div id="block-167" class="col-md-3 sell-167">Контент вырезан</div>
    <div id="block-318" class="col-md-3 sell-318">Контент вырезан</div>
    <div id="block-51" class="col-md-3 sell-51">Контент вырезан</div>
    <div id="block-235" class="col-md-3 sell-235">Контент вырезан</div>
    <div id="block-88" class="col-md-3 sell-88">Контент вырезан</div>
    <div id="block-258" class="col-md-3 sell-258">Контент вырезан</div>
    <div id="block-302" class="col-md-3 sell-302">Контент вырезан</div>
    <div id="block-35" class="col-md-3 sell-35">Контент вырезан</div>
    <div id="block-341" class="col-md-3 sell-341">Контент вырезан</div>

    Помогите пожалуйста чтобы посты не дублировались.

  • Amira:

    К примеру в коде выше пост под ID 35; вывелся 3 раза.. И так не только данный пост.

    <div id="block-35" class="col-md-3 sell-35">Контент вырезан</div>
  • Олександр:

    Огромное спасибо прекрасный материал!

  • Александр:

    Добрый день Михаил!
    Очень помогла ваша статья !
    Но есть проблема ... не могу доделать что бы подгруженный контент отображался нормально. Помогите
    http://delaem-podarki.ru/portfolio/

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

    $args = array( 'post_type' => 'portfolio', 'posts_per_page' => -1, 'orderby' => 'menu_order', 'order' => 'ASC' );
  • Слава:

    Миша, спасибо! Слов нет!
    Изначально что-то ни понял ничего, как оказалось просто ленился прочитать по человечески.
    Пошел в google искать способ ctrl + c ctrl + v В итоге нашел боль головную и всякие не рабочие плагины (Infinite Scroll)
    Вернулся, прочитал, все сделал, все работает - благодарю тебя. Добра тебе и твоему дому!!!!

  • Виталий:

    Миша, добрый день!
    У меня проблема с этой функцией, есть плагин Advanced Post Types Order, с помощью которого я фиксирую, например, 10 постов в верхней части категории. Но функция true_load_posts этого не учитывает и выводит повторно эти посты на второй странице, а некоторые посты, получается, вообще не выводятся в разделе. Можно здесь посмотреть http://mos-holidays.ru/ekskursii-po-moskve/ Т.е. получается так, что true_load_posts работает с лентой постов, которая должна быть по-умолчанию и часть постов, которые должны быть на первой странице вообще не выводятся, т.к. вместо них на первой странице те, которые зафиксированы плагином Advanced Post Types Order.
    Например, вот эту экскурсию в разделе вообще не получится найти http://mos-holidays.ru/peshexodnaya-ekskursiya-eta-xitraya-xitrovka-ot-kompanii-shag-za-shagom/ , а эта http://mos-holidays.ru/avtobusnaya-ekskursiya-legendy-i-mify-stalinskix-vysotok/ дублируется.
    Можно как-то доработать функцию true_load_posts, чтобы она в моем случае работала корректно ?

  • Виталий:

    Пока сделал там обычную пагинацию(

  • Иван:

    Михаил, подскажите пожалуйста мне нужно выводить после нажатия кнопки другое количество постов (установлено в настройках - 10) как прописать в обработчике нужный параметр, чтоб выводил например фиксированно только 2 поста?
    То есть после загрузки страницы выводится 10 постов, нажимаю на кнопку - еще два поста подгружается - вот так мне надо, спасибо!

  • Евгений Кириллов:

    Очень добрый день.
    Сделал подгрузку через кнопку со стилями.

    Данные передаю через

    data-true-posts='<?php echo serialize($query->query_vars); ?>'

    Возвращаю

    $args = unserialize(stripslashes($_POST['query']));

    Но у меня в цикле массив рубрик, которые надо вывести

    $args = array( 
    							'post_type' => 'post',
    							'publish' => true,
    							'posts_per_page' => 4,
    							'category__in' => array(173,154,124,189,44,49,47,84,8,50,7,10,203,5,14,52,164,9,24,26,188,162,132,6)
    						);
    						$query = new WP_Query( $args );

    А подгружает только посты из первой рубрике в массиве.
    Как вывести посты со всех рубрик, указанных в массиве?

  • Евгений Кириллов:

    Проверил.
    В обработчике php...

    function true_load_posts(){
    	$templ = $_POST['template'];
    	$args = unserialize(stripslashes($_POST['query']));
    	$args['paged'] = $_POST['page'] + 1; // следующая страница
    	$args['post_status'] = 'publish';
    	$args['posts_per_page'] = $_POST['ppp'];
     
    	foreach ($args['category__in'] as $value) {
    		echo $value.'<br>';
    	}
     
    	/* Здесь все ок. Выводится весь массив категорий */
     
    	$q = new WP_Query($args);
    	if( $q->have_posts() ):
    		while($q->have_posts()): $q->the_post();
     
    			foreach( get_the_category() as $category ){ 
    				echo $category->cat_ID;
    			}
    			/* А вот здесь уже только первая категория осталась */
     
    ...
  • Valeriy:

    Здравствуйте, подскажите как в дополнение к постраничной подгрузке, сделать дополнительную кнопку "Показать все". Что бы по нажатию на нее подгружались все страницы за один раз, возможно с небольшой задержкой, дабы уменьшить нагрузку...

    • Миша:

      Здравствуйте!

      То есть давайте предположим, что в данный момент мы подгрузили две страницы (на каждой странице по умолчанию - 10 постов) и находимся на третьей, и теперь хотим нажать кнопку "Показать всё".

      Алгоритм:

      1. Прежде всего для обработки я рекомендую использовать отдельную PHP функцию.
      2. Добавьте кнопку показа всего, привяжите её к функции, потестируйте что всё работает и тестовое сообщение (любое, например "привет") выводится.
      3. После этого вам нужно на стороне jQuery определить количество подгруженных постов, их можно вычислить непосредственно во время подгрузки постов, то есть выделить на них отдельную переменную, но также при нажатии на кнопку показа всех постов вы можете и определять их моментально, зная лишь CSS-класс блока поста.
        $('.entry-post').length;
      4. Со стороны PHP всё, что вам требуется, это передать в WP_Query два основных параметра — posts_per_page и offset следующим образом:
        $args = array(
        	'posts_per_page' => -1, // все посты
        	'offset' => $_POST['offset'] // начать с n-ного поста, в нашем случае с 31
        );
  • Леонид:

    За статью Вам спасибо. Но меня приучали к тому что JS-код не должен находиться в файлах шаблонов, и поэтому предлагаю поправить:

    <?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; ?>

    на

    <?php if( $wp_query->max_num_pages > 1 ): ?>					
    	<a href="#" class="show-more-articles">Загрузить еще</a>
    <?php endif; ?>

    а переменные передавать с функцией wp_localize_script:

    wp_localize_script('ajax-load-articles', 'Object', [
    																'url' => get_site_url().'/wp-admin/admin-ajax.php',
    																'true_posts' => serialize($wp_query->query_vars),
    																'current_page' => (get_query_var('paged')) ? get_query_var('paged') : 1,
    																'max_pages' => $wp_query->max_num_pages,
    			]);

    В обработчике ajax соответственно имена переменных изменятся так true_posts - Object.true_posts и т.д.

  • Леонид:

    Только в функцию подключающую скрипты нужно будет передать из глобальной области видимости объект $wp_query, и забыл поправить первый параметр функции wp_localize_script под Ваш пример.

    • Миша:

      Леонид, спасибо большое за полезное дополнение к статье!

      Я в первую очередь делал упор на то, чтобы сделать код в статье максимально доступным для максимального числа пользователей 🙂 В том числе я не стал усложнять код функцией wp_localize_script() — у некоторых с ней возникают трудности.

      • Леонид:

        Понимаю) У меня она тоже вызывает взрыв мозга, но по сути она незатейливая - первым параметром просто пишется имя скрипта, перед которым будут вставляться переменные, а дальше просто описываются эти данные.

  • Леонид:

    Столкнулся с такой проблемой - у меня выводятся записи на двух страницах - новости и блог, соответственно в каждом из шаблонов передается в запрос параметр для фильтрации категорий - как мне передать этот параметр в данную функцию подгрузки контента, чтобы при расчете параметра max_pages подставлялись верные данные (Кнопка "Показать еще" показывается пока цикл не пройдет по всем постам)?

  • Иван:

    Приветствую!
    Спасибо за код, все работает, стандартные посты выводит.
    Есть еще на сайте кастомные записи, у которых отличается внешний вид превью поста.
    Получается надо в function.php дублировать код и менять переменные? Или возможно там прописать условие типа если пост типа post то выводить так, а если кастомный то так?

    • Миша:

      Добрый день, Иван,

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

      После того, как вы это определите, в любом случае вам понадобится использовать переменную $q->post->post_type в functions.php внутри цикла.

  • Иван:

    Попробовал сделать вот так и не выводит по нажатию на кнопку.
    Сам цикл кастомных записей вывожу вот так:

       <?php
    	$args = array (
    	'post_type' => 'present',
    	'posts_per_page' => 6,
    	'orderby' => 'date',
    	'paged'=>get_query_var('paged')
    	 );
     
    	$present = new WP_Query($args); ?>
     
    	<?php while ( $present->have_posts() ) : $present->the_post(); ?>
     
    	HTML код вывода превью кастомных постов
     
    	<?php endwhile; ?>
     
    	<?php wp_reset_postdata(); ?>
     
        <?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>
     
        <?php endif; ?>
     
        <div id="true_loadmore" class="all_news shad">Загрузить ещё презентации</div>

    Вот так в function.php добавил условие elseif после вывода стандартных:

     
    function true_load_posts(){
    	$args = unserialize(stripslashes($_POST['query']));
    	$args['paged'] = $_POST['page'] + 1; // следующая страница
    	$args['post_status'] = 'publish';
    	$q = new WP_Query($args);
    	if( $q->have_posts() ):
    		while($q->have_posts()): $q->the_post(); 	?>
     
    HTML код вывода стандартных постов
     
    	<?php endwhile;
     
          elseif ( $present->have_posts() ):
          while($present->have_posts()): $present->the_post(); ?>
     
    HTML код вывода кастомных постов
     
     <?php endwhile;
    endif;
     
    	wp_reset_postdata();
    	die();
    }
     
    add_action('wp_ajax_loadmore', 'true_load_posts');
    add_action('wp_ajax_nopriv_loadmore', 'true_load_posts');
  • Иван:

    Спасибо! Вот так работает)
    $present я убрал вообще, вывожу стандартным циклом
    просто создал страницу archive-{post-type-name}.php

  • Александр:

    Привет)

    Мегашикарный пост, но я словил баг там, где количество постов меньше указанного в админке - http://test.yarovikov.ru/category/svadba/

    Can't find variable: true_posts

    Вывожу цикл так:

    $loop = new WP_Query( array( 
       'orderby' => 'menu_order',
       'order' => 'DESC',
       'cat' => get_query_var('cat')  
       ));
  • Иван:

    А кстати, как убрать кнопку "Загрузить еще", если пока выводится меньшее кол-во, чем указано в админке?

    К примеру стоит на вывод 6 записей, опубликовано пока 3, а кнопка "Загрузить еще" стоит и смущает)

    Т.е. по идее надо кнопку убирать если выведено меньшее или равное кол-во записей указанных в админке.

Оставить комментарий / вопрос

phpjsHTMLCSSSQLПросто код
  Комментарии закрыты.