0
votes

We use latest WP (5.2.2). We have a custom post type called Stories (slug: stories) with the following capabilities during setup.

    Public: true
    Publicly Queryable: true
    Show UI: true
    Has Archive: true
    Exclude From Search: false
    Hierarchical: false
    Rewrite: true
    Custom Rewrite Slug: stories/%category%
    Show in Nav Menus: true
    Show in REST API: true
    With Front: true
    Query Var: true

This works fine. For example, we create a new story called "Huckleberry Cafe Opens" and assign it to a category called "Food", and the URL works:

site.com/stories/food/huckleberry-cafe-open

Our permalinks are set to /%category%/%postname%, but for custom post types we also use the helpful plugin, Permalink Manager Lite. This contains "permastructures" and we use a matching pattern to the "custom rewrite slug" from our custom post type above:

stories/%category%/%stories%

We naturally have a category page for this, in archive-stories.php. This way whether the category was Food, or Fashion, or Home Repairs, the same overall theme works for this custom post type.

The problem lies with Pagination. With some helpful commentary from this website and posts like these, I can now finally see the page numbers.

PROBLEM: Clicking on Page 2 or beyond just gives me the same thing as Page 1.

I used the helpful permalink debug script from Github and it does show me that the "template used" varies across page 1 and 2.

Page 1: /stories/food Uses the usual category.php (Why? This is a custom post type!)

Page 2: /stories/food/page/2 Uses the more predictable archive-stories.php

Note that these categories are the same across all our website's custom post types. We have custom post types like Stories, Shop, etc. All of them are assigned the same base categories (Food, Style, Home Repairs..).

In both archive-stories.php and category.php (which are currently, for testing, the exact same file), we have the following WP_Query up top:

<?php

$paged = get_query_var('paged') ? get_query_var('paged') : 1;
$args = array(
        'post_type'      => 'stories',
        'orderby'        => 'date',
        'order'          => 'DESC',
        'posts_per_page' => 10,
        'post_status'    => array('publish', 'pending', 'draft'),
        'paged'          => $paged
    );

$the_query = new WP_Query($args);
while( $the_query->have_posts() ) : $the_query->the_post(); 

 ?>

 ......LOOP HERE.....

<?php


// DO THE "TOTAL PAGES" THING
$total_pages = $the_query->max_num_pages;
if ($total_pages > 1){

    $current_page = max(1, get_query_var('paged'));
    echo paginate_links(array(
        'base' => get_pagenum_link(1) . '%_%',
        'format' => '/page/%#%',
        'current' => $current_page,
        'total' => $total_pages,
        'prev_text'    => __('« prev'),
        'next_text'    => __('next »'),
    ));
}    


?>

This does show the loop itself well, and it shows the pagination correctly. But clicking page 2 and beyond always shows the exact same page as page 1.

Btw, if we dump the WP_Query() with a print_r($the_query);, we see that the SQL being created is the exact same for both page 1 and page 2, which explains why the page is the same. The "offset" value in LIMIT clause is always 0. On Page 2, this should be 10, on Page 3, this should be 20, etc. We're not sure why it is 0 though.

SELECT SQL_CALC_FOUND_ROWS  
    wp_posts.ID 
FROM wp_posts  
WHERE 1=1  
      AND wp_posts.post_type = 'stories' 
      AND ((wp_posts.post_status = 'publish' OR wp_posts.post_status = 'draft' OR wp_posts.post_status = 'pending'))  
      ORDER BY wp_posts.post_date 
      DESC LIMIT 0, 10
;

If it helps, we notice that we need the following code in functions.php for our /page/2 to work at all, otherwise it throws a 404. This is from the plugin for Category Pagination Fix:

     function remove_page_from_query_string($query_string)
    { 
        if (isset($query_string['name']) && $query_string['name'] == 'page' && isset($query_string['page'])) {
            unset($query_string['name']);
            // 'page' in the query_string looks like '/2', so i'm spliting it out
            @list($delim, $page_index) = explode('/', $query_string['page']);
            $query_string['paged'] = $page_index;
        }      
        return $query_string;
    }
    // I will kill you if you remove this. I died two days for this line 
    add_filter('request', 'remove_page_from_query_string');

    // following are code adapted from Custom Post Type Category Pagination Fix by jdantzer
    function fix_category_pagination($qs){
        if(isset($qs['category_name']) && isset($qs['paged'])){
            $qs['post_type'] = get_post_types($args = array(
                'public'   => true,
                '_builtin' => false
            ));
            array_push($qs['post_type'],'post');
        }
        return $qs;
    }
    add_filter('request', 'fix_category_pagination');

Many thanks for any pointers!

2

2 Answers

2
votes

I am the author of Permalink Manager. It looks like you posted the same question here, but did not respond after: https://wordpress.org/support/topic/custom-post-type-pagination-issue/

The problem in your case is that you are using the wrong pagination slug. For single posts, pages and custom post type items you should not use /page/, eg.:

/stories/food/huckleberry-cafe-opens/page/2

but only a numeric index, eg.:

/stories/food/huckleberry-cafe-opens/2

There are two different pagination endpoints in Wordpress. One (paged) is used by archives and terms, the another one (page) is used by single posts: https://wordpress.stackexchange.com/a/180785/38240


If you would like to use /page/ endpoint anyway, you can use the following code snippet:

function pm_adjust_pagination($request) {
    if(!empty($request['post_type']) && !empty($request['name']) && $request['paged']) {
        $request['page'] = $request['paged'];
        unset($request['paged']);
    }

    return $request;
}
add_filter('request', 'pm_adjust_pagination', 99);

Best regards, Maciej

1
votes

I´m not sure if its going to solve your problem but you could try to set offset within your $args

$paged = get_query_var('paged') ? get_query_var('paged') : 1;
$posts_per_page = 10;
$offset = ( $paged - 1 ) * $posts_per_page;

$args = array(
        'post_type'      => 'stories',
        'orderby'        => 'date',
        'order'          => 'DESC',
        'posts_per_page' => $posts_per_page,
        'post_status'    => array('publish', 'pending', 'draft'),
        'paged'          => $paged,
        'offset' => $offset
    );

After the changes try to flush your permalinks. Wordpress->Settings->Permalinks->Save

and clear cache