a computer screen with a bunch of code on it

Why Your WordPress Custom Post Type Pagination Keeps Breaking (and How to Fix It for Good)

As a web developer, there are few things more frustrating than a bug that “fixes itself” only to break again the moment you look away. Last week, I ran into a classic WordPress headache: Custom Post Type pagination throwing 404 errors. I’d go into Settings > Permalinks, hit “Save,” and everything would work perfectly. Five minutes later? Page 2 was a 404 again.

After years of building complex WordPress architectures, I know that when “saving permalinks” is the temporary cure, the disease is usually Rewrite Rule Corruption. If you’re seeing this on your site, you aren’t crazy—WordPress is just losing its map.

Here is exactly what I found during my deep dive and how I fixed it for good.

The “Why”: Why does it break?

The most common culprit is Rewrite Rule Corruption. WordPress stores a “map” of your URL structure in the database. When a plugin updates, a new post is saved, or a certain hook is triggered, that map can get scrambled. If your CPT configuration isn’t perfect, WordPress loses the path to your paginated pages.

3 Steps to Permanent Fixes

1. Avoid the “Slug Clash”

In my experience, this is the most frequent oversight. WordPress gets confused if a Page and a Custom Post Type share the same slug.

  • The Error: You have a page named projects and a CPT registered with the slug projects.
  • The Fix: Make sure your CPT archive slug is unique. If you need them to be the same, you must set 'has_archive' => true and ensure your rewrite rules are specific.

2. The posts_per_page Mismatch

This is the “silent killer” of pagination. If your WordPress global settings (Settings > Reading) say show 10 posts, but your custom template query says show 5 posts, the math fails.

  • The Logic: When you visit /page/2/, WordPress checks the global setting. If you only have 8 posts total, WordPress thinks page 2 shouldn’t exist because $8 < 10$. It serves a 404 before your custom template even has a chance to run its query.
  • The Fix: Use the pre_get_posts hook in functions.php to tell WordPress exactly how many posts to expect before the page loads.

3. Stop Manual Flushing

I’ve seen developers put flush_rewrite_rules(); directly in the init hook. Don’t do this. * The Impact: It forces WordPress to rebuild its entire URL map on every single page load. This leads to race conditions where the rule isn’t ready when the page requests it, causing those intermittent 404s.

The Code Solution

I recommend adding this to your functions.php file. This aligns the WordPress core “math” with your custom display requirements:

PHP

function fix_my_cpt_pagination( $query ) {
    // Only target the main query on the front-end for your specific CPT
    if ( !is_admin() && $query->is_main_query() && is_post_type_archive('your_cpt_slug') ) {
        $query->set( 'posts_per_page', 10 ); // Match this to your design
    }
}
add_action( 'pre_get_posts', 'fix_my_cpt_pagination' );

Summary Checklist

  • [ ] Unique Slugs: Is your CPT slug different from your Page titles?
  • [ ] Query Sync: Does your posts_per_page match your Reading settings?
  • [ ] No Auto-Flush: Did you remove flush_rewrite_rules from your active code?
  • [ ] One Last Save: Go to Permalinks and hit “Save” one final time.

Expert Tip: If you’re using an SEO plugin, check if “Strip Category Base” or “Clean Permalinks” is active. These features often “clean” the pagination rules right out of your database.

Share


Categories