Create Template Files Inside My WordPress Plugin

A Step-by-Step Guide: 
Create Template Files Inside My WordPress Plugin

If you’ve ever needed to add custom functionality or layout options to your WordPress site without touching your theme files, creating template files within a plugin is the way to go. By bundling the templates directly into your plugin, you ensure easier updates, better organization, and greater flexibility for future enhancements.

If your looking to elevate your site with a custom plugin that does exactly what you need.
Contact us to start your custom plugin project today!

Create Template Files Inside My WordPress Plugin

What Can I Create Template Files For?

When building a WordPress plugin, you’re not limited to just a specific type of page or post. WordPress offers a robust template hierarchy that allows you to customize virtually any part of your site’s front-end experience. Because these templates live inside your plugin, you maintain a clear separation between your theme files and your custom functionality. This makes it easier to update or switch themes in the future without losing your carefully crafted layouts or customizations.

Here are some of the most common areas where you can create custom template files:

Archive Pages:

Customize the layout for lists of posts or other content types like your custom post types.

Category Pages:

 Define how category archives should appear, including special layouts or filters for each category.

Custom Post Types:

Create a unique look and feel for your custom post types with dedicated templates.

Search Results:

Offer a more branded or targeted experience by customizing how search results are displayed.

404 Pages:

Create a helpful or humorous “Page Not Found” screen to guide users back to relevant content.

Single Pages:

Tweak the display of individual posts, pages, or single pages of your custom post types.

Taxonomy Pages:

 For any custom taxonomies, you can create dedicated templates that cater to their unique structure.

Tag Pages:

Customize the way tags are shown, allowing you to highlight relevant information or style tag archives differently.

Author Pages:

Showcase author profiles with additional details or a personalized layout.

Examples of how to use template files inside your plugin:

CHARITY DONATIONS

Archive Template:
List of all organizations that have donated sorted from newest to oldest. Displayed in a timeline like design.

Things Todo App

Archive Template:
Display a list of all things todo in a particular location.

Single Template:
Displays all the detailed information about the specific business or thing todo in that city.

RECYCLING FACILITY

Archive Template:
Displays all recycling depot locations.

Single Template:
Displays all the details about a specific recycling depot.

How To Create Template Files For Custom Post Types
Inside a WordPress Plugin

Step 1: Setup a custom wordpress plugin.

Make sure to follow the previous steps on how to setup wordpress development environment and how to setup a custom wordpress plugin. Then you will be ready to add these code snippets to your plugin. You can also add these code snippets to your functions.php file in your theme.

Step 2: Create a custom post type

Follow this tutorial on how to create a custom post type for a movie review website. We will expand on this creating custom template files for this custom post type.

Step 3: Create the Template Files in Your Plugin

Inside your plugin directory, create a folder called templates. Then add these PHP files:

single-movie_review.php
This file handles single Movie Review posts (i.e. URLs like yoursite.com/movie-reviews/the-godfather).

archive-movie_review.php
This file handles the archive of all Movie Reviews (i.e. URLs like yoursite.com/movie-reviews).

taxonomy-genre.php
This file handles the genre taxonomy archives (i.e. yoursite.com/genre/action).

templates/
├─ single-movie-review.php
├─ archive-movie-review.php
└─ taxonomy-genre.php

Step 4: Set Up Template Filter

Tell WordPress to Use Your Plugin Templates

/**
* Force single "movie_review" CPT to use our plugin template.
*/
add_filter( 'single_template', 'WCFP_load_single_movie_review_template' );
function WCFP_load_single_movie_review_template( $single ) {
    global $post;

    // Check if we’re looking at a single post of CPT "movie_review"
    if ( is_singular( 'movie_review' ) ) {
        $plugin_template = plugin_dir_path( __FILE__ ) . 'templates/single-movie-review.php';
        if ( file_exists( $plugin_template ) ) {
            return $plugin_template;
        }
    }
    // Otherwise, return the normal template
    return $single;
}

/**
 * Force the archive for "movie_review" to use our plugin template.
 */
add_filter( 'archive_template', 'WCFP_load_archive_movie_review_template' );
function WCFP_load_archive_movie_review_template( $archive ) {
    if ( is_post_type_archive( 'movie_review' ) ) {
        $plugin_template = plugin_dir_path( __FILE__ ) . 'templates/archive-movie-review.php';
        if ( file_exists( $plugin_template ) ) {
            return $plugin_template;
        }
    }
    return $archive;
}

/**
 * Force the "genre" taxonomy archive to use our plugin template.
 */
add_filter( 'taxonomy_template', 'WCFP_load_genre_taxonomy_template' );
function WCFP_load_genre_taxonomy_template( $taxonomy_template ) {
    // If it’s the "genre" taxonomy archive
    if ( is_tax( 'genre' ) ) {
        $plugin_template = plugin_dir_path( __FILE__ ) . 'templates/taxonomy-genre.php';
        if ( file_exists( $plugin_template ) ) {
            return $plugin_template;
        }
    }
    return $taxonomy_template;
}

