I recently spent several hours driving myself crazy trying to implement a continuous pagination loop in WordPress, so I thought I’d post my solution to save someone else the trouble. It turns out that pagination is quite complicated, and the functions that find the beginning, ending and adjacent posts in the loop may be flawed as well. All I got when I Googled was “doesn’t work”.
The first function you need for pagination is “get_adjacent_post()”. That determines if your post has a previous or next post, in other words, if it is not the first or last post in your blog or in a specified category. You can go to the codex reference for the full details, but the tldr is that you need a minimum of three arguments:
- Stay in the same category (boolean)
- exclude category (can be empty)
- previous/next (true/false)
Since WordPress shows posts in descending chronological order, “previous” means a newer post and “next” means older. That’s where it gets tricky, because if you enter the loop on your newest post, there isn’t going to be a “previous” post, and if you enter in the middle of the chronology your “next” and “previous” buttons will have a mismatch between the WordPress navigational direction and the wording on the link.
It looks like this to go to the next (older) post:
if( get_adjacent_post(true, '', true) ) { previous_post_link('<span class="next-post">%link</span>'); }
It looks like this to go to the previous (newer) post:
if( get_adjacent_post(true, '', false) ) { next_post_link( '<span class="prev-post">%link</span>' ); }
That’s fine if you want the navigation to disappear when you get to the end of the posts. Unfortunately for me, I wanted a continuous loop, because my posts formed a product carousel that could be entered at any point in the chronology. I initially tried doing a new query, sorting in either ascending or descending order and going to the first result of each, but it only worked going forward. Below is the example code that I used for returning to the newest post at the end of the loop (replace “DESC” with “ASC” to get the last post):
else { $first = new WP_Query('posts_per_page=1&order=DESC'); $first->the_post(); echo '<span class="next-post"><a href="' . get_permalink() . '">First post</a></span>'; wp_reset_query(); };
There is another WordPress function that was made to get the first and last posts: “get_boundary_post()“. But even that didn’t work going in reverse in an “else” statement. It didn’t make it any easier that the example WordPress gave left out the quotes in the second argument, which caused it to fail. Their example was
get_boundary_post(true, , false, 'category')
But it should have been
get_boundary_post(true, '', false, 'category')
After scouring the web and seeing “solutions” that called for replacing the boundary post function with a custom implementation, I managed to come up with something that finally worked and was simple enough. I got the first and last posts with the boundary function before I began my pagination logic. Storing them in variables at the outset solved the problems I was having with my backward pagination getting stuck on the last post. I also threw in a check to not show paginate if there was only a single post in my category. Here is my final result. (It was meant to be run within the loop, so it assumes it is already enclosed within PHP tags):
//First post $first = get_boundary_post( true, '', true); $pID = $first[0]->ID; //Last post $last = get_boundary_post( true, '', false); $pID2 = $last[0]->ID; //Only run paging if you only have multiple posts if ( $pID != $pID2 ) { if( get_adjacent_post(true, '', true) ) { //"%link" is the post title wrapped in an anchor. previous_post_link('<span class="next-post">%link</span>'); } else { echo '<span class="next-post"><a href="' . get_permalink($pID2) . '">Go back to the last post</a></span>'; }; if( get_adjacent_post(true, '', false) ) { next_post_link( '<span class="prev-post">%link</span>' ); } else { echo '<span class="prev-post"><a href="' . get_permalink($pID) . '">Go back to the first post</a></span>'; }; };
This code was implemented for a client and can be viewed on their website.