Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I've been trying to set up a way to write posts in a series on my site. The idea is that each post can belong to a different series in a custom taxonomy. I've gotten just about everything set up the way I want it ... with one exception.

Registering the Taxonomy

This part is working. I've dropped the following code into a plug-in:

function jdm_build_series_taxonomy() {
    $labels = array(
        'name' => _x('Series Labels', 'taxonomy general name'),
        'singular_name' => _x('Series Label', 'taxonomy singular name'),
        'search_items' => __('Search Series Labels'),
        'popular_items' => __('Popular Series Labels'),
        'all_items' => __('All Series Labels'),
        'parent_item' => __('Parent Series Label'),
        'parent_item_colon' => __('Parent Series Label:'),
        'edit_item' => __('Edit Series Label'),
        'update_item' => __('Update Series Label'),
        'add_new_item' => __('Add New Series Label'),
        'new_item_name' => __('New Series Label Name')
    );

    register_taxonomy(
        'series',
        'post',
        array(
            'hierarchical' => true,
            'label' => __('Series'),
            'labels' => $labels,
            'query_var' => true,
            'rewrite' => true
        )
    );
}

add_action( 'init', 'jdm_build_series_taxonomy', 0 );

This adds "Series Labels" to the Posts dropdown menu and gives me a "Series Labels" box on the post edit screen. Everything's working, and I can mark posts as a part of a series perfectly. The problem lies in the next section ...

Listing items in the Taxonomy

My goal is to allow readers to walk through a series one post at a time, starting with the oldest post and moving forwards chronologically. This is different than a typical archive page, because I have 10 posts per page for my archives, but I obviously want only one post per page for my series archive.

I've created a taxonomy-series.php file inside my template. And it half works. The first page will work just fine - http://localhost/wp/series/my-test-series/ displays the first article in the series with the "Next Entry »" link on the bottom of the page. So far, so good ...

But when you click "Next Entry »" and go to the next page (http://localhost/wp/series/my-test-series/page/2/) it's a) the wrong article and b) the wrong template!

However, if I set "Blog pages show at most:" to "1" on the Reading page (it's normally set to 10) then things work just fine. Page 2 displays the second article, page 3 displays the third, etc.

So ... what do I need to double check to force the taxonomy archive page to display only one post on each page? I've tried the following:

$new_query = wp_parse_args(
    $query_string, 
    array(
        'posts_per_page' => 1,
        'paged' => $paged
    )
);

query_posts($new_query);

and

query_posts($query_string.'&posts_per_page=1&paged='.$paged);

to no avail ... ideas? Tips? Suggestions?

share|improve this question

2 Answers 2

up vote 5 down vote accepted

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.

share|improve this answer
    
I ended up using most of this for what I'm doing. The urls for my series are now along the lines of http://localhost/wp/series/my-test-series/ and http://localhost/wp/series/my-test-series/2/. I'll eventually add some server controls to dynamically number the pages so you can delete/drag/drop/order the series within the UI ... right now it's hard coded with explicitly-incremented values in a custom meta field. –  EAMann Sep 13 '10 at 0:11
    
@EAMann Cool! Glad it helped. Looking forward to seeing the results. –  MikeSchinkel Sep 13 '10 at 1:28
    
So ... here are the results: mindsharestrategy.com/series/wp-xmlrpc This is a series I'm working on (updated Fridays) that covers a step-by-step tutorial of WP's XML-RPC system. My series plugin is still in development, but you can see contextual navigation at the bottom and pagination is working just fine as well. –  EAMann Sep 27 '10 at 15:18

Here is code I use to modify number of posts on archive pages of categories and tags:

query_posts( array_merge( array(
'posts_per_page' => 1
), $wp_query->query ) );

If you can't make this work with custom taxonomy try with native (categories, tags) to check if problem is with code itself, with taxonomy or something else entirely.

Also I am not sure if you missed this or left out, but $paged is not global variable. It must be fetched as get_query_var( 'paged' )

share|improve this answer
    
I am using $paged = get_query_var('paged') but left that out since my code snippets were already getting pretty long. I'll try your method and see if that helps! –  EAMann Sep 11 '10 at 18:31

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.