How It Works:

add_filter('single_template', 'FUNCTION_NAME' );

By default, WordPress determines which template file to load using its template hierarchy. WordPress only auto-detects these files if they’re in your theme folder. But since they’re in a plugin, we’ll hook into the template loading filters to override the default. By using filters like single_template, archive_template, and taxonomy_template, we can override or “force” WordPress to use a specific template file of our choosing. We then add some extra checks to make sure its the right page and that the template file exists. If all checks out we return the new template.

single_template

Applied whenever WP looks for a single post template. We then check if the post is of type movie_review and if so, we load our single-movie-review template file.

archive_template

Applied whenever WP loads an archive page. We then check if the post type archive is movie_review and if so, load our archive-movie-review template file.

taxonomy_template

Applied whenever WP loads a taxonomy archive. We then check if the taxonomy is genre and if so, load our taxonomy-genre template file.

Other Template Filters You Can Use

page_template

Applied whenever a page is displayed.

category_template

Applied whenever a category archive is displayed.

tag_template

Applied whenever a tag archive is displayed.

author_template

Applied whenever an author archive is displayed.

date_template

date-based archive (year, month, day) is displayed.

home_template

When the posts page is displayed (the blog homepage), if the site is set to show your latest posts on the front page.

frontpage_template

When the Front Page is displayed and is set to a static page

search_template

When a search results page is displayed

404_template

When WordPress can’t find any content for the requested URL and displays a 404 Not Found page.

Coding Your Templates

Single Template Example

single-movie_review.php

<?php
get_header();
?>

<main id="WCFP-site-content" role="main">
    <?php
    if ( have_posts() ) :
        while ( have_posts() ) :
            the_post();

            // Get the Featured Image URL (full size).
            $featured_image_url = get_the_post_thumbnail_url( get_the_ID(), 'full' );
            $featured_image_alt = esc_attr( get_the_title() );

            // Retrieve Custom Fields
            $director          = get_post_meta( get_the_ID(), '_mr_director', true );
            $release_year      = get_post_meta( get_the_ID(), '_mr_release_year', true );
            $rating            = get_post_meta( get_the_ID(), '_mr_rating', true );
            $cast              = get_post_meta( get_the_ID(), '_mr_cast', true );
            $production_budget = get_post_meta( get_the_ID(), '_mr_production_budget', true );
            $box_office        = get_post_meta( get_the_ID(), '_mr_box_office', true );
            ?>
            
            <!-- The Title -->
            <h1><?php the_title(); ?></h1>
            
            <?php
            if ( $featured_image_url ) {
                // Create your own <img> tag for maximum control over the display
                echo '<img src="' . esc_url( $featured_image_url ) . '" alt="' . $featured_image_alt . '" class="WCFP-featured-image" />';
            }
            ?>

            <!-- Main Content Area -->
            <div class="WCFP-entry-content">
                <?php the_content(); ?>
            </div>

            <div class="WCFP-movie-review-details">
                <?php if ( $director ) : ?>
                    <p><strong>Director:</strong> <?php echo esc_html( $director ); ?></p>
                <?php endif; ?>

                <?php if ( $release_year ) : ?>
                    <p><strong>Release Year:</strong> <?php echo esc_html( $release_year ); ?></p>
                <?php endif; ?>

                <?php if ( $rating ) : ?>
                    <p><strong>Rating:</strong> <?php echo esc_html( $rating ); ?></p>
                <?php endif; ?>

                <?php if ( $cast ) : ?>
                    <p><strong>Cast:</strong> <?php echo esc_html( $cast ); ?></p>
                <?php endif; ?>

                <?php if ( $production_budget ) : ?>
                    <p><strong>Production Budget:</strong> <?php echo esc_html( $production_budget ); ?></p>
                <?php endif; ?>

                <?php if ( $box_office ) : ?>
                    <p><strong>Box Office:</strong> <?php echo esc_html( $box_office ); ?></p>
                <?php endif; ?>
            </div>

            <?php
        endwhile;
    endif;
    ?>
</main>

<?php get_footer(); ?>

Archive Template Example

archive-movie-review.php

<?php
get_header();
?>

