WordPress custom post query breaking pagination
2010-08-08Ran into this issue last week at work. We had a custom query on the front page of a WordPress site that was retrieving posts from a specific category, using the WP query_posts() function. That worked well until the site added enough posts to roll over onto a second page, but then we found out that the "page 2" link just redisplayed the home page with no modifications.
It turns out the hard-coded query_posts()
call couldn't handle the built-in pagination functions, so to get around that I added a check for "/page/#" as part of the URL. Here's what I ended up with:
<?php
$matches = array();
preg_match('/\/page\/(\d)$/', $_SERVER['REQUEST_URI'], $matches);
$query = ('/' === $matches[0]) ? 'cat=9' : 'cat=9&paged=' . $matches[1];
query_posts($query);
if (have_posts()) : //do stuff
?>
Even though the URL is going to be short, I decided to use regular expressions, which in this case meant the preg_match() function. Feel free to skim the manpage if you're unsure how the $matches
array above comes into play, it doesn't really work the way a normal function does.
First line just initializes an empty array to hold the regex matches. It's a good coding practice but not strictly necessary for the example. To test out regular expressions I recommend the very handy RegExr web tool. Our mod_rewrite rules for this site are such that the homepage is going to have a REQUEST_URI of a single slash so that makes the pattern matching pretty simple, at least as far as regex is ever simple or pretty. The second line checks to see if the REQUEST_URI ends with "/page/" followed by a number, and if it does, save that number in the $matches
array. We use the results of that regex to see whether the URL the user requested was just a plain slash or if they want a page of older posts.
The third line uses a quick ternary operator (handy for variable assignments, but otherwise too tricky to read easily) to set the value of $query
to either our plain query or the WP query results split into pages, starting with the user's requested page, which we pull from the $matches
array. Once that's all done we're free to run the query and carry on with rendering the template.
Hope you found this helpful!