Fixing a WordPress pagination 404 error

I’ve recently had a load of WordPress work.

Much of these jobs are similar, so I’ve had a good chance to try and learn more about better theme and plugin design.

One of these sites had a strange error when paginating the posts page. Permalinks were set to Day and Name, with the category base set to news and blog index set to the news page.

This creates the illusion of a standard site with all news namespaced under /news.

Calling mysite.com/news gave the first page of posts, using the index.php template file. Calling mysite.com/news/my-category/ gave the latest posts within that category, and pagination worked correctly when calling mysite.com/news/my-category/page/2.

But, annoyingly, calling mysite.com/news/page/2 gave a 404 error.

I googled far and wide but could not find an exact match to my problem (although it seems to be common with custom post types).

Changing permalinks back to the default setting worked, so I left it at that so I could dig deeper.

After some googling I found a recommendation to use the Debug This plugin. It gives detailed breakdowns of debugging data on any page or post. I was only interested in the rewrite rules so this is as far as I got with it.

Using Debug This to list the rewrite rules, I could see which one was being matched and what the redirect was doing in the background. It’s done with the Debug This menu item, and selecting Query > Rewrites.

When I called mysite.com/news this was the output:

Matched Rule: (.?.+?)(/[0-9]+)?/?$
Matched Query: pagename=news&page=

Calling mysite.com/news/my-category/ gave:

Matched Rule: news/(.+?)/?$
Matched Query: category_name=my-category

And mysite.com/news/my-category/page/2 gave:

Matched Rule: news/(.+?)/page/?([0-9]{1,})/?$
Matched Query: category_name=my-category&paged=2

Strangely mysite.com/news/page/2 did not match any rules. So the quickest option was to add my own rule to get things going again.

The third matched rule above is close to what I want, just without the category part of the url. So news/page/?([0-9]{1,})/?$ should work OK, provided that it was checked before the other rules.

In functions.php I added the following code:

function mg_news_pagination_rewrite() {
  add_rewrite_rule(get_option('category_base').'/page/?([0-9]{1,})/?$', 'index.php?pagename='.get_option('category_base').'&paged=$matches[1]', 'top');
}
add_action('init', 'mg_news_pagination_rewrite');

This simply adds a rewrite rule for pagination of the category_base value.

I added top as a third argument to insert the rule at the beginning of the list. It would otherwise match news/(.+?)/?$ (as it did originally) where it would throw a 404 error after failing to find a page category.

I’ve purposely used get_option('category_base') instead of news here too, so you can copy and paste into your own functions.php file.

The Source of the Problem

After writing this post I tried to replicate this on a fresh install, to see if it’s a problem within WordPress or not.

Setting the blog index to a static page, e.g. blog, works fine. Posts are viewed under /blog and pagination works automatically, following the standard blog/page/2 pattern.

The problem arose as I had the category base set to news.

The WordPress rewrite rule list has the category rewrites at the beginning, followed by tags, comments, author, posts by date etc, then finally the wildcards for pages. You can view a sample full list of rules on the WordPress plugin API pages.

In this case news was right at the top, so the match was made before reaching the page wildcard rules.

This is how it’s meant to happen, and my trick to imitate a sub directory of news would not work by design.

However, I think that the solution above is valid.