/ Wordpress / Фильтр Ajax

Фильтр Ajax

HIT

10.10.2017

6659

2

Очередная попытка сделать фильтр wordpress, в этот раз применяя технологию ajax. По сути программирование фильтра — это изобретение велосипеда, но есть 2 момента: во-первых в процессе я начинаю лучше понимать процессы и механизмы wordpress, во-вторых я могу создать фильтр который мне необходим для конкретной задачи.

Итак, фильтр состоит из 3-х компонентов:

1. Сама форма фильтра и область вывода результатов.
2. Функция обработчик, которая по сути создает новый измененный запрос.
3. Скрипт js который доставляет без перезагрузки информацию на сервер и обратно.

Форма фильтра

Форма практически ничем не отличается от формы обычного фильтра. Стили можно также взять из того же фильтра.

<div id="filter"> 
<form class="filter" action="" method="">
  
<?php 

$getcat = get_the_category();
if($getcat[0]){
$cat_id=$getcat[0]->term_id;
}

//$cat_id = 35;

$args = array( 
'posts_per_page' => -1, 
'cat' => $cat_id,
//'post_type' => 'slide' 
);
$catposts = get_posts( $args );
?>	
	
	
  
<!-- Фильтр по произвольному полю -->	
	
<div><span class="name-group">Метаполя</span>
<span class="group-filter">  

<?php
foreach( $catposts as $post ){ 
  
setup_postdata($post);
							   						  
$all_meta_objects = get_post_meta($post->ID, 'country', true); // Для одиночных значений метаполей
$all_email_objects = get_post_meta($post->ID, 'power', true);							  
							  							  			  
if($all_meta_objects){ 
  $all_meta_ids[] = $all_meta_objects;
}
							  
if($all_email_objects){ 	
$all_meta2_ids[] = $all_email_objects;
}	
							  
}

wp_reset_postdata();
    
  
if ( $all_meta_ids ): ?>
  
<?php $meta_ids_unique = array_unique($all_meta_ids); ?> 
  
<label><select name="country" id="country">  
<option value=""></option>

<?php foreach($meta_ids_unique as $meta): ?>
  
<option value="<?php echo $meta; ?>"><?php echo $meta; ?> 
  
(<?php $args = array(
    //'post_type' => 'slide',
	'cat' => $cat_id,
    'meta_key' => 'country',
    'meta_value' => $meta,
    'posts_per_page' => -1); 

$posts = get_posts($args);
$number = 0;
foreach ($posts as $post) :
    $number++;
endforeach;

echo $number;
wp_reset_query(); ?>)</option>    

<?php endforeach; ?>
  
</select></label>  

<?php endif; ?>	
  
<?php if ( $all_meta2_ids ): ?>
  
<?php $meta2_ids_unique = array_unique($all_meta2_ids); ?>  
  
<label><select name="power" id="power"> 
<option value=""></option> 

<?php foreach($meta2_ids_unique as $meta2): ?>  
  
<option value="<?php echo $meta2; ?>"><?php echo $meta2; ?></option> 
  
<?php endforeach; ?>
  
</select></label>
  
<?php endif; ?>	
  
</span></div>

<div>
<span class="name-group">Даты записей</span>  
<span class="group-filter">   

<div class="box">с <input type="date" name="date-68" value="" class="textbox" id="date-after"></div>
<div class="box">по <input type="date" name="date-69" value="" class="textbox" id="date-before"></div>
  
</span>  
</div>



<!-- Фильтр по меткам -->
  
<div>
<span class="name-group">Метка</span> 
<span class="group-filter">	  
<?php

foreach( $catposts as $post ){ setup_postdata($post);
							   
	$all_tag_objects = get_the_tags();												  
							  
	if($all_tag_objects){
  
		foreach($all_tag_objects as $tag) {
		  
			if($tag->count > 0) { $all_tag_ids[] = $tag->term_id; }
		}
	}						   
}

wp_reset_postdata();




if ( $tag->count > 0 ): ?>
  
<?php $tag_ids_unique = array_unique($all_tag_ids); ?>  

<?php foreach($tag_ids_unique as $tag_id): ?>
  
  
<?php $post_tag = get_term( $tag_id, 'post_tag' ); ?>
  
<label>
<input class="metka" type="checkbox" name="tags" 
  value="<?php echo $post_tag->term_id; ?>">
  
 <span><?php echo $post_tag->name; ?> 
 <sup>

<?php 

$args = array(
	'category__in' => $cat_id, 
    'tag__in' => $post_tag->term_id,
    'posts_per_page' => -1
);
	


$posts = get_posts($args);
$number = 0;
foreach ($posts as $post) :
    $number++;
endforeach;

