I've created a Custom Post Type and I want to theme it. I want to apply a Page Template to instances of my Custom Post Type.

I want to avoid creating a child theme.

Ideally I'd like to create a Page Template within a plugin, and have the template be applied to the Custom Post Type automatically.

How do I do this?

  • I'm not sure about your exact query, you want to load a custom page template for a specific post of your CPT, or you want to load a specific template for all your posts of that particular CPT? Nov 20, 2019 at 4:19
  • Sorry @MayeenulIslam. I mean that I want to apply a template to all instances of my CPT.
    – bob.dobbs
    Nov 20, 2019 at 4:23
  • Possible duplicate of How can I load a page template from a plugin? Nov 20, 2019 at 4:25
  • This isn't a great approach, because not all themes are structured the same, and your template will likely look broken in most themes. You'd be better off using the the_content filter to output your post type template. Nov 20, 2019 at 4:53
  • @MayeenulIslam that solves a different problem. I don't want to add a new choice of template to the page templates dropdown. I'd like my own page template to be applied automatically to my cpt.
    – bob.dobbs
    Nov 20, 2019 at 5:03

1 Answer 1


Here you are - a plugin that is registering a Custom Post Type (CPT) and pushing template file from the plugin for that particular CPT.

 * Plugin Name: WPSE352898 Template Test
 * Author:      Mayeenul Islam
 * Author URI:  https://mayeenulislam.github.io

 * Register My Custom Post Type.
function wpse352898_register_cpt() {
    register_post_type('mycpt', array(
        'labels' => array(
            'name'          => 'My CPT',
            'singular_name' => 'My CPT',
            'menu_name'     => 'My CPT',
        'public'              => true,
        'publicly_queryable'  => true,
        'exclude_from_search' => false,
        'has_archive'         => true,
        'query_var'           => true,
        'rewrite'             => true,

add_action( 'init', 'wpse352898_register_cpt' );

 * Template loader
 * @param string $template The template that is called.
 * @return string          Template, that is thrown per modification.
function wpse352898_template_loader( $template ) {
    $find = array();
    $file = '';
    if ( is_single() && 'mycpt' === get_post_type() ) {
        // Singular template for CPT 'mycpt' in a theme.
        $file   = 'single-mycpt.php';
        $find[] = $file;
        // Directory in a theme, where user can define their custom template to override plugin imposed template.
        $find[] = 'mycpt-templates/' . $file;
    if ( $file ) {
        $template = locate_template( array_unique( $find ) );
        if ( ! $template ) {
            // Load template file from the plugin under this directory.
            $template = untrailingslashit( plugin_dir_path( __FILE__ ) ) . '/templates/' . $file;
    return $template;

add_filter( 'template_include', 'wpse352898_template_loader' );

After activating the plugin you will need to flush rewrite rules manually by saving the form in Settings » Permalinks without any modification. But you can also flush the rewrite rules from the plugin on register_activation_hook (which is not shown here).

To display a template file from the plugin the plugin will look into the template here: <plugin>/templates/single-mycpt.php.

There will be provision to override the plugin imposed template from the active theme, where it will look into the overridden template here: <active-theme>/mycpt-templates/single-mycpt.php.

Hope it helps. :)

  • 1
    Thank you! With a little modification for my particular use-case, this worked
    – bob.dobbs
    Nov 20, 2019 at 8:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.