Load More Posts Button + Numeric Pagination

For those, who doesn’t know, this post is the addition to the original tutorial about creating Load More button in WordPress.

But why do we need it? The answer is pretty simple – it is more user and SEO friendly.

Step 1. Custom Pagination Function

Everything begins with a custom pagination function, because the default the_posts_pagination() or functions from plugins won’t work for you, so below is the working one. Actually you don’t have to make any changes in it, just insert it to your current theme functions.php.

Please note, that the example below is prepared for WordPress default Twenty Seventeen theme and its child themes! It means that you have to replace the function twentyseventeen_get_svg() in code (lines 66 and 80) with arrows or text.

function misha_paginator( $first_page_url ){

	// the function works only with $wp_query that's why we must use query_posts() instead of WP_Query()
	global $wp_query;

	// remove the trailing slash if necessary
	$first_page_url = untrailingslashit( $first_page_url );


	// it is time to separate our URL from search query
	$first_page_url_exploded = array(); // set it to empty array
	$first_page_url_exploded = explode("/?", $first_page_url);
	// by default a search query is empty
	$search_query = '';
	// if the second array element exists
	if( isset( $first_page_url_exploded[1] ) ) {
		$search_query = "/?" . $first_page_url_exploded[1];
		$first_page_url = $first_page_url_exploded[0];
	}

	// get parameters from $wp_query object
	// how much posts to display per page (DO NOT SET CUSTOM VALUE HERE!!!)
	$posts_per_page = (int) $wp_query->query_vars['posts_per_page'];
	// current page
	$current_page = (int) $wp_query->query_vars['paged'];
	// the overall amount of pages
	$max_page = $wp_query->max_num_pages;

	// we don't have to display pagination or load more button in this case
	if( $max_page <= 1 ) return;

	// set the current page to 1 if not exists
	if( empty( $current_page ) || $current_page == 0) $current_page = 1;

	// you can play with this parameter - how much links to display in pagination
	$links_in_the_middle = 4;
	$links_in_the_middle_minus_1 = $links_in_the_middle-1;

	// the code below is required to display the pagination properly for large amount of pages
	// I mean 1 ... 10, 12, 13 .. 100
	// $first_link_in_the_middle is 10
	// $last_link_in_the_middle is 13
	$first_link_in_the_middle = $current_page - floor( $links_in_the_middle_minus_1/2 );
	$last_link_in_the_middle = $current_page + ceil( $links_in_the_middle_minus_1/2 );

	// some calculations with $first_link_in_the_middle and $last_link_in_the_middle
	if( $first_link_in_the_middle <= 0 ) $first_link_in_the_middle = 1;
	if( ( $last_link_in_the_middle - $first_link_in_the_middle ) != $links_in_the_middle_minus_1 ) { $last_link_in_the_middle = $first_link_in_the_middle + $links_in_the_middle_minus_1; }
	if( $last_link_in_the_middle > $max_page ) { $first_link_in_the_middle = $max_page - $links_in_the_middle_minus_1; $last_link_in_the_middle = (int) $max_page; }
	if( $first_link_in_the_middle <= 0 ) $first_link_in_the_middle = 1;

	// begin to generate HTML of the pagination
	$pagination = '<nav id="misha_pagination" class="navigation pagination" role="navigation"><div class="nav-links">';

	// when to display "..." and the first page before it
	if ($first_link_in_the_middle >= 3 && $links_in_the_middle < $max_page) {
		$pagination.= '<a class="page-numbers" href="'. $first_page_url . $search_query . '">1</a>';

		if( $first_link_in_the_middle != 2 )
			$pagination .= '<span class="page-numbers extend">...</span>';

	}

	// arrow left (previous page)
	if ($current_page != 1)
		$pagination.= '<a class="prev page-numbers" href="'. $first_page_url . '/page/' . ($current_page-1) . $search_query . '">' . twentyseventeen_get_svg( array( 'icon' => 'arrow-left' ) ) . '</a>';


	// loop page links in the middle between "..." and "..."
	for($i = $first_link_in_the_middle; $i <= $last_link_in_the_middle; $i++) {
		if($i == $current_page) {
			$pagination.= '<span class="page-numbers current">'.$i.'</span>';
		} else {
			$pagination .= '<a class="page-numbers" href="'. $first_page_url . '/page/' . $i . $search_query .'">'.$i.'</a>';
		}
	}

	// arrow right (next page)
	if ($current_page != $last_link_in_the_middle )
		$pagination.= '<a class="next page-numbers" href="'. $first_page_url . '/page/' . ($current_page+1) . $search_query .'">' . twentyseventeen_get_svg( array( 'icon' => 'arrow-right' ) ) . '</a>';


	// when to display "..." and the last page after it
	if ( $last_link_in_the_middle < $max_page ) {

		if( $last_link_in_the_middle != ($max_page-1) )
			$pagination .= '<span class="page-numbers extend">...</span>';

		$pagination .= '<a class="page-numbers" href="'. $first_page_url . '/page/' . $max_page . $search_query .'">'. $max_page .'</a>';
	}

	// end HTML
	$pagination.= "</div></nav>";

	// haha, this is our load more posts link
	if( $current_page < $max_page )
		$pagination.= '<div id="misha_loadmore">More posts</div>';

	// replace first page before printing it
	echo str_replace(array("/page/1?", "/page/1\""), array("?", "\""), $pagination);
}

The function supports the large amount of pages as well, you can see what I mean on this screenshot — the function will work great even if you have 154 pages of content.

AJAX Load More button with Pagination in WordPress

Once done, let’s continue configuring the other parts of your loadmore code.

Step 2. Add one more parameter to wp_localize_script()

In the second step of the main tutorial about the load more button we enqueued scripts to our theme with WordPress wp_enqueue_scripts action hook.

You can leave everything without changes except ONE thing — add one more parameter to wp_localize_script() function.


...

wp_localize_script( 'misha_scripts', 'misha_loadmore_params', array(
	
	...
	
	'first_page' => get_pagenum_link(1) // here it is
) );

...

Step 3. Add Custom Pagination Function in Theme Template and wp_ajax_ function

The most uncertain step because everything depends on your theme code here. Insert the below line of code just after your main loop endwhile;.


misha_paginator( get_pagenum_link() );

This line of code insert after the endwhile; of the loop in wp_ajax_ function.


misha_paginator( $_POST['first_page'] );

Does it seem too difficult? The ready child theme for Twenty Seventeen is still here, ready for download.

Step 4. Check your JavaScript file

Your jQuery code will be slightly different than the code from the original tutorial. I would say simplified. I commented the lines with changes


jQuery(function($){
	// we will remove the button and load its new copy with AJAX, that's why $('body').on()
	$('body').on('click', '#misha_loadmore', function(){
		$.ajax({
			url : misha_loadmore_params.ajaxurl,
			data : {
				'action': 'loadmore',
				'query': misha_loadmore_params.posts,
				'page' : misha_loadmore_params.current_page,
				'first_page' : misha_loadmore_params.first_page // here is the new parameter
			},
			type : 'POST',
			beforeSend : function ( xhr ) {
				$('#misha_loadmore').text('Loading...'); 
			},
			success : function( data ){

				$('#misha_loadmore').remove(); // remove button
				$('#misha_pagination').before(data).remove(); // add new posts and remove pagination links
				misha_loadmore_params.current_page++;


			}
		});
		return false;
	});
});

That’s all, if you have a question, please scroll down to the comment section.

Misha Rudrastyh

Misha Rudrastyh

Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.

Need some developer help? Contact me

Follow me on X