You can make CPT’s have “slugless” permalinks fairly easily:
register_post_type( 'service', [
'hierarchical' => true,
'public' => true,
// Other args, no need for "rewrite"
]);
// Change service to top-level permalink.
add_permastruct( 'service', '%service%', [
'with_front' => false,
'paged' => false,
'feed' => false,
]);
// Remove all default service rewrite rules.
add_filter( 'service_rewrite_rules', '__return_empty_array' );
… which should be wrapped in a function and hooked to init
. Then to “catch” these post types, we need a little pre_get_posts
magic:
add_action( 'pre_get_posts', function ( $wp_query ) {
if (
$wp_query->is_main_query() &&
$wp_query->is_singular() &&
$wp_query->get( 'pagename' )
) {
if ( ! $post_type = $wp_query->get( 'post_type' ) )
$post_type = [];
elseif ( ! is_array( $post_type ) )
$post_type = [ $post_type ];
$wp_query->set( 'post_type', array_merge( $post_type, [
'page',
'service',
]));
}
});
Make sure to then flush your rewrite rules (just load Settings > Permalinks in the admin).