echo $number;
wp_reset_query(); ?> 
 
 </sup></span>
</label>  

<?php endforeach; ?>

<?php endif; ?>		  
</span>
</div>






<!-- Фильтр по терминам произвольной таксономии -->

<div><span class="name-group">Лэйбл</span> 
<span class="group-filter">	

<?php

foreach( $catposts as $post ){ setup_postdata($post);
							   						  
$all_term_objects = wp_get_post_terms($post->ID, 'label');							  
							  
							  
						   
if($all_term_objects){
	foreach($all_term_objects as $term) {
			if($term->count > 0) { $all_term_ids[] = $term->term_id;}
		}
	}						   
}

wp_reset_postdata();
    
  
if ( $term->count > 0 ): ?>
  
<?php $term_ids_unique = array_unique($all_term_ids); ?>  
  
<?php foreach($term_ids_unique as $term_id): ?>
  
  
<?php $post_term = get_term( $term_id, 'label' ); ?>


  
<label>
<input class="label" type="checkbox" name="labels" 
  value="<?php echo $post_term->term_id; ?>">

<span><?php echo $post_term->name; ?> 
<sup>
  
<?php $args = array(
	'tax_query' => array(
		array(
			'taxonomy' => 'label',
		    'field' => 'id',
			'terms' => $post_term
		),
	),  
	'cat' => $cat_id,
	'posts_per_page' => -1
);  

$posts = get_posts( $args );

$number = 0;
foreach ($posts as $post) :
    $number++;
endforeach;

echo $number;
wp_reset_query(); ?>   
  
</sup></span>
</label>  

<?php endforeach; ?>

<?php endif; ?>		  
</span>
</div>  




  
<button type="submit" class="taguniq" title="<?php echo $cat_id; ?>"><i class="fa fa-filter" aria-hidden="true"></i>Фильтровать</button>
  
<div id="all" ><i class="fa fa-refresh" aria-hidden="true"></i> Очистить</div>
    
</form>
</div>

Функция-обработчик

Многие строки функции закомментированы, т.к. функция находится на стадии разработки. Скрипт полностью переработан, теперь он работает по технологии смешивания двух различных запросов. т.к. условия meta_query и tax_query в один запрос поместить невозможно, также и tax_query и tag. А остальные параметры можно добавлять к финальному объединенному запросу.

function ajax_filter_posts_scripts() {

  wp_register_script( 'afp_script', plugins_url('/ajax-filter-posts.js', __FILE__), array('jquery'), null, false );
  wp_enqueue_script( 'afp_script' );

  wp_localize_script( 'afp_script', 'afp_vars', array(
        'afp_nonce' => wp_create_nonce( 'afp_nonce' ), // Create nonce which we later will use to verify AJAX request
        'afp_ajax_url' => admin_url( 'admin-ajax.php' ),
      )
  );
}
add_action('wp_enqueue_scripts', 'ajax_filter_posts_scripts', 100);


// Собственно фильтр изменяющий запрос

