Remove slug from custom post type post URLs

It seems that all web resources based on the subject of removing a custom post type slug ie

yourdomain.com/CPT-SLUG/post-name 

are now very outdated solutions often referencing pre WP version 3.5 installs. A common one is to:

'rewrite'   => array( 'slug' => false, 'with_front' => false ),  

within your register_post_type function. This no longer works and is misleading. So I ask the community in Q4 2020…

What are the modern and efficient ways to remove the Post Type Slug from a Custom Post Type post’s URL from within the rewrite argument or anywhere else?

UPDATE:
There seems to be several ways to force this to work with regex. Specifically the answer from Jan Beck should you be consistently willing to monitor content creation to ensure no conflicting page/post names are created…. However I’m convinced that this is a major weakness in WP core where it should be handled for us. Both as an option/hook when creating a CPT or an advanced set of options for permalinks. Please support the track ticket.

Footnote: Please support this trac ticket by watching/promoting it: https://core.trac.wordpress.org/ticket/34136#ticket

The following code will work, but you just have to keep in mind that conflicts can happen easily if the slug for your custom post type is the same as a page or post’s slug…

First, we will remove the slug from the permalink:

function na_remove_slug( $post_link, $post, $leavename ) {

    if ( 'events' != $post->post_type || 'publish' != $post->post_status ) {
        return $post_link;
    }

    $post_link = str_replace( "https://wordpress.stackexchange.com/" . $post->post_type . "https://wordpress.stackexchange.com/", "https://wordpress.stackexchange.com/", $post_link );

    return $post_link;
}
add_filter( 'post_type_link', 'na_remove_slug', 10, 3 );

Just removing the slug isn’t enough. Right now, you’ll get a 404 page because WordPress only expects posts and pages to behave this way. You’ll also need to add the following:

function na_parse_request( $query ) {

    if ( ! $query->is_main_query() || 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
        return;
    }

    if ( ! empty( $query->query['name'] ) ) {
        $query->set( 'post_type', array( 'post', 'events', 'page' ) );
    }
}
add_action( 'pre_get_posts', 'na_parse_request' );

Just change “events” to your custom post type and you’re good to go. You may need to refresh your permalinks.

Leave a Comment