0

In my category template (category.php) I have the following code:

<?php
// Setup custom loop -- we need to exclude featured posts from listing so they aren't repeated
$paged = get_query_var('paged') ? absint(get_query_var( 'paged' )) : 1;
$args = [
    'post_type' => 'post',
    'cat'=> $current_category->cat_ID,
    'post_status' => 'publish',
    'paged' => $paged,
    'posts_per_page' => $posts_per_page,
    'orderby' => 'date',
    'order' => 'DESC'
];

// If we have posts to exclude -- add that argument
if (!empty($featured_posts_to_exclude)) {
    $args['post__not_in'] = $featured_posts_to_exclude;
}

$category_posts = new WP_Query($args);

if ( $category_posts->have_posts() ) :

    // Used in template part to vary content
    $loop_count = 0;

    /* Start the Loop */
    while ( $category_posts->have_posts() ) : $category_posts->the_post();
            // We use this instead of "get_template_parts" so that we can pass loop vars
            include(locate_template('template-parts/content-horz-ads.php', false, false));
            $loop_count++;
    endwhile;

    // Add pagination
    im_numeric_posts_nav($category_posts);

    // Reset since we are using a custom loop.
    wp_reset_postdata();

else :

    get_template_part( 'template-parts/content', 'none' );
endif;

My pagination function is as follows (I'm posting it for the sake of completeness, but it works absolutely fine whether posts_per_page is set to 10, or 6 or whether it's a custom loop or not -- it displays the correct links, and number of links):

function im_numeric_posts_nav($custom_query_object = null) {

    // If we're on a singular page, we don't need navigation
    if (is_singular()) {
        return;
    }

    // If a custom loop was passed in, use it...otherwise use global loop
    if ($custom_query_object !== null) {
        $wp_query = $custom_query_object;
    } else {
        global $wp_query;
    }

    /** Stop execution if there's only 1 page */
    if ($wp_query->max_num_pages <= 1) {
        return;
    }

    $paged = get_query_var('paged') ? absint(get_query_var( 'paged' )) : 1;
    $max = intval($wp_query->max_num_pages);

    /** Add current page to the array */
    if ($paged >= 1) {
        $links[] = $paged;
    }

    /** Add the pages around the current page to the array */
    if ($paged >= 3) {
        $links[] = $paged - 1;
        $links[] = $paged - 2;
    }

    if (($paged + 2) <= $max) {
        $links[] = $paged + 2;
        $links[] = $paged + 1;
    }

    echo '<div class="pagination"><ul>' . "\n";

    /** Previous Post Link */
    if (get_previous_posts_link('&laquo;')) {
        printf('<li>%s</li>' . "\n", get_previous_posts_link('&laquo;'));
    }

    /** Link to first page, plus ellipses if necessary */
    if (!in_array( 1, $links)) {
        $class = 1 == $paged ? ' class="active"' : '';

        printf('<li%s><a href="%s">%s</a></li>' . "\n", $class, esc_url(get_pagenum_link(1)), '1');

        if (!in_array(2, $links)) {
            echo '<li>…</li>';
        }
    }

    /** Link to current page, plus 2 pages in either direction if necessary */
    sort($links);
    foreach ((array) $links as $link) {
        $class = $paged == $link ? ' class="active"' : '';
        printf('<li%s><a href="%s">%s</a></li>' . "\n", $class, esc_url(get_pagenum_link($link )), $link);
    }

    /** Link to last page, plus ellipses if necessary */
    if (!in_array($max, $links)) {
        if (!in_array($max - 1, $links)) {
            echo '<li>…</li>' . "\n";
        }

        $class = $paged == $max ? ' class="active"' : '';
        printf('<li%s><a href="%s">%s</a></li>' . "\n", $class, esc_url(get_pagenum_link($max)), $max);
    }

    /** Next Post Link */
    if (get_next_posts_link('&raquo;', $max)) {
        printf('<li>%s</li>' . "\n", get_next_posts_link('&raquo;', $max));
    }

    echo '</ul></div>' . "\n";
}

On category pages with featured posts, $posts_per_page is set to 6.

It shows only 6 posts but the pagination query still thinks there is 10 posts per page.

There are 214 posts but there should be 35 pages only, but if I go to any page after page 22, I get a 404. Which tells me that it's still using the posts per page that is set in the WordPress admin under the Reading settings.

If I change that to "6" -- everything is perfectly rosey. However i don't want that default set to 6. I want to be able to set that via the posts_per_page var in the custom query.

Any idea why this is happening, or what I have wrong here? I'm really banging my head on this.

  • Is your $posts_per_page variable being set correctly? in the code above it's not initialized anywhere. – guiniveretoo Nov 23 '16 at 19:16
  • It is being set above, and being set correctly...I'll re-check and get back to you. Maybe it's where it's being initialized that is causing the issue...That's a good point. – kevindeleon Nov 23 '16 at 19:17
  • Just realized, it is being initialized correctly...otherwise I'd be seeing 10 posts per page....I'm seeing 6 as I would expect...but the underlying pagination just isn't working correctly...if I go to ../page/33 it should be showing posts...instead it's showing nothing (404)...pagination stops working at 22 which is the expected behavior for 10 per page...even though posts_per_page is set to 6. – kevindeleon Nov 23 '16 at 19:49
  • Makes sense. Have you checked if the '6 per page' query is perhaps missing posts in between pages? Theoretically WP should calculate the offset properly, but maybe not? (as in, page 1 has posts 1-6, page 2 has posts 11-16) – guiniveretoo Nov 23 '16 at 20:00
  • 1
    Okay. Is it possible to stop using a custom query on that template page? You're basically overriding the default query by creating $category_posts. Rather than doing that, what about using a pre_get_posts filter? something like this? – guiniveretoo Nov 23 '16 at 21:16
0

Stop overriding the default loop and use pre_get_posts instead. Like this:

function wpse_247208_custom_category_query( $query ) {
    // Return early for any situation you aren't interested in.
    if ( is_admin() || ! $query->is_main_query() || !is_category() ) {
        return;
    }

    $query->set( 'posts_per_page', 6 );

    // Don't use a global; create a function to populate this value
    // I just don't know how you created this value so I wanted to make sure 
    // it is represented.
    $featured_posts_to_exclude = get_featured_posts_to_exclude();
    // If we have posts to exclude -- add that argument
    if (!empty($featured_posts_to_exclude)) {
        $query->set('post__not_in', $featured_posts_to_exclude);
    }
}
add_action( 'pre_get_posts', 'hwl_home_pagesize', 1 );

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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