Есть много способов разбить ваши архивы WordPress на страницы. Функция paginate_links() является одной из них. Он вернет ссылки на номера страниц для ваших архивов. Однако эта разбивка на страницы будет отображать сообщения на отдельных страницах, таких как 1, 2, 3 и т. д. Но есть способ загрузить больше сообщений в ваш архив, не обновляя всю страницу. Мы изучим наиболее эффективный способ сделать это с помощью простого API-интерфейса JavaScript. В этом руководстве рассматривается весь процесс использования API выборки без какой-либо зависимости от jQuery.

Начните с цикла WordPress

Самая основная настройка файла index.php или archive.php в WordPress очень проста. Основной цикл while() будет извлекать самые последние сообщения в хронологическом формате. Вот пример кода, который мы будем использовать в наших архивах и индексной странице.

<?php 
get_header();
if (have_posts()) :
	global $wp_query;
?>
<div class="posts-wrapper">
	<?php while (have_posts()) : the_post(); ?>
	<article <?php post_class(); ?>>
	<?php 
		the_post_thumbnail('medium');
		the_title('<h2>','</h2>');
		the_excerpt();
	?>
	</article>
	<?php endwhile; ?>
</div>
<?php
//default WordPress pagination links
echo paginate_links();
//load more button for JS fetch API
printf(
	'<div class="load-more" data-totalpages="%s"><button id="load_more_posts">%s</button></div>',
	esc_attr( $wp_query->max_num_pages ),
	esc_html__('Load More','text-doamin')
);
endif;
get_sidebar();
get_footer(); 
?>

Это базовый цикл WordPress. Но я должен указать на пару вещей, на которые мы будем ориентироваться при написании кода на JavaScript. Div с классом .posts-wrapper является нашим целевым контейнером, а article.post — нашим индивидуальным контейнером сообщений.

Кнопка "Загрузить больше"

В приведенном выше коде мы добавили кнопку для события «Загрузить больше». Если вы заметили, мы передали общее количество доступных страниц в HTML-атрибут data-totalpages, который позже будет использоваться в нашем JS. Это все, что касается первоначальной настройки файлов index.php и archive.php. Это покажет сообщения на основе настроек чтения для количества сообщений на странице.

Создайте и поставьте в очередь файл JS

Теперь мы создадим новый файл JS в папке нашей темы. Откройте текстовый редактор, добавьте новый файл и сохраните его как fetch-posts.js в папке JS, например:

theme's root folder
    -- js (folder)
        -- fetch-posts.js (file)

Мы поставим в очередь файл JS из function.php нашей темы. Пожалуйста, используйте код ниже -

function enqueue_scripts(){
	//enqueue the fetch-posts js for archives and home only
	if( is_archive() || is_home() ){
		wp_enqueue_script('fetch-posts', get_theme_file_uri('/js/fetch-posts.js'), NULL, '', true );
	}
}
add_action( 'wp_enqueue_scripts', 'enqueue_scripts', 10 );

Итак, мы настроили все для JS. Прежде чем перейти к коду JS, давайте проверим пару вещей:

  1. Убедитесь, что у вас есть нумерация страниц, проверив общее количество сообщений и сообщений на странице в настройках чтения.
  2. Если доступно разбиение на страницы, вы можете увидеть ссылки на страницы прямо над кнопкой «Загрузить еще».

Вы можете проверить, правильно ли работает пагинация. Однако, если у вас хорошие настройки постоянной ссылки, вы можете проверить нумерацию страниц, добавив ?paged=2 в конец URL-адреса страницы в адресной строке. Если у вас есть простые настройки постоянной ссылки, вы можете проверить это, добавив &paged=2 в конец URL-адреса страницы.

API выборки

Fetch API предоставляет интерфейс для получения ресурсов (в том числе по сети). Он покажется знакомым любому, кто использовал XMLHttpRequest, но новый API предоставляет более мощный и гибкий набор функций.

Концепции и использование API выборки JavaScript

Fetch предоставляет общее определение объектов Request и Response (и других вещей, связанных с сетевыми запросами). Метод fetch() принимает один обязательный аргумент — путь к ресурсу, который вы хотите получить. Он возвращает Promise, который разрешается в Response для этого запроса, независимо от того, успешен он или нет. После извлечения Response существует ряд доступных методов для определения того, что представляет собой содержимое тела и как с ним следует обращаться.

Базовый запрос на выборку очень прост в настройке. Взгляните на следующий код:

fetch('http://example.com/movies.json')
  .then(response => response.json())
  .then(data => console.log(data));

Возможно, вам будет интересно узнать больше о методе fetch() и его использовании здесь — Использование Fetch. Это очень простой и мощный метод для получения данных JSON или любых текстовых данных с заданного URL-адреса. Наш URL-адрес страницы будет предоставлять нам HTML. Поэтому нам нужно преобразовать его в строку с помощью метода text() вместо метода json(). Позже мы преобразуем это в узлы HTML, используя DOMParser(), и извлечем из него наши данные записи.

В этом процессе мы будем использовать ключевые слова async и await, а затем fetch(). Как код ниже -

async function x(){
    let data = await ( await fetch( Url ).catch( errorHandle ) ).text()
    console.log(data)
}
function errorHandle(err){
    console.log(err)
}

