Загрузить больше постов в WordPress без перезагрузки страницы

Загрузка постов с помощью ajax – очень популярная задача для современного веб-сайта. Для этого конечно можно использовать плагины, конструкторы страниц или использовать темы, имеющие встроенный функционал загрузки постов. Но, на самом деле, совсем не сложно написать собственный код для загрузки постов ajax. Итак, давайте покажу как это делаю я.

Запрос WordPress для загрузки постов из (пользовательского) типа записи

Давайте начнем с основного запроса для получения наших постов. Запрос отобразит первые 6 сообщений из нашего кастомного post type ‘publications’. Как вы можете видеть, я также добавил параметр ‘paged’, и жестко задал ему значение 1. Это нужно для того чтобы при загрузке страницы получить посты только с первой страницы пагинации. Самой пагинации не будет, но мы будем подгружать каждый раз посты из следующей страницы пагинации при помощи javascript.

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

<?php 
$publications = new WP_Query([
  'post_type' => 'publications',
  'posts_per_page' => 6,
  'orderby' => 'date',
  'order' => 'DESC',
  'paged' => 1,
]);
?>

<?php if($publications->have_posts()): ?>
  <ul class="publication-list">
    <?php 
      while ($publications->have_posts()): $publications->the_post();
        get_template_part('parts/card', 'publication');
      endwhile;
    ?>
  </ul>
<?php endif; ?>
<?php wp_reset_postdata(); ?>

<div class="btn__wrapper">
  <a href="#!" class="btn btn__primary" id="load-more">Load more</a>
</div>
Code language: PHP (php)

Приведенный выше код можно разделить на 3 основных раздела. Первый – это запрос на фактическое получение первых 6 постов из ‘publications’. Вторая часть – это наш цикл по результатам запроса $publications. Не забудьте в конце вызвать функцию wp_reset_postdata(), чтобы убедиться, что остальная часть нашей страницы продолжает работать правильно. Наконец, мы также добавляем кнопку “загрузить больше” под нашим списком, чтобы иметь возможность загружать больше сообщений.

Теперь, когда наша базовая настройка готова, пришло время связать некоторые javascript и Ajax с этой кнопкой загрузки!

Ajax функция загрузки постов

Теперь пришло время добавить событие клика по нашей кнопке “загрузить еще”. В этом руководстве я буду использовать jQuery, поскольку он используется по умолчанию с WordPress.

Нам нужно добавить javascript в котором мы будем отслеживать событие клика по кнопке. Сделать это можно либо прямо в вашем шаблоне либо в отдельном файле JS, сам скрипт выглядит так:

