I have two custom post types:
I have a new taxonomy that both these CTP’s share:
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!
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:
- 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
- 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
- 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