If you have ever created a custom WP_Query
object, chances are you have potentially needed to also provide pagination for the resulting loop and display of posts. Sadly, WordPress core does not make this the easiest to achieve, but it is possible depending on which pagination-based functions you use. This tutorial aims to show how to achieve functional pagination without getting very “dirty” in your code.
What I mean by “dirty” in this case is having to utilize the global $wp_query
variable name. Many of the following functions rely on that specifically, without allowing custom setting overrides. If you have ever come across a tutorial that brings up setting the original $wp_query
object to a temporary variable, and then setting $wp_query
to null before re-purposing it, then you know what I am referring to here.
Pagination functions to use
The biggest key is the ability to provide a “max pages” value. The WordPress core source code shows that the only two functions that provide the ability to custom set those are:
get_next_posts_link()
get_previous_posts_link()
They have a second parameter available that allows you to set your own max_num_pages
value, instead of relying on the $wp_query
variable name.
Imagine your custom WP_Query
object is named $my_query
, to use its own max_num_pages
property, you just need to do the following:
printf( '<div>%s</div>', get_next_posts_link( 'Older posts', $my_query->max_num_pages ) ); printf( '<div>%s</div>', get_previous_posts_link( 'Newer posts', $my_query->max_num_pages ) );
This makes the two functions use the custom query’s values instead of the global $wp_query
values which get used if nothing is passed in.
Pagination functions to avoid for clean pagination
These functions do not allow a way to filter in or pass in “max pages” overriding values, and all rely on the global $wp_query
object instead.
posts_nav_link()
get_posts_nav_link()
get_the_posts_navigation()
get_the_posts_pagination()
the_posts_pagination()
Full Basic WP_Query example
$paged = 1; if ( get_query_var( 'paged' ) ) { $paged = get_query_var( 'paged' ); } else if ( get_query_var( 'page' ) ) { // This will occur if on front page. $paged = get_query_var( 'page' ); } $my_query = new WP_Query( array( 'post_type' => 'movie', 'posts_per_page' => 2, 'paged' => $paged, ) ); while ( $my_query->have_posts() ) : $my_query->the_post(); ?> <h2><?php the_title(); ?></h2> <?php the_excerpt(); endwhile; printf( '<div>%s</div>', get_next_posts_link( 'Older posts', $my_query->max_num_pages ) ); printf( '<div>%s</div>', get_previous_posts_link( 'Newer posts', $my_query->max_num_pages ) );
What this example does is grab the paged value for the current pagination, and pass it into the WP_Query calls, along with our movie post type and 2 posts per page. Afterwards, it’ll show the title and excerpt of any found movies, and pass in its own max number of pages into our pagination functions.
Conclusion
While not the most flexible, it does show that there is possible pagination available for custom WP_Query
calls. At least in theory, re-purposing the $wp_query
variable name specifically, should make the other functions work as well, but on a personal level, I’ve never been a fan of that method. Thankfully we have a couple functions that allow overriding of the value so that we can provide a more “clean” option.
Webmentions