49

I am having trouble working with WordPress rewrite rules, and could use some help.

I have a custom post type called _shows_.

All shows have a single custom taxonomy category _show-category_. A _show_ will never have more than one _show-category_.

I would like my urls to route in this manner:

www.mysite.com/shows/  =>  archive-shows.php

www.mysite.com/shows/%category%/ => taxonomy-show-category.php

www.mysite.com/shows/%category%/%postname%/ => single-shows.php

So as a real world example, lets say we have a _show-category_ "Foo" and a _show_ post titled "Bar" that has "Foo" as it's _show-category_. I would expect my WordPress app to look like this:

www.mysite.com/shows/foo/ => shows all posts under the foo category
www.mysite.com/shows/foo/bar => shows the indivual post

I try to avoid plugins when possible, but am open to any solution.

2
  • 1
    just pointing you to something i had to do before.. wordpress.stackexchange.com/questions/102246/… Commented Aug 1, 2013 at 17:14
  • Brilliant question, and the accepted answer by @Milo is so well done it really should be in official Wordpress documentation. This is a VERY common use case for proper URLs.
    – Khom Nazid
    Commented Apr 6, 2022 at 1:36

1 Answer 1

93

First, register your taxonomy and set the slug argument of rewrite to shows:

register_taxonomy(
    'show_category',
    'show',
    array(
        'rewrite' => array( 'slug' => 'shows', 'with_front' => false ),
        // your other args...
    )
);

Next, register your post type and set the slug to shows/%show_category%, and set has_archive argument to shows:

register_post_type(
    'show',
    array(
        'rewrite' => array( 'slug' => 'shows/%show_category%', 'with_front' => false ),
        'has_archive' => 'shows',
        // your other args...
    )
);

Last, add a filter to post_type_link to substitute the show category in individual show permalinks:

function wpa_show_permalinks( $post_link, $post ){
    if ( is_object( $post ) && $post->post_type == 'show' ){
        $terms = wp_get_object_terms( $post->ID, 'show_category' );
        if( $terms ){
            return str_replace( '%show_category%' , $terms[0]->slug , $post_link );
        }
    }
    return $post_link;
}
add_filter( 'post_type_link', 'wpa_show_permalinks', 1, 2 );

EDIT

Forgot the has_archive argument of register_post_type above, that should be set to shows.

22
  • 5
    If you're making a change to an existing WordPress instance, make sure you go to Settings > Permalinks and click save. The changes you've made in functions.php won't take effect until you do.
    – Jay Neely
    Commented Jan 5, 2016 at 0:14
  • 3
    This almost worked for me in that the taxonomy displays on the post type page, the /post_type/taxonomy/ is a legitimate page (previously 404) but my /post_type/taxonomy/post is 404'ing. I noticed when registering the taxonomy above both "show_category", "show" were being registered, even though only the show_category is the taxonomy. I'm only registering the taxonomy. Commented Sep 28, 2016 at 7:16
  • 4
    @Milo any way to get this to work with sub sub tax like shows/tax/subtax/post ?
    – Benn
    Commented Jan 26, 2017 at 14:22
  • 5
    I so wished this would work for me as well but every singular ends in a 404....
    – Beee
    Commented Mar 2, 2019 at 16:39
  • 3
    I had the same 404 issue on individual show post pages as commented by other users, but was able to work around it by adding add_rewrite_rule( 'shows/([^/]+)/([^/]+)', 'index.php?show =$matches[2]', 'top' ); to my functions. This will match the second slug portion after 'show' to a show post name.
    – Sarah
    Commented Jan 8, 2020 at 13:31

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