/ Wordpress / Фильтр Ajax

Фильтр Ajax

HIT

10.10.2017

7377

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();
			}
		})
	  
	  
    });
  
});
[site-socialshare]
  • Похожие записи
  • Комментарии
  • Вложения
Технология Ajax

Технология Ajax

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

Фильтры Woocommerce

Фильтры Woocommerce

В базовую комплектацию Woocommerce входит набор виджетов для фильтрации товаров. Но данные виджеты необходимо несколько доработать. WooCommerce Навигация по слоям В этом виджете необходимо задать атрибут товара по которому будет Читать далее »

/ /
Фильтр записей на главной странице

Фильтр записей на главной странице

Задокументирую очередной вариант фильтра постов. Фильтр располагается в шаблоне главной страницы. Верстка в шаблоне Подключение ajax и включение функции фильтра (из плагина): Верстка формы фильтра Скрипт отправки значений формы Для Читать далее »

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

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

  1. Илья

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

    1. Alexandr

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

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