Рано или поздно, любой веб-разработчик сталкивается с задачей реализации Ajax-фильтрации. Когда-то и я, совершенно не понимал, как это работает и обладая небольшим познаниями в PHP и Javascript, мне казалось, что это мне не по силам. Но на практике, всё оказалось довольно просто (конечно в рамках не очень сложных задач). В этой статье я поделюсь своим опытом и по мере возможности буду дополнять статью полезной информацией.
Совсем немного теории
Нет смысла расписывать какой-то большой теоретический блок, просто коротко объясню как всё это будет работать: мы сделаем простенькую форму фильтрации, затем напишем PHP-функцию, которая будем формировать нужные нам данные (например список постов с нужными нам параметрами), а затем повесим обработчик с помощью Javascript (jQuery), который будет вызывать эту функцию и возвращать результат в нужное на сайте место после отправки формы. В качестве примера, я буду фильтровать произвольный тип записей "Врачи" по таким параметрам как: специализация (таксономия) и стаж (произвольное поле созданное через ACF).
к содержанию ↑Добавляем произвольный тип записи и таксономию
Если вы хотите фильтровать произвольный тип записи и не знаете как её создать, можете воспользоваться этим кодом. Он создаст произвольный тип записи "Врачи" и таксономию "Специализации".
//Регистрация типа записи "Врачи"
function doctors_post_type() {
$labels = array(
'name' => ('Врачи'),
'singular_name' => ('Врач'),
'menu_name' => ('Врачи'),
'name_admin_bar' => ('Врачи'),
'all_items' => ('Все врачи'),
'add_new_item' => ('Добавить врача'),
'add_new' => ('Добавить'),
'new_item' => ('Новый врач'),
'edit_item' => ('Редактировать'),
'update_item' => ('Обновить'),
'view_item' => ('Просмотр'),
'search_items' => ('Поиск'),
'not_found' => ('Не найдено'),
);
$args = array(
'label' => ('Врачи'),
'labels' => $labels,
'supports' => array('title', 'thumbnail', 'editor' ),
'taxonomies' => array('specializaciya'),
'hierarchical' => true,
'supports' => array('title','editor','thumbnail',),
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'menu_position' => 5,
'show_in_admin_bar' => true,
'show_in_nav_menus' => true,
'can_export' => true,
'has_archive' => 'doctors',
'exclude_from_search' => false,
'publicly_queryable' => true,
'capability_type' => 'page',
);
register_post_type( 'doctors', $args );
}
add_action( 'init', 'doctors_post_type' );
//Регистрация таксономии
function doctors_taxonomy() {
register_taxonomy(
'specializaciya',
'doctors',
array(
'hierarchical' => true,
'label' => 'Специализации',
'query_var' => true,
'rewrite' => array(
'slug' => 'doctors',
'with_front' => false
)
)
);
}
add_action( 'init', 'doctors_taxonomy' );
После этого создайте несколько специализаций из админки, для их вывода в фильтре и занесите нескольких врачей. Для это воспользуйтесь плагином ACF, что бы создать нужный набор произвольных полей.
к содержанию ↑Создаём HTML-форму фильтрации
Форма имеет динамические значения. Все значения полей select берутся из базы данных. Естественно адаптируйте под свои задачи. Вставляйте в нужное место своего шаблона.
<form id="filter" action="" method="POST">
<label>Специализации</label>
<?php
//Получаем термины таксономии(список специализаций)
$terms = get_terms( [
'taxonomy' => 'specializaciya',
'hide_empty' => false, //Не выводить специализации в которых нет врачей
]);
?>
<select name="specializaciya">
<?php foreach($terms as $term): ?>
<option value="<?php echo $term->term_id;?>"><?php echo $term->name;?></option>
<?php endforeach; ?>
</select>
<label>Опыт</label>
<?php
//Нужно вывести доступные для фильтрации значения (произвольные поля, в нашем случае количество лет опыта, в вашем случае любые другие поля). Конечно, если данных будет очень много, тот этот подход не подойдёт, нужно будет делать отдельные таблицы в базе данных и использовать произвольные SQL запросы.
$my_experience = new WP_Query;
$experience = $my_experience->query( array(
'post_type' => 'doctors',
'meta_query' => [
'relation' => 'AND',
[
'key' => 'experience',
'compare' => 'EXISTS'
],
]));
//Теперь получаем непосредственно сами значения мета-полей
$options = [];
foreach($experience as $option) {
$options[] = get_field('experience', $option->ID);
}
//Удаляем дубликаты
$select_options = array_unique($options);
?>
<select name="experience">
<?php foreach($select_options as $option): ?>
<option value="<?php echo $value;?>"><?php echo $value;?></option>
<?php endforeach; ?>
</select>
</form>
к содержанию ↑
PHP-функция для формирования результатов
Теперь давайте напишем функцию, которая будет получать отфильтрованные результаты. Напомню, что наш фильтр имеет два поля "Специализация" и "Стаж". Наша функция будет получать эти данные посредствам POST-запроса. Размещаем её в functions.php
<?php
//Добавляем хуки для того, что бы функция запускалась при AJAX-запросе
add_action( 'wp_ajax_getDoctors', 'getDoctors' );
add_action( 'wp_ajax_nopriv_getDoctors', 'getDoctors' );
//Наша функция не будет получать никаких аргументов, весь массив данных будет доступен в глобальном массиве $_POST внутри функции
function getDoctors() {
$my_doctors= new WP_Query;
$doctors = $my_doctors->query( array(
'post_type' => 'doctors',
'meta_query' => [
'relation' => 'AND',
[
'key' => 'experience',
'value' => sanitize_text_field($_POST['experience']),
'compare' => '='
],
'tax_query' => [
'relation' => 'AND',
[
'taxonomy' => 'specializaciya',
'field' => 'term_id',
'terms' => sanitize_text_field($_POST['specializaciya']),
]
]
]));
}//Добавляем хуки для того, что бы функция запускалась при AJAX-запросе
add_action( 'wp_ajax_getDoctors', 'getDoctors' );
add_action( 'wp_ajax_nopriv_getDoctors', 'getDoctors' );
//Наша функция не будет получать никаких аргументов, весь массив данных будет доступен в глобальном массиве $_POST внутри функции
function getDoctors() {
//Формируем запрос для выборки записей
$args = array(
'post_type' => 'doctors',
'meta_query' => [
'relation' => 'AND',
[
'key' => 'experience',
'value' => sanitize_text_field($_POST['experience']),
'compare' => '='
],
'tax_query' => [
'relation' => 'AND',
[
'taxonomy' => 'specializaciya',
'field' => 'term_id',
'terms' => sanitize_text_field($_POST['specializaciya']),
]
]
]);
//Отправляем запрос на выборку
$doctors= new WP_Query($args);
?>
have_posts()) : $doctors->the_post(); ?>
<?php
wp_die();
}//Добавляем хуки для того, что бы функция запускалась при AJAX-запросе
add_action( 'wp_ajax_getDoctors', 'getDoctors' );
add_action( 'wp_ajax_nopriv_getDoctors', 'getDoctors' );
//Наша функция не будет получать никаких аргументов, весь массив данных будет доступен в глобальном массиве $_POST внутри функции
function getDoctors() {
$my_doctors= new WP_Query;
$doctors = $my_doctors->query( array(
'post_type' => 'doctors',
'meta_query' => [
'relation' => 'AND',
[
'key' => 'experience',
'value' => sanitize_text_field($_POST['experience']),
'compare' => '='
],
'tax_query' => [
'relation' => 'AND',
[
'taxonomy' => 'specializaciya',
'field' => 'term_id',
'terms' => sanitize_text_field($_POST['specializaciya']),
]
]
]));
}
Теперь, когда у нас есть каркас формы фильтрации, функция фильтрации, осталось только написать Javascript-код для отправки AJAX-запроса при выборе значений фильтра и отобразить результаты.
к содержанию ↑Отправка AJAX-запроса через jQuery при изменении в форме фильтра
jQuery(function($){
$( "#filter" ).change(function() {
$.ajax({
url: '/wp-admin/admin-ajax.php',
type: 'POST',
data: $('#filter').serialize() + '&action=getDoctors',
beforeSend: function( xhr ) {
//Перед отправкой запроса рекомендую сделать анимацию
},
success: function( data ) {
//Убираем анимацию загрузки, так как данные загружены
//Удаляем данные если они уже вставлены
$('.ajax-result').remove();
//Вставляем данные в нужное место шаблона сайта
$('.main').append(data);
}
});
});
});
Теперь, у вас есть базовый каркас фильтра, который вы можете дорабатывать по собственному усмотрению. По мере возможности я постараюсь дополнить статью, в планах описать механизм добавления пагинации и снять поясняющее видео.
Очень интересно. Попробую создать на предложенной основе свой фильтр