Filter WordPress posts by custom taxonomy term with AJAX
Usage in WordPress page:
[ajax_filter_posts per_page="1"]
Or if you would like to use it in your template file:
<?php echo do_shortcode('[ajax_filter_posts per_page="1"]'); ?>
Basically, this is just a get_terms function from WordPress Codex and some additional markup that is needed to make this work properly.
Each anchor tag contains taxonomy and term slug in data attribute, this is required so we can get these data with jQuery and get results for clicked tag.
If you look at the source you will notice that tag looks for example like:
<a href="?path-to-tag" data-tax="post_tag" data-term="term-slug">
functions.php
<?php
/**
* AJAC filter posts by taxonomy term
*/
function vb_filter_posts() {
if( !isset( $_POST['nonce'] ) || !wp_verify_nonce( $_POST['nonce'], 'bobz' ) )
die('Permission denied');
/**
* Default response
*/
$response = [
'status' => 500,
'message' => 'Something is wrong, please try again later ...',
'content' => false,
'found' => 0
];
$tax = sanitize_text_field($_POST['params']['tax']);
$term = sanitize_text_field($_POST['params']['term']);
$page = intval($_POST['params']['page']);
$qty = intval($_POST['params']['qty']);
/**
* Check if term exists
*/
if (!term_exists( $term, $tax) && $term != 'all-terms') :
$response = [
'status' => 501,
'message' => 'Term doesn\'t exist',
'content' => 0
];
die(json_encode($response));
endif;
if ($term == 'all-terms') :
$tax_qry[] = [
'taxonomy' => $tax,
'field' => 'slug',
'terms' => $term,
'operator' => 'NOT IN'
];
else :
$tax_qry[] = [
'taxonomy' => $tax,
'field' => 'slug',
'terms' => $term,
];
endif;
/**
* Setup query
*/
$args = [
'paged' => $page,
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => $qty,
'tax_query' => $tax_qry
];
$qry = new WP_Query($args);
ob_start();
if ($qry->have_posts()) :
while ($qry->have_posts()) : $qry->the_post(); ?>
<article class="loop-item">
<header>
<h2 class="entry-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
</header>
<div class="entry-summary">
<?php the_excerpt(); ?>
</div>
</article>
<?php endwhile;
/**
* Pagination
*/
vb_ajax_pager($qry,$page);
$response = [
'status'=> 200,
'found' => $qry->found_posts
];
else :
$response = [
'status' => 201,
'message' => 'No posts found'
];
endif;
$response['content'] = ob_get_clean();
die(json_encode($response));
}
add_action('wp_ajax_do_filter_posts', 'vb_filter_posts');
add_action('wp_ajax_nopriv_do_filter_posts', 'vb_filter_posts');
/**
* Shortocde for displaying terms filter and results on page
*/
function vb_filter_posts_sc($atts) {
$a = shortcode_atts( array(
'tax' => 'category', // Taxonomy
'terms' => false, // Get specific taxonomy terms only
'active' => false, // Set active term by ID
'per_page' => 12 // How many posts per page
), $atts );
$result = NULL;
$terms = get_terms($a['tax']);
if (count($terms)) :
ob_start(); ?>
<div id="container-async" data-paged="<?php echo $a['per_page']; ?>" class="sc-ajax-filter">
<ul class="nav-filter">
<?php foreach ($terms as $term) : ?>
<li<?php if ($term->term_id == $a['active']) :?> class="active"<?php endif; ?>>
<a href="<?php echo get_term_link( $term, $term->taxonomy ); ?>" data-filter="<?php echo $term->taxonomy; ?>" data-term="<?php echo $term->slug; ?>" data-page="1">
<?php echo $term->name; ?>
</a>
</li>
<?php endforeach; ?>
</ul>
<div class="status"></div>
<div class="content"></div>
</div>
<?php $result = ob_get_clean();
endif;
return $result;
}
add_shortcode( 'ajax_filter_posts', 'vb_filter_posts_sc');
/**
* Pagination
*/
function vb_ajax_pager( $query = null, $paged = 1 ) {
if (!$query)
return;
$paginate = paginate_links([
'base' => '%_%',
'type' => 'array',
'total' => $query->max_num_pages,
'format' => '#page=%#%',
'current' => max( 1, $paged ),
'prev_text' => 'Prev',
'next_text' => 'Next'
]);
if ($query->max_num_pages > 1) : ?>
<ul class="pagination">
<?php foreach ( $paginate as $page ) :?>
<li><?php echo $page; ?></li>
<?php endforeach; ?>
</ul>
<?php endif;
}
main.js
(function($) {
$doc = $(document);
$doc.ready( function() {
/**
* Retrieve posts
*/
function get_posts($params) {
$container = $('#container-async');
$content = $container.find('.content');
$status = $container.find('.status');
$status.text('Loading posts ...');
$.ajax({
url: bobz.ajax_url,
data: {
action: 'do_filter_posts',
nonce: bobz.nonce,
params: $params
},
type: 'post',
dataType: 'json',
success: function(data, textStatus, XMLHttpRequest) {
if (data.status === 200) {
$content.html(data.content);
}
else if (data.status === 201) {
$content.html(data.message);
}
else {
$status.html(data.message);
}
},
error: function(MLHttpRequest, textStatus, errorThrown) {
$status.html(textStatus);
/*console.log(MLHttpRequest);
console.log(textStatus);
console.log(errorThrown);*/
},
complete: function(data, textStatus) {
msg = textStatus;
if (textStatus === 'success') {
msg = data.responseJSON.found;
}
$status.text('Posts found: ' + msg);
/*console.log(data);
console.log(textStatus);*/
}
});
}
/**
* Bind get_posts to tag cloud and navigation
*/
$('#container-async').on('click', 'a[data-filter], .pagination a', function(event) {
if(event.preventDefault) { event.preventDefault(); }
$this = $(this);
/**
* Set filter active
*/
if ($this.data('filter')) {
$this.closest('ul').find('.active').removeClass('active');
$this.parent('li').addClass('active');
$page = $this.data('page');
}
else {
/**
* Pagination
*/
$page = parseInt($this.attr('href').replace(/\D/g,''));
$this = $('.nav-filter .active a');
}
$params = {
'page' : $page,
'tax' : $this.data('filter'),
'term' : $this.data('term'),
'qty' : $this.closest('#container-async').data('paged'),
};
// Run query
get_posts($params);
});
$('a[data-term="all-terms"]').trigger('click');
});
})(jQuery);
Source website: https://www.bobz.co/filter-wordpress-posts-by-custom-taxonomy-term-with-ajax-and-pagination
Author
Jayesh Patel
Jayesh Patel is a Professional Web Developer & Designer and the Founder of InCreativeWeb.
As a highly Creative Web/Graphic/UI Designer - Front End / PHP / WordPress / Shopify Developer, with 14+ years of experience, he also provide complete solution from SEO to Digital Marketing. The passion he has for his work, his dedication, and ability to make quick, decisive decisions set him apart from the rest.
His first priority is to create a website with Complete SEO + Speed Up + WordPress Security Code of standards.