AJAX загрузка постов в WordPress

Рассмотрим, как реализовать кнопку AJAX загрузки постов в WordPress. Т.е. загрузка постов будет осуществляться при нажатии на кнопку «загрузить еще» без перезагрузки страницы.

Содержание:

  1. AJAX загрузка постов при нажатии на кнопку
    1. JavaScript
    2. PHP
    3. счётчик оставшихся записей/страниц
    4. AJAX загрузка с множеством кнопок
  2. AJAX загрузка при скролле

Подгрузка записей при нажатии на кнопку

AJAX WordPress

Примерный код для страницы шаблона вывода постов.

<?php $posts = new WP_Query(array(
    "post_type"        => "{тип_записи}",                  # post, page, custom_post_type
    "post_status"      => "publish",                       # статус записи
    "posts_per_page"   => 6,                               # кол-во постов вывода/загрузки

    "category_name"    => "{название_рубрики}",            # если рубрика

    "tax_query" => array(                                  # если элемент (термин) таксономии
        array(
            "taxonomy" => "{название_таксономии}",         # таксономия
            "field"    => "slug",                          # slug/id
            "terms"    => "{ярлык/id_элемента_таксономии}" # термин (ярлык/id)
        )
    ),

)); ?>

<?php if ($posts->have_posts()) : ?>
    <?php while ($posts->have_posts()) : $posts->the_post(); ?>
        <?php get_template_part("template-parts/loop-{шаблон}"); ?>
    <?php endwhile; ?>
<?php endif; ?>
<?php wp_reset_postdata(); ?>

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

<?php // AJAX загрузка постов
if ($posts->max_num_pages > 1) { ?>
    <script>
        var current_page = 1;
    </script>

    <button 
        type="button"
        class="btn--load"
        data-param-posts='<?= json_encode($posts->query_vars); ?>' 
        data-max-pages="<?= $posts->max_num_pages; ?>"
        data-tpl="portfolio"
    >
        Загрузить ещё
    </button>
<?php } ?>

В JavaScript обработчик передаём:

  • current_page — номер текущей страницы;
  • data-param-posts — параметры поста (post_type, post_status, posts_per_page и другие);
  • data-max-pages — сколько всего страниц;
  • data-tpl — тип записи (необходим чтобы на сайте использовать множество кнопок подгрузки записей с одним обработчиком, но разными шаблонами вывода).

JavaScript обработчик

Создадим файл ajax-load-more.js и подключим его в functions.php

jQuery(function ($) {
    $(".btn--load").on("click", function () {
        const button = $(this);
        button.html("Загрузка...");

        const data = {
            "action": "load_more",
            "query": button.data("param-posts"),
            "page": current_page,
            "tpl": button.data("tpl")
        }

        $.ajax({
            url: "/wp-admin/admin-ajax.php",
            data: data,
            type: "POST",
            success: function (data) {
                if (data) {
                    button.html("Загрузить ещё");
                    button.prev().prev().append(data);
                    current_page++;
                    if (current_page == button.attr("data-max-pages")) {
                        button.remove();
                    }
                } else {
                    button.remove();
                }
            }
        });
    });
});

Здесь необходимо обратить внимание на button.parent().after(data);

Здесь указываем место, где выводить записи на странице. Используйте перемещение по DOM-дереву:

  • prev() — предыдущий элемент,
  • next() — следующий,
  • parent() — на уровень выше,
  • children() — на уровень ниже.

И вставляйте в нужном месте:

  • before() — до элемента (рядом),
  • after() — после элемента (рядом),
  • prepend() — до элемента (внутри)
  • append() — после элемента (внутри).

Можете ознакомиться со шпаргалкой jQuery.

Теперь подключим полученный файл ajax-load-more.js в functions.php или же код выше можно просто скопировать в ваш главный файл scripts.js / main.js.

wp_enqueue_script("{название_темы}-load-more", get_template_directory_uri() . "/js/ajax-load-more.js", array("jquery"), "", true );

PHP обработчик

Напишем функцию для AJAX загрузки постов нужного шаблона.

<?php

add_action("wp_ajax_load_more", "load_posts");
add_action("wp_ajax_nopriv_load_more", "load_posts");
function load_posts()
{
    $args = json_decode(stripslashes($_POST["query"]), true);
    $args["paged"] = $_POST["page"] + 1;

    $posts = new WP_Query($args);
    $html = '';

    if ($posts->have_posts()) : while ($posts->have_posts()) : $posts->the_post();

            if ($_POST["tpl"] === "news") {
                $html .= get_template_part("template-parts/loop-portfolio");
            }

        endwhile;
    endif;

    wp_reset_postdata();
    die($html);
}

Для выполнения AJAX запроса /wp-admin/admin-ajax.php, нам необходимо использовать:

  • wp_ajax_(action) — для авторизованных пользователей;
  • wp_ajax_nopriv_(action) — для НЕ авторизованных.


Чтобы добавить новый параметр (или изменить его), используйте следующий код. Пример.

$args["posts_per_page"] = 3; // по сколько записей подгружать

Чтобы удалить параметр(ы), используйте код:

$args = remove_query_arg(["post_parent"]); // удаление параметра «post_parent»

Теперь необходимо подключить данный файл в functions.php. Назовём его load-posts.php

