Remove Slug from Custom Post Type

May 28, 2014

If you create a custom post type in WordPress, its slug will be added to the URL structure by default. So if the CPT slug is “my-cpt-slug”, the URLs will look like this: example.com/my-cpt-slug/post-name. This can be desirable for grouping types of posts together, but it can also result in longer, harder-to-remember URLs, not to mention articles that don’t rank as highly on Google according to Yoast, who is an authority on WordPress search engine optimization (SEO). In this post, I’ll cover how to safety and properly remove the custom post type slug from your URLs.

Recently, I began creating a number of sites for a racing company that puts on 5K, 10K, marathon, and other distance races and fun runs. For these sites, I created a custom post type called race. This resulted in URLs such as example.com/race/race-title. As you can see, this is not nearly as clean, easy to remember, or search engine optimized as having URLs like example.com/race-title would be. I found a great Remove Slug from Custom Post Type post on the WordPress.com VIP site that I followed and it worked great. It appears that that post has been deleted though, so I’ll outline the process below.

Steps to Remove Slug from Custom Post Type

  1. Create a new file named km-remove-slug-from-custom-post-type.php in the /plugins/ folder for your site.
  2. Paste in this code, replacing the references to my-cpt-slug with the slug of your custom post type:
    <?php
    /**
    * Plugin Name: Remove Slug from Custom Post Type
    * Description: Remove slug from custom post type URLs.
    * Version: 0.1.0
    * Author: Kellen Mace
    * Author URI: https://kellenmace.com/
    * License: GPLv2 or later
    * License URI: http://www.gnu.org/licenses/gpl-2.0.html
    */
    /**
    * Remove the slug from published post permalinks. Only affect our custom post type, though.
    *
    * @param string $post_link The post permalink (URL).
    * @param WP_Post $post The post object.
    *
    * @return string $post_link The post permalink (URL), possibly modified.
    */
    function km_remove_cpt_slug( $post_link, $post ) {
    if ( 'my-cpt-slug' === $post->post_type && 'publish' === $post->post_status ) {
    $post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
    }
    return $post_link;
    }
    add_filter( 'post_type_link', 'km_remove_cpt_slug', 10, 2 );
    /**
    * Have WordPress match postname to any of our public post types (post, page, my-cpt-slug).
    * All of our public post types can have /post-name/ as the slug, so they need to be unique across all posts.
    * By default, WordPress only accounts for posts and pages where the slug is /post-name/.
    *
    * @param $query The current query.
    */
    function km_add_cpt_post_names_to_main_query( $query ) {
    // Bail if this is not the main query.
    if ( ! $query->is_main_query() ) {
    return;
    }
    // Bail if this query doesn't match our very specific rewrite rule.
    if ( ! isset( $query->query['page'] ) || 2 !== count( $query->query ) ) {
    return;
    }
    // Bail if we're not querying based on the post name.
    if ( empty( $query->query['name'] ) ) {
    return;
    }
    // Add CPT to the list of post types WP will include when it queries based on the post name.
    $query->set( 'post_type', array( 'post', 'page', 'my-cpt-slug' ) );
    }
    add_action( 'pre_get_posts', 'km_add_cpt_post_names_to_main_query' );

That’s it! The first function tells WordPress to remove the slug from the URLs it creates for the CPT’s posts. The second function tells WordPress that posts, pages, and your CPT can all have URLs that don’t include the post type slug. So that means that when a request comes in, all of these will resolve correctly, for instance: example.com/post-name/, example.com/page-name/, example.com/cpt-post-name/.

FAQ / Troubleshooting

Can I put this code in the functions.php file of my theme?

Yes, that will work, but just be careful - if the theme were ever changed, these URL structure changes would be lost! Creating a standalone plugin for that purpose as recommended in the article above is best practice.

My CPT URLs aren’t loading

You may want to try going to Settings > Permalinks and saving the permalink structure to end in /%postname%/.

I have other issues!

There are 100+ comments below from folks trying to get this working in various ways. Check them out!

comments


Kellen Mace

Written by Kellen Mace, who lives in Rochester Hills, MI and builds cool stuff on the web. About Kellen // Follow him on Twitter →