After following Jeffs suggestion on this thread to create nested parent and child taxonomy terms within a permalink like...


It mostly works except for one problem.

Before I continue, I should mention I have a custom post type called gallery and a taxonomy called gallery_cat.


/gallery/ - archive-gallery.php
/gallery/wedding-cakes/ - parent taxonomy - taxonomy-gallery_cat.php     
/gallery/wedding-cakes/chocolate/ - child taxonomy - taxonomy-gallery_cat.php      
/gallery/wedding-cakes/chocolate/cpt-entry/ - CPT entry under child taxonomy - single-gallery.php


/gallery/wedding-cakes/cpt-entry/ - CPT entry under parent taxonomy

Here is my code in functions.php:

add_action('init', 'create_gallery_post_type');

function create_gallery_post_type() {

        'label' => 'Categories',
        'singular_label' => 'Category',
        'hierarchical' => true,
        'query_var' => true,
        'rewrite' => array('slug' => 'gallery', 'hierarchical' => true ),

$labels = array(
    'name' => _x('Gallery', 'post type general name'),
    'singular_name' => _x('Photo', 'post type singular name'),
'add_new' => _x('Add New', 'gallery'),

$args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true,
    'query_var' => true,
    'capability_type' => 'post',
    'hierarchical' => false,
    'menu_position' => null,
    'supports' => array('title','editor','thumbnail', 'excerpt', 'author', 'comments'),
    'rewrite' => array(
        'slug' => 'gallery/%gallery_cat%',
        'with_front' => false
    'has_archive' => 'gallery',
    'menu_icon' => get_bloginfo('template_directory') . '/images/gallery-icon.png' //16x16 png if you want an icon

register_post_type( 'gallery' , $args );

function filter_post_type_link($link, $post) {
if ($post->post_type != 'gallery')
    return $link;
if ($cats = get_the_terms($post->ID, 'gallery_cat')) {
    $link = str_replace('%gallery_cat%', rtrim(get_taxonomy_parents(array_pop($cats)->term_id, 'gallery_cat', false, '/', true),"/"), $link); // see custom function defined below
return $link;
add_filter('post_type_link', 'filter_post_type_link', 10, 2);

// my own function to do what get_category_parents does for other taxonomies
function get_taxonomy_parents($id, $taxonomy, $link = false, $separator = '/', $nicename = false, $visited = array()) {    
$chain = '';   
$parent = &get_term($id, $taxonomy);

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

if ($nicename)    
    $name = $parent -> slug;        
    $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, $separator, $nicename, $visited);
if ($link) {
    // nothing, can't get this working :(
} else    
    $chain .= $name . $separator;
return $chain;    

//Rewrite rules
add_filter('rewrite_rules_array', 'gallery_rewrite_rules');
function gallery_rewrite_rules($rules) {
$newRules  = array();

$newRules['gallery/(.+)/(.+)/(.+)/?$'] = 'index.php?gallery=$matches[3]';   
$newRules['gallery/(.+)/(.+)/?$'] = 'index.php?gallery_cat=$matches[2]'; 
$newRules['gallery/(.+)/?$']      = 'index.php?gallery_cat=$matches[1]';

return array_merge($newRules, $rules);

Now, I think the problem is where I need to add the following line to the rewrite rules array:

$newRules['gallery/(.+)/(.+)/?$'] = 'index.php?gallery=$matches[2]';

because my custom structure won't always have the post name as the 3rd uri segment because if the CPT is only under a parent taxonomy, than it will be in the 2nd uri segment.

But when I add that, it breaks things. My best guess is that it is clashing with this line...

$newRules['gallery/(.+)/(.+)/?$'] = 'index.php?gallery_cat=$matches[2]';

Jeff, who helped me make it this far from this thread, said the following...

If you'll have varying levels of nested terms then you'll need to write a function to check whether the the last uri segment is a custom post type or a taxonomy term to know which rule to add

Anyone know how this can be accomplished?


1 Answer 1


To see how we can make this work, have a read through the Query Overview Codex page, particularly the What Plugins can Modify section:

Modify the query specification, after variable values are saved (request filter or parse_request action; if you want to use conditional tag tests, use the parse_query or pre_get_posts action, as these run after the is_ variables are set).

In this case, we want to filter request, which will be an array of the query vars which were set by the parse_request method of the WP class (scroll to the end of this function to see where the filter is applied).

In our filter, we'll check if gallery_cat is set, and if the requested term is actually an existing gallery_cat term. If it's not, we'll assume it's a gallery post, and reset the query vars to make WordPress query for the post instead of the term. To do that we need to set 3 different query vars- gallery, name, and post_type.

function wpd_gallery_request_filter( $request ){
    if( array_key_exists( 'gallery_cat' , $request )
        && ! get_term_by( 'slug', $request['gallery_cat'], 'gallery_cat' ) ){
            $request['gallery'] = $request['gallery_cat'];
            $request['name'] = $request['gallery_cat'];
            $request['post_type'] = 'gallery';
            unset( $request['gallery_cat'] );
    return $request;
add_filter( 'request', 'wpd_gallery_request_filter' );
  • Thanks @Milo, can you please tell me where and how I would use this function exactly?
    – serks
    Commented Feb 4, 2015 at 5:59
  • it would go in your functions.php file with the rest of your code, just paste it in there and it'll do its thing.
    – Milo
    Commented Feb 4, 2015 at 6:06
  • How that worked goes completely over my head (even though you explained it very well) but yes it worked. Had to flush the permalinks. Thanks Milo
    – serks
    Commented Feb 4, 2015 at 6:12
  • I am having another problem that is related to the above question. The main archive page of my gallery is at url.com/gallery Now when the pagination occurs, it becomes /gallery/page/2. But this clashes with the rewrite_rules_array filter function causing a 404 page not found. What can I add to the rewrite_rules_array to solve this?
    – serks
    Commented Feb 5, 2015 at 7:11
  • you have to add another rule with /page/ and set the paged query var. if you var_dump the contents of $rules inside your filter, you'll see the pagination rules WordPress generates for other archives and you can copy that format.
    – Milo
    Commented Feb 7, 2015 at 1:05

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.