Dev Notes

Software Development Resources by David Egan.

WordPress Pagination with WP_Query - Page Slug Causing Error


WP_Query, WordPress
David Egan

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.

Scenario

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 WP_Query().

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:

<?php
// Log the args to `debug.log`
error_log( json_encode($args) );

// The Custom Query
$custom_query = new \WP_Query( $args );

This outputs the arguments to debug.log. Your site must be configured to log errors - your config should include this:

<?php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);

…and 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 www-data.

The Arguments passed to WP_Query() in this case are as follows (JSON encoded for readability):

{
  "post_type":["person"],
  "post_status":["publish"],
  "posts_per_page":2,
  "order":"ASC",
  "orderby":"menu_order",
  "nopaging":false,
  "paged":1
}

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.

Solution

Options:

  1. Amend the rewrite rule for the custom post type
  2. 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