I'm trying a new approach to paginate posts returned in a category.php file. I want to see snippets of 10 posts at a time. Filename is category-xyz.php and this worked before I changed to this method, although I was using showposts=200 and it was returning all 180 posts in that category.

I changed method because several calls I used were deprecated (eg showposts) or not advised. I am using this post's solution for reference:

How to fix pagination for custom loops?

Here's my code:

// Define custom query parameters
$custom_query_args = array( 
'cat' => 76, 
'posts_per_page' => 5

// Get current page and append to custom query parameters array
$custom_query_args['paged'] = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;

// Instantiate custom query
$custom_query = new WP_Query( $custom_query_args );

// Pagination fix
$temp_query = $wp_query;
$wp_query   = NULL;
$wp_query   = $custom_query;

        // Output custom query loop rather than use wp_query
        if ( $custom_query->have_posts() ) : 
             while ( $custom_query->have_posts() ) : 
        // Loop output goes here
            <div class="pcrmbimgholder">
            <a href="<?php the_permalink() ?>" rel="bookmark"><img src="<?php echo pcrmbimagegrab() ?>" alt="<?php the_title(); ?>" /></a>
        <h2><a href="<?php the_permalink() ?>" rel="bookmark"><?php the_title(); ?></a></h2>
        <?php the_content_limit(190, ""); ?>                
                <?php $customField = get_post_custom_values("price"); 
                 if (isset($customField[0])) { 
                 echo "<strong>Price: ".$customField[0];
                 echo "   </strong>";
                } else { 
                <?php $customField = get_post_custom_values("sku"); 
                 if (isset($customField[0])) { 
                 echo "&#124;   Stock Reference: ".$customField[0] . "&#32;&#32;&#32;";
                } else { 
        <a class="postbutton" href="<?php the_permalink() ?>" rel="bookmark"><span>View</span></a><div class="separator"></div>     


// Reset postdata

// Custom query loop pagination
previous_posts_link( 'Older Posts' );
next_posts_link( 'Newer Posts', $custom_query->max_num_pages );

// Reset main query object
$wp_query = NULL;
$wp_query = $temp_query;


I have also tried this because I am not sure which parameters I need in the custom query array:

// Define custom query parameters
$custom_query_args = array( 
'cat' => 76, 
'posts_per_page' => 5,
'max_num_pages' => 20,
'paged' => $paged,

The pagination link goes to /category/category-name/page/2/ which results in a 404 error. Any ideas why?

  • try to enable DEBUG codex.wordpress.org/Debugging_in_WordPress to possibly get error messages – Michael Nov 24 '13 at 20:43
  • Thanks. I did this and it said there was an unexpected colon in the code of the custom query loop. I copied and pasted again and it seemed to work. However the pagination link goes to /category/category-name/page/2/ which results in a 404 error. Will update the post. – Sara44 Nov 24 '13 at 21:27
  • 1
    This: $custom_query->while ( have_posts() ) : should be written as while ( $custom_query->have_posts() ) :. It was wrong in the source Answer too. – Charles Clarkson Nov 24 '13 at 23:55
  • @CharlesClarkson Thanks Charles, good catch. I did correct this (the linked answer has 2 examples of that code, 1 is correct) and now I'm at the 404 error mentioned above. – Sara44 Nov 25 '13 at 9:57
  • Thanks for catching that, @CharlesClarkson. Probably one of my best typos of all time. (I fixed the other one, too.) – Chip Bennett Nov 25 '13 at 12:23

The main query runs before the template is loaded, and WordPress decides what template to load based on the results of that query.

You say your default posts_per_page is set to 200, and there are 180 posts in that category, so as far as WordPress knows, there is no page 2. Your custom query that you run in the template with a different posts per page setting is unrelated to the main query.

The solution is to make adjustments to the main query before the template is loaded, via the pre_get_posts action. This would go in your theme's functions.php file:

function category_posts_per_page( $query ) {
    if ( !is_admin()
        && $query->is_category()
        && $query->is_main_query() ) {
        $query->set( 'posts_per_page', 5 );
add_action( 'pre_get_posts', 'category_posts_per_page' );

You can then run the normal loop in the template and pagination will work as expected. Also see is_category() in Codex if you want this to apply to a specific single category.

| improve this answer | |
  • In the original files I was using 'showposts'. I have changed it to this <?php $recent = new WP_Query("cat=154&posts_per_page=-1"); while($recent->have_posts()) : $recent->the_post();?> but it still doesn't work with the new function you mentioned. Can you explain what you mean by 'normal loop' please? – Sara44 Nov 25 '13 at 18:52
  • normal loop meaning no custom query, get rid of all your custom query code and just run the plain while( have_posts() ) loop. – Milo Nov 25 '13 at 18:58
  • That doesn't seem to work, I still get all posts returned. Should that posts_per_page in functions.php override my posts_per_page=-1 in the category template file? – Sara44 Nov 25 '13 at 19:49
  • if you've removed the custom query from your template, there should be no query arguments there at all. your template should just be the default, plain, unedited category template. – Milo Nov 25 '13 at 20:03
  • That works a treat thanks, removed all query calls like you said. – Sara44 Nov 25 '13 at 21:41

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.