require get_template_directory() . '/functions/load-posts.php';

«Загрузить ещё» со счётчиком оставшихся записей/страниц в WordPress

В шаблоне вывода постов изменим код после тега script.

<?php

// Получить кол-во постов в определенной категории (типе записи)
$count_posts = wp_count_posts("{тип_записи}"); // post, page, custom_post_type
$published_posts_all = $count_posts->publish;  // общее кол-во записей

// ИЛИ
// Получить кол-во постов в определённом термине таксономии
$terms = get_terms(array(
    "taxonomy" => "{название_таксономии}",     // таксономия
    "slug"     => "{термин_таксономии}"        // элемент таксономии
));
foreach ($terms as $terms) {
    $count_posts = $terms->count;              // получаем сколько всего постов
}

$published_posts_remain = $count_posts - 10;   // оставшееся кол-во записей
?>

<button>
    Загрузить ещё
    <span><?= $published_posts_remain; ?></span> из
    <span><?= $published_posts_all; ?></span>
</button>

AJAX загрузка постов с множеством кнопок

Может встретиться такая задача: у нас в разных вкладках выводятся записи для разных категорий (таксномий).

Т.е. в первой вкладке — записи из «категории 1», во второй — записи из «категории 2» и так далее.
Соответственно у нас будет множество кнопок подгрузки записей.

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

<?php $tax_terms = get_terms("portfolio_category") ?>

<?php if ($tax_terms) : $i = 1; ?>
    <ul>
        <?php foreach ($tax_terms as $term) : ?>
            <li>
                <button <?= $i == '1' ? "class=\"active\"" : "" ?> href="#tab-<?= $i ?>">
                    <?= $term->name ?>
                </button>
            </li>
        <?php $i++;
        endforeach; ?>
    </ul>
<?php endif; ?>

<?php if ($tax_terms) : $j = 1; ?>
    <?php foreach ($tax_terms as $term) : ?>

        <?php $posts = new WP_Query(array(
            "post_type"        => "portfolio",
            "post_status"      => "publish",
            "posts_per_page"   => 3,
            "tax_query" => array(
                array(
                    "taxonomy" => $term->taxonomy,
                    "field"    => "slug",
                    "terms"    => $term->slug
                )
            ),

        )); ?>

        <div id="tab-<?= $j ?>" <?= $j == '1' ? "style=\"display:block;\"" : "style=\"display:none;\"" ?>>
            <div class="portfolio-item">
                <?php if ($posts->have_posts()) :
                    while ($posts->have_posts()) : $posts->the_post();
                        get_template_part("template-parts/loop-portfolio");
                    endwhile;
                endif;
                wp_reset_postdata(); ?>
            </div>

            <?php if ($posts->max_num_pages > 1) { ?>
                <script>
                    window['this_page_<?= $j ?>'] = 1;
                </script>
                <button 
                    class="btn--load" 
                    type="button" 
                    data-param-posts='<?= json_encode($posts->query_vars); ?>' 
                    data-max-pages="<?= $posts->max_num_pages; ?>" 
                    data-tpl="portfolio"
                    data-num="<?= $j ?>"
                >
                    Больше
                </button>
            <?php } ?>

        </div>

    <?php $j++;
    endforeach; ?>
<?php endif; ?>

Тогда JavaScript будет выглядеть примерно так:

jQuery(function ($) {
    $(".btn--load").on("click", function () {
        const button = $(this);
        const num = button.attr("data-num");
        button.html("Загрузка...");

        const data = {
            "action": "load_more",
            "query": button.attr("data-param-posts"),
            "page": window['this_page_' + num],
            "tpl": button.data("tpl")
        }

        $.ajax({
            url: "/wp-admin/admin-ajax.php",
            data: data,
            type: "POST",
            success: function (data) {
                if (data) {
                    button.html("Загрузить ещё");
                    button.prev().prev().append(data);
                    window['this_page_' + num]++;
                    if (window['this_page_' + num] == button.attr("data-max-pages")) {
                        button.remove();
                    }
                } else {
                    button.remove();
                }
            }
        });
    });
});

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

AJAX загрузка постов при скролле

Вместо кнопки напишем следующий код:

<?php if ($posts->max_num_pages > 1) { ?>
    <script>
        var current_page = 1;
        var param_posts = '<?= json_encode($posts->query_vars); ?>';
        var max_pages = '<?= $posts->max_num_pages; ?>';
    </script>
<?php } ?>

Заменим JavaScript:

jQuery(function ($) {
    const bottom_offset = 3000; // расстояние (в px)
    let can_be_loaded = true;

    $(window).scroll(function () {
        const data = {
            'action': 'load_posts',
            'query': param_posts,
            'page': current_page
        };
        if ($(document).scrollTop() > ($(document).height() - bottom_offset) && can_be_loaded == true) {
            $.ajax({
                url: "/wp-admin/admin-ajax.php",
                data: data,
                type: 'POST',
                beforeSend: function (xhr) {
                    can_be_loaded = false;
                },
                success: function (data) {
                    if (data) {
                        $('.grid').find('.grid__item:last-of-type').after(data); // где вставить
                        current_page++;
                        can_be_loaded = true;
                        if (current_page == max_pages) {
                            can_be_loaded = false;
                        }
                    }
                }
            });
        }
    });
});

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