$('#load-more').on('click', function() {
  // Вся магия будет происходить тут
}
Code language: JavaScript (javascript)

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

Преимущество использования Ajax для загрузки дополнительных постов заключается в том, что все будет происходить без перезагрузки страницы. Поэтому мы можем запоминать некоторые данные в обычном javascript, без необходимости хранить их в localStorage или использовать какой-либо $store, как в React или Vue. Отлично подойдет простая javascript-переменная.

Давайте отредактируем наш фрагмент javascript кода добавив в него новую переменную, которая позволит нам отслеживать текущую страницу, а также добавим $ajax вызов в нашу ajax функцию, которую мы напишем чуть позже.

let currentPage = 1;
$('#load-more').on('click', function() {
  currentPage++; // поскольку мы хотим именно загрузить следующую страницу

  $.ajax({
    type: 'POST',
    url: '/wp-admin/admin-ajax.php',
    dataType: 'html',
    data: {
      action: 'weichie_load_more',
      paged: currentPage,
    },
    success: function (res) {
      $('.publication-list').append(res);
    }
  });
});
Code language: JavaScript (javascript)

Не торопитесь использовать этот код, он еще не закончен. Если вы внимательны, то наверняка заметили, что в 10 строке мы вызываем функцию WordPress, которую мы еще не написали! Итак, прежде чем тестировать или жаловаться, что все не работает, давайте сначала напишем ее.

Конечно, чтобы убедиться, что мы движемся в правильном направлении можно и протестировать. Когда вы нажмете кнопку “загрузить еще”, визуально на странице ничего не произойдет. Но если вы откроете инструменты разработки в браузере и перейдете на вкладку “Сеть”, то там вы сможете увидеть, что мы отправили ajax-запрос на admin-ajax.php.

Загрузить больше постов в WordPress без перезагрузки страницы

Этот запрос к admin-ajax.php появится только тогда, когда вы нажимаете на кнопку. Повторный клик по кнопке повторит запрос (и тогда в пункте payload должно быть ‘paged: 3’). Мы можем увидеть два параметра в нашем payload: “action” и “paged’. Эти параметры мы и передали в нашем вызове javascript $ajax в разделе data {}. Сейчас запрос должен вернуть нам ошибку, так как не может найти функцию ‘weichie_load_more’.

Payload (Полезная нагрузка) – это то, что мы отправляем с нашего интерфейса на наш сервер. Благодаря payload у нас есть доступ к странице, которую мы хотим загрузить в нашей PHP функции, в которой мы будем выполнять запрос. Итак, следующий шаг: создадим функцию weichie_load_more, которая фактически загрузит для нас больше постов.

Загрузка больше постов с помощью WordPress

В файл functions.php, который находится в корне нашей темы, добавим этот сниппет

function weichie_load_more() {
  $ajaxposts = new WP_Query([
    'post_type' => 'publications',
    'posts_per_page' => 6,
    'orderby' => 'date',
    'order' => 'DESC',
    'paged' => $_POST['paged'],
  ]);

  $response = '';

  if($ajaxposts->have_posts()) {
    while($ajaxposts->have_posts()) : $ajaxposts->the_post();
      $response .= get_template_part('parts/card', 'publication');
    endwhile;
  } else {
    $response = '';
  }

  echo $response;
  exit;
}
add_action('wp_ajax_weichie_load_more', 'weichie_load_more');
add_action('wp_ajax_nopriv_weichie_load_more', 'weichie_load_more');
Code language: PHP (php)

Как вы можете видеть, наша часть запроса на самом деле представляет собой то же самое, что и в шаблоне страницы. Мы выполняем точно такой же запрос, но единственное отличие здесь в том, что мы извлекаем paged: 2 (или 3, или 4) вместо первой страницы.

$ajaxposts это запрос к WordPress, который мы будем повторять (точно так же, как мы делаем в нашем шаблоне страницы). Мы также объявляем переменную $response, которая будет хранить наши результаты. Затем мы перебираем посты ajax и на каждой итерации добавляем template_part к ответу, используя выражение .= . И, наконец, мы повторяем наш $response, и это то, что мы отправим обратно в наш javascript.

Все дело в пагинации. Мы не хотим извлекать одни и те же посты при нажатии на кнопку “загрузить больше”, мы хотим получить такое же количество постов, но со следующей страницы. Теперь, когда у нас есть эта функция, мы можем проверить, по-прежнему ли нажатие на кнопку возвращает ошибку или нет. Мы ожидаем, что сервер ответит HTML-блоками из 6 постов начиная со страницы 2. Вы можете проверить это снова на вкладке “сеть”, но вместо перехода к Payload (то, что мы отправляем на серверную часть) мы можем проверить в разделе Response (то, что серверная часть отправляет обратно на интерфейс)

Загрузить больше постов в WordPress без перезагрузки страницы

Круто, теперь пришло время разместить на вебсайте эту HTML разметку полученную в ответ на запрос. “Response”, который мы видим на нашей вкладке сети, автоматически возвращается к нашему запросу $ajax.

Давайте еще раз взглянем на наш код JS, заметьте, что у нас уже есть функция success в вызове ajax:

// Все без изменений. Это только для того чтобы было понятно о чем я говорю.
$.ajax({
  ...
  dataType: 'html',
  ...
  success: function (res) {
    $('.publication-list').append(res);
  }
});
Code language: JavaScript (javascript)

Функция success принимает параметр ‘res’, который содержит наш ajax-ответ. Поскольку мы передали dataType с параметром “html”, то это значит, что мы ожидаем HTML для ответа. Далее мы просто аппендим этот HTML в блок с классом ‘.publication-list’.

Отладка: Если этот код у вас не работает, то возможно понадобится его как-то отладить. Попробуйте зарегистрировать свой res в консоли и проверьте какой тип данных возвращается. Самым подходящим местом для этого будет success: function() { … } – внутри этой функции мы можем написать например console.log(res).

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

Теперь, когда наш код работает, вы, вероятно, вскоре обнаружите другую проблему – что, если больше нет сообщений? Пример: У нас есть 4 страницы, и мы достигли страницы 4, затем нажатие на кнопку “загрузить еще” загрузит страницу 5 -> которая пуста. Логично что нам нужно как-то скрыть кнопку “Загрузить еще” когда мы дойдем до последней страницы, например добавить класс, который сделает кнопку невидимой.

Итак давайте приступим. Нам понадобится немного изменить наш Ajax запрос. Раньше в response мы получали сразу только HTML разметку, но теперь мы изменим тип данных в ответе на JSON. Это позволит в ответ поместить как наш HTML-ответ, так и max_pages. Это нужно, чтобы проверить, больше ли ваш текущий индекс страницы или равен max_pages. Если больше, то это значит, что мы достигли максимального количества страниц, и можем скрыть кнопку.

Итак для начала, давайте обновим наш Ajax-запрос, чтобы он работал с JSON вместо HTML. Пожалуйста, обратите внимание, что внесение этого изменения приведет к нарушению работы всего на данный момент, но мы исправим это в ближайшее время!

В вашем JS-файле измените запрос ajax на следующий:

$.ajax({
  type: 'POST',
  url: '/wp-admin/admin-ajax.php',
  dataType: 'json', // <-- Изменим тип данных с 'html' на 'json'
  data: {
    action: 'weichie_load_more',
    paged,
  },
  success: function (res) {
    $('.publication-list').append(res);
  }
});
Code language: JavaScript (javascript)

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

function weichie_load_more() {
  $ajaxposts = new WP_Query([
    'post_type' => 'publications',
    'posts_per_page' => 6,
    'orderby' => 'date',
    'order' => 'DESC',
    'paged' => $_POST['paged'],
  ]);

  $response = '';
  $max_pages = $ajaxposts->max_num_pages;

  if($ajaxposts->have_posts()) {
    ob_start();
    while($ajaxposts->have_posts()) : $ajaxposts->the_post();
        $response .= get_template_part('parts/card', 'publication');
    endwhile;
    $output = ob_get_contents();
    ob_end_clean();
  } else {
    $response = '';
  }

  $result = [
    'max' => $max_pages,
    'html' => $output,
  ];

  echo json_encode($result);
  exit;
}
add_action('wp_ajax_weichie_load_more', 'weichie_load_more');
add_action('wp_ajax_nopriv_weichie_load_more', 'weichie_load_more');
Code language: PHP (php)

Давайте рассмотрим более подробно что мы изменили. Во-первых сам запрос остается нетронутым. У нас также все еще есть наша пустая строка $response = “”; . Затем с помощью стандартных средств WordPressа ($max_pages = $ajaxposts->max_num_pages;) мы получаем максимальное количество возможных страниц и передаем его. Таким образом, наша кнопка “загрузить больше” может максимально загрузить “max_num_pages” – количество страниц.

Во-вторых, когда мы перебираем наш запрос и добавляем каждое найденное сообщение в строку $results, мы фактически помещаем его в буфер PHP, называемый output buffer. Пока буферизация выходных данных активна, выходные данные из скрипта не отправляются, а вместо этого сохраняются во внутреннем буфере. Прежде чем мы завершим output buffer, сохраним результат в другой переменной с именем $output.

И наконец, в третьих, перед тем, как мы вернем наши результаты обратно в файл javascript, мы создаем возвращаемый массив таким образом:

// Ничего нового, просто указываю на кусок из вышеприведенного кода
$result = [
  'max' => $max_pages,
  'html' => $output,
];
echo json_encode($result);
Code language: PHP (php)

Здесь мы создаем массив, который принимает значение $max_pages, чтобы вернуть максимальное количество страниц для этого запроса, и наш HTML. Затем мы кодируем массив обратно в json и возвращаем.

Наконец, чтобы работать с нашим новым выводом, нужно немного донастроить наш javascript. Поскольку в качестве ответа мы получаем теперь не HTML, а JSON, то нам нужно перейти на один уровень глубже при печати ответа на страницу. Измените свою функцию success на следующую:

$.ajax({
  ...
  success: function (res) {
    if(paged >= res.max) {
      $('#load-more').hide();
    }
    $('.publication-list').append(res.html);
  }
});
Code language: JavaScript (javascript)

Наш ‘res’ из function(res) теперь будет содержать объект json с 2 парами ключ-значений. Ключ ‘max’ – содержит наши max_num_pages, а ключ ‘html’ – содержит HTML.

Чтобы снова отобразить наш HTML-список на странице, теперь нужно будет использовать res.html . Мы также проверяем, если страницы > = res.max, чтобы увидеть, нужно ли нам скрывать нашу кнопку, или мы еще не достигли максимального количества страниц.

Использование WordPress pagination вместе с Offset (смещением)

в документации сказано:

Paged нельзя использовать совместно с параметром offset, потому что offset более приоритетный и заменит этот параметр.

Как быть если мне нужно скажем сначала показать 3 поста, а затем подгружать по 6? Та еще задачка, но вот вам рабочий вариант. Нам нужно как-то пропустить 3 самых последних поста и уже после этого делать разбивку на страницы по 6 постов.

$recent_publications = new WP_Query([
  'post_type' => 'publications',
  'posts_per_page' => 3,
  'orderby' => 'date',
  'order' => 'DESC',
  'fields' => 'ids',
]);

$ajaxposts = new WP_Query([
  'post_type' => 'publications',
  'posts_per_page' => 6,
  'orderby' => 'date',
  'order' => 'DESC',
  'paged' => $_POST['paged'],
  'post__not_in' => $recent_publications->get_posts()
]);Code language: JavaScript (javascript)

Сначала я создаю запрос, который извлекает самые последние 3 поста. После этого я создаю наш фактический запрос WP и вместо использования смещения исключаю записи из нашего первого запроса. Другими словами: пропустите самые последние 3 сообщения в запросе, где мы хотим использовать разбивку на страницы. Это то же самое, что и смещение, но с дополнительными шагами.

Если вы нашли более простое решение для разбиения на страницы со смещением, пожалуйста, оставьте свое решение в комментариях!

Вывод

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

Like this post? Please share to your friends:
Leave a Reply

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: