Проблемы с реализацией функциональности Загрузить больше

Вопрос или проблема

Я пытаюсь создать свою собственную функцию “Загрузить еще” (по клику) в моей дочерней теме, используя последние стандарты в WordPress. Я не чувствую себя уверенно, работая с PHP, и я сбиваюсь с толку, что на самом деле необходимо. Я знаю, что здесь много похожих вопросов, но очень трудно выбрать фрагменты информации из случайных постов, у всех из которых похожие, но не одинаковые проблемы/решения. Извините, если я кого-то расстраиваю, задавая вопрос.
Предупреждение – английский не мой родной язык, так что пожалуйста, будьте тщательными и терпеливыми со мной.

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

Насколько я понимаю, функция “Загрузить еще” требует использования REST, верно? В противном случае невозможно объединить возможности PHP и JavaScript.
Для этого я использую метод wp_localize_script(). Я начинал использовать 'ajaxurl' => admin_url('admin-ajax.php'). Однако с тех пор меня проинформировали, что это старый метод, и я не хочу использовать устаревшие решения. Вместо этого я пытаюсь использовать rest_url().

В целом, вот что я сделал на данный момент (или, если быть честным, в основном скопировал и вставил 😄):

Functions.php:

function itc_included_files() {
    wp_register_script('itc-load-more-js', get_stylesheet_directory_uri() . '/build/assets/js/load-more.js', array('jquery'), false, true);

    // Даем в js-скрипт доступ к REST
    wp_localize_script( 'itc-load-more-js', 'load_ajax_data', array(
        'restURL' => rest_url(),
        'restNonce' => wp_create_nonce('wp_rest')
        )
    );

    wp_enqueue_script('itc-load-more-js');
}

Подключено в самом верху functions.php, как так:

require_once(get_stylesheet_directory() . '/inc/itc-load-more-ajax.php');

Ниже находится этот фрагмент кода:

<?php
function itc_load_more() {

    $ppp = (isset($_POST["ppp"])) ? $_POST["ppp"] : 1;
    $page = (isset($_POST['pageNumber'])) ? $_POST['pageNumber'] : 0;

    header("Content-Type: text/html");

    $args = array(
        'suppress_filters' => true,
        'post_type' => 'radgivare',
        'posts_per_page' => $ppp,
        'paged' => $page,
    );

    $loop = new WP_Query($args);

    $out="";

    if ($loop->have_posts()) : while ($loop->have_posts()) : $loop->the_post();
            $out .= get_template_part('template-parts/content', 'page');
        endwhile;
    endif;
    wp_reset_postdata();
    die($out);
}

add_action('wp_ajax_nopriv_itc_load_more', 'itc_load_more');
add_action('wp_ajax_itc_load_more', 'itc_load_more');
?>

Файл шаблона

<section class="advisor__wrapper">
    <h2 class="title-lg is-outlined">Большой заголовок</h2>

    <?php
    $agent_posts = new WP_Query([
        'post_type' => 'radgivare',
        'post_status' => 'publish',
        'posts_per_page' => 4,
        'orderby' => 'post_date',
        'order' => 'DESC'
    ]);

    if ($agent_posts->have_posts()) : ?>
        <div id="load-more-posts-container" class="itc-row gutter">
            <?php
            while ($agent_posts->have_posts()) : $agent_posts->the_post();
                get_template_part('template-parts/content', 'radgivare');
            endwhile;
            ?>
        </div>
    <?php endif; ?>
    <?php wp_reset_postdata(); ?>
    <input type="hidden" id="totalpages" value="<?= $loop->max_num_pages ?>">
    <div class="advisor__wrapper__btn-wrapper">
        <a href="" class="btn rounded btn-margin-lg btn--violet" id="btn-load-more">Показать больше советников</a>
    </div>
</section>

И, наконец, мой js-файл:

var ppp = 1; // Постов на страницу
var pageNumber = 2;
var total = jQuery('#totalpages').val();

jQuery("#btn-load-more").on("click", function ($) { // Когда нажата кнопка.
    jQuery("#btn-load-more").attr("disabled", true); // Отключить кнопку на время.
    pageNumber++;
    var str="&pageNumber=" + pageNumber + '&ppp=' + ppp + '&action=itc_load_more';
    jQuery.ajax({
        type: "GET",
        dataType: "json",
        url: load_ajax_data.restURL,
        data: str,
        success: function (data) {
            var $data = jQuery(data);
            if ($data.length) {
                jQuery("#load-more-posts-container").append($data);
                jQuery("#btn-load-more").attr("disabled", false);
            } else {
                jQuery("#btn-load-more").attr("disabled", true);
            }                
            if (total < pageNumber) {
                jQuery("#btn-load-more").hide();
            }
        },
        error: function (jqXHR, textStatus, errorThrown) {
            $loader.html(jqXHR + " :: " + textStatus + " :: " + errorThrown);
        }

    });
    return false;
});

