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.

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
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
Hi Misha,
i have one question about the original tutorial (Load More Posts with AJAX. Step by Step Tutorial. No plugins.) I’m really sorry to ask here, but i can’t comment the original tutorial and i didn’t find answer in the comments.
I have custom query that loads posts from specific category. The load more button works but it loads also two posts from another category (there are more than two posts in “wrong” category). I followed these comments https://rudrastyh.com/wordpress/load-more-posts-ajax.html/comment-page-2#comment-1506
I have two different queries in same page but i need the “load more” button only to first query.
Hi Jacob,
The comments are closed there because all the possible questions are already answered. All the new questions begin to repeat the same. And your question seems too.
Did you pass the parameters for your custom query with
wp_localize_script()
?Another wonderful post! Thanks Misha!!! <3
Always welcome! 😊
Many thanks, you can make a guide on how to sort the list of articles by alphabet from A to Z.
Hey James,
Do you mean to sort automatically, without filters?
https://imgur.com/TFpvI1c
like this.
Am I able to combine this solution with your filters solution, found here? https://rudrastyh.com/wordpress/ajax-post-filters.html
Thanks
Yes, you’re, but I suppose you have to spend some time to make it working.
I’d like first to thank you for what you’re sharing here as it has been very useful for me so far. Following Jonathan’s comment, could you give us at least a basic approach on how to combine filters and pagination ? This is something really missing to the filter function you made before.
Thank you in advance for your time.
Hi,
I hope this tut will help you a little bit.
Will there be a tutorial for pagination and filters together? I’ve been trying to piece them together but could definitely use some lessons.
Thanks!
I’m not sure yet.
I was about to ask the same thing, Misha!
The awesome tutorials you have provided are great on their own, but it is quite cumbersome trying to combine them!
The filters in particular work perfectly when all the content is on one page, but with multiple pages it breaks the loop / pagination / order (I am not sure what to call it).
Regardless, the knowledge you have been sharing with us is greatly appreciated, I have learned so much thanks to you!
Thank you 🙃
Ok, I will try to publish the tutorial in March.
Hi, we’re still waiting on your tutorial. Can you tell when it will be?
Hi,
here it is.
I know, but Am I able to combine this solution with your filters solution. when I tried to combine them, it didn’t work.
Lol, I sent you the link to the same tutorial. Sorry!
Yes, you are able to do it but some code changes are required of course. I think I will publish a complete pagination tutorial later.
Any ideas how to approach this if you have custom wp_query which fetches let say some category posts?
wp_localize_script()
should be presented like a<script>
tag directly on the page.Hello, this pagination is also ajax?
I’m trying to make navigation both on rozetka.com.ua
Hey,
Pagination is not ajax-based, but it is the addition for the load more button which is ajax-based.
Hi Misha! I have a questiones about https://rudrastyh.com/wordpress/load-more-posts-ajax.html:
Is it possible to load a different number of post between query php and load more button? for example, in the query php load 4 post 4 and by clicking on the button that loads 2.
Hi Santiago,
You can do it with the
offset
query parameter.Example:
On the first “page”, load 4 post.
and the following pages (when clicking on button), will load 2 post?
Thanks!
Just to clarify, we have 4 posts on the page loaded without AJAX and we want to load posts by 2 with AJAX.
To do it, you have to:
1. Set main query
posts_per_page
parameter to 4 and with no offset parameters.2. Inside the AJAX query set
posts_per_page
to 2 andoffset
to 2, or just begin with the 3rd page.How i use this code in my wp_query??
i already follow the step but still not working
Hi @Misha,
pretty cool tutorial, you saved me plenty of time, thanks!
I have tweaked it a bit: if you want to change as well URL accordingly to page you are at (when pressing the load more button) you could use pushState following way:
Just add this code after your current page incrementing.
P.S. What do you use for those comments with code?
Hi Karolína,
Thank you for your comment! 🙃
P.S. I’m not sure that I understood your last question. Do you mean the code buttons in the comment editor?
Yeah, exactly. The formatter you use is very nice.
Thank you!
It is just custom coding.
Hi Misha!
Have you managed to prepare a tutorial for pagination and filters together yet? I can’t find it anywhere…
Best regards
Hey Pawel,
I don’t have one. Just separately about load more + pagination and load more + filters.
Would love a combo tutorial with this and the AJAX Filter post as I got that first one working, but have no idea how this could work with it properly.
Hi Misha,
Great article and explanation for how to add a load more!
We like your post filter and load more examples. Is it possible to use the Ajax post filter with the load more feature in this article?
Cheers
Hey Mark,
Please check this tutorial.
Hi Misha,
How to update this code to use only load more, or to use only pagination. I want to do unversal function for all my projects.
And is there way to update the URL when i click load more button?
Hey,
Not sure about your first question. I suppose you have to add a PHP if/else condition there.
About URLs – I think
window.history.pushState
should help you. Please check the examples, maybe in stackoverflow.Is this will work with WooCommerce?
Yes, why not
I mean for Woocommerce products on shop page, is this work or maybe I need some changes?
Hello Misha,
Thanks for this overwhelming tutorial. I am a beginner I was looking to put the ajax on next prev button is it possible.
nice work!
First of all, great tutorial! Really like your stuff. But I got one question: If I trigger the AJAX filter the pagination will disappear :(
Hi Jim,
Let me clarify – do you use AJAX load more + AJAX filters + pagination, correct?
Hi Misha.
Love your tutorial!
I am trying to use the loadmore + pagination twice (or more) with a custom query in a tabbed box.
But I can figure out how to separate the two instances?
As it is now, the loadmore will trigger both instances and read the data from the last query.
Can you help me out?