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('«')) { printf('<li>%s</li>' . "\n", get_previous_posts_link('«')); } /** 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('»', $max)) { printf('<li>%s</li>' . "\n", get_next_posts_link('»', $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.
$posts_per_pagevariable being set correctly? in the code above it's not initialized anywhere.pre_get_postsfilter? something like this?