I've created an Ajax category filter to display the posts on my website. The filter uses input
checkboxes, so the user can select one or multiple categories.
The issue is when I select a category (or various) it displays all the posts, it doesn't filter.
What I'm also trying to do is when none of the categories are selected, it should always display all the posts by default.
The PHP filter:
<?php if( $terms = get_terms( array( 'taxonomy' => 'category', 'parent' => 0, 'hide_empty' => true ) ) ) : echo ' <form data-ajax-url="'. get_site_url() .'/wp-admin/admin-ajax.php" method="POST" id="filter" class="js-filter"> <ul class="js-filter-list">'; foreach( $terms as $term ) : $term_id = $term->term_id; $term_name = $term->name; $term_slug = $term->slug; $term_color = get_term_meta( $term_id, 'post-category-settings__color', true ); echo ' <li class="js-filter-item js-filter-term" data-slug="'. esc_attr( $term_slug ) .'"> <input type="checkbox" class="c-filter__check" id="' . esc_attr($term_id) . '" name="' . esc_attr($term_id) . '" /> <label class="semi-medium" for="' . esc_attr($term_id) . '"><span></span>' . esc_html($term_name) . '</label> </li>'; endforeach; echo ' </ul> <input type="hidden" name="action" value="filterpost"> </form>'; endif; ?> <div class="js-container"></div>
The Javascript:
if (document.querySelector('.js-filter')) { const ajax_url = document.querySelector(".js-filter").dataset.ajaxUrl; let filterBtn = document.querySelectorAll('.js-filter-term'); var i; for( i = 0; i < filterBtn.length; i++ ){ filterBtn[i].addEventListener('change', function(){ const containerTerm = document.querySelector(".js-container"); const data = new FormData(); let term_slug = this.dataset.slug; data.append( 'action', 'filterpost' ); data.append( 'category', term_slug ); fetch(ajax_url, { method: "POST", body: data }) .then((response) => response.text()) .then((data) => { if (data) { containerTerm.innerHTML=data; } }) .catch((error) => { }); }); }; }
The Ajax handler:
<?php function site_filter_post() { if( $terms = get_terms( array( 'taxonomy' => 'category' ) ) ) : $terms_list = array(); foreach( $terms as $term ) { if( isset( $_POST[$term->term_id ] ) && $_POST[$term->term_id] == 'on' ) $terms_list[] = $term->slug; } endif; $tax_query = array( 'relation' => 'AND' ); if ( ! empty( $terms_list ) ) { $tax_query[] = array( array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => $terms_list, ) ); } $args = array( 'post_type' => 'post', 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'date', 'tax_query' => $tax_query ); $query = new WP_Query( $args ); if($query->have_posts()) { while($query->have_posts()) : $query->the_post(); get_template_part( 'template-parts/content', 'archive' ); endwhile; } else { echo 'No result.'; } exit; } add_action('wp_ajax_filterpost', 'site_filter_post'); add_action('wp_ajax_nopriv_filterpost', 'site_filter_post'); ?>
EDIT
I think the problem comes from my JS code. I made a test with jQuery and it works. Howvever I don't want to use jQuery, only pure Javascript.
The jQuery code:
$('.js-filter').change(function(){ var filter = $('.js-filter'); $.ajax({ url:filter.attr('action'), data:filter.serialize(), type:filter.attr('method'), beforeSend:function(xhr){ }, success:function(data){ $('.js-ajax-response').html(data); } }); return false; });
Thanks!