Permalink post_type structure with taxonomy slug in it
Let’s look at the simple example of a eshop on WordPress.
The shop has custom post type product
and category for products product_cat
. By default product links looks like /product/product-name/
.
How to change it to /{product category name}/{product name}/
?
For example we want to change /product/burton-cartel/
to /snowboard-bindings/burton-cartel/
.
The following code will let you do that. The code is for your current theme functions.php
file and works great with the following permalink settings:
Rewrite Post type links and Change default request
add_filter('post_link', 'rudr_post_type_permalink', 20, 3);
add_filter('post_type_link', 'rudr_post_type_permalink', 20, 3);
function rudr_post_type_permalink($permalink, $post_id, $leavename) {
$post_type_name = 'product'; // post type name, you can find it in admin area or in register_post_type() function
$post_type_slug = 'product'; // the part of your product URLs, not always matches with the post type name
$tax_name = 'product_cat'; // the product categories taxonomy name
$post = get_post( $post_id );
if ( strpos( $permalink, $post_type_slug ) === FALSE || $post->post_type != $post_type_name ) // do not make changes if the post has different type or its URL doesn't contain the given post type slug
return $permalink;
$terms = wp_get_object_terms( $post->ID, $tax_name ); // get all terms (product categories) of this post (product)
if ( !is_wp_error( $terms ) && !empty( $terms ) && is_object( $terms[0] ) ) // rewrite only if this product has categories
$permalink = str_replace( $post_type_slug, $terms[0]->slug, $permalink );
return $permalink;
}
add_filter('request', 'rudr_post_type_request', 1, 1 );
function rudr_post_type_request( $query ){
global $wpdb;
$post_type_name = 'product'; // specify your own here
$tax_name = 'product_cat'; // and here
$slug = $query['attachment']; // when we change the post type link, WordPress thinks that these are attachment pages
// get the post with the given type and slug from the database
$post_id = $wpdb->get_var(
"
SELECT ID
FROM $wpdb->posts
WHERE post_name = '$slug'
AND post_type = '$post_type_name'
"
);
$terms = wp_get_object_terms( $post_id, $tax_name ); // our post should have the terms
if( isset( $slug ) && $post_id && !is_wp_error( $terms ) && !empty( $terms ) ) : // change the query
unset( $query['attachment'] );
$query[$post_type_name] = $slug;
$query['post_type'] = $post_type_name;
$query['name'] = $slug;
endif;
return $query;
}
How to perform 301 redirect from the old post URLs
add_action('template_redirect', 'rudr_post_type_redirect');
function rudr_post_type_redirect() {
$post_type_name = 'product'; // specify your own here
$post_type_slug = 'product'; // here
$tax_name = 'platform'; // and here
if( strpos( $_SERVER['REQUEST_URI'], $post_type_slug ) === FALSE) // do not redirect if the URL doesn't contain the given post type slug
return;
if( is_singular( $post_type_name ) ) : // if post type page
global $post, $wp_rewrite;
$terms = wp_get_object_terms( $post->ID, $tax_name ); // get terms attached
if ( !is_wp_error( $terms ) && !empty( $terms ) && is_object( $terms[0] ) ) :
wp_redirect( site_url() . '/' . $wp_rewrite->front . '/' . $terms[0]->slug . '/' . $post->post_name, 301 );
// wp_redirect( get_permalink( $post->ID ), 301 ); // depends on the previous code from this post
exit();
endif;
endif;
}

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
The code works,
but it turns out this error:
Notice: Undefined index: attachment in /home2/qgpalazz/public_html/sviluppo_fincos/wp-content/plugins/cpt-immobili/cpt-immobili.php on line 148
In the line 148:
$slug = $query[‘attachment’]; // when we change the post type link, WordPress thinks that these are attachment pages
How we can resolve the error?
Thanks,
Riccardo
other request:
If I call the page with the same name as the URL changes,
It can ensure that the url remains the same because there is already the beginning of taxonomy url that holds different url?
Thanks,
Riccardo
Hi Riccardo,
to prevent “Notice: Undefined index” you may turn off WP_DEBUG in
wp-config.php
, or in my code add the condition:if( isset( $query['attachment'] ) )
.I don’t recommend to name the page the same name as the URL slugs.
There is a problem when you have 2 post types… For one i need to add category and for another one i need to just remove the base slug.
The task becomes more difficult when you work with 2 and more post types/taxonomies. Actually you can just copy the code for another post type.
Hmm.. I think I will publish a simple plugin for that later.
Hehe. Thank you!
Show this error “Oops! That page can’t be found” ???
Settings > Permalinks, then Save Changes
Hi there, is there an easy way to modify this code to work with a custom structure of /%category%/%postname%/? Or if that is impossible, is there a way to re-add /%category%/ to just the default post type? Any help is greatly appreciated. And thanks for sharing this code!
Hi Chris,
Sorry, maybe I just do not understand you, but the code in this post is just for this purpose.
Oh I was referring to the built in post type, not a custom one. My site also uses a the built in post type with categories and the permalink structure was set up to be: /%category%/%postname%/.
Your code works perfectly for my custom post type but I had to change /%category%/%postname%/ to /%postname%/ in my permalink settings to get it to work so now all of my built in WP posts are just domain.com/postname/ instead of doamin.com/categoryname/postname/.
Any way you can think of to get around that?
I appear to have solved it by reusing your code once more to rewrite the built in post type to have /%category%/ used before /%postname%/ essentially bypassing WP permalink setting requirements.
I’m glad you’ve figured it out. Thanks for sharing your code.
Hi !
I have found this works really well, better than all others I tested, think because yours has the redirect.
but one issue I’m having is I get a 404 on child posts of a parent post (hierarchical cpt)
any ideas?
Thanks heaps
Hi Jamie,
For any hierarchical items (no matter post types or terms) the code will be different. Unfortunately I do not have ready code for you.
Hi Misha
is it just the redirect part that needs to be different or the whole thing?
It’s for a client project.
Hello,
Thanks for the wonderful work. It works perfectly fine but is not working when I have to parent taxonomy as well to the permalink.
e.g. f/news/post-name
This throws 404 error.
How can this be solved?
Hello,
If you have parent taxonomies, the code will be different. If you need my personal help with the code, you can contact me by email.
Hi, thanks for this tutorial, it`s very helpful! Is there some way to make show subtax slug in url also?
hey thank you so much for the code.. its really very helpful to me..