Hướng dẫn Load More Posts with AJAX. Step by Step Tutorial

24th Jun 2021
Table of contents

Step 1. Load more button

We begin with the button HTML. Here is just one main rule – do not show the button if there are not enough posts. We will check it with $wp_query->max_num_pages.

<?php
global $wp_query; // you can remove this line if everything works for you
 
// don't display the button if there are not enough posts
if (  $wp_query->max_num_pages > 1 )
    echo '<div class="misha_loadmore">More posts</div>'; // you can use <a> as well
?>

I inserted the button just under the standart pagination (for TwentySeventeen – index.php line 55), but you can remove it as well. To style the button the according way use CSS below.

.misha_loadmore{
    background-color: #ddd;
    border-radius: 2px;
    display: block;
    text-align: center;
    font-size: 14px;
    font-size: 0.875rem;
    font-weight: 800;
    letter-spacing:1px;
    cursor:pointer;
    text-transform: uppercase;
    padding: 10px 0;
    transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, color 0.3s ease-in-out;  
}
.misha_loadmore:hover{
    background-color: #767676;
    color: #fff;
}

Step 2. Enqueue jQuery and myloadmore.js. Pass query parameters to the script. 

Well, that’s where the magic happens. This small piece of code allows you to pass the according parameters to the script that’s why the button can work on any page – tags, categories, custom post type archives, search etc. You can also use it for WooCommerce to load more products.

function misha_my_load_more_scripts() {

  global $wp_query; 


  // In most cases it is already included on the page and this line can be removed

  wp_enqueue_script('jquery');


  // register our main script but do not enqueue it yet

  wp_register_script( 'my_loadmore', get_stylesheet_directory_uri() . '/myloadmore.js', array('jquery') );


  // now the most interesting part

  // we have to pass parameters to myloadmore.js script but we can get the parameters values only in PHP

  // you can define variables directly in your HTML but I decided that the most proper way is wp_localize_script()

  wp_localize_script( 'my_loadmore', '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' => get_query_var( 'paged' ) ? get_query_var('paged') : 1,

    'max_page' => $wp_query->max_num_pages

  ) );


  wp_enqueue_script( 'my_loadmore' );

}

add_action( 'wp_enqueue_scripts', 'misha_my_load_more_scripts' );

 

If you still do not know, the above code is for your functions.php. And please note, my load more button is adapted for the main loop only. If you need it for a custom loop, ask me in comments.

You can also pass ajaxurl like this admin_url( 'admin-ajax.php' ). Many forget about this parameter and got an error “ajaxurl is not defined”.

Step 3. myloadmore.js – what is inside?

It is a small JS file, actually you can place it anywhere you want, for simpleness I decided to place it just in a theme directory (line 9 of previous code).

I also think that I should give you a choice – a load more button or just load posts by scroll.

Option 1. Load More button

If you choose the option 1, skip the option 2 and vice versa.

jQuery(function($){ // use jQuery code inside this to avoid "$ is not defined" error
	$('.misha_loadmore').click(function(){
 
		var button = $(this),
		    data = {
			'action': 'loadmore',
			'query': misha_loadmore_params.posts, // that's how we get params from wp_localize_script() function
			'page' : misha_loadmore_params.current_page
		};
 
		$.ajax({ // you can also use $.post here
			url : misha_loadmore_params.ajaxurl, // AJAX handler
			data : data,
			type : 'POST',
			beforeSend : function ( xhr ) {
				button.text('Loading...'); // change the button text, you can also add a preloader image
			},
			success : function( data ){
				if( data ) { 
					button.text( 'More posts' ).prev().before(data); // insert new posts
					misha_loadmore_params.current_page++;
 
					if ( misha_loadmore_params.current_page == misha_loadmore_params.max_page ) 
						button.remove(); // if last page, remove the button
 
					// you can also fire the "post-load" event here if you use a plugin that requires it
					// $( document.body ).trigger( 'post-load' );
				} else {
					button.remove(); // if no data, remove the button as well
				}
			}
		});
	});
});

Please note that line 23 can be different for your theme, it depends on your HTML document structure. I think you should know some basic jQuery DOM traversal methods – prev()next()parent() etc.

Option 2. No button, just load posts on scroll (lazy load)

jQuery(function($){
	var canBeLoaded = true, // this param allows to initiate the AJAX call only if necessary
	    bottomOffset = 2000; // the distance (in px) from the page bottom when you want to load more posts
 
	$(window).scroll(function(){
		var data = {
			'action': 'loadmore',
			'query': misha_loadmore_params.posts,
			'page' : misha_loadmore_params.current_page
		};
		if( $(document).scrollTop() > ( $(document).height() - bottomOffset ) && canBeLoaded == true ){
			$.ajax({
				url : misha_loadmore_params.ajaxurl,
				data:data,
				type:'POST',
				beforeSend: function( xhr ){
					// you can also add your own preloader here
					// you see, the AJAX call is in process, we shouldn't run it again until complete
					canBeLoaded = false; 
				},
				success:function(data){
					if( data ) {
						$('#main').find('article:last-of-type').after( data ); // where to insert posts
						canBeLoaded = true; // the ajax is completed, now we can run it again
						misha_loadmore_params.current_page++;
					}
				}
			});
		}
	});
});

 

Step 4. wp_ajax_

This is the AJAX handler function. Insert it to your functions.php file.

function misha_loadmore_ajax_handler(){
 
	// prepare our arguments for the query
	$args = json_decode( stripslashes( $_POST['query'] ), true );
	$args['paged'] = $_POST['page'] + 1; // we need next page to be loaded
	$args['post_status'] = 'publish';
 
	// it is always better to use WP_Query but not here
	query_posts( $args );
 
	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_loadmore', 'misha_loadmore_ajax_handler'); // wp_ajax_{action}
add_action('wp_ajax_nopriv_loadmore', 'misha_loadmore_ajax_handler'); // wp_ajax_nopriv_{action}

If you have any questions, please check comments below.

Bạn thấy bài viết này như thế nào?
0 reactions

Add new comment

Image CAPTCHA
Enter the characters shown in the image.
Câu nói tâm đắc: “Điều tuyệt với nhất trong cuộc sống là làm được những việc mà người khác tin là không thể!”

Related Articles

Nếu bạn muốn liệt kê tất cả các danh mục có sẵn cho một loại bài đăng tùy chỉnh, đoạn mã này có thể giúp bạn.

WP_Query là một lớp mạnh mẽ và cung cấp nhiều bộ lọc và hành động mà bạn có thể sử dụng để thay đổi cách vòng lặp WordPress hiển thị dữ liệu và cách truy vấn truy xuất dữ liệu.

If you want to build a simple, similar post list – in a single page view – when you query the latest or random posts from a post type you can use WP_Query.