Pagination can be tricky. This post outlines a problem that can arise due to a page slug that conflicts with a custom post type rewrite base.
Hopefully this post will help me to avoid repeating the error in a months time (I’ve just spent an hour fixing this). If you find this post after a Google search for “WordPress pagination 404 error on page 2” - hopefully you’ll find it useful.
A static page that calls
WP_Query() to build a custom loop. In this case, the page is called ‘People’ (the page slug is ‘people’) and
WP_Query() builds a loop of ‘person’ custom post types.
Pagination works, but clicking the link to “page 2” results in a 404 error.
The Custom Loop
I use a wrapper to simplify generation of
Rather than hunt through the wrapper classes (which apply overrides by merging arrays), it’s usually easiest to check the arguments passed in to
WP_Query() by examining them just before they are used:
This outputs the arguments to
debug.log. Your site must be configured to log errors - your config should include this:
wp-content/debug.log should be writable by your server process. In my case (Ubuntu 16.04, Apache 2.4), the file should be owned by
The Arguments passed to
WP_Query() in this case are as follows (JSON encoded for readability):
These aruments look pretty OK to me.
Switching permalinks to WP plain option fixes the issue. This is a clue.
It’s not a solution, because the URLs look terrible.
The Custom Post Type
In this case, the custom post type “person” had a rewrite rule so that the individual custom post type URLs were: http://example.com/people/joe-bloggs/.
And that’s the issue right there.
You can verify this by temporarily amending the page slug for the static page that calls the custom loop. Do this so that is is anything other than ‘people’ and pagination will work.
- Amend the rewrite rule for the custom post type
- Amend the page slug
I went with option 1. The client can live with http://example.com/person/joe-bloggs - the whole point of the static page with custom loop is to have a more controllable (pseudo) archive page, so the rewrite is pretty redundant - the http://example.com/people was originally set up as a more semantically meaningful archive URL.
comments powered by Disqus