Pagination with Custom Taxonomy – No More 404s

Have you ever wanted to have a Custom Taxonomy page with a number of posts_per_page less than the setting in Settings->Reading?  If so, I’ll bet you got ‘404 – Not Found’ errors when trying to link to some pages.

This is a known common problem with pagination for Custom Taxonomies.  Here is one solution.

This code was tested using WP 3.4.2, WP-PageNavi, and the theme Gears 1.0.0 ( Gears is just for convenience).  The code is not specific to Gears and should work with all themes.  However, since it has only been tested with one theme, please let me know if you find it useful or find problems with other themes.

The basic problem appears to be that WP issues a taxonomy query using the value in Settings->Reading before it loads the custom template which assigns a lower number of posts_per_page, causing higher page numbers to request posts past the existing number.

The solution I used is to add an argument to the query string and use its value to filter the posts_per_page using the options_post_per_page filter.

There are four parts to the solution:

  1. In your template, assign the desired number of posts to a variable and use that variable in the query.
  2. Modify the pagination calls to wp-pagenavi() and/or previous/next_posts_link() to add the special argument to the links.
  3. Create a special function to add the argument to the links.  Using add_query_arg() directly on these links will not work.
  4. Create the filter on options_post_per_page.

The code for part 1 should be similar to this:

global $wp_query;
$mamposts_per_page = 2;
query_posts(
   array_merge(
      $wp_query->query,
      array(
         'posts_per_page' => $mamposts_per_page,
      )
   )
);

This preserves the original query arguments except for the new number of posts_per_page, and reissues the query.

Part 2 modifies the navigation to use the function from part 3 to add the ‘mamposts’ argument to the links.

<div id="navigation">
<?php if(function_exists('wp_pagenavi')) :
   echo mam_add_query_arg('mamposts',$mamposts_per_page,wp_pagenavi(array('echo' => false)));
else : ?>
   <div class="alignleft"><?php echo mam_add_query_arg('mamposts',$mamposts_per_page, get_next_posts_link(__('&laquo; Older Entries','web2feel'))) ?></div>
   <div class="alignright"><?php echo mam_add_query_arg('mamposts',$mamposts_per_page, get_previous_posts_link(__('Newer Entries &raquo;','web2feel'))) ?></div>
   <div class="clear"></div>
<?php endif; ?>
</div>

This (part 2) is probably where the code is most Gear-specific.  In particular, you might need a different div id than ‘navigation’ and different parameters to wp-pagenavi() and previous/next_posts_link().  The important part is the use of mam_add_query_arg to add the ‘mamposts’ to the links.

Parts 3 and 4 are both added to functions.php.

function mam_add_query_arg ($key,$value,$string) {
   // Adds the parameter $key=$value to anchor tags hrefs in $string,
   // or replaces it if already there.
   // Necessary because add_query_arg fails when the URL(S) are in links,
   // as in next_posts_link.
   if (strpos($string,'href')) {
     // <a> tags generally include href="a-url-here"
     $hrefpat = '/(href *= *([\"\']?)([^\"\' ]+)\2)/';
   } else {
     // Also want to handle raw URLs
     $hrefpat = '/(([\"\']?)(http([^\"\' ]+))\2)/';
   }
   if (preg_match_all($hrefpat,$string,$matches)) {
      // print_r('<p>MATCHES:');print_r($matches);print_r('</p>');
      // echo "<p>HREFPAT:$hrefpat</p>";
      // Only want to process a URL once, so elimate dups.
      $unique_urls = array_unique($matches[3]);
      foreach ($unique_urls as $url) {
         $newurl = add_query_arg($key,$value,$url);
         // echo '<p>OLDURL:' . htmlentities($url) . '</p>';
         // echo '<p>NEWURL:' . htmlentities($newurl) . '</p>';
         $string = str_replace($url,$newurl,$string);
      }
   }

   return $string;
}

add_filter( 'option_posts_per_page', 'mam_option_posts_per_page' );
function mam_option_posts_per_page( $value ) {
   // Change number of posts_per_page to nn if mamposts=nn arg exists.
    $taxposts = (intval($_GET['mamposts'])) ? $_GET['mamposts'] : $value;
    return $taxposts;
}

Again, please let me know if you use this code, and the results you get.

3 Responses to Pagination with Custom Taxonomy – No More 404s

Leave a Reply

Your email address will not be published. Required fields are marked *

*