Pagination with custom post types results in 404 issues

I’ve a very simple index.php:

<div id="content">
  <? get_template_part('content', get_post_format()) ?>
</div>

<div id="pagination">
  <? previous_posts_link() ?>
  <? next_posts_link() ?>
</div>

And my content.php looks roughly like this:

Read More
<?
$paged = get_query_var('paged') ? get_query_var('paged') : 1;
query_posts([
  'post_type' => ['articles', 'projects', 'tips'],
  'orderby' => 'date',
  'posts_per_page' => 7,
  'paged' => $paged
]);
?>

<? while(have_posts()): the_post() ?>
  <article class="post">
    <h2><? the_title() ?></h2>
    <p><? the_excerpt() ?></p>
    <ul>
      <? foreach($categories as $cat): ?>
      <li class="category"><a href="#"><?= $cat->name ?></a></li>
      <? endforeach ?>
    </ul>
  </article>
<? endwhile ?>

There are 14 posts in total but the “next” posts is always redirecting to a 404 on /page/2 instead of showing the remaining 7 posts.

Edit: If I use a custom WP_Query instead of query_posts then the next and previous links won’t even show. https://gist.github.com/elclanrs/4782705

I’ve been trying to find a solution to this issue since yesterday. I’m aware of all the other questions similar to this one, but for my particular set-up none of the solutions I found worked, including:

I’m also aware of pre_get_posts but I would like to know what’s the problem with my current setup. Any ideas?

Related posts

Leave a Reply

2 comments

  1. By the time you reach the template, WordPress has already queried the database and decided what to display based on those results.

    You’re seeing a 404 error because based on the default main query, there are no more posts to show.

    When you call query_posts in the template, you overwrite that original query. Despite the fact that your new query results contain more posts, WordPress has no awareness of this modified query.

    This is why you should never use query_posts in the template. You’ve provided the solution to your issue already, use the pre_get_posts action to modify the main query before it happens.

  2. Another solution that worked for me if using the Custom Post Type UI plugin, was to alter the rewrite settings in the interface for the custom post type.

    For example, I had a custom ‘news’ post type, no issues other than pagination wouldn’t work (e.g. /news/page/2 would 404). The two solutions I found were to either:

    • Turn the ‘Rewrite’ setting to false (resulting in news article URLs like domain.co.uk/?=title-of-news-article)
    • Or keep the ‘Rewrite’ setting to true, but use a custom slug, like in my case ‘newsstory’, which solves the 404 and then rewrites the article URLs to be domain.co.uk/newsstory/title-of-news-article

    Ultimately, though, I imagine the above is just a fix if your listing page is called the same as your post type. E.g. the page by ‘news’ post type was showing on, had the slug ‘news’ too so this could have confused matters.