Custom Post Type Templates from Plugin Folder?

I’d like to offer my custom post type as a Plugin, so that people can use it without touching their theme folder. But custom post type templates — such as single-movies.php — reside in the theme folder. Is there a way to get WP to check for a single-movies.php in the plugin’s folder? Hooking a function into the Filer Hierarchy? Or get_template_directory(); ?

Solutions Collecting From Web of "Custom Post Type Templates from Plugin Folder?"

You can use single_template filter hook.

/* Filter the single_template with our custom function*/
add_filter('single_template', 'my_custom_template');

function my_custom_template($single) {

    global $wp_query, $post;

    /* Checks for single template by post type */
    if ( $post->post_type == 'POST TYPE NAME' ) {
        if ( file_exists( PLUGIN_PATH . '/Custom_File.php' ) ) {
            return PLUGIN_PATH . '/Custom_File.php';
        }
    }

    return $single;

}

Added a check for a custom post type specific template in theme folder to @Brainternet answer.

function load_person_template($template) {
    global $post;

    // Is this a "my-custom-post-type" post?
    if ($post->post_type == "my-custom-post-type"){

        //Your plugin path 
        $plugin_path = plugin_dir_path( __FILE__ );

        // The name of custom post type single template
        $template_name = 'single-my-custom-post-type.php';

        // A specific single template for my custom post type exists in theme folder? Or it also doesn't exist in my plugin?
        if($template === get_stylesheet_directory() . '/' . $template_name
            || !file_exists($plugin_path . $template_name)) {

            //Then return "single.php" or "single-my-custom-post-type.php" from theme directory.
            return $template;
        }

        // If not, return my plugin custom post type template.
        return $plugin_path . $template_name;
    }

    //This is not my custom post type, do nothing with $template
    return $template;
}
add_filter('single_template', 'load_person_template');

Now you can let the plugin users to copy the template from your plugin to their theme to override it.

With this example, templates must be in the root directory of both plugin and theme.

I would like to point out that when you are using the filter method for this, it is extremely important to prioritize the filter like so:

add_filter('single_template', 'my_custom_template', 99);

If you don’t do this, sometimes WP will attempt to recheck after this filter. Was pulling my hair out because of this for like 2 hours.

Above is a great answer, but checking for the $single var allows the template to override a template if one is provided by the theme/child theme.

/* Filter the single_template with our custom function*/
add_filter('single_template', 'your_cpt_custom_template');

function your_cpt_custom_template( $single ) {
    global $wp_query, $post;
    /* Checks for single template by post type */
    if ( !$single && $post->post_type == 'cpt' ) {
        if( file_exists( plugin_dir_path( __FILE__ ) . 'single-cpt.php' ) )
            return plugin_dir_path( __FILE__ ) . 'single-cpt.php';
    }
    return $single;
}