How to create AJAX Post Filters only 3 step
Table of Contents
So many people asks me about post filters. So I decided to write a simple post about it — so everyone could understand how it works
In this post I will show you how to create an asynchronous AJAX filter by yourself, which allows to filter posts by taxonomy terms, meta values and sort results by publish date.
I do not recommend to use plugins for these purposes if possible.
Step 1. Everything begins with a HTML form
Our filter form will consist of 4 parts. I’ll describe each part of the form separately.
1.1 Filter posts by a category or by taxonomy terms
First part of the form is a dropdown <select>
of taxonomies. To create that <select>
you can freely use get_terms()
function. This function works not only for custom taxonomies but for default categories and tags as well.
if( $terms = get_terms( array( 'taxonomy' => 'category', // to make it simple I use default categories 'orderby' => 'name' ) ) ) : // if categories exist, display the dropdown echo '<select name="categoryfilter"><option value="">Select category...</option>'; foreach ( $terms as $term ) : echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as an option value endforeach; echo '</select>'; endif;
You can replace the taxonomy
parameter value on line 2 with any custom taxonomy name or post_tag
.
By the way, it is also possible to combine this code with my multisite plugin and network_get_terms() function. So, all network categories will be in the select dropdown and all the network posts will be displayed as the filter search results.
1.2 Filter posts by custom field values as well
I use range of prices. In our case price is a custom field value that is stored in wp_postmeta
table under the _price
key in database.
<input type="text" name="price_min" placeholder="Min price" /> <input type="text" name="price_max" placeholder="Max price" />
I will show you how to create a meta_query
filter in step 3 of this tutorial but you can also read more about meta_query
usage here.
1.3 Ascending or Descending Order
Simple radio buttons will help us to sort posts in ascending or descending order.
<label> <input type="radio" name="date" value="ASC" /> Date: Ascending </label> <label> <input type="radio" name="date" value="DESC" selected="selected" /> Date: Descending </label>
For simpleness I decided to sort posts by date only, but you can easily sort posts by name alphabetically or by custom fields values.
1.4 Checkbox filter – Display posts with featured images only
Actually the featured image is just an attachment ID that is stored like a custom field value under _thumbnail_id
key. We will just check if it exists.
<label> <input type="checkbox" name="featured_image" /> Only posts with featured images </label>
You can also add a search field just like a simple <input type="text" />
and in Step 3 use s=
parameter of WP_Query
. Easy-peasy ?
Complete form code
You can skip all the previous field descriptions and use the code below as is. Insert it anywhere you want the filter to be.
<form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php" method="POST" id="filter"> <?php if( $terms = get_terms( array( 'taxonomy' => 'category', 'orderby' => 'name' ) ) ) : echo '<select name="categoryfilter"><option value="">Select category...</option>'; foreach ( $terms as $term ) : echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option endforeach; echo '</select>'; endif; ?> <input type="text" name="price_min" placeholder="Min price" /> <input type="text" name="price_max" placeholder="Max price" /> <label> <input type="radio" name="date" value="ASC" /> Date: Ascending </label> <label> <input type="radio" name="date" value="DESC" selected="selected" /> Date: Descending </label> <label> <input type="checkbox" name="featured_image" /> Only posts with featured images </label> <button>Apply filter</button> <input type="hidden" name="action" value="myfilter"> </form> <div id="response"></div>
Some comments:
- Line #1. I use default WordPress function
site_url()
to get an actual website URL - Line #1.
admin-ajax.php
is the default WordPress AJAX processor. I place it into the form action attribute just for simplicity, you can also get it withadmin_url('admin-ajax.php')
. - Line #23. Hidden input field with the
myfilter
attribute is required — this is how WordPress recognize what function to use. - Line #25.
#response
div element is the container where the code will paste the result data.
Step 2. jQuery script to Send a Request and to Receive Result Data
In this part of the tutorial I suppose that you know just a little bit about jQuery, at least how to include it to a website page. Here is the complete jQuery-based processing code. It will send the request when the form is submitted.
jQuery(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; }); });
Step 3. PHP code to Process the Request
I think it is the most interesting part. In this part you decide how to filter the posts the best way. This code is fully based on WP_Query
. But it is also a good idea to do it with query_posts()
.
add_action('wp_ajax_myfilter', 'misha_filter_function'); // wp_ajax_{ACTION HERE} add_action('wp_ajax_nopriv_myfilter', 'misha_filter_function'); function misha_filter_function(){ $args = array( 'orderby' => 'date', // we will sort posts by date 'order' => $_POST['date'] // ASC or DESC ); // for taxonomies / categories if( isset( $_POST['categoryfilter'] ) ) $args['tax_query'] = array( array( 'taxonomy' => 'category', 'field' => 'id', 'terms' => $_POST['categoryfilter'] ) ); // create $args['meta_query'] array if one of the following fields is filled if( isset( $_POST['price_min'] ) && $_POST['price_min'] || isset( $_POST['price_max'] ) && $_POST['price_max'] || isset( $_POST['featured_image'] ) && $_POST['featured_image'] == 'on' ) $args['meta_query'] = array( 'relation'=>'AND' ); // AND means that all conditions of meta_query should be true // if both minimum price and maximum price are specified we will use BETWEEN comparison if( isset( $_POST['price_min'] ) && $_POST['price_min'] && isset( $_POST['price_max'] ) && $_POST['price_max'] ) { $args['meta_query'][] = array( 'key' => '_price', 'value' => array( $_POST['price_min'], $_POST['price_max'] ), 'type' => 'numeric', 'compare' => 'between' ); } else { // if only min price is set if( isset( $_POST['price_min'] ) && $_POST['price_min'] ) $args['meta_query'][] = array( 'key' => '_price', 'value' => $_POST['price_min'], 'type' => 'numeric', 'compare' => '>' ); // if only max price is set if( isset( $_POST['price_max'] ) && $_POST['price_max'] ) $args['meta_query'][] = array( 'key' => '_price', 'value' => $_POST['price_max'], 'type' => 'numeric', 'compare' => '<' ); } // if post thumbnail is set if( isset( $_POST['featured_image'] ) && $_POST['featured_image'] == 'on' ) $args['meta_query'][] = array( 'key' => '_thumbnail_id', 'compare' => 'EXISTS' ); // 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 '<h2>' . $query->post->post_title . '</h2>'; endwhile; wp_reset_postdata(); else : echo 'No posts found'; endif; die(); }
Now you know the basics and you can easily create filters like this in WordPress
If you still have problems with filters, please leave a comment below.