WordPress custom post query breaking pagination

2010-08-08

Ran 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&amp;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!

Tags: wordpress, php

Comments