Очередная попытка сделать фильтр 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]
Что-то у меня сайт ложится, когда пытаюсь добавить этот код в functions.php
Это сложный функционал. Тут однозначно не смогу сказать где может быть ошибка. Смотрите на какой строке ошибка php.