Пишем ajax пагинацию и фильтр по таксономиям в WordPress

Пишем ajax пагинацию

В этом посте рассматривается кейс создания ajax фильтров и пагинации для постов. Без плагинов. Изучив данный кейс, вы сможете написать такую же пагинацию для любого типа постов и таксономий. Имеем такую страницу:

Пишем ajax пагинацию

Это архив кастомного типа поста «projects» и 2 прикрепленные к нему таксономии: «projects_country» и «projects_services», а так же кнопка подгрузки следующей страницы. Пока компилируется код в вашем редакторе, здесь можно купить сессии телеграм. Для начала в шаблоне страницы выведем таксономии и посты. Код файла potfolio-page.php :

 

<?php
/**
 * Template Name: Portfolio
 */
get_header();?>
    <div class="white-block white-projects">
        <div class="wrapper filter-line">
            <div class="select-block">
                <i></i>
                <select name="country" class="country" id="country-select">
                    <option selected>Country</option>
                    <?php $countries = get_terms('projects_country');
                    foreach ($countries as $country) {
                        echo '<option value="'.$country->slug.'" data-country-id="'. $country->term_id.'">'.$country->name.'</option>';
                    }
                    ?>
                </select>
            </div>
            <ul class="filter">
                <li><a href="#">All</a></li>
                <?php
                $tax = 'projects_services';
                $args = array(
                    'taxonomy' => $tax,
                    'hide_empty' => false,
                );
                $terms = get_terms( $args );
                foreach ($terms as $term): ?>
                    <li><a href="#" data-service-id="<?php echo $term->term_id?>"><?php echo $term->name;?></a></li>
                <?php endforeach;?>

</ul>
</div>
</div>
<?php
$args = array(
‘post_type’ => ‘projects’,
);
$projects = new WP_Query($args);
$max_pages = $projects->max_num_pages; // узнаем общее количество страниц постов
if($projects->have_posts()) : ?>
<div class=»projects» id=»ajax-portfolio-container»>
<div class=»project-block» >
<?php while($projects->have_posts()): $projects->the_post();?>
<a href=»<?php the_permalink();?>»>
<?php the_post_thumbnail(‘project-thumb’)?>
<p class=»title-events big-text»><?php the_title();?></p>
</a>
<?php endwhile;?>
</div>
<?php
if($max_pages > 1){ ?> // если страниц больше одной, то выводим кнопку с data-атрибутом следующей страницы
<a id=»load-more-events» href=»#» class=»btn btn-orange» data-page=»2″>Load More</a>
<?php }?>
</div>

<?php wp_reset_postdata();
endif;?>
<?php get_footer();?>
</code></pre>
<p> </p>
<p>Данный код выводит select  со странами, список с типами услуг, сами посты, а так же кнопку «Загрузить еще», если есть вторая страница с постами. Обратите внимание на data-атрибуты в тегах с таксономиями и кнопке подгрузки. Именно из них мы и будем получать нужные данные для фильтрации и пагинации. Для того, что бы работать с ajax запросами в WordPress через фронт-энд нам нужно: создать функцию обработчик в <strong>functions.php </strong>нашей темы; написать jQuery код для отправки запроса на обработчик. Для начала выведем  в глобальнуюю Javascript переменную адрес «/wp-admin/admin-ajax.php». На этот адрес мы будем отправлять наши запросы. В <strong>functions.php </strong>добавляем такой код:</p>
<p> </p>
<pre><code class=»php»>
<?php
function js_variables(){
$variables = array (
‘ajax_url’ => admin_url(‘admin-ajax.php’),
);
echo ‘<script type=»text/javascript»>window.wp_data = ‘ . json_encode($variables) . ‘;</script>’;
}
add_action(‘wp_head’,’js_variables’);
?>

 

Данный код выводит select со странами, список с типами услуг, сами посты, а так же кнопку «Загрузить еще», если есть вторая страница с постами. Обратите внимание на data-атрибуты в тегах с таксономиями и кнопке подгрузки. Именно из них мы и будем получать нужные данные для фильтрации и пагинации. Для того, что бы работать с ajax запросами в WordPress через фронт-энд нам нужно: создать функцию обработчик в functions.php нашей темы; написать jQuery код для отправки запроса на обработчик. Для начала выведем в глобальнуюю Javascript переменную адрес «/wp-admin/admin-ajax.php». На этот адрес мы будем отправлять наши запросы. В functions.php добавляем такой код:

 <?php
function js_variables(){
    $variables = array (
        'ajax_url' => admin_url('admin-ajax.php'),
    );
    echo '<script type="text/javascript">window.wp_data = ' . json_encode($variables) . ';</script>';
}
add_action('wp_head','js_variables');
?>

Далее напишем jQuery код для обработки клика по селекту, списку с категориями и кнопке «Загрузить еще», который будет собирать данные из data-атрибутов и отправлять POST на адрес «/wp-admin/admin-ajax.php» и экшн, который мы создадим позже. Фильтровать мы будем по двум таксономиям одновременно и отношением «И». Т.е. «страна» И «тип услуги». Обработаем смену select’а со странами:

<script>
 jQuery('#country-select').on('change', function(){
        var service = jQuery('.white-projects .filter a.active').data('service-id'); //собираем данные из data-атрибутов
        var country = jQuery(this).find('option:selected').data('country-id');
        $.ajax({
            type: "POST",
            url: window.wp_data.ajax_url, //адрес из глобальной переменной
            data : {
                action : 'get_projects', //название нашего обработчика, который создадим поже
                service_id : service, //id услуги из списка услуг
                country_id : country //id страны
            },
            success: function (data) {
                jQuery('#ajax-portfolio-container').html(data); // заменяем содержимое контейнера ответом с сервера
                $('#ajax-portfolio-container .project-block a').css('opacity', 1);
            }
        });
    });
