3

Is it a problem to have a custom taxonomy and a custom post type use the same rewrite structure?

I have a custom taxonomy people and a custom post type people_bio. The idea is that you get a list of posts about a person with a short biography on top of the page. I combine them in my taxonomy-people.php template file. The permalink is /people/[person-slug].

Both the custom taxonomy and the custom post type have the rewrite argument set to array('slug' => 'people'). This appears to work: get_term_link('seth-godin', 'people') returns /people/seth-godin/, and for a custom post type with slug seth-godin, get_permalink() also returns /people/seth-godin/. The taxonomy is defined first, and it seems to "win": on a /people/[slug] page, is_tax() is true, while is_single() is false.

So, it works, but I don't feel comfortable with it. Is someone more experienced with the rewrite engine, and can you tell me whether this might break other things?


The relevant part of the plugin file, called in the init action:

register_taxonomy(
    'people',
    'post',
    array(
        'labels' => array(
            'name' => 'People',
            'singular_name' => 'Person',
            'search_items' => 'Search people',
            'popular_items' => 'Popular people',
            'all_items' => 'All people',
            'parent_item' => null,
            'parent_item_colon' => null,
            'edit_item' => 'Edit person',
            'update_item' => 'Update person',
            'add_new_item' => 'Add person',
            'new_item_name' => 'New person',
            'separate_items_with_commas' => 'Separate people with commas',
            'add_or_remove_items' => 'Add or remove people',
            'choose_from_most_used' => 'Choose from the most used people',
        ),
        'public' => true,
        'show_ui' => true,
        'show_tagcloud' => true,
        'hierarchical' => false,
        'update_count_callback' => '',
        'rewrite' => array(
            'slug' => 'people',
            'with_front' => true,
        ),
        'query_var' => 'people',
        'capabilities' => array(),
        'show_in_nav_menus' => true,
    )
);


register_post_type(
    'people_bio',
    array(
        'label' => 'People Bio',
        'labels' => array(
            'name' => 'Biographies',
            'singular_name' => 'Biography',
            'add_new' => 'Add new',
            'add_new_item' => 'Add new biography',
            'edit_item' => 'Edit biography',
            'new_item' => 'New biography',
            'view_item' => 'View biography',
            'search_items' => 'Search biographies',
            'not_found' => 'No biographies found',
            'not_found_in_trash' => 'No biographies found in trash',
            'parent_item_colon' => null,
        ),
        'description' => 'Biography pages of interesting people',
        'public' => true,
        'exclude_from_search' => true,
        'publicly_queryable' => true,
        'show_ui' => true,
        'menu_position' => null,
        'menu_icon' => null,
        'capability_type' => 'post',
        'capabilities' => array(),
        'hierarchical' => false,
        'supports' => array(
            'title',
            'editor',
            //'author',
            'thumbnail',
            'excerpt',
            //'trackbacks',
            'custom-fields',
            //'comments',
            //'revisions',
            //'page-attributes',
        ),
        'register_meta_box_cb' => null,
        'taxonomies' => array(),
        'permalink_epmask' => EP_PERMALINK,
        //'rewrite' => false,
        'rewrite' => array(
            'slug' => 'people',
            'with_front' => true,
        ),
        'query_var' => true,
        'can_export' => true,
        'show_in_nav_menus' => true,
    )
);

register_taxonomy_for_object_type('people', 'people_bio');

(I always use all parameters with register_*(), many with their default values, as an extra documentation, as long as the Codex is not up-to-date)


The taxonomy-people.php template file:

<?php
get_header();

$people_biography = get_posts(array(
    'numberposts' => -1,
    'post_type' => 'people_bio',
    'taxonomy' => 'people',
    'term' => $wp_query->get_queried_object()->slug,
));
?>
<div class="container_24">
    <div class="grid_18" id="content" role="main">
        <?php if ($people_biography) :
            foreach ($people_biography as $bio) : ?>
                <h1><?php echo get_the_title($bio->ID); ?></h1>
                <?php
                echo get_the_post_thumbnail($bio->ID);
                echo apply_filters('the_content', $bio->post_content); ?>
        <?php
            endforeach;
         else: ?>
            <h1><?php esc_html_e($wp_query->get_queried_object()->name); ?></h1>
        <?php endif; ?>
        <?php get_template_part( 'loop', 'archive' ); ?>
    </div><!-- .content -->

    <div class="grid_6" id="default_sidebar">
        <?php dynamic_sidebar('default-sidebar'); ?>
    </div><!-- #default_sidebar -->
