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.

WordPress Bootstrap Plugin: Bootstrap Column widget

Download Bootstrap Column from WordPress Plugins, or fork Bootstrap Column widget on Github.

WordPress Bootstrap Plugin

Although I’ve built a few custom WordPress plugins over the years, this is the first I’ve released publicly.

bootstrap-column

Bootstrap Column simply adds a widget which nicely works with Bootstrap v3 based themes.

It’s not dissimilar to the standard WordPress textbox widget, but it offers extra Bootstrap v3 layout functionality.

Those familiar with Bootstrap will quickly understand how it works.

Bootstrap offers a 12 column grid within four break points at which to change the layout. These breakpoints start from mobile first:

  • Extra Small – for smartphones at less than 768px screen width
  • Small – for tablets between 768px and 992px
  • Medium – for larger tablets and small desktops between 992px and 1200px
  • Large – for everything else above 1200px

Bootstrap provides a set of classes which not only control column width, but also their behaviour at these different screen sizes.

For example, take the following <div class="col-lg-4 col-md-6">.

Both Small (sm) and Extra Small (xs) are left out, so Bootstrap will default this div to a full width layout, i.e. 12 columns.

At the Medium (md) breakpoint the div will stretch to 6 columns, or half the page width. At the Large (lg) breakpoint it will only be four columns in width.

Ideally it would be partnered with another div with this class value <div class="col-lg-8 col-md-6">. At Large this gives you two columns at 1/3 and 2/3 page widths. At Medium it gives two equally sized columns.

These CSS features are very powerful and enables very quick layouts and prototyping.

Hopefully my plugin will make things a bit easier for other Bootstrappers.

Poor Code

Working on the plugin has really highlighted the standard of coding in WordPress. Although it’s a quick way of adding widgets, the code’s structure is not to be copied.

The widget framework is a quick and easy way to create plugins, but very messy and has little in common with the SOLID principles of programming.

For example, the single responsibility principle is ignored here. The class that extends the plugin class is responsible for saving and updating the widget’s contents and settings, and also rendering the HTML for both the front and back ends.

A nice templating system would be a tidy addition to the current way of doing things.