Custom Post Type with two hierarchical Custom Taxonomies: strategy to generate best permalink structure

this is my situation:

I have a Custom Post Type named struttura (like accommodation):

Read More
function custom_post_struttura() {
    $labels = array(
        'name'               => _x( 'Strutture', 'post type general name' ),
        'singular_name'      => _x( 'Struttura', 'post type singular name' ),
        'add_new'            => _x( 'Aggiungi nuova', 'book' ),
        'add_new_item'       => __( 'Aggiungi nuova Struttura' ),
        'edit_item'          => __( 'Modifica Struttura' ),
        'new_item'           => __( 'Nuova Struttura' ),
        'all_items'          => __( 'Tutte le Strutture' ),
        'view_item'          => __( 'Vedi Struttura' ),
        'search_items'       => __( 'Cerca Struttura' ),
        'not_found'          => __( 'Nessuna Struttura trovata' ),
        'not_found_in_trash' => __( 'Nessuna Struttura trovata nel cestino' ),
        'parent_item_colon'  => '',
        'menu_name'          => 'Strutture'
    );
    $args = array(
        'labels'        => $labels,
        'description'   => 'Inserisci una nuova struttura',
        'public'        => true,
        'menu_position' => 5,
        'supports'      => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' ),
        'has_archive'   => true,
        'hierarchical'  => true,
        'rewrite'       => array('slug' => 'strutture/%regione%'),
        'query_var'     => true,
    );
    register_post_type( 'struttura', $args );
}
add_action( 'init', 'custom_post_struttura' );

and a Custom Taxonomy named regione:

function taxonomies_regione() {
    $labels = array(
        'name'              => _x( 'Regioni', 'taxonomy general name' ),
        'singular_name'     => _x( 'Regione', 'taxonomy singular name' ),
        'search_items'      => __( 'Cerca Regione' ),
        'all_items'         => __( 'Tutte le Tipologie' ),
        'parent_item'       => __( 'Parent Regione' ),
        'parent_item_colon' => __( 'Parent Regione:' ),
        'edit_item'         => __( 'Modifica Regione' ),
        'update_item'       => __( 'Aggiorna Regione' ),
        'add_new_item'      => __( 'Aggiungi nuova Regione' ),
        'new_item_name'     => __( 'Nuova Regione' ),
        'menu_name'         => __( 'Regione' ),
    );
    $args = array(
        'labels' => $labels,
        'hierarchical'  => true,
        'public'        => true,
        'query_var'     => true,
        'rewrite'       =>  array(
            'slug' => 'strutture',
            'hierarchical' => true
        ),
    );
    register_taxonomy( 'regione', 'struttura', $args );
}
add_action( 'init', 'taxonomies_regione', 0 );

Now I add into Taxonomy regione these hierarchical categories:

  • Tuscany
    • Florence
      • Empoli
      • Vinci

where Tuscany is parent-category, Florence is sub-parent-category and Empoli / Vinci are a sub-sub-parent-category.

I wanted to obtain a permalink structure like these:

  1. www.example.com/tuscany
  2. www.example.com/tuscany/florence
  3. www.example.com/tuscany/florence/vinci
  4. www.example.com/tuscany/florence/vinci/postname

So I added these three function:

add_filter('rewrite_rules_array', 'mmp_rewrite_rules');
function mmp_rewrite_rules($rules) {
    $newRules  = array();
    $newRules['strutture/(.+)/(.+)/(.+)/(.+)/?$'] = 'index.php?struttura=$matches[4]';
    $newRules['strutture/(.+)/?$']                = 'index.php?regione=$matches[1]'; 

    return array_merge($newRules, $rules);
}

function filter_post_type_link($link, $post) {
    if ($post->post_type != 'struttura')
        return $link;

    if ($cats = get_the_terms($post->ID, 'regione')) {
        $link = str_replace('%regione%', get_taxonomy_parents(array_pop($cats)->term_id, 'regione', false, '/', true), $link);
    }
    return $link;
}
add_filter('post_type_link', 'filter_post_type_link', 10, 2);

function get_taxonomy_parents($id, $taxonomy, $link = false, $nicename = false, $visited = array()) {    
    // removed $seperator="/" after $link, otherwise there was a double slash before the post name in the link    
    $chain = '';   
    $parent = &get_term($id, $taxonomy);

    if (is_wp_error($parent)) {
        return $parent;
    }

    if ($nicename)    
        $name = $parent -> slug;        
    else    
        $name = $parent -> name;

    if ($parent -> parent && ($parent -> parent != $parent -> term_id) && !in_array($parent -> parent, $visited)) {    
        $visited[] = $parent -> parent;    
        $chain .= get_taxonomy_parents($parent -> parent, $taxonomy, $link, $nicename, $visited); //removed $seperator after $link
        $chain .= "/"; //add a / after every category
    }

    if ($link) {
        // nothing, can't get this working :(
    } else    
        $chain .= $name; //don't need the . $separator anymore
    return $chain;
}

