How to enable hierarchical permalinks for hierarchical taxonomies

The question:

If you have a category called “term” and a subcategory called “subterm”, your can access subterm posts at /cat/subcat. But this doesn’t work out of the box with custom taxonomies. They are accessible at /taxonomy/subterm, but not /taxonomy/term/subterm.

They’ve gone over this in the WordPress Trac (, and it kind of looks like they have a solution, but as I’ve never used the Trac and don’t fully understand its language (diffs, etc), I need someone more experienced to actually tell me how to implement this. Is there code there that I have to paste into WordPress core files? Is this already implemented and I can add something to my theme’s functions.php?

If possible I’d prefer not to modify any core files. Help!

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

This is implemented in WordPress now as of 3.1.

When you register your taxonomy, make sure to set rewrite hierarchical to true as well as the taxonomy itself:

register_taxonomy('genre',array('book'), array(
'hierarchical' => true, // this makes it hierarchical in the UI
'labels' => $labels,
'show_ui' => true,
'query_var' => true,
'rewrite' => array( 'hierarchical' => true ), // this makes hierarchical URLs

Method 2

Is there a way to add a parameter to an already-registered custom taxonomy? All of my taxonomies were built with a plugin, so it would be nice if I could add something to functions.php that would just add ‘rewrite’ => array( ‘hierarchical’ => true ) to those taxonomies.

You should be able to use register_taxonomy to re-register the taxonomy you want to affect.

WARNING: Untested code!
(Just off the top of my head, mostly. I take no responsibility for broken sites.):

function reregister_taxonomy() {
    # the post types that the taxonomy is registered to
    $post_types = array('post');
    # set this to the taxonomy name
    $tax_name = 'TAXONOMY_NAME_TO_CHANGE';
    # load the already created taxonomy as array so we can
    # pass it back in as $args to register_taxonomy
    $tax = (array)get_taxonomy($tax_name);

    if ($tax) {
        # adjust the hierarchical necessities
        $tax['hierarchical'] = true;
        $tax['rewrite']['hierarchical'] = true;

        # adjust the hierarchical niceties (these could be ignored)
        $tax['labels']['parent_item'] = sprintf(__("Parent %s"),
        $tax['labels']['parent_item_colon'] = sprintf(__("Parent %s:"),

        # cast caps to array as expected by register_taxonomy
        $tax['capabilities'] = (array)$tax['cap'];
        # cast labels to array
        $tax['labels'] = (array)$tax['labels'];
        # register the taxonomy with our new settings
        register_taxonomy($tax_name, array('post'), $tax);
# init action with a late priority so other taxonomies are loaded
# alternatively could be done with the `registered_taxonomy` action hook
add_action('init', 'reregister_taxonomy', 9999);

Only after writing this did I realize this question was a year-and-a-half old, mayhaps somebody will find it useful anyhow.

Method 3

To make hierarchical permalinks working you need to add rewrite rules. I’ve managed to assemble some code making a custom post type with a custom taxonomy working with parent/child terms reflected in permalinks. It’s not perfect, but it’s working!

function keha_add_rewrite_rules() {
        add_rewrite_rule( '^posttype_slug/(.+?)/(.+?)/(.+?)$', 'index.php?taxonomy=$matches[1]&taxonomy=$matches[2]&posttype=$matches[3]', 'top' );
        add_rewrite_rule( '^posttype_slug/(.+?)/(.+?)/$', 'index.php?posttype=$matches[2]', 'top' );
        add_rewrite_rule( '^posttype_slug/(.+?)/(.+?)/(.+?)$', 'index.php?posttype=$matches[3]', 'top' );
        add_rewrite_rule( '^posttype_slug/(.+?)/(.+?)/?$', 'index.php?taxonomy=$matches[2]', 'top' );
        add_rewrite_rule( '^posttype_slug/(.+?)$', 'index.php?taxonomy=$matches[1]', 'top' );
add_action('init', 'keha_add_rewrite_rules');

View my working example at Github:

Method 4

Thanks to @anubhava

A little study about WP Rewrite API find out the solution.

1) I have created a custom rewrite url and placed it into my functions.php

function services_rewrite_basic() {
  add_rewrite_rule('^services/.*', 'index.php?page_id=110&level=$matches[1]&level=$matches[1]&level=$matches[1]', 'top');
add_action('init', 'services_rewrite_basic');

2) And finally just saved permlink page without any changes and it does the trick.

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment