Create an asynchronous AJAX filter, which allows to filter posts by taxonomy terms and meta values.
See live working filter here
Create a page template template-resources.php
<?php /** * Template Name: Resources Page */ $blog_posts_query = new WP_Query([ 'post_type' => 'resources', 'posts_per_page' => -1, 'tax_query' => array( 'relation' => 'AND', // redundant default value 'AND' but I still put it in.. array( 'taxonomy' => 'resources_cat', 'field' => 'id', 'terms' => 'resources', //'terms' => array(39,40,41,42,43,44,45,46,47), ), ) ]); ?> <?php get_header(); ?> <?php partial('partials/hero'); ?> <div class="wrapper" id="page-wrapper"> <div class="resources-section s-pt-6 s-pb-6"> <div class="container"> <div class="row"> <div class="col-md-4"> <form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php" method="POST" id="filter"> <div class="filters"> <h2>Search Resources</h2> <div class="quicksearch-container"> <span class="material-icons">search</span><input type="text" name="quicksearch" class="quicksearch" placeholder="Search Keyword ..." /> </div> <?php // Get the taxonomy's terms $terms = get_terms( array( 'taxonomy' => 'resources_cat', 'hide_empty' => false, ) ); // Check if any term exists if ( ! empty( $terms ) && is_array( $terms ) ) { ?> <div class="ui-group ui-group-type d-none"> <p>Publications: </p> <select name="categoryfilter"> <option value="">All</option> <?php foreach ( $terms as $term ) { ?> <option value="<?php echo $term->term_id; ?>"><?php echo $term->name; ?></option> <?php } ?> </select> </div> <?php } ?> <div class="ui-group ui-group-type"> <p>Type: </p> <select name="typefilter"> <option value="">All</option> <option value="video">Video</option> <option value="article">Article</option> <option value="whitepaper">Whitepaper</option> <option value="posters-presentations">Posters & Presentations</option> <option value="sds">SDS</option> </select> </div> <div class="ui-group ui-group-product"> <p>Product: </p> <select name="productfilter"> <option value="">All</option> <option value="mt-prep-extraction">MT-Prep Extraction</option> <option value="puryx-extraction">Puryx Extraction</option> <option value="mt-pcr">MT-PCR</option> <option value="robotic-platforms">Robotic platforms</option> </select> </div> <div class="ui-group ui-group-topic"> <p>Topic: </p> <select name="topicfilter"> <option value="">All</option> <option value="covid19">COVID19</option> <option value="respiratory">Respiratory</option> <option value="enteric-pathogens">Enteric Pathogens</option> <option value="urinogenital-hpv">Urinogenital & HPV</option> <option value="drug-resistance">Drug Resistance</option> <option value="critical-testing">Critical testing</option> <option value="fungal">Fungal</option> <option value="genetics">Genetics</option> <option value="small-animals">Small animals</option> <option value="livestock">Livestock</option> <option value="agricultural-farming">Agricultural & Farming</option> <option value="water-testing">Water testing</option> <option value="food-testing">Food testing</option> </select> </div> <div class="ui-group ui-group-date"> <p>Year: </p> <select name="yearsfilter"> <option value="">All</option> <option value="2005">2005</option> <option value="2006">2006</option> <option value="2007">2007</option> <option value="2008">2008</option> <option value="2009">2009</option> <option value="2010">2010</option> <option value="2011">2011</option> <option value="2012">2012</option> <option value="2013">2013</option> <option value="2014">2014</option> <option value="2015">2015</option> <option value="2016">2016</option> <option value="2017">2017</option> <option value="2018">2018</option> <option value="2019">2019</option> <option value="2020">2020</option> <option value="2021">2021</option> </select> </div> <div class="button-group"> <button class="btn btn-primary">Apply Filter</button> <input type="hidden" name="action" value="myfilter"> </div> </div> </form> </div> <div class="col-md-8"> <div id="response"> <?php if ($blog_posts_query->have_posts()): ?> <?php while ($blog_posts_query->have_posts()): ?> <?php $blog_posts_query->the_post(); ?> <?php $file = get_field('file'); $name = get_field('display_file_name'); $updated = get_field('add_updated_date'); $note = get_field('note'); $icon = get_field('add_file_icon'); $link = get_field('link'); $video = get_field('video', false, false); /* FILTERS */ $types = get_field('filter_types'); $products = get_field('filter_products'); $topics = get_field('filter_topics'); $years = get_field('filter_years'); ?> <div class="color-shape resource <?php if( $types ): foreach( $types as $type ): echo $type.' '; endforeach; endif; if( $products ): foreach( $products as $product ): echo $product.' '; endforeach; endif; if( $topics ): foreach( $topics as $topic ): echo $topic.' '; endforeach; endif; echo $years;?>"> <?php if( $file || $link || $video): ?> <?php if(!empty( $link)): $link_url = $link['url']; $link_title = $link['title']; $link_target = $link['target'] ? $link['target'] : '_self'; ?> <a href="<?php echo esc_url( $link_url ); ?>" target="<?php echo esc_attr( $link_target ); ?>"> <?php else: ?> <?php if( $icon == 'download' ): ?> <a href="<?php echo $file['url']; ?>" target="_blank" download> <?php elseif( $icon == 'video' ): ?> <a href="<?php echo $video; ?>" target="_blank"> <?php else: ?> <a href="<?php echo $file['url']; ?>" target="_blank"> <?php endif; ?> <?php endif; ?> <?php if( $icon == 'link' ) { echo '<span class="iconify" data-icon="eva:external-link-fill" data-inline="false"></span>'; }elseif( $icon == 'download' ) { echo '<span class="iconify" data-icon="bx:bxs-download" data-inline="false"></span>'; }elseif( $icon == 'video' ) { echo '<span class="iconify" data-icon="dashicons:format-video" data-inline="false"></span>'; }else{ echo '<span class="iconify" data-icon="mdi-file-pdf" data-inline="false"></span>'; } ?> <?php echo get_the_title() ?> <?php if( $name ): echo '<span>('.$name.')</span>'; endif; ?> <?php if( $note ): echo '<span>('.$note.')</span>'; endif; ?> <?php if( $updated ): echo '<span>('.$updated.')</span>'; endif; ?></a> <?php else: ?> <?php echo get_the_title() ?> <?php if( $name ): echo '<span>('.$name.')</span>'; endif; ?> <?php if( $note ): echo '<span>('.$note.')</span>'; endif; ?> <?php if( $updated ): echo '<span>('.$updated.')</span>'; endif; ?> <?php endif; ?> </div> <?php endwhile; ?> <?php endif; ?> </div> </div> </div> </div> </div> <!-- <?php //nu__display_section_builder(); ?> --> <!--?php if (!get_field("disable_cta")): ?> <?php //partial('partials/global--cta-section'); ?> <?php //endif; ?> --> </div> <?php get_footer();
Add JS Code resources.js
;(function ($) { $('#filter').submit(function(){ var filter = $('#filter'); $.ajax({ url:filter.attr('action'), data:filter.serialize(), // form data type:filter.attr('method'), // POST beforeSend:function(xhr){ filter.find('button').text('Processing...'); // changing the button label }, success:function(data){ filter.find('button').text('Apply filter'); // changing the button label back $('#response').html(data); // insert data } }); return false; }); })(jQuery)
Add PHP Code for resource
<?php $file = get_field('file'); $name = get_field('display_file_name'); $updated = get_field('add_updated_date'); $note = get_field('note'); $icon = get_field('add_file_icon'); $link = get_field('link'); $video = get_field('video', false, false); /* FILTERS $types = get_field('filter_types'); $products = get_field('filter_products'); $topics = get_field('filter_topics'); $years = get_field('filter_years'); */ ?> <div class="resource"> <?php if( $file || $link || $video): ?> <?php if(!empty( $link)): $link_url = $link['url']; $link_title = $link['title']; $link_target = $link['target'] ? $link['target'] : '_self'; ?> <a href="<?php echo esc_url( $link_url ); ?>" target="<?php echo esc_attr( $link_target ); ?>"> <?php else: ?> <?php if( $icon == 'download' ): ?> <a href="<?php echo $file['url']; ?>" target="_blank" download> <?php elseif( $icon == 'video' ): ?> <a href="<?php echo $video; ?>" target="_blank"> <?php else: ?> <a href="<?php echo $file['url']; ?>" target="_blank"> <?php endif; ?> <?php endif; ?> <?php if( $icon == 'link' ) { echo '<span class="iconify" data-icon="eva:external-link-fill" data-inline="false"></span>'; }elseif( $icon == 'download' ) { echo '<span class="iconify" data-icon="bx:bxs-download" data-inline="false"></span>'; }elseif( $icon == 'video' ) { echo '<span class="iconify" data-icon="dashicons:format-video" data-inline="false"></span>'; }else{ echo '<span class="iconify" data-icon="mdi-file-pdf" data-inline="false"></span>'; } ?> <?php echo get_the_title() ?> <?php if( $name ): echo '<span>('.$name.')</span>'; endif; ?> <?php if( $note ): echo '<span>('.$note.')</span>'; endif; ?> <?php if( $updated ): echo '<span>('.$updated.')</span>'; endif; ?></a> <?php else: ?> <?php echo get_the_title() ?> <?php if( $name ): echo '<span>('.$name.')</span>'; endif; ?> <?php if( $note ): echo '<span>('.$note.')</span>'; endif; ?> <?php if( $updated ): echo '<span>('.$updated.')</span>'; endif; ?> <?php endif; ?> </div>
Add Codes in function.php
add_action('wp_ajax_myfilter', 'brens_filter_function'); // wp_ajax_{ACTION HERE} add_action('wp_ajax_nopriv_myfilter', 'brens_filter_function'); function brens_filter_function(){ $args = array( 'post_type' => 'resources', 'posts_per_page' => -1, 'orderby' => 'date', // we will sort posts by date 'order' => $_POST['date'], 'tax_query' => array( 'relation' => 'AND', // redundant default value 'AND' but I still put it in.. array( 'taxonomy' => 'resources_cat', 'field' => 'id', 'terms' => 'resources', //'terms' => array(39,40,41,42,43,44,45,46,47), ), ) ); // SEARCH //if( isset( $_POST['quicksearch']) && $_POST['categoryfilter'] ): if( isset( $_POST['quicksearch'])) $search_query = sanitize_text_field( $_POST['quicksearch'] ); $args = array( 'post_type' => 'resources', 'posts_per_page' => -1, 's' => $search_query, 'orderby' => 'date', 'order' => $_POST['date'], 'tax_query' => array( 'relation' => 'AND', // redundant default value 'AND' but I still put it in.. array( 'taxonomy' => 'resources_cat', 'field' => 'id', //'terms' => $_POST['categoryfilter'], 'terms' => 'resources', //'terms' => array(39,40,41,42,43,44,45,46,47), ), ) ); /*else: $search_query = sanitize_text_field( $_POST['quicksearch'] ); $args = array( 'post_type' => 'resources', 's' => $search_query, 'orderby' => 'date', 'order' => $_POST['date'], 'tax_query' => array( 'relation' => 'AND', // redundant default value 'AND' but I still put it in.. array( 'taxonomy' => 'resources_cat', 'field' => 'id', 'terms' => array(39,40,41,42,43,44,45,46,47), ), ) ); endif;*/ // TYPE if( isset( $_POST['typefilter'] ) ) $args['meta_query'][] = array( 'key' => 'filter_types', 'value' => $_POST['typefilter'], 'compare' => 'LIKE' ); // PRODUCT if( isset( $_POST['productfilter'] ) ) $args['meta_query'][] = array( 'key' => 'filter_products', 'value' => $_POST['productfilter'], 'compare' => 'LIKE' ); // TOPIC if( isset( $_POST['topicfilter'] ) ) $args['meta_query'][] = array( 'key' => 'filter_topics', 'value' => $_POST['topicfilter'], 'compare' => 'LIKE' ); // YEARS if( isset( $_POST['yearsfilter'] ) ) $args['meta_query'][] = array( 'key' => 'filter_years', 'value' => $_POST['yearsfilter'], 'compare' => 'LIKE' ); // if you want to use multiple checkboxed, just duplicate the above 5 lines for each checkbox $query = new WP_Query( $args ); if( $query->have_posts() ) : while( $query->have_posts() ): $query->the_post(); echo partial('partials/resource'); endwhile; wp_reset_postdata(); else : echo '<p>No resources found</p>'; endif; die(); }
SCSS Code for the resources page
body.page-template-template-resources, body.page-template-template-resources-test{ .filters{ @include pr(calc(8.33333% + 30px)); @include mb(2rem); @include media-breakpoint-down(lg) { @include pr(30px); } @include media-breakpoint-down(md) { @include pr(0); } .quicksearch-container{ border-bottom: 2px solid $grey; @include py(1rem); height: 54px; @include mt(2rem); .material-icons{ color: $link-colour; font-size: 1rem; } input{ border: none; font-size: 0.875rem; font-weight: $font-weight-semibold; color: $link-colour; width: calc( 100% - 1rem); &:active, &:focus{ outline: none; background-color: none; } } } .ui-group{ border-bottom: 2px solid $grey; position: relative; display: block; width: 100%; p{ @include py(1rem); float: left; font-size: 0.875rem; font-weight: $font-weight-semibold; color: $link-colour; @include mb(0); height: 54px; } select{ float: right; border: none; @include py(1rem); font-size: 0.875rem; font-weight: $font-weight-semibold; color: $link-colour; -webkit-appearance: none; -moz-appearance: none; appearance: none; /* Remove default arrow */ background-image: url('../img/select-drop-down-grey.png'); background-repeat: no-repeat; background-position: right center; background-size: 16px 16px; &:active, &:focus{ outline: none; } } &:after{ content:""; display: block; clear: both; } &-type{ select{ width: calc( 100% - 86px ); } } &-product{ select{ width: calc( 100% - 86px ); //width: calc( 100% - 57px ); } } &-topic{ select{ width: calc( 100% - 86px ); //width: calc( 100% - 40px ); } } &-date{ select{ width: calc( 100% - 86px ); //width: calc( 100% - 38px ); } } } .button-group{ @include mt(2rem); .btn{ min-width: 100%; &:focus, &:active{ outline: none; } } } } .grid, #response{ @include mt(1rem); &:after { content: ''; display: block; clear: both; } } .resource{ @include mb(2rem); position: relative; font-size: 1.125rem; font-weight: $font-weight-light; width: 100%; .iconify{ color: $secondary; position: absolute; top:4px; left: 0; font-size: 1.125rem; width: 20px; height: 20px; } a{ color: $text-colour; @include pl(1.5rem); display: block; transition: all 0.3s ease; &:hover{ text-decoration: none; color: $secondary; } span{ color: $link-colour; } } } } * { box-sizing: border-box; }