Edited: 2022-11-15
Since originally writing this post, I have found Permalink Manager Lite and presently recommend it in favor of the custom code below.
One question that comes up semi-regularly with my support work for Custom Post Type UI is how to remove the post type slug from a given permalink. While I know that the slug is an important component, I also understand why some people may want to have it removed as well.
Without the slug in place, WordPress will be looking for just posts with the post
post type, and thus not find a result to display.
For my tutorial today, I am going to provide some code that will help remove the slug from the generated permalink value as well as help WordPress still query for the post type when it’s making its request.
All of the code can go in your active theme’s functions.php or child theme if you have one of that. Alternatively you could create your own quick plugin or drop the code into a file put in your mu-plugin
folder.
Permalink string
For the first part of the code, we will remove the slug from the generated permalink string. We are also only going to do this for published posts in our post type. Our example post type slug is movie
and you will need to change that to whatever post type slug you’re removing in your own example.
function cptui_demo_remove_slug_from_permalink_string( $post_link, $post ) {
if ( 'publish' !== $post->post_status ) {
return $post_link;
}
if ( 'movie' === $post->post_type ) {
$post_link = str_replace(
'/' . $post->post_type . '/',
'/',
$post_link
);
}
return $post_link;
}
add_filter( 'post_type_link', 'cptui_demo_remove_slug_from_permalink_string', 10, 2 );
Query modification
Now that we have the generated link recognized, the next thing to do is make sure WordPress includes the post type in its queries going forward. For that we will make use of the pre_get_posts
action hook. This is a very actively used hook so we have multiple guards in place. We do not want this being run if you are in the WordPress admin dashboard and if not on the main query for a given request. Lastly, we need to make sure are querying by post name. If all conditions check out, then we add in our post type for consideration. By default, WordPress is only doing this for the post
and page
post types.
function cptui_demo_add_post_type_to_query( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( empty( $query->query['name'] ) ) {
return;
}
$query->set(
'post_type',
[
'post',
'page',
'movie',
]
);
}
add_action( 'pre_get_posts', 'cptui_demo_add_post_type_to_query' );
Once both parts are in place, you may need to visit your permalinks page to flush the rewrite rules, but once done, you should not be receiving any 404 errors for your slug-less post type posts any more.
Adapted from a post made by Kellen Mace.
Hey Michael!
It worked for me.. I used Code Snippet plugin to write the codes so i dont lose them after i update the theme. Just wondering what if i have multiple custom post types? What should the code look like?
Probably need to amend this line:
`if ( ‘movie’ === $post->post_type ) {` to do extra checks, and make sure to include all the ones you’re adding, to the query portion.
`if ( ‘movie’ === $post->post_type || ‘tv_show’ === $post->post_type ) {`
Hi Michael!
I am recreating my WordPress tutorial web site and this time using the Custom Post Type UI (CPTUI) plugin where I made a CPT I called tutorials. As I am updating a bunch of older tutorials I would like to keep the same slug they have had for many years. This meant I had to remove the tutorials CPT slug. Using your tutorial I was able to remove the slug.
Thank you!
Hi Michael,
I also need to remove the slug. I’m redesigning one page with Oxygen, so I decided to make a custom post type and ACF for products, which were in old version as pages. So because of SEO I would like to have same structure of slug http://www.page.xx/product. But when I use your code, slug is removed, but my Oxygen template isn’t applied anymore. Is there some advice please? Thanks.
Tomas
Very valid question, but I don’t have an answer about that. Oxygen support may be a better avenue to seek out some help from. I don’t have experience with their product.
Perfect, thanks!
Very sorry for the delay in response and comment approval here Ben.
Admittedly, I do not have much of a lead on what may be causing this. To be clear, which of the functions is the issue? the one removing the slug from the permalink string? or the one affecting the post query? I’m guessing the latter, and I am wondering if Divi is expecting other post types included.
Unsure if it’s possible with PHP to detect if Divi Frontend is enabled, but that’d be awesome if possible.
Hi Michael, I tried to use your guide and got a 404 error.
I spent some time looking for reasons and this will happen if you are also using Elementor on the site.
The solution for me was simple. I added precedence to the last line of code.
Something like:
add_action( 'pre_get_posts', 'cptui_demo_add_post_type_to_query', 20, 2 );
Thank you, you saved my day 🙂
Hey, regarding Elementor, the single templates are not working after using this snippet.
Did you had this issue as well?
I had not done any testing with Elementor. I also added that I now recommend Permalinks Manager Lite instead of manually adjusting with the original code snippet. I am hopeful that they are much better tested for more scenarios than my code is.
Thank you for your tutorial! It worked to eliminate the slug for the CPT I wanted it to–but it broke links to other CPT. Is there a way to make sure this only applies to one CPT–not others?
Just out of some extra curiosity, what’s your permalink structure looking like, and did you replace the rewrite slug value in your CPTUI setting for your post type(s)? Perhaps with `/` only?
Hello my post permalink ended with ‘.html’, and because of that, am getting error 404. How do I make it work with the extension?
If you’re referring to how to do that with the Permalink Manager Lite plugin, you’d need to ask their support representatives. I haven’t tried to get that to work with `.html` values.
Great snippet 🙂
How can is use it for two post types?
When i duplicate it, the website is down.
Second thing is all the Elementor singles templates are not opening after using the snippet.
Any ideas?
Thanks 🙂
For multiple post types, you’d need to adjust `if ( ‘movie’ === $post->post_type ) {` to include more. Whether it be more equality checks, or maybe an `in_array()` check. Then you’d also need to add the extra post types to the `pre_get_posts` callback.