function ajax_filter_get_posts() { 
  
//echo 'Поле1: ' .$_POST['taxonomy'];
//echo 'Поле2: ' .$_POST['taxonomy2']; 
  
//echo 'Метки: ' .$_POST['tags'];
//echo 'Лэйбл: ' .$_POST['labels'];  

//echo 'От: ' .$_POST['date'];
//echo 'До: ' .$_POST['date2']; 

//echo 'Количество: ' .$_POST['number'];
//echo 'Сортировать: ' .$_POST['sort'];
//echo 'Страница: ' .$_POST['pagine'];

  
  
// first query
if ($_POST['taxonomy'] != '') { 
$country =  $_POST['taxonomy'];
} else {
$country = 0;  
}

if ($_POST['taxonomy2'] != '') { 
$power =  $_POST['taxonomy2'];
} else {
$power = 0;  
}

$first_ids = get_posts( array(
    'fields'         => 'ids',
    'posts_per_page' => -1,
	'meta_query' => array(
  			'relation' => 'OR',
  			array(
			'key' => 'country',
			'value' => $country
			),
			array(
			'key' => 'power',
			'value' => $power
			)
	)
    
));

// second query
$tags = explode(" ", $_POST['tags']);

if ($_POST['labels'] != '') { 
$labels = explode(" ", $_POST['labels']);
} else {
$labels = 0;  
}

$second_ids = get_posts( array(
    'fields'         => 'ids',
	'posts_per_page' => -1,
	'tax_query' => array(
			'relation' => 'OR', //AND - записи которые одновременно входят в указанные таксономии; OR - записи принадлежащие любой из указанных таксономий
			array(
			'taxonomy' => 'post_tag',
  			'field'    => 'id',
			'terms'    => $tags,
            'operator' => 'IN' //AND - в записи должны быть все выбранные термины, IN - в записи должен быть хотя бы один из выбранных терминов
			),
			array(
			'taxonomy' => 'label',
  			'field'    => 'id',
			'terms'    => $labels,
            'operator' => 'IN'
			)
	)
)); 
  

// merging ids
$post_ids = array_merge( $first_ids, $second_ids);
  
//print_r ($post_ids);  
  
$args = array( 
  'post_type' => 'post',
  'post_status' => 'publish',
  'cat' => $_POST['category'],
  'posts_per_page' => $_POST['number'],
  'paged' => $_POST['pagine'], 
  'post__in'  => $post_ids,
  
);
  
$args['date_query'][] = array(
			'after'     => $_POST['date'],
			'before'    => $_POST['date2'],
			'inclusive' => true,
);

// Варианты сортировки
if ($_POST['sort'] == 'newest')  { $args['orderby'] = 'date'; $args['order'] = 'DESC';}
if ($_POST['sort'] == 'lastest') { $args['orderby'] = 'date'; $args['order'] = 'ASC'; }
if ($_POST['sort'] == 'title')   { $args['orderby'] = 'title'; $args['order'] = 'ASC';}
if ($_POST['sort'] == 'correct') { $args['orderby'] = 'modified';}
if ($_POST['sort'] == 'power')   { $args['orderby'] = 'meta_value_num'; $args['meta_key'] = 'power';}
if ($_POST['sort'] == 'count')   { $args['orderby'] = 'meta_value_num'; $args['meta_key'] = 'post_views_count';}

  
$theme_post_query = new WP_Query( $args );



while( $theme_post_query->have_posts() ) : 
   
$theme_post_query->the_post();
  
include(TEMPLATEPATH."/solus.php");  
  
endwhile;
  
 
 
// количество записей в дополнительном запросе 
if ($theme_post_query->found_posts == 0) {
  echo 'Нет записей удовлетворяющих запросу';
} else {
  echo 'В дополнительном запросе ';
  plural_form(
    $theme_post_query->found_posts,
    array('запись','записи','записей')
  );
}
  

//пэйджинация
if (  $theme_post_query->max_num_pages > 1 ) {
  
echo '<label><select name="posts_per_page" id="pagine">';
echo '<option value="1">1</option>';
 
echo $theme_post_query->max_num_pages;
echo ' страниц<br>';  

$i = 2;
  
while( $i <= $theme_post_query->max_num_pages ) :  
  
  echo '<option value="'.$i.'">'.$i.'</option>';
  
$i++;
  
endwhile;
  echo '</select></label>';
}


  
  
  
exit;  
}


add_action('wp_ajax_filter_posts', 'ajax_filter_get_posts');
add_action('wp_ajax_nopriv_filter_posts', 'ajax_filter_get_posts');

Дополнил сортировкой и пока примитивной пэйджинацией (возможно нужно взять стандартную функцию пэйджинации и перезагружать ее). Чтобы работала сортировка где-то на странице нужно вывести это:

<div id="posts-sorting">
  
<form method="get" id="sorting" action="">
<div><span class="group-filter">  
  
<label><select name="select" id="sort">
<option value="">Исходная сортировка</option>  
<option value="lastest">по дате (сначала старые)</option>
<option value="title">по заголовку</option>  
<option value="correct">по дате изменения</option>
<option value="power">по мощности</option>
<option value="count">по количеству просмотров</option> 
</select></label>
  
<label><select name="posts_per_page" id="number">
<option value="">по 20 записей</option>  
<option value="40">по 40 записей</option>
<option value="60">по 60 записей</option>  
<option value="-1">все</option>
</select></label> 
  
</span></div>	  
</form>
  
</div>

Параметры произвольных полей

В фильтре у нас может встречаться множество произвольных полей. Необходимо выбрать принцип их взаимодействия:

  • AND — выводить записи содержащие оба поля
  • OR — выводить записи содержащие одно из полей

Но есть такой момент, что если в фильтре мы не выберем значения, то переменная передаст пустое значение и параметр выдаст все записи, у которых этот metakey пустой. Чтобы этого избежать делаем такую проверку,для разных полей она может быть разной:

if ($_POST['taxonomy'] != '') { 
$country =  $_POST['taxonomy'];
} else {
$country =  0;  
}

Либо можно придумать какой либо универсальный символ, которые не будет встречаться ни в одном meta — $country = ‘_’;

JS скрипт

Данный скрипт отлавливает значения полей формы и доставляет их в обработчик, и заменяет содержимое блока вывода результатов. Дополнил скрипт альтернативным срабатыванием по изменению формы (но в этом случае, нужно вовсе убирать кнопку Фильтровать, т.к. она будет обновлять страницу).

