Ajax-фильтр для WordPress своими руками

Комментариев: 3

Рано или поздно, любой веб-разработчик сталкивается с задачей реализации 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);
             }
         });
 });
 });

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

Уведомлять о новых комментариях
Уведомлять
guest
3 комментариев
Inline Feedbacks
View all comments
Dima
Dima
2 лет назад

Очень интересно. Попробую создать на предложенной основе свой фильтр

Этоя
Этоя
2 лет назад

Умственно отсталый код…