How to Combine AJAX load more button with AJAX filters

As usual I work with one of the default WordPress themes – Twenty Seventeen, why not. I would like this post to be clear for you, so I split it into steps – Step 1 is all about HTML, Step 2,3 is all about JavaScript and Step 4 is all about PHP.

To understand how it works, watch this video:

[youtube_embed placeholder=”https://rudrastyh.com/wp-content/uploads/2017/06/test1.jpg” caption=”You can also download the child theme from the video!”]https://www.youtube.com/embed/vn9OGFaJ7gk[/youtube_embed]

If you’re looking for infinite scrolling not load more button, the instruction is here.

Step 1. Creating «Posts per page» and «Order by» filters. Load more button.

First of all make sure that all the posts on the page are wrapped into the container, but the load more button and the filter form are outside of this container. Example:


<!-- Filters will be here -->
<div id="misha_posts_wrap">
	<!-- Posts will be here -->
</div>
<!-- Load more button will be here -->

Filters

I decided to make this code simple and use only two dropdown selects – for posts per page and for ordering posts. If you’re interested in sorting posts by meta values or by categories (taxonomy terms), I recommend you to look at this tutorial for more information.

<form id="misha_filters" action="#">
	<label for="misha_number_of_results">Per page</label>
	<select name="misha_number_of_results" id="misha_number_of_results">
		<option><?php echo get_option( 'posts_per_page' ) ?></option><!-- it is from Settings > Reading -->
		<option>5</option>
		<option>10</option>
		<option value="-1">All</option>
	</select>
				
	<label for="misha_order_by">Order</label>
	<select name="misha_order_by" id="misha_order_by">
		<option value="date-DESC">Date &darr;</option><!-- I will explode these values by "-" symbol later -->
		<option value="date-ASC">Date &uarr;</option>
		<option value="comment_count-DESC">Comments &darr;</option>
		<option value="comment_count-ASC">Comments &uarr;</option>
	</select>
				
	<!-- required hidden field for admin-ajax.php -->
	<input type="hidden" name="action" value="mishafilter" />
				
	<button>Apply Filters</button>
</form>

You can find some CSS styles in the child theme, link is under the video above.

Load more button

If the code below doesn’t work for you, try to add global $wp_query; before.

if (  $wp_query->max_num_pages > 1 ) :
	echo '<div id="misha_loadmore">More posts</div>'; // you can use <a> as well
endif;

In this case I do not recommend you to use another form of conditional statement because there could be conflicts in theme.

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

wp_localize_script() function is the awesome thing that allows you not only to translate strings in your JavaScript code but also pass the dynamically generated parameters in it.

So, nothing especial below – we just use WordPress default wp_enqueue_scripts action hook to include our script.js and pass some parameters there (yes, create please script.js somewhere, I did it in the theme directory).

add_action( 'wp_enqueue_scripts', 'misha_script_and_styles');

function misha_script_and_styles() {
	// absolutely need it, because we will get $wp_query->query_vars and $wp_query->max_num_pages from it.
	global $wp_query;

	// when you use wp_localize_script(), do not enqueue the target script immediately
	wp_register_script( 'misha_scripts', get_stylesheet_directory_uri() . '/script.js', array('jquery') );
 
	// passing parameters here
	// actually the <script> tag will be created and the object "misha_loadmore_params" will be inside it 
	wp_localize_script( 'misha_scripts', 'misha_loadmore_params', array(
		'ajaxurl' => site_url() . '/wp-admin/admin-ajax.php', // WordPress AJAX
		'posts' => json_encode( $wp_query->query_vars ), // everything about your loop is here
		'current_page' => $wp_query->query_vars['paged'] ? $wp_query->query_vars['paged'] : 1,
		'max_page' => $wp_query->max_num_pages
	) );
 
 	wp_enqueue_script( 'misha_scripts' );
}

A little more description of this process you can find in the post about load more button.

Code to functions.php.

Step 3. The Load More and AJAX Filtering Script

It is much simpler than you think. Here it is:

add_action('wp_ajax_loadmorebutton', 'misha_loadmore_ajax_handler');
add_action('wp_ajax_nopriv_loadmorebutton', 'misha_loadmore_ajax_handler');

function misha_loadmore_ajax_handler(){
 
	// prepare our arguments for the query
	$params = json_decode( stripslashes( $_POST['query'] ), true ); // query_posts() takes care of the necessary sanitization 
	$params['paged'] = $_POST['page'] + 1; // we need next page to be loaded
	$params['post_status'] = 'publish';
 
	// it is always better to use WP_Query but not here
	query_posts( $params );
 
	if( have_posts() ) :
 
		// run the loop
		while( have_posts() ): the_post();
 
			// look into your theme code how the posts are inserted, but you can use your own HTML of course
			// do you remember? - my example is adapted for Twenty Seventeen theme
			get_template_part( 'template-parts/post/content', get_post_format() );
			// for the test purposes comment the line above and uncomment the below one
			// the_title();
 
 
		endwhile;
	endif;
	die; // here we exit the script and even no wp_reset_query() required!
}
 
 
 
add_action('wp_ajax_mishafilter', 'misha_filter_function'); 
add_action('wp_ajax_nopriv_mishafilter', 'misha_filter_function');

function misha_filter_function(){

	// example: date-ASC 
	$order = explode( '-', $_POST['misha_order_by'] );
	
	$params = array(
		'posts_per_page' => $_POST['misha_number_of_results'], // when set to -1, it shows all posts
		'orderby' => $order[0], // example: date
		'order'	=> $order[1] // example: ASC
	);
 
	
	query_posts( $params );
	
	global $wp_query;
	
	if( have_posts() ) :
 
 		ob_start(); // start buffering because we do not need to print the posts now
 		
		while( have_posts() ): the_post();
 
			// adapted for Twenty Seventeen theme
			get_template_part( 'template-parts/post/content', get_post_format() );
 
		endwhile;
 
 		$posts_html = ob_get_contents(); // we pass the posts to variable
   		ob_end_clean(); // clear the buffer
	else:
		$posts_html = '<p>Nothing found for your criteria.</p>';
	endif;
	
	// no wp_reset_query() required
 
 	echo json_encode( array(
		'posts' => json_encode( $wp_query->query_vars ),
		'max_page' => $wp_query->max_num_pages,
		'found_posts' => $wp_query->found_posts,
		'content' => $posts_html
	) );
 	
	die();
}

And I want to remind you one more time – if code seems complicated for you, just download Twenty Seventeen child theme with the ready functionality, link is under the video at the beginning of this post.

Misha Rudrastyh

Misha Rudrastyh

I develop websites since 2008, so it is total of 13 years of experience, oh my gosh. Most of all I love love love to create websites with WordPress and Gutenberg, some ideas and thoughts I share throughout my blog.

Need some developer help? Contact me