4

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?

3 Answers 3

6

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.

3
  • 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, 2010 at 0:11
  • @EAMann Cool! Glad it helped. Looking forward to seeing the results. Sep 13, 2010 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, 2010 at 15:18
2

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' )

2
  • 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, 2010 at 18:31
  • query_posts()! That's sooo 2010!
    – kaiser
    Sep 22, 2015 at 19:30
0

Once I have faced problem about this and passed hard times hrs to hrs by pulling hair. I googled and didn't found any specific solution about the topics. I found several talents' article but they weren't satisfying my problems. Actually custom taxonomy archive page pagination is depends on some settings of arguments of related functions. So I am actually going here sharing my thoughts of solving the taxonomy archive pagination problem.

Five things you need for custom taxonomy archive page pagination working perfectly:

( 1 ) Don't put exclude_from_search parameter key as register_post_type argument parameter or set it 'exclude_from_search' => false. By default it is set false.

( 2 ) The taxonomy that will be use with the custom post type set 'taxonomies' => 'custom_taxonomy_name' as register_post_type argument parameter or use register_taxonomy_for_object_type() directly. Custom taxonomies still need to be registered with register_taxonomy().

( 3 ) While querying within new WP_Query ($args)

i ) If not set in admin static front page use before new WP_Query($args)

$paged = ( get_query_var('paged') ) ? get_query_var('paged') : 1;

and use $query = new WP_Query( array( 'paged' => $paged ) );

ii ) If set in admin static front page use before 'new WP_Query($args)':

  $paged = ( get_query_var('page') ) ? get_query_var('page') : 1;

and use $query = new WP_Query( array( 'page' => $paged ) );

Remember to use posts_per_page and paged parameter in new WP_Query($arg) argument array.

If not set static front page, then you should use page parameter in new WP_Query ($arg) argument array.

( 4 ) Use Wordpress paginate_links( $args ) function like the example below to render pagination in archive template file.

<?php $big = 999999999; // need an unlikely integer
echo paginate_links( array(
                  'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
                  'format' => '?paged=%#%',  or   '/paged=%#%',  // if using pretty permalink
                   'current' => max( 1, get_query_var('paged') ),
                   'total' => $query->max_num_pages ) ); // Here $max_num_pages is the properties of  new WP_Query() object . It is total number of pages. Is the result of $found_posts / $posts_per_page
 ?>

( 5 ) The paginate_links() function output the ul li listing with page-numbers class. If you use bootstrap inject pagination class to the ul with the help of javascript or jquery and a nice fancy pagination will be output.

Hope you can now enjoy pagination in the taxonomy archive template without any 404 problem :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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