Remove post type slugs from permalinks

⏲️ Time: 2 mins

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.


Michael is a seasoned developer who loves helping build stuff for the internet. He brings over a decade of varied experiences working with both front and back end developer stacks.

His primary focus has been WordPress and PHP and all the components that go along with them. During the day, he is a Support Engineer with WebDevStudios, helping clients get the best that they can out of their own websites.

Categories: Web DevelopmentTags: , ,

17 thoughts on “Remove post type slugs from permalinks

  1. 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?

    1. tw2113 says:

      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 ) {`

  2. 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!

  3. Tomáš says:

    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

    1. tw2113 says:

      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.

  4. Sherwin says:

    Perfect, thanks!

  5. tw2113 says:

    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.

  6. Sergey says:

    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 );

    1. Basel says:

      Thank you, you saved my day 🙂

    2. Shepherdog says:

      Hey, regarding Elementor, the single templates are not working after using this snippet.
      Did you had this issue as well?

      1. Michael says:

        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.

  7. Gretchen says:

    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?

    1. tw2113 says:

      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?

  8. Mr. KingsHOK says:

    Hello my post permalink ended with ‘.html’, and because of that, am getting error 404. How do I make it work with the extension?

    1. tw2113 says:

      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.

  9. Shepherdog says:

    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 🙂

    1. Michael says:

      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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Webmentions