Очередная реализация ajax загрузки постов в WP

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

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

<a href="#" class="load" title="<?php _e('Click to load more posts', 'your locale'); ?>" data-container-id="content" data-template="home"><?php _e('Load more', 'your locale'); ?></a>

В data-container-id помещаем id обертки, html елемента внутри которого выведены все посты, и в которые будут добавляться новые.
data-template — название шаблона для вывода каждого поста, о нем чуточку позже.

Дальше на нужно написать сам скрипт который отправляет запрос на сервер и добавляет принятые данные внутрь контейнера, назовем его script.js и поместим в папку с темой:

(function( $ ) {
    $( document ).ready( function() {
        /**
         * Load post ajaxify.
         *
         * For adding new, set link class to '.load' and add data-container-id
         *   and data-template params.
         * 'data-container-id' - id of wrapper with articles to append,
         * 'data-template' - loop-{template}.php file, to add allowed template
         *   use `mytheme_ajax_available_templates`
         *   filer.
         *
         * If need to masonry reload, add class '.masonry-container' to container.
         * Notice: child of container must have tag 'article'.
         */
        $( 'a.load' ).click( function ( e ) {
            e.preventDefault();
            var containerID = $( this ).data( 'container-id' );
            var template = $( this ).data( 'template' );
            var container = $( '#' + containerID );
            if ( container.length ) {
                var data = {
                    action:   'more_posts',
                    offset:   container.find( 'article' ).length,
                    template: template
                };
                $.post( params.ajax_url, data, function ( response ) {
                    container.append( response );
                    if ( container.hasClass( 'masonry-container' ) )
                        container.masonry( 'reload' );
                } );
            }
        } );
    });
})(jQuery);

Одно из условий работы скрипта это чтобы внутри выбранного контейнера, id которого мы указываем в ссылке, были посты обернуты в тег article. На самом деле это не принципиально важно, просто тогда придется в скрипте немного поправить селектор у параметра data.offset. Этот параметр указывает сколько постов нам нужно пропустит в запросе, ну чтобы посты не подгружались те же самые.
Параметр data.action — это наш action на который сработает наша функция в functions.php которую мы сейчас и напишем…
Кстати скрипт поддерживает masonry (который есть из коробки в wordpress), для этого добавь контейнеру класс .masonry-container, и после добавления элементов скрипт сам сделает reload.

Теперь этот скрипт нужно подключить, для этого в functions.php повесим обработчик на событие init:

/**
 * Add custom scripts
 */
function my_theme_init_action() {
        wp_register_script( 'theme_script', get_template_directory_uri() . '/script.js' );
        wp_enqueue_script( 'theme_script' );
        wp_localize_script( 'theme_script', 'params', array(
                'ajax_url' => admin_url( 'admin-ajax.php' )
        ) );
}

add_action( 'init', 'my_theme_init_action' );

С помощью функции wp_localize_script() мы передаем массив params в наш скрипт, в нем есть элемент ajax_url в котором указан путь к по которому нужно делать ajax запрос.

Скрипт написан, подключен и должен работать. Работу скрипта можно проверить с помощью firebug’а, или инспектора элементов в браузере, на вкладке network.

Теперь пришла пора написать бек-энд который будет отдавать посты. Для этого в functions.php повесим на функцию на два события: wp_ajax_more_posts и wp_ajax_nopriv_more_posts, где wp_ajax_nopriv это событие для пользователей без привилегий, т.е. не авторизованных, а more_posts это наше название события которое мы отправляем в ajax запросе (смотри в script.js параметр data.action).

/**
 * Ajax callback. Load more posts.
 */
function my_theme_more_posts_action_callback() {
        $offset = ( $_POST[ 'offset' ] ) ? (int) $_POST[ 'offset' ] : 5;
        $available_templates = apply_filters( 'ajax_available_templates', array(
                'front',
                'category',
        ) );
        if ( in_array( (string) $_POST[ 'template' ], $available_templates ) ) {
                query_posts( 'offset=' . $offset );
                get_template_part( 'loop', $_POST[ 'template' ] );
        }
        die();
}
add_action( 'wp_ajax_more_posts', 'my_theme_more_posts_action_callback' );
add_action( 'wp_ajax_nopriv_more_posts', 'my_theme_more_posts_action_callback' );

Если расписывать построчно, то сначала мы берем передаваемый параметр offset, в котором указываем сколько пропустить постов уже показанных, и добавляем его, и только его, дальше в query_posts. Дальше я для безопасности добавил массив разрешенных к выводу шаблонов, расширить который можно легко с помощью фильтров, и проверил есть ли в этом массиве передаваемый параметр template, если есть то после запроса выводим все посты согласно указанному шаблону с приставкой loop, т.е. если мы передали template=category, то выводим для показа шаблон loop-category.php, а если его не будет то выведется стандартный loop.php. Все в соответствии с логикой в wordpress.

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

p.s. Так же в скрипт можно добавить такие плюшки как анимация при загрузке и прочее, но это уже совсем другая история…

Очередная реализация ajax загрузки постов в WP: 11 комментариев

  1. adrin

    На первый взгляд толковый скрипт, но что-то у меня не заработал. Поможете разобраться? Сделал вроде все по описанию, единственное заменил offset: container.find( ‘article’ ).length, на div елемент. Потому как у меня каждая отдельная запись обернута в div. Не понял по поводу data-template=»home», почему именно home или это без разницы, имя связано с какими то другими элементами? А так же что несет в себе «your locale» второй параметр передаваемый в функцию ?

      1. adrin

        Да, спасибо, я действительно сам уже разобрался. Твой вариант возвращаемых данных у меня так и не заработал, но мне собственно и не нужно было выводить все посты, я туда подставил свой кусок, он и возвращается.

        1. zviryatko Автор записи

          Ну вот и отлично. Можешь поделиться и своим примером, кому-то точно поможет в будущем.

          1. adrin

            Та у меня там «костыли с велосипедами», такое стыдно показывать)

          2. zviryatko Автор записи

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

  2. adrin

    Тут мы запускаем скипт по клику на ссылку с классом .load «…$( ‘a.load’ ).click( function ( e ) {…», а тут «…<a href="#" title="» data-container-id=»content» data-template=»home»>…» никакого класcа .load — нету.

  3. adrin

    «data-template — название шаблона для вывода каждого поста, о нем чуточку позже.» — и где это «позже»?

    1. zviryatko Автор записи

      Дальше я для безопасности добавил массив разрешенных к выводу шаблонов, расширить который можно легко с помощью фильтров, и проверил есть ли в этом массиве передаваемый параметр template, если есть то после запроса выводим все посты согласно указанному шаблону с приставкой loop, т.е. если мы передали template=category, то выводим для показа шаблон loop-category.php, а если его не будет то выведется стандартный loop.php

  4. Александр

    Привет! Мало шарю в программировании но нужна данная реализация на сайте.

    Можно ли какой то пример уже рабочего сайта. Или более подробно что нужно сделать что бы заработало. Заранее спасибо!

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *