Custom WP_query and Pagination

Web Dev Tips

I posted this a few years back on StackExchange. It continues to be popular, so I’m adding the same information here….

Unfortunately to this day there isn’t a lot of good information about pagination with a custom post type wp_query. It’s very surprising considering the endless uses for custom post types (CPT) and how long they have been part of WordPress. Additionally, a lot of the information out there about this topic is unclear or in my opinion not the best advice. Anyway, moving on, I am here today to hopefully help someone out with this.

There are 3 ways that I would suggest to tackle the problem, though I strongly recommend option #1. Alright, time to dig in!

Option 1 – use max_num_pages variable
1
2
3
4
5
6
7
8
9
10
11
<?php
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = array(
'posts_per_page' => 1,
'paged' => $paged,
'post_type' => 'cpt_type'
);
$cpt_query = new WP_Query($args);
?>
 
<?php if ($cpt_query->have_posts()) : while ($cpt_query->have_posts()) : $cpt_query->the_post(); ?>

// YOUR LOOP CODE WILL NOW BE HERE … Followed by this below …

1
2
3
4
5
6
7
<?php endwhile; endif; ?>
<nav>
  <ul>
    <li><?php previous_posts_link( '&laquo; PREV', $cpt_query->max_num_pages) ?></li>
    <li><?php next_posts_link( 'NEXT &raquo;', $cpt_query->max_num_pages) ?></li>
  </ul>
</nav>

You’ll see above, a slightly different format for ‘previous_posts_link’ and ‘next_posts_link’ which now access the ‘max_num_pages’ variable. Be sure to use your own query variable name when accessing ‘max_num_pages’. Notice I use $cpt_query since that is the variable for my query example.

Option 2 – temporarily use the $wp_query variable for your loop query

This is what a lot of folks recommend, but be careful to asign the $wp_query variable to a temp variable and re-assign it or you will run in to all kinds of troubles. Which is why I recommend Option #1. As noted on CSS Tricks, you can do something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
  $temp = $wp_query;
  $wp_query = null;
  $wp_query = new WP_Query();
  $wp_query->query('showposts=6&post_type=news'.'&paged='.$paged);
  while ($wp_query->have_posts()) : $wp_query->the_post();
?>
 
  <!-- LOOP: Usual Post Template Stuff Here-->
 
<?php endwhile; ?>
 
<nav>
  <?php previous_posts_link('&laquo; Newer') ?>
  <?php next_posts_link('Older &raquo;') ?>
</nav>
 
<?php
  $wp_query = null;
  $wp_query = $temp; // Reset
?>
NOTE:

For the pagination code in Option #1, what you can do instead is use the popular WP-PageNavi plugin, but make one change in the code, remove everything within the “nav” element and replace with this code below:

1
2
3
<nav>
  <?php wp_pagenavi( array( 'query' => $cpt_query ) ); ?>
</nav>