Remove Post Type Slug from URLs
I’ve been asked about how to do it probably a million times. The question is how to make the URLs of your custom post types (or WooCommerce products) to look like Pages.
For example how to have example.com/t-shirt/
instead of example.com/product/t-shirt/
.
In this tutorial I am going to provide you a complete guide! As an example we are going to remove /product/ from WooCommerce product URLs. But before we begin I would like to warn you that you have to avoid it if possible, because it may slows down the overall performance of your website and you have to be extra-careful when assigning a specific slug for your posts.
Let’s begin with a simple post_type_link
filter hook.
add_filter( 'post_type_link', 'rudr_remove_cpt_slug', 20, 3 );
function rudr_remove_cpt_slug( $permalink, $post_id, $leavename ) {
// please add a post type slug that is currently displaying in URL
$cpt_slug = 'product';
$permalink = str_replace( "/{$cpt_slug}/", '/', $permalink );
return $permalink;
}
$cpt_slug
here is what is provided in Settings – Permalinks, under Product Permalinks. For custom post types it is either a post type name or the rewrite slug parameter.
I used the default value, but theoretically you could reduce the number of possible errors if you use something custom here.

Now, if you go to WooCommerce shop page, you will see that the product links has been changes… but… when you try to open any product page you will get 404 error. It is because we changed the URLs but we didn’t change the way WordPress processes them.
Custom URL processing can be done in request
hook. Please keep in mind that the code below is also dependent on permalinks common settings. It will work great for a post name value.

Finally, the code:
add_filter( 'request', function( $query ){
if( empty( $query[ 'name' ] ) ) {
return $query;
}
global $wpdb;
$cpt_name = 'product'; // not slug!!
// yeah... we have to run one more SQL query...
$post_id = $wpdb->get_var(
$wpdb->prepare(
"
SELECT ID
FROM $wpdb->posts
WHERE post_name = '%s'
AND post_type = '%s'
",
array(
$query[ 'name' ],
$cpt_name
)
)
);
if( $post_id ) {
$query[ $cpt_name ] = $query[ 'name' ];
$query[ 'post_type' ] = $cpt_name;
}
return $query;
}, 1 );
Still got 404 error? Just flush permalinks (you can update them in settings without changing).
That’s actually it! Maybe you would also like to configure redirects from old URLs to new ones with template_redirect
hook but it is optional here.

Misha Rudrastyh
Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me