Изначально тип был установлен на "POST", а dataType на "html". Ничего из этого не работает.

В моем коде явно отсутствует какая-то фундаментальная часть, потому что он просто не работает. Образовательная и конструктивная помощь в этом вопросе очень приветствуется, потому что я не знаю, что делаю не так. Спасибо!

Предыстория

В качестве слишком широкой аналогии между устаревшей системой обработки AJAX и API REST:

  • Система обработки AJAX – это немного больше, чем способ соединить запрос к конкретному PHP файлу с обратным вызовом WordPress, оставляя все остальные детали реализации на усмотрение разработчика.
  • REST API больше похожа на “фреймворк HTTP API”, который предоставляет различным системам, инструментам и соглашениям помощь в обеспечении доступа к данным и функциональности по логическим URI организованным образом.

REST API также предоставляет всю необходимую функциональность для автоматического доступа к большинству данных и общих взаимодействий WordPress. Из коробки, вы можете создавать/читать/обновлять/удалять пользователей WordPress, страницы, посты, таксономии и т. д. с помощью стандартизированных HTTP-запросов к обычным конечным точкам.

Как вы уже видели, процесс предоставления данных ядра для пользовательского типа записи на REST API может быть настолько прост, как нажатие переключателя в вызове register_post_type() для CPT:

register_post_type(
  'radgivare',
  [
    // ...
    'show_in_rest' => true
  ]
);

После чего тип записи будет доступен через REST API по маршруту

/wp-json/wp/v2/radgivare

И конкретные посты этого типа через параметризованный маршрут

/wp-json/wp/v2/radgivare/<id>

Нет необходимости писать всю логику для запроса, создания, обновления или удаления вашего CPT через HTTP-запрос, как вам бы пришлось это делать, если бы вы хотели выполнять эти операции, используя старую систему обработки AJAX – REST API уже решила базовые задачи за вас, что довольно круто 🙂

Тип взаимодействия с данными, доступными по маршруту, определяется HTTP-методом запроса. Запрос POST используется для обновления или вставки. Запрос DELETE удаляет. Запрос GET извлекает/запрашивает данные – это также означает, что посещение маршрута непосредственно в вашем браузере выполнит такого рода операции (рекомендую использовать расширение браузера для формата JSON, когда исследуете маршруты REST API в браузере, чтобы не сойти с ума).

Это лишь поверхностный обзор REST API – настоятельно рекомендую потратить время на чтение справочника REST API, чтобы лучше познакомиться с его концепциями и системами. Это также удобная справочная информация о базовых маршрутах и параметрах, которые они принимают, и формате возвращаемых данных.

Главные маршруты REST API также само-документируются – это означает, что подробные описания каждого из основных маршрутов доступны в виде данных в ответах. В основном через маршрут GET /wp-json/wp/v2. Руководство гораздо проще для восприятия, но иногда вы можете найти обратную связь по полям и функциональности, которая была добавлена плагинами, в ответе.


Решение

Существует множество способов доставки контента записи, отрендеренного через часть шаблона. Одно из решений – добавить поле в ответ API REST для запроса GET для вашего CPT, которое будет содержать разметку, отрендеренную шаблоном.

Поскольку get_template_part() просто выполняет указанный PHP-файл, разметка в этом файле будет отправлена на вывод (например, с помощью echo), а не будет return – невозможно получить разметку в виде строки через что-то вроде $out = get_template_part(...);. Вместо этого нам нужно использовать “буферы вывода” PHP, чтобы захватить вывод, затем преобразовать его в строку.

function wpse408606_rest_radgivare_templated_content_field() {
  // Добавляем новое поле в ответы на запросы для `radgivare` постов, которое
  // будет заполнено возвращаемым значением из `get_callback`.
  register_rest_field(
    'radgivare',
    'templated_content',
    [
      'get_callback' => 'wpse408606_get_radgivare_templated_content',
    ]
  );
}

add_action( 'rest_api_init', 'wpse408606_rest_radgivare_templated_content_field' );

function wpse408606_get_radgivare_templated_content() {
  ob_start(); // Создаем новый, пустой буфер для захвата любого последующего вывода.

  // Объект $post уже настроен так, чтобы мы находились в Loop.
  // Загружаем шаблон.
  get_template_part( 'template-parts/content', 'page' );

  return ob_get_clean(); // Закрываем буфер вывода и преобразуем его содержимое в строку.
}

Это все, что необходимо на стороне PHP. Новое поле с именем templated_content теперь будет доступно в ответах на запросы для постов radgivare, содержащее вывод этой части шаблона.

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

Ваш код jQuery становится таким