Everything works but I obtain this kind of permalink:

  1. www.example.com/strutture/tuscany
  2. www.example.com/strutture/tuscany/florence
  3. www.example.com/strutture/tuscany/florence/vinci
  4. www.example.com/strutture/tuscany/florence/vinci/postname

where strutture is basename. I want to specify that the default post hello-world works.

Now comes the fun part.

I want to add another Custom Taxonomy named tipologia (type) to CPT struttura:

function taxonomies_tipologia() {
    $labels = array(
        'name'              => _x( 'Tipologie', 'taxonomy general name' ),
        'singular_name'     => _x( 'Tipologia', 'taxonomy singular name' ),
        'search_items'      => __( 'Cerca Tipologia' ),
        'all_items'         => __( 'Tutte le Tipologie' ),
        'parent_item'       => __( 'Parent Tipologia' ),
        'parent_item_colon' => __( 'Parent Tipologia:' ),
        'edit_item'         => __( 'Modifica Tipologia' ), 
        'update_item'       => __( 'Aggiorna Tipologia' ),
        'add_new_item'      => __( 'Aggiungi nuova Tipologia' ),
        'new_item_name'     => __( 'Nuova Tipologia' ),
        'menu_name'         => __( 'Tipologia' ),
    );
    $args = array(
        'labels' => $labels,
        'hierarchical'  => true,
        'public'        => true,
        'query_var'     => true
    );
    register_taxonomy( 'tipologia', 'struttura', $args );
}
add_action( 'init', 'taxonomies_tipologia', 0 );

Tipologia has two categories:

  • hotel
  • villa

Now I want to obtain these kind of permalink:

  1. www.example.com/tuscany
  2. www.example.com/tuscany/florence
  3. www.example.com/tuscany/florence/vinci
  4. www.example.com/hotel/tuscany/florence/vinci
  5. www.example.com/hotel
  6. www.example.com/hotel/tuscany/florence/vinci/postname

So I have made some change to the functions:

In the Custom Post Type struttura I modify the rewrite rules

'rewrite' => array('slug' => 'strutture/%tipologia%/%regione%'),

I have changed the mmp_rewrite_rules function

add_filter('rewrite_rules_array', 'mmp_rewrite_rules');
function mmp_rewrite_rules($rules) {
    $newRules  = array();
    $newRules['strutture/(.+)/(.+)/(.+)/(.+)/?$'] = 'index.php?struttura=$matches[4]';
    $newRules['strutture/(.+)/(.+)/?$'] = 'index.php?regione=$matches[2]';
    $newRules['strutture/(.+)/?$'] = 'index.php?tipologia=$matches[1]'; 

    return array_merge($newRules, $rules);
}

I have added this function

function filter_post_type_link_due($link, $post) {
    if ($post->post_type != 'struttura')
        return $link;

    if ($cats = get_the_terms($post->ID, 'tipologia')) {
        $link = str_replace('%tipologia%', get_taxonomy_parents(array_pop($cats)->term_id, 'tipologia', false, '/', true), $link);
    }
    return $link;
}
add_filter('post_type_link', 'filter_post_type_link_due', 10, 2);

With this configuration I obtain this kind of permalink structure:

  1. www.example.com/regione/tuscany
  2. www.example.com/regione/tuscany/florence
  3. www.example.com/regione/tuscany/florence/vinci
  4. www.example.com/strutture/hotel/tuscany/florence/vinci error 404
  5. www.example.com/hotel/tuscany/florence/vinci error 404
  6. www.example.com/tipologia/hotel
  7. www.example.com/strutture/hotel/tuscany/florence/vinci/postname

where regione is the name of Custom Taxonomy, tipologia is the name of Custom Taxonomy and strutture is a basename. The default post name hello-world works.

If I change something into rewrite rule like slugs I obtain 404.

My questions are:

is it possible to obtain this kind of permalink structure?

  1. www.example.com/tuscany
  2. www.example.com/tuscany/florence
  3. www.example.com/tuscany/florence/vinci
  4. www.example.com/hotel/tuscany/florence/vinci
  5. www.example.com/hotel
  6. www.example.com/hotel/tuscany/florence/vinci/postname

How can I remove the basename from CPT, CT and permalinks?

Is this the right way to obtain this structure?

I saw this permalink strategy here:

  1. http://www.agriturismo.net/tuscany/
  2. http://www.agriturismo.net/tuscany/florence/
  3. http://www.agriturismo.net/tuscany/florence/vinci/
  4. http://www.agriturismo.net/villa/tuscany/florence/vinci/
  5. http://www.agriturismo.net/villa

Thank you in advance.

PS: I go into permalink page to flush rewrite every time. I’m trying this strategy from five weeks.

Related posts