最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

custom post types - How to properly rewrite pagination rules for a CPT to avoid 404 error on page2

programmeradmin5浏览0评论

I have custom post type called News and a static page that uses a custom template (page-news.php) and indexes all the news posts under homepage/news url.

The problem is that I want to paginate the news page so that homepage/news/page/2 would show more posts etc. but it returns a 404 error.

This is how I'm changing the pagination rules in functions.php:

function my_pagination_rewrite() {
    add_rewrite_rule('page/?([0-9]{1,})/?$', 'page-news.php?category_name=blog&paged=$matches[1]', 'top');
}
add_action('init', 'my_pagination_rewrite');

And here is my custom query in the page-news.php:

<?php
    $paged = ( get_query_var('paged') ) ? get_query_var( 'paged' ) : 1;
    $query = new WP_Query(array(
        'post_type' => 'news',
        'post_status' => 'publish',
        'posts_per_page' => '4',
        'paged' => $paged
    ));
    $temp_query = $wp_query;
    $wp_query   = NULL;
    $wp_query   = $query;
    while ($query->have_posts()):
        $query->the_post();
        
    <!-- ECHOING THE NEWS POSTS-->

    endwhile;
    wp_reset_postdata();

    echo '<div class="pagination">';

            echo paginate_links( array(
                'base'         => str_replace( 999999999, '%#%', esc_url( get_pagenum_link( 999999999 ) ) ),
                'total'        => $query->max_num_pages,
                'current'      => max( 1, get_query_var( 'paged' ) ),
                'format'       => '?paged=%#%',
                'show_all'     => false,
                'type'         => 'plain',
                'end_size'     => 2,
                'mid_size'     => 1,
                'prev_next'    => true,
                'prev_text'    => sprintf( '<i></i> %1$s', __( 'Newer Posts', 'text-domain' ) ),
                'next_text'    => sprintf( '%1$s <i></i>', __( 'Older Posts', 'text-domain' ) ),
                'add_args'     => false,
                'add_fragment' => '',
            ) );

    echo '</div>';
    
    $wp_query = NULL;
    $wp_query = $temp_query;
?>

I have custom post type called News and a static page that uses a custom template (page-news.php) and indexes all the news posts under homepage/news url.

The problem is that I want to paginate the news page so that homepage/news/page/2 would show more posts etc. but it returns a 404 error.

This is how I'm changing the pagination rules in functions.php:

function my_pagination_rewrite() {
    add_rewrite_rule('page/?([0-9]{1,})/?$', 'page-news.php?category_name=blog&paged=$matches[1]', 'top');
}
add_action('init', 'my_pagination_rewrite');

And here is my custom query in the page-news.php:

<?php
    $paged = ( get_query_var('paged') ) ? get_query_var( 'paged' ) : 1;
    $query = new WP_Query(array(
        'post_type' => 'news',
        'post_status' => 'publish',
        'posts_per_page' => '4',
        'paged' => $paged
    ));
    $temp_query = $wp_query;
    $wp_query   = NULL;
    $wp_query   = $query;
    while ($query->have_posts()):
        $query->the_post();
        
    <!-- ECHOING THE NEWS POSTS-->

    endwhile;
    wp_reset_postdata();

    echo '<div class="pagination">';

            echo paginate_links( array(
                'base'         => str_replace( 999999999, '%#%', esc_url( get_pagenum_link( 999999999 ) ) ),
                'total'        => $query->max_num_pages,
                'current'      => max( 1, get_query_var( 'paged' ) ),
                'format'       => '?paged=%#%',
                'show_all'     => false,
                'type'         => 'plain',
                'end_size'     => 2,
                'mid_size'     => 1,
                'prev_next'    => true,
                'prev_text'    => sprintf( '<i></i> %1$s', __( 'Newer Posts', 'text-domain' ) ),
                'next_text'    => sprintf( '%1$s <i></i>', __( 'Older Posts', 'text-domain' ) ),
                'add_args'     => false,
                'add_fragment' => '',
            ) );

    echo '</div>';
    
    $wp_query = NULL;
    $wp_query = $temp_query;
?>
Share Improve this question asked Aug 5, 2020 at 15:50 Em KarimifarEm Karimifar 52 bronze badges 2
  • 1 You can't add rewrite rules for other files, it must to be index.php. WP rewrite rules aren't like Apache or Nginx rules, they're just a regex mapping of pretty URLs on to query variables on index.php ( the same query variables that WP_Query uses ). Also that index.php is not the index.php in your theme, it's the index.php at the root of the WP site, but for rewrite rules it's just a formality, it is always index.php?param=value&etc... – Tom J Nowell Commented Aug 5, 2020 at 16:06
  • 1 Also, is there a reason you created a dedicated template that doubles up the number of queries from scratch? You could have told WP when registering the news CPT that it had a permalinks front of page/ then used the archive-news.php, and all the pagination would have just worked out of the box with a standard post loop, with sitemaps and RSS feeds etc too if you wanted them – Tom J Nowell Commented Aug 5, 2020 at 16:09
Add a comment  | 

1 Answer 1

Reset to default 1

You don't need the rewrite rules, and that's not how they'd work anyway.

The fundamental problem is that you decided not to modify the main query, but to replace it.

There's no need for the custom WP_Query or custom pagination, or a page template. Not to mention by running the main query then discarding the result to make a new one, it doubled the amount of work that needs doing, a major performance hit/slowdown

You can just use an archive-news.php template with a standard post loop, then use pre_get_posts to change how many posts are shown on the page:

// only show 4 posts per page on the news archive
add_action(
    'pre_get_posts',
    function( \WP_Query $query ) {
        // we only want the news post archive, exit early if it isn't
        if ( ! $query->is_main_query() || ! $query->is_post_type_archive( 'news' ) ) {
            return;
        }
        $query->set( 'posts_per_page', 4 );
    }
);

Now the news archive will show 4 posts per page. No rewrite rules, no CPT adjustments, no special page with a page template for the pagination, it should all just work out the box with that hook. You can use normal standard main loops like the default themes. It'll even be faster! You're no longer doubling up all the queries by discarding the main query and putting your own in.

With that, your above code can be simplified to this in an archive-news.php template:

while ( have_posts() ) {
    the_post();
    <!-- ECHOING THE NEWS POSTS-->
}

echo '<div class="pagination">';
echo paginate_links();
echo '</div>';
发布评论

评论列表(0)

  1. 暂无评论