Fixing Pagination with Custom Taxonomy Archive

Hi @EAMann:

I cringe anytime I need to do something creative with URLs in WordPress as the URL system is in my opinion by far the most inelegant aspect of WordPress. I always feel like I’m having to fight WordPress to get it to do what I want, and that WordPress is actively fighting me back related to URLs. So with that opener…

Thinking through your issue I’m going to make a suggestion which isn’t exactly what you asked for. If you don’t find it to be what you are looking for that’s okay just please don’t anyone down-vote because I’m just trying to help.

Taxonomy Isn’t Single Increment and Has No Meta

One of the problems with what you are trying to do is the taxonomy system doesn’t a single increment ordering and it doesn’t have meta. For example in a 3 post series you might find terms with IDs of 373, 411 and 492; you can figure that 373 = #1, 411 = #2 and 492 = #3 but that’s all happenstance and relative to each other. It’s like trying to location the root of your WordPress site in plugin code but you don’t know how many levels deep your code will be stored. Of course can write code to figure it all out and map them but that gets tricky and I’m not sure you’d get much value out of trying to figure it out instead of using a different approach.

Explicitly Assign Your Page Numbers

So the first thing I would suggest is that you explicitly assign your page numbers for each post in your series using post meta/custom fields (I picked the term installment instead of page because it made more sense to me but clearly you could use any term that fits for your use-case.)

Assigning page/installment numbers has the benefit of you being in complete control and that way you’ll know what to fix when somethings out of whack and if you want to reorder you can do so just by changing the numbers. I’m assuming you’ll have a edit metabox for a custom field name _installment for selecting the installment numbers (and it could even manage/juggle installment numbers via AJAX if you want to get creative so that you never have pages out of sync.)

Use $wp_rewrite->add_rule() to Explicitly Assign Your URL

I won’t go in depth since I know you’ve generally got mad WordPress skilz so I’ll just point
out that $wp_rewrite->add_rule() is the cruz of getting this all to work. Everything else is just providing support around that function’s result. Use the init hook assign your URL rule:

<?php
add_action('init', 'add_series_installment_url');
function add_series_installment_url() {
  global $wp,$wp_rewrite;
  $wp->add_query_var('series');
  $wp->add_query_var('installment');
  $wp_rewrite->add_rule('series/([^/]+)/(installment-\d+)','index.php?series=$matches[1]&installment=$matches[2]','top');
  $wp_rewrite->flush_rules(false);  // This should really be done in a plugin activation
}

Use parse_query hook to Translate URL to Query Vars

The 2nd half of this solution uses the parse_query hook which I know you much be familiar with. In general we capture the query_vars defined in init and captured via the URL rule and convert them into what we need to query WordPress posts with taxonomy+term handling your series and meta_key+meta_value handling the explicitly assigned installment/page:

<?php
add_action('parse_query', 'apply_series_installment_to_query');
function apply_series_installment_to_query(&$query) {
  if (isset($query->query['series']) && isset($query->query['installment']) && 
     preg_match('#^installment-(\d+)$#',$query->query['installment'],$match)) {
    $query->query_vars['post_type'] = 'post';
    $query->query_vars['taxonomy'] = 'series';
    $query->query_vars['term'] = $query->query['series'];
    $query->query_vars['meta_key'] = '_installment';
    $query->query_vars['meta_value'] = $match[1];
    unset($query->query_vars['series']);            // You don't need this
    unset($query->query_vars['installment']);       // or this
    unset($query->query_vars['name']);              // or this
  }
}

Summary

Normally I would have gone into a lot more depth explaining an answer but it’s late, I’ve had too little sleep in the past 48 hours, and most importantly I know you can figure it out, you probably just needed one thing I mentioned here.

So I hope you like this solution. Even if you don’t the two parts with init and parse_query and the $wp_rewrite->add_rule() and the $query->query_vars[] respectively are what you need even if you want to stick with your original architecture. Good luck and looking forward to seeing it when you have it done and online!

Anyway,
Hope this helps.

Leave a Comment