Multiple custom post types using the same taxonomy = URL frustrations

I have two custom post types:

  • Events
  • Businesses

I have a new taxonomy that both these CTP’s share:

Read More
  • Locations

If I go to “domain.com/events/” I see an archive of all the events, and if I go to “domain.com/businesses/” I see an archive of all the businesses. So far, so good.

If I go to “domain.com/locations/” I see an archive of all the events AND businesses, which is Ok.

However, how do I view the event locations only? “domain.com/locations/events” or “domain.com/events/locations” doesn’t work.

Do I have to change the rewrite settings for either the locations taxonomy or the CPT? It seems I’m stuck!

Related posts

2 comments

  1. You’ll have to add some new rewrite rules, thankfully WordPress makes it fairly straightforward using a few function calls.

    // use the init action to modify rewrite rules
    add_action( 'init', function() {
        global $wp_rewrite;
    
        // add rewrite tag for the post type
        // - %posttype% is a new tag that will be replaced with the regex in the actual query
        // - the regex will extract the post_type name from the URL and use it in the query
        add_rewrite_tag( '%posttype%', '([^/]+)', 'post_type=' );
    
        // create the new permastruct by combining the post type & taxonomy permastructs
        // - custom taxonomies and post types are added to the extra_permastructs array in WP_Rewrite
        // - change 'category' to desired taxonomy
        // - output will be '%posttype%/category/%category%'
        $types_and_cats_permastruct = '%posttype%' . $wp_rewrite->get_extra_permastruct( 'category' );
    
        // add the permastruct for post type & taxonomy
        add_permastruct( 'post_type_and_category', $types_and_cats_permastruct, array(
            'with_front' => true,           //  - with_front (bool) - Should the structure be prepended with WP_Rewrite::$front? Default is true.
            'ep_mask' => EP_ALL_ARCHIVES,   //  - ep_mask (int) - Endpoint mask defining what endpoints are added to the structure. Default is EP_NONE.
            'paged' => true,                //  - paged (bool) - Should archive pagination rules be added for the structure? Default is true.
            'feed' => true,                 //  - feed (bool) - Should feed rewrite rules be added for the structure? Default is true.
            'forcomments' => false,         //  - forcomments (bool) - Should the feed rules be a query for a comments feed? Default is false.
            'walk_dirs' => false,           //  - walk_dirs (bool) - Should the 'directories' making up the structure be walked over and rewrite
                                            //    rules built for each in turn? Default is true.
            'endpoints' => true             //  - endpoints (bool) - Should endpoints be applied to the generated rewrite rules? Default is true.
        ) );
    
    } );
    

    So to explain what I’m doing above:

    1. Adding a rewrite tag with add_rewrite_tag() so that when you put the custom post type name into the URL (eg. /events/location/uk/) it will be recognised by the regular expression and the resulting query WP runs would contain post_type=events
    2. Making a new permastruct to generate rules for using the tag we just added and the existing taxonomy permastruct, in your case this would be location so /event/location/uk will show uk events and /business/location/uk will show uk businesses
    3. Adding the new permastruct with add_permastruct() so that WP generates the new rewrite rules whenever permalinks are refreshed. In the 3rd parameter it’s very important to have walk_dirs set to false as you’ll get some undesirable aggressive rewrite rules with archives for /%posttype%/category/ and /%posttype%/

    Gotchas

    • Generating links – if you want to use the_terms() to output location links for a business or event that only shows the originating post type you’ll have to filter the URLs or write a custom function to output URLs to match your permastruct
    • If you never want an archive listing both events and businesses then 2 separate taxonomies is a better idea as you’ll more easily be able to tell if a term has any posts in it eg. when generating links and deciding whether to output a link to an empty archive or not. In that case @richard-howarth’s answer is correct
  2. You can specify the slug to use in the args when calling the register_taxonomy function by using ‘rewrite’.

    So, you’d have something like the following:

    $args = array(
        'labels' => $labels,
        'rewrite' => array( 'slug'=>'events/locations' )
    );
    register_taxonomy( 'event_location_tax_name', 'event_location_cpt_name', $args );
    

    And then replicate for Businesses :

    $args = array(
        'labels' => $labels,
        'rewrite' => array( 'slug'=>'businesses/locations' )
    );
    register_taxonomy( 'business_location_tax_name', 'business_location_cpt_name', $args );
    

    Hope that helps?!

    Thanks
    Rik

Comments are closed.