</div><!-- .container_24 -->
<div class="clear"></div>
<?php
get_footer();
?>

Update: The generated rewrite rules

The output of my Rewrite Analyzer seems to tell me the taxonomy "wins" for regular taxonomy pages (which is what I noticed), but the custom post type gets all other URLs (including second pages, feeds, ...). This is what I was afraid of, and which I will need to investigate further. Rewrite rules for people taxonomy and post type

3
  • @Jan Fabry - Can you copy in your taxonomy-people.php into your question for review? Oct 18, 2010 at 20:09
  • @Jan Fabry - I misunderstood and thought you were defining your CPT and CT in taxonomy-people.php (of course, I wasn't thinking...) So I was asking for the code where you define your CPT and CT. Oct 19, 2010 at 3:41
  • @Mike: The code defining the taxonomy and post type has been added. I'll remove my first comment to clean up this thread.
    – Jan Fabry
    Oct 19, 2010 at 6:21

3 Answers 3

1

Question: Is it a problem to have a custom taxonomy and a custom post type use the same rewrite structure?

Answer: Yes.

If they share the exact same structure, you will get a race condition, so one of those won't work. But I assume that your scenario does not automatically lead to the same rewrite rules as the two things are differently prefixed.

4
  • Can you expand this answer and give specific examples of what can go wrong?
    – Jan Fabry
    Nov 9, 2010 at 20:29
  • I know one of them won't work, that's no problem since I combine the content of both structures in one template page. My issue is that I should know which template page to use: taxonomy or custom post type? If the rewrite rules are deterministic, and I can always assume that "taxonomy wins" or "post type wins", that would solve my question. I have updated my text with an image of the actual rewrite rules, which shows it seems to be a mixed situation.
    – Jan Fabry
    Nov 10, 2010 at 8:33
  • @Jan: Ah okay, now I understand what you are after. I would need to analyze wp core to find out. But I somehow smell that this could be something to break as this is sort of a grey area and likely to change. Instead it might be a better way just to make taxonomy and post-type templates including the other and you're set for any case as always the "right" template is loaded . Isn't that an easy way to solve it?
    – hakre
    Nov 10, 2010 at 13:38
  • Indeed, I could copy the template file, but you know how similar-but-slightly-different files give you headaches when you fix a bug in one but forget the other... In my quest to understand WP_Rewrite (or die trying), I will hopefully find out how add_rewrite_tag() and add_permastruct() influence the resulting rules.
    – Jan Fabry
    Nov 10, 2010 at 13:52
1

This happens because the permastructure rewrite rules (which includes those created by registering post_types and taxonomies) are run through an array_merge(). The array_merge will replace any rewrite_rules with the same regex in the current location of the array, but add any that don't conflict to the end of the array.

Your best option may be to set the 'rewrite' argument to false for one of the two registrations and adding separate code to add any missing needed rewrite rules to the rewrite_rules_top.

2
  • Indeed, I suspected a merge based on the regex would happen. I'll concentrate on a way that leaves for example people_bio out of the rewrite rules, but allows it to work with get_permalink(). Let's see what that pre_post_link filter allows me to do...
    – Jan Fabry
    Nov 10, 2010 at 14:41
  • This ticket may be relevant to you in implementing the correct solution: core.trac.wordpress.org/ticket/14991 Nov 10, 2010 at 15:36
1

Yes, this will give issues. The four rewrite rules that are generated by the custom taxonomy are also used by the custom post type. The one that you register first gets overwritten by the one that you register after that. Depending on the exact configuration (hierarchical vs. non-hierarchical) similar rules might end up in the final rewrite rules list, but only the first one will "win".

This can have the effect that /people/seth-godin/ queries for a custom taxonomy but /people/seth-godin/page/2/ queries for a custom post type.

Your Answer

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

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