Асинхронная функция — это функция, объявленная с ключевым словом async. Асинхронные функции являются экземплярами конструктора AsyncFunction, и в них разрешено ключевое слово await. Ключевые слова async и await позволяют писать асинхронное поведение на основе промисов в более чистом стиле, избегая необходимости явно настраивать цепочки промисов. Вы можете найти подробнее об асинхронности здесь.

Наш фрагмент кода

Теперь, когда у нас есть общее представление об API-интерфейсе выборки JavaScript и асинхронной функции, мы перейдем к нашему фактическому кодированию JS. Откройте файл fetch-posts.js в текстовом редакторе, например vscode. Добавьте в него следующий код и сохраните.

/**
 * Load more function for WordPress archives and category pages
 * Works on all types of permalinks
 */
//set all initial variables
let postContainer = document.querySelector('.posts-wrapper'),
    loadMore_btn = document.querySelector('#load_more_posts'),
    totalPages = document.querySelector('.load-more').getAttribute('data-totalpages'),
    currentPage = 1,
    url = document.location.href,
    fetchUrl = url.match(/[?]/) ? url + '&paged=' : url + '?paged=',//checking permalink structure
    parser = new DOMParser();//Initialize the DOM parser
    //console.log(totalPages, url)
if( currentPage == totalPages ) {
    //run if there is only 1 page
    loadMore_btn.classList.add('end-page')
    loadMore_btn.disabled = true
    loadMore_btn.innerHTML = 'No more posts'
}else if( currentPage < totalPages ){
    //run if there is more than 1 page
    loadMore_btn.disabled = false
    //add event listner for the load more button
    loadMore_btn.addEventListener( 'click', loadMorePosts )
}
/**
 * @callback loadMorePosts
 * async function for the fetch function with await
 */
async function loadMorePosts(){
    //increment page number for each click
    currentPage++
    //change button text while loading
    this.innerHTML = 'Loading...'
    //fetch function and returned data
    let data = await ( await fetch( fetchUrl + currentPage ).catch( errorHandle ) ).text(),
        //use DOMParser to convert text string to HTML nodes
        htmlData = parser.parseFromString( data, 'text/html' ),
        //select posts that will be appended
        posts = htmlData.querySelectorAll('article.post')
    for( let i = 0; i<posts.length; i++ ){
        //initially add 'hide' class to the posts for fadein effect
        posts[i].classList.add('hide')
        //then append it to the container
        postContainer.append( posts[i] )
    }
    /*********** fadein effect ***********/
    //select all hidden posts
    let hiddenPosts = postContainer.querySelectorAll('.hide'),
        //set time out and make the posts visible
        //css transition will fade in
        timer = setTimeout( function(){
            Array.prototype.map.call( hiddenPosts, function(el){
                el.classList.remove('hide')
                el.classList.add('show')
            })
        }, 300)
    /*********** fadein effect ends ***********/
    if( currentPage == totalPages ){
        //if there is no more page,
        //disable the button
        this.classList.add('end-page')
        this.disabled = true
        this.innerHTML = 'No more posts'
    }else{
        //if there is more pages,
        //change the button text
        this.innerHTML = 'Load More'
    }
    
}
/**
 * @callback errorHandle
 * @param err to handle errors 
 */
function errorHandle(err){
    console.warn(err)
}

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

CSS для эффекта затухания и кнопки «Загрузить больше».

Когда вы читаете код, вы должны видеть, что мы добавили сообщения с классом .hide, а затем с тайм-аутом мы удалили класс .hide и добавили класс .show к добавленным сообщениям. Теперь мы можем написать немного CSS для этого класса, и эффект плавного появления будет виден. Давайте добавим следующий код в ваш файл style.css.

.load-more{
    text-align: center;
}
.show {
    opacity: 1;
    transition: opacity 1000ms;
}
.hide {
    opacity: 0;
    transition: opacity 1000ms;
}
.end-page, 
.end-page:hover {
    opacity: 0.5;
    pointer-events: none;
}

Дополнительный эффект затухания

Если вам действительно не нужен эффект постепенного появления добавленных сообщений, вы можете просто удалить следующие строки кода из JS-файла.

//initially add 'hide' class to the posts for fadein effect
posts[i].classList.add('hide')
/*********** fadein effect ***********/
//select all hidden posts
let hiddenPosts = postContainer.querySelectorAll('.hide'),
    //set time out and make the posts visible
    //css transition will fade in
    timer = setTimeout( function(){
        Array.prototype.map.call( hiddenPosts, function(el){
            el.classList.remove('hide')
            el.classList.add('show')
        })
    }, 300)
/*********** fadein effect ends ***********/

Аналогичным образом удалите коды CSS .show и .hide из файла style.css. Это удалит эффект затухания. На этом этапе вы можете удалить код разбиения на страницы по умолчанию paginate_links() из связанных php-файлов. Или вы можете использовать CSS, чтобы скрыть элемент.

Задача для вас

Хотите поиграть с кодом? Вот у меня есть задание для вас подумать и сделать. Наш JavaScript управляется событиями с помощью кнопки «Загрузить еще». Теперь изучите объекты window и document и попробуйте сделать с ними бесконечную прокрутку. Вы можете это сделать? С нетерпением жду этого.

#task 2 — В этом руководстве Архив пользовательских сообщений WordPress с REST API и ajax мы использовали jQuery ajax. Попробуйте преобразовать его в чистый JavaScript с помощью fetch() API.

Полезные ресурсы для API выборки JavaScript

Здесь вы можете найти несколько полезных ресурсов для руководств по JavaScript —

https://youtu.be/PoRJizFvM7s