AJAX filters for WordPress Posts with Load More Or Pagination Button

In This Post, I Will Show you that How To Filter Any Post or Custom Post Type With Load More or Pagination Button using by Ajax Function.

Step 1. Create a Shortcode

You Need To Write this code into functions.php file of your activated theme or you can download the code snippet plugin from wordpress dashboard and put this script into that.

add_shortcode( 'ajax_filter_posts', array($this,'hitdeals_filter_posts'));    
function hitdeals_filter_posts($atts) {
    $a = shortcode_atts( array(
        'tax'      => 'post_tag', // Taxonomy
        'terms'    => false, // Get specific taxonomy terms only
        'active'   => false, // Set active term by ID
        'per_page' => 12, // How many posts per page
        'post_type' => 'post', // Custom Post
        'pager'    => 'pager' // 'pager' to use numbered pagination || 'infscr' to use loadmore
    ), $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">
                    <li>
						<a href="#" data-filter="<?= $terms[0]->taxonomy; ?>" data-term="all-terms" data-page="1" data-post_type="<?= $a['post_type']; ?>" data-pager="<?= $a['pager']; ?>"> Show All </a>
					</li>
                    <?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" data-post_type="<?= $a['post_type']; ?>" data-pager="<?= $a['pager']; ?>">
                                <?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;
    }

Step 2. Pagination and Load More Function

function hitdeals_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;
    }

   function load_more_pager($query = null) {
        if ( $query->max_num_pages > 1 ) :
          echo  '<nav class="infscr-pager"><a href="#" class="btn btn-primary">Load More</a></nav>';
        endif;
    }

Step 3. Script connection, passing parameters to wp_localize_script() 

/**
    * AJAC filter posts by taxonomy term
    */
    function hitdeals_filter_posts() {

    if( !isset( $_POST['nonce'] ) || !wp_verify_nonce( $_POST['nonce'], 'post' ) )
        die('Permission denied');

    /**
     * Default response
     */
    $response = [
        'status'  => 500,
        'message' => 'Something is wrong, please try again later ...',
        'content' => false,
        'found'   => 0
    ];

    $post_type  = sanitize_text_field($_POST['params']['post_type']); 
    $tax  = sanitize_text_field($_POST['params']['tax']);
    $term = sanitize_text_field($_POST['params']['term']);
    $page = intval($_POST['params']['page']);
    $qty  = intval($_POST['params']['qty']);
    $pager  = sanitize_text_field($_POST['params']['pager']);

    /**
     * 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,
        'post_type'      => $post_type
    ];

    $qry = new WP_Query($args);
    $max_pages = $qry->max_num_pages;

    ob_start();
        if ($qry->have_posts()) :
            while ($qry->have_posts()) : $qry->the_post(); ?>

                <article class="loop-item">
                    <header>
                    <?php if(has_post_thumbnail()){ the_post_thumbnail(); } ?>
                        <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
             */
            if($pager!= 'infscr'){
                $this->hitdeals_ajax_pager($qry,$page);
            } else {
                $this->load_more_pager($qry);
            }
           

            $response = [
                'status'=> 200,
                'found' => $qry->found_posts
            ];

            
        else :

            $response = [
                'status'  => 201,
                'message' => 'No posts found'
            ];

        endif;
    $response['max'] = $max_pages;
    $response['content'] = ob_get_clean();

    die(json_encode($response));

    }

Step 4. Enqueue CSS and AJAX Filtering Script 

 add_action( 'wp_enqueue_scripts', array($this,'post_shortcode_assets'));
 
 /* Enqueue Script and Style */
    function post_shortcode_assets() {
        wp_register_style( 'main', plugins_url( '/css/main.css' , __FILE__ ) );
        wp_register_script( 'main', plugins_url( '/js/main.js' , __FILE__), ['jquery'], null, true );

        wp_enqueue_style( 'main' );
        wp_enqueue_script( 'main' );
        wp_localize_script( 'main', 'postObject', array(
            'nonce'    => wp_create_nonce( 'post' ),
            'ajax_url' => admin_url( 'admin-ajax.php' )
        ));
    }

Step 5. Ajax Filtering Javascript

(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: postObject.ajax_url,
	            	data: {
	            			action: 'do_filter_posts',
					        nonce: postObject.nonce,
					        params: $params,
	            		},
	            		type: 'post',
	            		dataType: 'json',
	            		success: function(data, textStatus, XMLHttpRequest) {
	            	
			            	if (data.status === 200) {
								currentPage++
			            		$content.html(data.content);
                                 if(currentPage > data.max){
                                    jQuery(".infscr-pager").hide();
                                 } 
								 
			            	}
			            	else if (data.status === 201) {
			            		$content.html(data.message);	
			            	}
			            	else {
			            		$status.html(data.message);
			            	}
			         },
			         error: function(MLHttpRequest, textStatus, errorThrown) {

					$status.html(textStatus);
					
			         },
				complete: function(data, textStatus) {
					
					msg = textStatus;

	            	if (textStatus === 'success') {
	            		msg = data.responseJSON.found;
	            	}

	            	$status.text('Posts found: ' + msg);
	            	
	            }
	        });
		}

		/**
		 * 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');
				currentPage = 1;
			}
			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'),
                'post_type' : $this.data('post_type'),
                'pager' : $this.data('pager'),
	        };

	        // Run query
	        get_posts($params);
		});

		$('#container-async').on('click', '.infscr-pager a', function(event) {
			if(event.preventDefault) { event.preventDefault(); }
 
		   $this = jQuery('.nav-filter li.active a');
	       $params    = {
	        	  'page' : currentPage,
	        	  'tax'  : $this.data('filter'),
	        	  'term' : $this.data('term'),
	        	  'qty'  : $this.closest('#container-async').data('paged'),
                  'post_type' : $this.data('post_type'),
                  'pager' : $this.data('pager')
	        };

	        // Run query
	        get_posts($params);
		}); 

		$('a[data-term="all-terms"]').trigger('click');
	});

})(jQuery);

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to Top