I have an URL like this: example.com/movies/157336/Interstellar
For reference: example.com/movies/%movie_id%/%movie_name%
Please note, the movie_id is a custom field, and not the actual post ID. The movie_name is the post title slug, but is only there for SEO reasons.
I need WordPress to load the page based on the custom field movie_id found in the URL and not use the page name, and if the movie_id is not found, throw the regular 404 error.
The main problem I am having, is that I can’t seem to get WordPress to load a page based on the custom field movie_id from the URL, it always uses movie_name as reference point.
How do I know that? Well the correct URL would be example.com/movies/157336/Interstellar
and if I change the title to example.com/movies/157336/Intersterlarxyz
then WordPress gives a 404 error.
And if I change the ID but leave the movie name correct, like this: example.com/movies/123/Interstellar
then WordPress still loads the correct page.
Based on this behavior, it's safe to say WordPress loads the page based on the page slug from the URL, rather than the movie ID, and that is what I need to fix.
Here is my code so far:
movie-plugin.php
// Register Custom Post Type "movies"
function register_moviedb_post_type() {
register_post_type( 'movies',
array(
'labels' => array(
'name' => __( 'Movies' ),
'singular_name' => __( 'Movies' )
),
'taxonomies' => array('category'),
'public' => true,
'has_archive' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => array('slug' => 'movies','with_front' => FALSE),
'supports' => array( 'title', 'editor', 'custom-fields','comments','page-attributes','trackbacks','revisions', 'thumbnail')
)
);
flush_rewrite_rules();
}
add_action( 'init', 'register_moviedb_post_type' );
// Add custom rewrite tag 'movie_id'
function custom_rewrite_tag() {
add_rewrite_tag('%movie_id%', '([^/]+)', 'movie_id=');
}
add_action('init', 'custom_rewrite_tag');
// Add rewrite rule
function custom_rewrite_basic() {
add_rewrite_rule(
'^movies/([^/]*)/([^/]*)/?',
//'index.php?post_type=movies&movie_id=$matches[1]',
'index.php?post_type=movies&movie_id=$matches[1]&name=$matches[2]',
'top'
);
}
add_action('init', 'custom_rewrite_basic');
// Query var 'movie_id'
function add_query_vars_filter( $vars ){
$vars[] = "movie_id";
return $vars;
}
add_filter( 'query_vars', 'add_query_vars_filter' );
// Custom Page Template
function custom_movie_page_template() {
if ( is_singular( 'movies' ) ) {
add_filter( 'template_include', function() {
return plugin_dir_path( __FILE__ ) . '/movies.php';
});
}
}
add_action( 'template_redirect', 'custom_movie_page_template' );
// Create custom post type link for movies
function movie_post_type_link( $link, $post = 0 ){
if ( $post->post_type == 'movies' ){
$id = $post->ID;
$post = &get_post($id);
$movie_id = get_post_meta($post->ID,'movie_id', true);
empty ( $post->slug )
and $post->slug = sanitize_title_with_dashes( $post->post_title );
return home_url(
user_trailingslashit( "movies/$movie_id/$post->slug" )
);
} else {
return $link;
}
}
add_filter( 'post_type_link', movie_post_type_link, 1, 2 );
If I remove the movie_name from the URL in add_rewrite_rule, WordPress just loads the archive page of that post type.
'index.php?post_type=movies&movie_id=$matches[1]',
If I use the page name in the URL rewrite, it always loads the page based on the name, rather than the movie_id.
'index.php?post_type=movies&movie_id=$matches[1]&name=$matches[2]',
I didn't test code below, but
movies.php
could be like this: