WP_Query pagination problems? Here’s a hack

It happens every time I use WP_Query. I get a beautiful-looking custom WP_Query. Then I try to add pagination and everything goes to hell.

I’ve spent hours looking up solutions. Every time. Nine times out of ten, they don’t work. And for no discernible reason. Here’s a hack that worked for me, and is mostly for my own benefit so I don’t forget it next time I am in this situation, but maybe it will help you.

This hack requires Lester Chan‘s plugin WP-PageNavi. Go get it and come back.
For me, this applies specifically to using custom post types. If I wasn’t using CPTs, my WP_Query might not have any problems. Feel free to let me know in the comments if you spot an issue with the way I’m doing things. As I said, this is a hack — meaning it’s not the preferred way to do this — but it’s a functional hack at least.

Let’s start with the query:

			rewind_posts();
			global $wp_query, $paged;
			$temp = $wp_query;
			$wp_query = null;
			$wp_query = new WP_Query();

This is pretty basic. I’m running a rewind_posts() here because I have some custom queries going on in the sidebars, so I threw this in there just to be on the safe side. The next bit is where the hack starts coming in…

			$showposts = 12;
			$offset = ( ( $showposts * $page ) - $showposts );

Here we introduce two variables, both of which we will use in the arguments later. $showposts is a hard-coded rule for the posts_per_page argument. Yes, this is required. The reason will become evident by looking at the next line. Our $offset is being multiplied by the $showposts value (for me, this is 12) and then subtracted by that value again. This is how we are going to fix the issue of not being able to go into paged navigation because it only displays the first page worth of posts — by creating an offset that is multiplied by the current page you are looking at ($page is a global variable that is built into WordPress to display the current page).

Now the $args:

			$args = array(
				'post_type' => 'ap_products',
				'posts_per_page' => $showposts,
				'offset' => $offset,
			);
			query_posts($args);

This is pretty straightforward also. All we’re doing here is declaring the post type (which is just for my use, you can omit this if you aren’t using a custom post type, or replace with your own post type), and then feeding the $showposts and $offset values in here. Then we’re running our query. The full loop looks like this:

<?php the_post(); ?>
	<div <?php post_class(); ?> id="post-<?php the_ID(); ?>">	
	<?php 			
			rewind_posts();
			global $wp_query, $paged;
			$temp = $wp_query;
			$wp_query = null;
			$wp_query = new WP_Query();
			$showposts = 12;
			$offset = ( ( $showposts * $page ) - $showposts ); 
			$args = array(
				'post_type' => 'ap_products',
				'posts_per_page' => $showposts,
				'offset' => $offset,
			);
			query_posts($args); 	?>				
			<div class="entry">
				<?php while ( have_posts() ) : the_post(); ?>				
					<!-- do stuff -->
				<?php endwhile; ?>
				<?php if(function_exists('wp_pagenavi')) { echo '<div class="navigation"><span class="pre-navi"><a href="' . home_url() . '" />1</a></span>'; wp_pagenavi() . '</div>'; } ?>
				<?php $wp_query = null; $wp_query = $temp; ?>
			</div>
		</div>

Notice what I’m doing at the end with the wp_pagenavi function. I’ve added this into my style.css:

.current { display: none; }
.pre-navi { float: left; }

This makes it so that the current page doesn’t display at all. I’m doing this because the current page is always 1 with my fantabulous error, and this way I can replace the page 1 with one that actually links (if you’re on any page other than 1).

And that’s it. It’s not elegant, but it works, and the only real issue is that page 1 is always a link. If you like this solution (or if you hate it), let us know in the comments!


Posted

in

by