<main id="WCFP-site-content" role="main">
    <h1>All Movie Reviews</h1>
    
    <?php if ( have_posts() ) : ?>
        <div class="WCFP-movie-reviews-archive-wrapper">
            <?php
            while ( have_posts() ) :
                the_post();

                // Get featured image URL in 'medium' size
                $featured_image_url = get_the_post_thumbnail_url( get_the_ID(), 'medium' );
                $featured_image_alt = esc_attr( get_the_title() );

                // Get custom fields
                $rating       = get_post_meta( get_the_ID(), '_mr_rating', true );
                $release_year = get_post_meta( get_the_ID(), '_mr_release_year', true );
                ?>
                
                <article class="WCFP-movie-review-excerpt <?php post_class(); ?>" id="post-<?php the_ID(); ?>">
                    <!-- Featured Image -->
                    <?php if ( $featured_image_url ) : ?>
                        <img 
                            src="<?php echo esc_url( $featured_image_url ); ?>" 
                            alt="<?php echo $featured_image_alt; ?>" 
                            class="WCFP-featured-image" 
                        />
                    <?php endif; ?>
                    
                    <!-- Title (links to single post) -->
                    <h2>
                        <a href="<?php the_permalink(); ?>">
                            <?php the_title(); ?>
                        </a>
                    </h2>
                    
                    <!-- Optional excerpt -->
                    <div class="WCFP-entry-excerpt">
                        <?php the_excerpt(); ?>
                    </div>

                    <!-- Display Custom Fields (Rating, Release Year) -->
                    <div class="WCFP-movie-review-details">
                        <?php if ( $rating ) : ?>
                            <p><strong>Rated:</strong> <?php echo esc_html( $rating ); ?></p>
                        <?php endif; ?>
                        
                        <?php if ( $release_year ) : ?>
                            <p><strong>Release Year:</strong> <?php echo esc_html( $release_year ); ?></p>
                        <?php endif; ?>
                    </div>
                    
                    <!-- "Read more" link -->
                    <p>
                        <a href="<?php the_permalink(); ?>">Read Full Review »</a>
                    </p>
                </article>
                
            <?php endwhile; ?>
        </div>

        <!-- Pagination for multiple pages of reviews -->
        <div class="WCFP-movie-review-pagination">
            <?php the_posts_pagination(); ?>
        </div>

    <?php else : ?>
        <p>No movie reviews found.</p>
    <?php endif; ?>
</main>

<?php
get_footer();

Taxonomy Template Example

taxonomy-genre.php

<?php
get_header();
?>

<main id="WCFP-site-content" role="main">
    <h1 class="WCFP-genre-title">
        Genre: <?php single_term_title(); ?>
    </h1>
    
    <?php if ( have_posts() ) : ?>
        <div class="WCFP-genre-archive-wrapper">
            <?php
            while ( have_posts() ) :
                the_post();
                
                // Retrieve the Featured Image URL for the post
                $featured_image_url = get_the_post_thumbnail_url( get_the_ID(), 'medium' );
                $featured_image_alt = esc_attr( get_the_title() );
                
                // (Optional) retrieve any custom fields you want to display
                $rating = get_post_meta( get_the_ID(), '_mr_rating', true );
                ?>
                
                <article class="WCFP-genre-archive-item <?php post_class(); ?>" id="post-<?php the_ID(); ?>">
                    <?php if ( $featured_image_url ) : ?>
                        <img 
                            src="<?php echo esc_url( $featured_image_url ); ?>" 
                            alt="<?php echo $featured_image_alt; ?>" 
                            class="WCFP-featured-image"
                        />
                    <?php endif; ?>
                    
                    <h2 class="WCFP-archive-item-title">
                        <a href="<?php the_permalink(); ?>">
                            <?php the_title(); ?>
                        </a>
                    </h2>
                    
                    <!-- Optional excerpt or any other info you'd like -->
                    <div class="WCFP-archive-item-excerpt">
                        <?php the_excerpt(); ?>
                    </div>
                    
                    <!-- Custom field example (Rating) -->
                    <?php if ( $rating ) : ?>
                        <p><strong>Rating:</strong> <?php echo esc_html( $rating ); ?></p>
                    <?php endif; ?>
                    
                    <p>
                        <a href="<?php the_permalink(); ?>" class="WCFP-readmore-link">Read Full Review »</a>
                    </p>
                </article>
                
            <?php endwhile; ?>
        </div>
        
        <!-- Pagination for multiple pages of posts in this genre -->
        <div class="WCFP-genre-pagination">
            <?php the_posts_pagination(); ?>
        </div>
        
    <?php else : ?>
        <p>No movie reviews found for this genre.</p>
    <?php endif; ?>
</main>

<?php
get_footer();

Common Issues:

404 Page Not Found - How To Fix Custom Post Type Template

Flushing Rewrite Rules

After adding or updating a custom post type slug, or taxonomy slug you need to flush the rewrite rules so WordPress recognizes the new URLs:

1. Go to Settings → Permalinks in the admin.

2. Click Save Changes (no need to edit anything).

3. This triggers WordPress to refresh its internal rewrite rules.

Flushing Rewrite Pragmatically

Make sure to flush your rewrite rules only once as you need it, dont add it somewhere it will refresh on every page load (which is resource-intensive). You can add this and comment it out while developing or use the UI approach above that does the same thing.

Flushing Rewrite Rules Pragmatically

flush_rewrite_rules();

Check out our FREE ONLINE
WordPress Plugin Development Course

Looking to develop a custom plugin, or create new features for your website?

Facebook Video