</script>

В данном коде action — название функции обработчика, которую мы создадим позже, service_id и country_id -это id терминов, по которым нужно выбрать посты. «jQuery(‘#ajax-portfolio-container’).html(data);» — заменит содержимое нашего контейнера ответом с сервера.

Далее обработаем клик по типу услуг:

<script>
jQuery('.white-projects .filter a').on('click', function(e){
        e.preventDefault();
        jQuery('.white-projects .filter a').removeClass('active');
        jQuery(this).addClass('active');
        var service = jQuery(this).data('service-id');
        var country = jQuery("#country-select").find('option:selected').data('country-id');
        $.ajax({
            type: "POST",
            url: window.wp_data.ajax_url,
            data : {
                action : 'get_projects',
                service_id : service,
                country_id : country
            },
            success: function (data) {
                jQuery('#ajax-portfolio-container').html(data);
                $('#ajax-portfolio-container .project-block a').css('opacity', 1);
            }
        });
    });
</script>

И, наконец, клик по кнопке «Загрузить еще»:

<script>
jQuery('body').on('click','#load-more-events', function(e){
        e.preventDefault();
        var service = jQuery(this).data('service-id'); // если посты уже отфильтрованы, то в кнопку для загрузки следующей страницы
        var country = jQuery(this).data('country-id'); // мы будем записывать id таксономий.
        var page = jQuery(this).data('page'); // номер страницы для загрузки
        var button = jQuery(this);
        $.ajax({
            type: "POST",
            url: window.wp_data.ajax_url,
            data : {
                action : 'get_projects',
                service_id : service,
                country_id : country,
                paged : page
            },
            success: function (data) {
                button.remove(); //удаляем кнопку
                jQuery('#ajax-portfolio-container').append(data); // добавляем в контейнер ответ с сервера
            }
        });
    });
</script>

Отправку запросов мы настроили, теперь нужно создать обработчик. Для этого нам нужно будет использовать два хука: wp_ajax_(action) и wp_ajax_nopriv_(action). Второй нужен для того, чтобы к нему могли обращаться неавторизованные пользователи. Итоговый код должен быть примерно таким :

<?php
function my_action_callback() {
    echo 'Hello!';
    wp_die();
}

add_action(‘wp_ajax_(action)’, ‘my_action_callback’);
add_action(‘wp_ajax_nopriv_(action)’, ‘my_action_callback’);
?>

Обратите внимание, что функция должна обязательно возвращать данные через return или echo. Так же в конце функции обязательно ставим wp_die(); . В нашем случае мы пишем такой код в functions.php :

<?php
function get_projects() {
    global $post;
    $service_id = $_POST['service_id'] ? $_POST['service_id'] : ''; //получаем POST данные 
    $country_id = $_POST['country_id'] ? $_POST['country_id'] : ''; //Если в POST пусто - оставляем переменные пустыми
    $paged = $_POST['paged'] ? $_POST['paged'] : 1; // Если в paged пусто, то будем считать, что нужна первая страница
    $return_html = ''; // Весь HTML код мы записываем в переменную
    $args = array( // составляем запрос
        'post_type' => 'projects',
        'paged' => $paged,
    );
    if (!empty($country_id) && !empty($service_id)) { // если переменные с ID таксономий не пусты, то добавляем tax_query с отношением "И"
        $args['relation'] = 'AND';
    }
    if (!empty($service_id)) {
        $args['tax_query'][] = array(
            'taxonomy' => 'projects_serices',
            'terms'    => $service_id
        );
    }
    if (!empty($country_id)) {
        $args['tax_query'][] = array(
            'taxonomy' => 'projects_country',
            'terms'    => $country_id
        );
    }
    $projects = new WP_Query($args);
    $max_pages = $projects->max_num_pages; // получаем общее число страниц с выбранными постами
    if ($projects->have_posts()):
        $return_html .= '<div class="project-block">'; // собираем такую же разметку как в начальном шаблоне
        while ($projects->have_posts()): $projects->the_post();
            $thumbnail = get_the_post_thumbnail($post->ID, 'project-thumb');
            $title = get_the_title();
            $permalink = get_the_permalink();
            $return_html .= '<a href="' . $permalink . '">';
            $return_html .= $thumbnail;
            $return_html .= '<p class="title-events big-text">' . $title . '</p>';
            $return_html .= '</a>';
        endwhile;
        $return_html .= '</div>';
    endif;
    if ($paged < $max_pages)  { // если текущая страница меньше общего числа страниц, то выводим кнопку для подгрузки
        $next_page = $paged + 1; // в дата атрибуты кнопки передаем номер следующей страницы и id текущих терминов
        $return_html .= '<a id="load-more-events" href="#" class="btn btn-orange" data-page="'. $next_page .'" data-service-id="'. $service_id .'" data-country-id="'.$country_id.'">Load More</a>';
    }
    wp_reset_postdata();
    echo $return_html; // возвращаем html код
    wp_die(); // обязательно "умираем"
}

add_action(‘wp_ajax_get_projects’, ‘get_projects’); // наши хуки
add_action(‘wp_ajax_nopriv_get_projects’, ‘get_projects’);
?>

Результат работы кода:

Как добавить кнопку сброса всех фильтров до первоначального состояния чтоб повторно отфильтровать?

Нужно послать ajax на get_projects без параметров сервиса, страны и страницы. И вам прилетит просто первая страница сервисов. Ну и сбросить фильтры в первоначальное положение с помощью jQuery.

Более подробно можно почитать здесь: https://wp-kama.ru/id_2018/ajax-v-wordpress.html