Variations of this issue have been posted a few times over the years however after going through all of these I have been unable to find a solution.
We need to have the same base slug for CPT post and CPT taxonomy terms. For example:
- domain.com/movies/ -> listing of all movies
- domain.com/movies/horror/ -> listing of movies of type horror
- domain.com/movies/texas-chainsaw-massacre/ -> a single movie post
The issue is that no matter what configuration I've tried, I am unable to get #2 and #3 to work together. One will always be a 404 error.
I know that this may be due to a conflict in URL lookups (Wordpress won't know whether we want a taxonomy term or a single post), and so it may not be possible using standard CPT/taxonomy setup. However if we NEED to have this structure for SEO purposes, how can we achieve this?
EDIT: Here's the solution thanks to @Sally CJ. Essentially registering the post type and taxonomy in that order makes Wordpress think every request is for the taxonomy. Single posts will return a 404. Then our code below checks each URL request and if it doesn't find a matching taxonomy term it tells Wordpress it is a single post request. Moving forward, we need to be careful not to create any posts with the same slug as a taxonomy term but this is not an issue for us.
add_action( 'init', 'register_post_type_movies', 12);
add_action( 'init', 'register_taxonomy_movie_type', 11 );
add_action( 'parse_request', function ( $wp ) {
if ( isset( $wp->query_vars['movie_type'] ) ) {
if ( preg_match( '#^movies/#', $wp->request ) &&
! term_exists( $wp->query_vars['movie_type'], 'types' ) ) {
// Change it to a "movies" post request.
$wp->query_vars['name'] = $wp->query_vars['movie_type'];
$wp->query_vars['post_type'] = 'movies';
// And "cancel" the category request.
unset( $wp->query_vars['movie_type'] );
}
}
} );