В этом посте хочу рассматривается кейс создания 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