0

I currently have the main posts archive page at /blog/ (custom permalink structure of /blog/%postname%/) and categories at /blog/category/ (categories base left empty so it defaults to this).

I have a custom post type of release-notes, which also shares the category taxonomy. The archive page is at /release-notes/, and this works fine along with pagination. It was created with CPT UI, and the only properties I changed were has_archive, with_front and taxonomies, so the $args if created manually should be something like:

  $args = array(
      'public'              => true,
      'has_archive'         => true,
      'exclude_from_search' => false,
      'show_in_rest'        => true,
      'rewrite'             => array( 'slug' => 'release-notes', 'with_front' => false ),
      'taxonomies'          => array( 'category' ),
  );

The issue I'm having is with the pagination on category pages, e.g. /release-notes/category/upgrades/, where pages 2 and beyond return a 404.

To allow for /release-notes/category/upgrades/ (upgrades category of release-notes custom post type) instead of /blog/category/upgrades/ (upgrades category of core post type), which WordPress defaults to, I added a rewrite rule for the URL, and I also added a pre_get_posts to return only release-notes similar to this question.

//Rewrite rule for release notes custom category URL structure
add_rewrite_rule('^release-notes/category/(.+?)/?$', 'index.php?&category_name=$matches[1]&is_release-notes_cat=1', 'top');

//Register is_release-notes_cat query variable
function query_vars( $vars ) {
  array_push($vars, 'is_release-notes_cat');
  return $vars;
}
add_filter( 'query_vars', 'query_vars' );

// Modify main query if is_release-notes_cat page
function set_category_archive_release_notes_posts($query) {
  if (is_category() && isset($query->query_vars['is_release-notes_cat'])) {
      if ($query->is_main_query()) {
          // Set the post type to 'release-notes' only for the main query
          $query->set('post_type', 'release-notes');
      }
  }
}
add_action('pre_get_posts', 'set_category_archive_release_notes_posts');

I'm running the main query in the template file and not a secondary query, so all changes as far as I understand are being made before the query.

      <?php if(have_posts()): ?>

        <div class="release-notes__cards">
          <?php while(have_posts()): the_post();

            get_template_part( 'template-parts/content-release_notes' );

            endwhile;
          ?>
        </div>

        <?php the_posts_pagination(array('class' => 'list--pagination')); ?>

      <?php endif; wp_reset_postdata(); ?>

I'm not sure why it's not working. Any help would be appreciated.

2
  • "the permalink structure for categories set to /blog/category/" - what is your permalink structure (for the core post type) - is it blog/%category%/%postname% (which is a Custom Structure)? Or is it %postname%, but the Category base is blog/category? How are you registering the release-notes post type, is it via a plugin? Can you add your post type registration code to your question?
    – Sally CJ
    Feb 5 at 11:02
  • 1
    @SallyCJ Sorry, I've updated the question to include the answers to your questions.
    – ajs_app
    Feb 6 at 1:03

1 Answer 1

1

The issue I'm having is with the pagination on category pages, e.g. /release-notes/category/upgrades/, where pages 2 and beyond return a 404.

That's because your custom rewrite rule does not support paged requests, i.e. it's missing the RegEx ( regular expression pattern ) and query for the paged parameter.

So you can either add another rewrite rule which has the above support, or you can use a single RegEx like so:

add_rewrite_rule(
    // I added the (?:/page/(\d+))? which is used to match against the page number.
    '^release-notes/category/(.+?)(?:/page/(\d+))?/?$',

    // I added the &paged=$matches[2] so that WordPress knows what the page number is.
    'index.php?category_name=$matches[1]&is_release-notes_cat=1&paged=$matches[2]',

    'top'
);

The 404 error should now be gone (after flushing the rewrite rules), however, you don't actually have to add the custom query var named is_release-notes_cat.

You could just add &post_type=release-notes to your rewrite rule's query, like so, and WordPress will know that the post type is release-notes when loading your custom category permalink:

add_rewrite_rule(
    // I added the (?:/page/(\d+))? which is used to match against the page number.
    '^release-notes/category/(.+?)(?:/page/(\d+))?/?$',

    // I added the &paged=$matches[2] so that WordPress knows what the page number is.
    // I also removed the &is_release-notes_cat=1 and added &post_type=release-notes.
    'index.php?category_name=$matches[1]&paged=$matches[2]&post_type=release-notes',

    'top'
);

/*
 * If you use the above, then you should remove these parts from your code:
 * add_filter( 'query_vars', 'query_vars' );
 * add_action('pre_get_posts', 'set_category_archive_release_notes_posts');
 */
6
  • Hmm, replacing the code with what you gave gives me a 404 on /release-notes/category/upgrades/ or any of the other category archive pages. I looked into add_permastruct(), and while I understand that it creates the permalink, I don't quite understand how it knows what to query. Is the permalink structure's name, release-notes-category in this case just an identifier and holds no other significance?
    – ajs_app
    Feb 6 at 6:26
  • I also realized that shortening my code by just writing add_rewrite_rule('^release-notes/category/(.+?)/?$', 'index.php?&category_name=$matches[1]&post_type=release-notes', 'top'); with the post type directly in the rewrite rule instead of with the pre_get_posts does the same thing as my original code, though /release-notes/category/upgrades/page/2/ still returns a 404. I'm also flushing the rewrite rules every time I make a change.
    – ajs_app
    Feb 6 at 6:30
  • 1
    See the revised answer, and I hope it helps?
    – Sally CJ
    Feb 6 at 8:20
  • 1
    Now (or soon) you can vote up (see the help page here) :) But I'm already grateful enough that you accepted my answer. So thank you and happy coding!
    – Sally CJ
    Feb 6 at 8:46
  • 1
    Great, it's working now. Thanks again :)
    – ajs_app
    Feb 7 at 2:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.