jQuery("#btn-load-more").on("click", function ($) { // Когда нажата кнопка.
    jQuery("#btn-load-more").attr("disabled", true); // Отключить кнопку на время.
    pageNumber++;

    var rest_route = `${load_ajax_data.restURL}wp/v2/radgivare?page=${pageNumber}&per_page=${ppp}`;

    jQuery.ajax({
        type: "GET",
        dataType: "json",
        url: rest_route,
        data: str,
        success: function (data) {
            for( var i = 0; i < data.length; i++ ) {
                $post_content = jQuery( data[i].templated_content );
                jQuery("#load-more-posts-container").append($ post_content );
            };

            if (total < pageNumber) {
                jQuery("#btn-load-more").hide();
            }
            else {
                jQuery("#btn-load-more").attr("disabled", false);
            }
        },
        error: function (jqXHR, textStatus, errorThrown) {
            $loader.html(jqXHR + " :: " + textStatus + " :: " + errorThrown);
        }

    });
    return false;
});

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

Ответ или решение

Реализация функции "Загрузить еще" в WordPress может вызывать множество вопросов, особенно если ваш опыт работы с PHP ограничен. Здесь я постараюсь дать четкие шаги и объяснения, которые помогут вам настроить эту функциональность для вашего дочернего шаблона, используя современные подходы.

Теория

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

Для реализации этой функции в WordPress вам потребуется использовать комбинацию PHP для серверной обработки запросов, и JavaScript (чаще всего с использованием AJAX) для обработки событий на клиентской стороне. Ранее для этого использовалась система AJAX-хендлеров, но современным подходом является использование REST API WordPress, что дает более мощные и гибкие возможности.

Пример

Давайте разберем ваши текущие наработки и предложим улучшения.

1. Регистрация пользовательского типа записей с поддержкой REST API

Если вы еще не сделали этого, добавьте поддержку REST API для вашего пользовательского типа записей, добавив 'show_in_rest' => true в функцию register_post_type.

register_post_type('radgivare', [
    // Другие параметры
    'show_in_rest' => true,
]);

Это позволит вашим записям быть доступными через стандартные маршруты REST API WordPress.

2. Регистрация и локализация скриптов

Используйте функцию wp_register_script для регистрации вашего JavaScript-файла и wp_localize_script для передачи данных из PHP в JavaScript.

function itc_included_files() {
    wp_register_script('itc-load-more-js', get_stylesheet_directory_uri() . '/build/assets/js/load-more.js', ['jquery'], false, true);

    wp_localize_script('itc-load-more-js', 'load_ajax_data', [
        'restURL' => rest_url(),
        'restNonce' => wp_create_nonce('wp_rest')
    ]);

    wp_enqueue_script('itc-load-more-js');
}
add_action('wp_enqueue_scripts', 'itc_included_files');

3. Реализация сервера

Вместо использования устаревшего обработчика AJAX, используйте расширение REST API для добавления нового поля, содержащего HTML-код.

function wpse408606_rest_radgivare_templated_content_field() {
    register_rest_field('radgivare', 'templated_content', [
        'get_callback' => 'wpse408606_get_radgivare_templated_content',
    ]);
}
add_action('rest_api_init', 'wpse408606_rest_radgivare_templated_content_field');

function wpse408606_get_radgivare_templated_content() {
    ob_start();
    get_template_part('template-parts/content', 'radgivare');
    return ob_get_clean();
}

Этот код добавит новое поле в ответ REST API, содержащее сгенерированный шаблон контента.

4. Реализация на клиентской стороне

Используйте jQuery для обработки события клика и отправки запросов на сервер.

var ppp = 1; // Постов на страницу
var pageNumber = 1; // Номер страницы
var total = jQuery('#totalpages').val();

jQuery("#btn-load-more").on("click", function (e) {
    e.preventDefault();
    jQuery("#btn-load-more").attr("disabled", "disabled");

    pageNumber++;
    var restRoute = `${load_ajax_data.restURL}wp/v2/radgivare?page=${pageNumber}&per_page=${ppp}`;

    jQuery.ajax({
        type: 'GET',
        dataType: 'json',
        url: restRoute,
        success: function (data) {
            for (var i = 0; i < data.length; i++) {
                var $postContent = jQuery(data[i].templated_content);
                jQuery("#load-more-posts-container").append($postContent);
            }

            if (total < pageNumber) {
                jQuery("#btn-load-more").hide();
            } else {
                jQuery("#btn-load-more").removeAttr("disabled");
            }
        },
        error: function (jqXHR, textStatus, errorThrown) {
            console.error(textStatus);
        }
    });
});

Применение

Следуя вышеприведенным шагам, вы сможете реализовать современную и функциональную "Загрузить еще" функцию для вашего дочернего шаблона в WordPress. Настройка REST API для взаимодействия клиент-сервер предоставляет гибкость и мощность для работы с пользовательскими записями.

Преимущества использования REST API заключаются в большей эффективности и возможности масштабирования функционала вашего сайта. Даже с минимальными знаниями PHP и JavaScript, следуя этим шагам, вы сможете создать работующую функциональность, которая улучшит взаимодействие пользователей с вашим сайтом. Не забудьте протестировать окончательное решение, чтобы убедиться, что оно соответствует вашим требованиям и работает без ошибок.

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

Капча загружается...