jQuery(document).ready(function($) {
	
		//$('.taguniq').click( function(event) { //По нажатию на кнопку
		$('.filter').on('change', function () {  //При изменении формы

		// Prevent defualt action - opening tag page
		if (event.preventDefault) {
			event.preventDefault();
		} else {
			event.returnValue = false;
		}

		// Get tag slug from title attirbute

	    var category = $(this).attr('title'); //Чтобы брать из этой же категории
	    var sortValues = $("#country option:selected").val();
	    var sortValues2 = $("#power option:selected").val();
	    var sortValues3 = $("#date-after").val();
	    var sortValues4 = $("#date-before").val();
	    var sortValues4 = $("#date-before").val();

	  
	    var arrList = $('.metka:checkbox:checked').map(function(){
    		return $(this).attr('value');
		}).get();
		var tags = arrList.join(', '); // преобразовываем массив в строку с разделителем ' '
		
		//alert (tags);
		
		var arrList = $('.label:checkbox:checked').map(function(){
    		return $(this).attr('value');
		}).get();
		var labels = arrList.join(', ');
			

		$('.tagged-posts').fadeOut();

		data = {
			action: 'filter_posts',
			afp_nonce: afp_vars.afp_nonce,
		    category: category,
			taxonomy: sortValues,
		    taxonomy2: sortValues2,
		    date: sortValues3,
		    date2: sortValues4,
		    tags: tags,
		  	labels:labels,
		};
	  
	  
		$.ajax({
			type: 'post',
			dataType: 'html',
			url: afp_vars.afp_ajax_url,
			data: data,
			success: function( data, textStatus, XMLHttpRequest ) {
				$('.tagged-posts').html( data );
				$('.tagged-posts').fadeIn();
				console.log( textStatus );
				console.log( XMLHttpRequest );
			},
			error: function( MLHttpRequest, textStatus, errorThrown ) {
				console.log( MLHttpRequest );
				console.log( textStatus );
				console.log( errorThrown );
				$('.tagged-posts').html( 'No posts found' );
				$('.tagged-posts').fadeIn();
			}
		})

	});
  
  
  
  	$('#all').click( function(event) {
	  

		// Получаем данные из различных атрибутов
	    var selecetd_cat = $('#curcat').attr('title');
 

		$('.tagged-posts').fadeOut();

		data = {
			action: 'filter_posts',
			afp_nonce: afp_vars.afp_nonce,
		    category: selecetd_cat, //Не передаем лишних параметров
		};
	  

		$.ajax({
			type: 'post',
			dataType: 'html',
			url: afp_vars.afp_ajax_url,
			data: data,
			success: function( data, textStatus, XMLHttpRequest ) {
				$('.tagged-posts').html( data );
				$('.tagged-posts').fadeIn();
				console.log( textStatus );
				console.log( XMLHttpRequest );
			},
			error: function( MLHttpRequest, textStatus, errorThrown ) {
				console.log( MLHttpRequest );
				console.log( textStatus );
				console.log( errorThrown );
				$('.tagged-posts').html( 'No posts found' );
				$('.tagged-posts').fadeIn();
			}
		})
	  
	  
    });
  
});

Поделиться в соц. сетях:

  • Похожие записи
  • Комментарии
  • Вложения
Отложенная загрузка изображений

Отложенная загрузка изображений

Если на странице есть несколько изображений или есть изображения дублирующиеся на всех страницах (header, footer), то чтобы ускорить общую загрузку сайта, можно установить для изображений отложенную загрузку. Изображение будет появляться Читать далее »

Имитация Ajax загрузки контента

Имитация Ajax загрузки контента

Создадим эффект перехода внутри сайта имитирующий подгрузку контента ajax’ом, как будто без перезагрузки. Принцип эффекта: при переходе по ссылке плавно скрываем изменяемую часть контента, и при загрузке новой плавно ее Читать далее »

WooCommerce AJAX Products Filter

WooCommerce AJAX Products Filter

Раннее данный фильтр участвовал в общем обзоре, в котором я приводил основные особенности. Рассмотрим подробнее работу с фильтром WooCommerce AJAX Products Filter (также он называется Advanced AJAX Product Filters). Работа Читать далее »

/

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

2 комментария

  1. Илья

    Что-то у меня сайт ложится, когда пытаюсь добавить этот код в functions.php

    1. Alexandr

      Это сложный функционал. Тут однозначно не смогу сказать где может быть ошибка. Смотрите на какой строке ошибка php.

Фильтр Ajax
Разница изображений было/стало
Рекомендации для васРазница изображений было/сталоOpttour.ru
Спасибо! Наш менеджер свяжется с Вами в течении 5 минут.