How to specify URLS for custom posts & taxonomies

I’ve read a few posts about this, but can’t find a clear answer 🙁

  • I have a custom post type called {ondemand}
  • Within the custom post, I have three taxonomies {speakers} and {categories} and {season}
  • Each taxonomy has 3-4 terms, for example under {speakers} there is one called [joebloggs]

Currently I have a main URL on our site, where the latest post is placed :
www.mysite.com/ondemand

When I filter the posts by taxonomy terms the URL defaults to:
www.mysite.com/ondemand/{speakers}/[joebloggs]
(uses taxonomy.php to display the results)

However I’d like the URL to be like this for any term filtered:
www.mysite.com/ondemand/[joebloggs]

Here’s the code that I’ve used in my functions.php – I tried a re-write in each taxonomy (commented out) but that didn’t work – they lead to a 404 page…. Any advice or re-code hints would be very much appreciated

/**
* On Demand TV Post Type
*/

add_action('init', 'ondemand');

function ondemand() {

$labels = array(
'name' => __('On Demand TV', 'post type general name'),
'singular_name' => __('TV Episode', 'post type singular name'),
'add_new' => __('New TV Episode', 'TV Episode'),
'add_new_item' => __('Add TV Episode'),
'edit_item' => __('Edit TV Episode Item'),
'new_item' => __('New TV Episode Item'),
'view_item' => __('View TV Episode Item'),
'search_items' => __('Search TV Episode'),
'not_found' => __('Nothing found'),
'not_found_in_trash' => __('Nothing found in Trash'),
'parent_item_colon' => ''
);

$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'query_var' => true,
'rewrite' => false,    
'capability_type' => 'post',
'hierarchical' => true,
'menu_position' => 3,   
'supports' => array('title','editor','comments','thumbnail')
); 

register_post_type( 'ondemand' , $args );

register_taxonomy("Categories", array("ondemand"), 
array("hierarchical" => true, 
"label" => "Category", 
"singular_label" => "Category", 
"rewrite" => true));

register_taxonomy("Speaker", array("ondemand"), 
array("hierarchical" => true, 
"label" => "Speakers", 
"singular_label" => "Speaker", 
"rewrite" => true));
//"rewrite" => array('slug' =>'ondemand', 'hierarchical' => true, 'with_front' => false)));

register_taxonomy("Season", array("ondemand"), 
array("hierarchical" => true, 
"label" => "Seasons", 
"singular_label" => "Season",
"rewrite" => true));
//"rewrite" => array('slug' =>'ondemand', 'hierarchical' => true, 'with_front' => true)));

}

1 Answer
1

I have done this before, but I warn you that this is something to avoid doing. It is best when you have a very limited number of terms that don’t change.

With the warning over, here is how to do it. You need create a rewrite rule with the term slugs in it to not break your rewrite rules. If you use a catch all, then it will break the rewrite rules for your pages.

function my_custom_rewrite_rules_array( $rules ) {
    global $wp_rewrite;

    // Generate the regexp for the terms
    $terms = get_terms( 'Speaker', array( 'hide_empty' => false ) );
    $term_slugs = array();
    foreach ( $terms as $term ) {
        $term_slugs[] = preg_quote( $term->slug );
    }

    // (term1-slug|term2-slug|term3-slug)
    $terms_regexp = '(' . implode( '|', $term_slugs ) . ')';

    // add_rewrite_tag( $tagname, $regex, $query )
    $wp_rewrite->add_rewrite_tag( "%speaker%", $terms_regexp, "taxonomy=speaker&term=" );
    // Use generate_rewrite_rules to make the various rules for pagination and other endpoints
    $speaker_rules = $wp_rewrite->generate_rewrite_rules( '/%speaker%/' );

    // Add our speaker rules
    return $speaker_rules + $rules;
}
add_filter( 'rewrite_rules_array', 'my_custom_rewrite_rules_array' );

As you may see, the downside of this is the rewrite rules need to be updated each time a new term is created. We can rebuild the rules whenever a change happens.

add_action( 'created_term', 'my_custom_flush_rewrite_rules', 10, 3 );
add_action( 'edited_term', 'my_custom_flush_rewrite_rules', 10, 3 );
add_action( 'delete_term', 'my_custom_flush_rewrite_rules', 10, 3 );
function my_custom_flush_rewrite_rules( $term_id, $tt_id, $taxonomy ) {
    $taxonomies_to_refresh = array( 'Speaker' );
    if ( in_array( $taxonomy, $taxonomies_to_refresh ) ) {
        flush_rewrite_rules();
    }
}

Leave a Comment