Background
// remove cpt slug from permalinks
function remove_cpt_slug( $post_link, $post, $leavename ) {
if ( $post->post_type != 'custom_post_type' ) {
return $post_link;
} else {
// remove cpt slug from permalink
$post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
return $post_link;
}
}
add_filter( 'post_type_link', 'remove_cpt_slug', 10, 3 );
function rewrite_rule_remove_cpt_slug() {
add_rewrite_rule(
'(.?.+?)(?:/([0-9]+))?/?$',
'index.php?custom_post_type=$matches[1]/$matches[2]&post_type=custom_post_type',
'bottom'
);
}
add_action( 'init', 'rewrite_rule_remove_cpt_slug', 1, 1 );
Here is what I have come up with while trying to create a solution that works on most if not all scenarios. This will properly remove CPT slug from CPT permalinks as well as instruct WordPress on finding CPT posts from those new permalinks. It doesn't rewrite rules in the database so you wouldn't need to resave your permalink structure. Besides, this solution is consistent with how WordPress actually parses requests to find posts from permalinks which helps make it a more acceptable solution.
Answer
Here is what I have come up with while trying to create a solution that works on most if not all scenarios. This will properly remove CPT slug from CPT permalinks as well as instruct WordPress on finding CPT posts from those new permalinks. It doesn't rewrite rules in the database so you won't need to resave your permalink structure. Besides, this solution is consistent with how WordPress actually parses requests to find posts from permalinks which helps make it a more acceptable solution.
// remove cpt slug from permalinkpermalinks
function remove_cpt_slug( $post_link, $post, $leavename ) {
if ( $post->post_type != 'custom_post_type' ) {
return $post_link;
} else {
// remove cpt slug from permalink
$post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
return $post_link;
}
}
add_filter( 'post_type_link', 'remove_cpt_slug', 10, 3 );
// instruct wordpress on how to find posts from the new permalinks
function parse_request_remove_cpt_slug( $query_vars ) {
// return if pretty permalinkadmin isn'tdashboard enabled
if ( ! get_optionis_admin( 'permalink_structure' ) ) {
return $query_vars;
}
$cpt// =return 'custom_post_type';if pretty permalink isn't enabled
if ( ! get_option( 'permalink_structure' ) ) {
$pagename = $query_vars['pagename']; return $query_vars;
$name}
$cpt = $query_vars['name'];'custom_post_type';
// store post slug value to a variable
if ( $pagenameisset( $query_vars['pagename'] ) ) {
$slug = $pagename;$query_vars['pagename'];
} elseif ( $nameisset( $query_vars['name'] ) ) {
$slug = $name;$query_vars['name'];
} else {
global $wp;
$uri
$path = $wp->request;
// use url path as slug
if ( $path && strpos( $uri$path, '/' ) === false ) {
$slug = $uri;$path;
} else {
$slug = false;
}
}
if ( $slug ) {
$post_match = get_page_by_path( $slug, 'OBJECT', $cpt );
if ( ! is_admin() && $post_match ) {
// remove any 404 not found error element, if any, from the query_vars array because a post match already exists in cpt
if ( isset( $query_vars['error'] ) && $query_vars['error'] == 404 ) {
unset( $query_vars['error'] );
}
// remove unnecessary elements from the original query_vars array
// unset($query_vars['page']);
unset($query_vars['pagename'] );
// add necessary elements in the the query_vars array
$query_vars['post_type'] = $cpt;
$query_vars['name'] = $slug;
$query_vars[$cpt] = $slug; // this constructs the "cpt=>post_slug" element
}
}
return $query_vars;
}
add_filter( 'request', "parse_request_remove_cpt_slug" , 1, 1 );
This solution intentionally leaves out Plain permalink structure Plain from its scope as it isn't one of the pretty permalink structures. So, it will work with all permalink structures apart from the PlainPlain one.
As WordPress doesn't automatically prevent creating duplicate slugs across different post types, you may find problems accessing posts having the same post slugs because of not havinglosing uniqueness in CPT permalinks after removing the CPT slugs. This code doesn't include any functionality to prevent that behavior so you may want to find a separate solution to address that.
In case there is a duplicate permalink, this code will prioritize your CPT over others and therefore display the post in your CPT when requested.