Rewrite CPT slug with two taxonomy slug instead of one

It seems WordPress breaks other rewrite rules when you use the character % for rewrite slug of CPTs. Not sure why.

Anyway, I got it to work making the following changes in your code.

  1. Stop using %. It’s not required actually:
$rewrite = array(
    'slug'       => 'sector/service',
    'with_front' => false // It has nothing to due with the solution, but you'd better put false here.
);
  1. Replace /sector/ and /service/ instead of %sector% and %service%:
function rewrite_location_post_slug( $post_link, $post ) {
    if ( $post->post_type == 'location' ) {
        $terms_service = wp_get_object_terms( $post->ID, 'service' );
        $terms_sector  = wp_get_object_terms( $post->ID, 'sector' );
        if ( $terms_service && $terms_sector ) {
            $sector_replaced = str_replace( '/sector/', "/{$terms_sector[0]->slug}/", $post_link );

            return str_replace( '/service/', "/{$terms_service[0]->slug}/", $sector_replaced );
        }
    }

    return $post_link;
}

add_filter( 'post_type_link', 'rewrite_location_post_slug', 1, 2 );

So far so good. Now, if you flush your permalinks you’ll see that your contact page is back, but your site_url/sector/service/location/ is gone. That relates to the missing %, so we have to add that custom rewrite rule we talked about in the comments, which is actually dangerous as it’s kind of a “fake pattern”:

function rewrite_sector_service_location_url() {
    add_rewrite_rule( '^([^/]+)/([^/]+)/([^/]+)/?', 'index.php?location=$matches[3]', 'top' );
}

add_action( 'init', 'rewrite_sector_service_location_url' );

Flush your rewrite rules and you’ll see that now everything works.

It should work for you, but I’d recommend you to use a prefix for your sectors and/or services, so we could add a standard to our rewrite pattern.

[EDIT]

I’ll try to explain the solution if you chose adding prefixes to your terms.

Assume you chose the prefix sector to be given to all terms from the taxonomy sector.

So if you had 2 terms: Chemical and Construction, their slugs by default would be chemical and construction. But following that prefix rule their slugs should be changed to sector-chemical and sector-construction, respectively. Btw, WordPress has a filter (https://developer.wordpress.org/reference/hooks/pre_insert_term/) which you could use to add the prefix automatically.

Using that prefix standard our rewrite rule should be changed to:

function rewrite_sector_service_location_url() {
    add_rewrite_rule( '^(sector-[^/]+)/([^/]+)/([^/]+)/?', 'index.php?location=$matches[3]', 'top' );
}

add_action( 'init', 'rewrite_sector_service_location_url' );

The rule above makes sure we would match something like
http://example.com/sector-chemical/service/post-slug
and would never match other URLs like:
http://example.com/blog/page/2.

Leave a Comment