Pagination for Custom Loops
There are different ways to create a pagination for WordPress posts in a loop:
- Using
next_posts_link()
andprevious_posts_links()
functions - Using
paginate_links()
orget_the_posts_pagination()
that allows to display numeric pagination. - In old times we also used plugins for that purpose, the most popular was WP-Pagenavi.
In this tutorial my goal is to show you how to create any kind of custom paginations for almost anything. For example did you know that do display page numbers in Appearance > Menus is also used paginate_links()
function?

Function paginate_links()
As I mentioned above this functions can be used to paginate almost anything. In order to do so, we need to pass some specific parameters to the functions.
Let me break down all function parameters into two groups:
For styling | For custom pagination |
---|---|
show_all , mid_size , end_size , prev_next , prev_text , next_text , before_page_number , after_page_number , type | total , current , base , format |
All parameters detailed description you can find in official WordPress documentation, but right now I am going to dive deep into parameters of the second group.
total
– total number of pages in pagination,current
– current page number,base
– it is how URL of a single navigation page looks like in formathttp://test-site/all_posts.php%_%
, symbols%_%
are going to be replaced with the value of format parameter, for example to/page/1
or?pg=1
. By default for archive pages WordPress uses the value ofget_pagenum_link()
function with%_%
on the end.format
– that’s the parameter which contains the actual page number in format?page=%#%
, where%#%
is the current page number.
Example of Custom WordPress Query Pagination
Right now let’s create a pagination for any custom WordPress query. We can use WP_Query
class to display posts or Network_Query
which works like WP_Query
but for all the posts in Multisite Network. But please note that in order to use the second class, my plugin should be installed on your website.
I decided to show you a pagination example based on a page template we created in a tutorial about global multisite search.
<?php
/*
* Template name: Global Search with Pagination
*/
get_header();
// could be almost anything but I don't recommend to use 'page' or 'paged'
$query_arg = 'current_page';
// URL of your search page
$page_url = get_permalink(); // or get_pagenum_link() or something custom
$current_page = ( isset( $_GET[ $query_arg ] ) && $_GET[ $query_arg ] ) ? absint( $_GET[ $query_arg ] ) : 1;
$args = array(
's' => 'wordcamp london', // the search query is here
'posts_per_page' => 10, // decide how much posts per page should be displayed
'paged' => $current_page
);
// run the custom query
$query = new Network_Query( $args );
if( $query->have_posts() ) :
while( $query->have_posts() ) : $query->the_post();
?><h2><?php echo $query->post->post_title ?></h2><?php
endwhile;
if( $query->max_num_pages > 1 ) {
echo paginate_links(
array(
'total' => $query->max_num_pages,
'current' => $current_page,
'base' => $page_url . '%_%',
'format' => '?' . $query_arg . '=%#%'
)
);
}
endif;
get_footer();

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
Thanks for the wonderful code. I need to display posts from all multisite blogs in the back-end, so that the editor can manage the posts in the wp-admin area like in the single site. How can we do it?
Hi again,
Anyway, I’ve added this feature. More info is here. No ACF columns are supported, but actually you can edit plugin’s
posts.php
file a little for your needs.Hi Misha,
Thanks for this amazing plugin. I’m excited to implement it on my site.
I’m having trouble getting the pagination working, though. As you suggested, I’m using a custom page template and have it set as my front page under Settings > Reading. On that custom page, I copied and pasted the code you have displayed above. I also copied the misha_pagination function into my functions.php file.
While I do see the page number links at the bottom of my home page, clicking any of them just displays same first 10 posts. I deactivated all other plugins and even tried this using the twentyten theme to keep it simple, but I’m having no luck. Any suggestions?
Nevermind. I just saw your comment in the code.
// (!) if you use the code on the front page, change PAGED to PAGE, e.g. get_query_var(‘page’)
That fixed it.
Hi,
Ok, I’m glad you’ve figured it out 🙃
I see on your site that Network_Query will accept all of the same arguments as WP_Query, but I’m having trouble getting the network query to exclude sticky posts. The code I’m using is below, but sticky posts are still being included. Can you help?
Hi,
get_option( 'sticky_posts' )
returns only sticky posts from your current blog/site where you use the query 🙃Is there a way that I could add an argument to the Network_Query that would exclude sticky posts from the results?
Yes, actually you can use the same
post__not_in
, but find a way to add sticky posts in one array common for all blogs.Or just use
'ignore_sticky_posts' => true
.