I'm working to optimize a site that I've recently taken management of, and it appears to me that there are a fair few unused templates. I want to remove all the unused and redundant template files so that we can focus our developments on those templates we do support, however there are 100+ pages and posts on this site, so I can't just do a spot check, I need a robust query.

I've established how to query which page template is being called from joining wp_posts and wp_postmeta, and I've sussed out which post formats are being used by querying wp_posts and wp_terms via wp_term_relationships BUT... this still doesn't seem to tell me whether the index.php is ever used (and I don't think it is).

I'm probably missing something obvious, but is there a way to see which of the normal Wordpress theme files are actually being called? OR is it that I have all the information already and 'index.php' just isn't being used.

Any help would be much appreciated!



5 Answers 5


Here's a rough function I use to handle this, it should work well for anyone out there wanting to do this quick and easy. Add this this your functions.php file and then visit your site with ?template_report added onto the URL to display a report for every custom theme template.

It's rough, I'd suggest commenting/uncommenting the add_action call when you want to use it.

 * Theme Template Usage Report
 * Displays a data dump to show you the pages in your WordPress
 * site that are using custom theme templates.
function theme_template_usage_report( $file = false ) {
    if ( ! isset( $_GET['template_report'] ) ) return;

    $templates = wp_get_theme()->get_page_templates();
    $report = array();

    echo '<h1>Page Template Usage Report</h1>';
    echo "<p>This report will show you any pages in your WordPress site that are using one of your theme's custom templates.</p>";

    foreach ( $templates as $file => $name ) {
        $q = new WP_Query( array(
            'post_type' => 'page',
            'posts_per_page' => -1,
            'meta_query' => array( array(
                'key' => '_wp_page_template',
                'value' => $file
            ) )
        ) );

        $page_count = sizeof( $q->posts );

        if ( $page_count > 0 ) {
            echo '<p style="color:green">' . $file . ': <strong>' . sizeof( $q->posts ) . '</strong> pages are using this template:</p>';
            echo "<ul>";
            foreach ( $q->posts as $p ) {
                echo '<li><a href="' . get_permalink( $p, false ) . '">' . $p->post_title . '</a></li>';
            echo "</ul>";
        } else {
            echo '<p style="color:red">' . $file . ': <strong>0</strong> pages are using this template, you should be able to safely delete it from your theme.</p>';

        foreach ( $q->posts as $p ) {
            $report[$file][$p->ID] = $p->post_title;

add_action( 'wp', 'theme_template_usage_report' );

The output looks like this:

enter image description here

  • This works very nicely! Simple and effective. Thank you.
    – MiB
    Commented Feb 22, 2019 at 13:30
  • Super useful, did exactly what I needed, thank you! Commented Aug 20, 2020 at 8:07

There is no query that will identify all of the theme files that are actively in use, or not in use. The only query I'm aware of which will identify some theme files is:

SELECT * FROM wp_postmeta WHERE meta_key = '_wp_page_template';

which will identify all custom Page templates which are in use. It won't identify standard theme files such as index.php, single.php, header.php, footer.php, because those are not custom Page templates. And it's best practice to include index.php, since it is a default/fallback if there is ever a problem with more specific theme files. In many cases the file is never used, but it's always good to have it there, and it usually shows you the barebones HTML structure of the site, which can be a helpful cue before you dive into more customized files.

If you want to continue down the reverse-engineering path, I would suggest including your theme-file-identifier code in the (as a comment if it's a live site) and manually go through each URL. If you use a plugin that generates an XML sitemap it can help you ensure that you hit every URL. Just bear in mind that whatever file is identified is probably not the only file in use. For example, if your Posts use the default single.php it is very likely to be making use of header.php and footer.php at a minimum. Some themes use template parts or includes, so after you have your initial list of the overarching template used on each URL, you will have to look through each of those templates and determine which files they call. You'll also want to check functions.php for the enqueued stylesheets and JS, as well as potentially other includes.

One alternative to this long process is to rebuild the theme from the ground up. I understand this isn't always possible, but it's the cleanest solution, and it's likely to take less time and be less risky than trying to slowly slough off parts of an old complex theme. For this process, I identify the most-used templates (if you have 50 of one CPT start there) and code those first on a dev/staging site, import or copy at least a handful of each post type and keep building from there. Once again you'll need to go through at least most of the site to make sure you don't overlook customizations, and the only way you'll be 100% certain you caught everything is to review every URL.


Drop this code in functions.php and login with a user that has the manage_options capability to create a page that shows the unused templates.

I advice against removing index.php as it's part of the WP Template Hierarchy and is the very last backup template for anything that doesn't have anything else to use.

// Hook into admin_menu
add_action( 'admin_menu', function() {

    // Add submenu page under "Tools" with manage_options capabilities
    add_submenu_page( 'tools.php', 'Page Templates Statistics', 'Page Templates Statistics', 'manage_options', 'page-template-statistics', 'wpse_260813_show_satistics' );
} );

// Function that renders the page added above
function wpse_260813_show_satistics() {

    // Get available templates within active theme
    $available_templates = get_page_templates();

    // Get used templates from database
    global $wpdb;
    $result = $wpdb->get_results(
            SELECT DISTINCT( meta.meta_value ) FROM {$wpdb->prefix}postmeta as meta
            JOIN {$wpdb->prefix}posts as posts ON posts.ID = meta.post_id
            WHERE meta.meta_key LIKE '_wp_page_template'
            AND posts.post_type = 'page'

    $used_templates = array();
    foreach ( $result as $template ) {
        $used_templates[] = $template->meta_value;

     * Compare available templates against used templates
     * Result is an array with the unused templates
    $unused_templates = array_diff( $available_templates, $used_templates );

    // Draw page to show unused templates
    <div class="wrap">
        <h1>Page Template Statistics</h1>
        The following templates are not being used:
                <th>Template name</th>
            <?php foreach ( $unused_templates as $name => $file ) : ?>
                    <td><?php echo $name; ?></td>
                    <td><?php echo $file; ?></td>
        <?php endforeach; ?>
  • This will find the overarching PHP files, but it won't find template parts or includes. Also, the second query only identifies Page templates - it will not show you where header.php, footer.php, index.php, single.php, etc. are in use as OP is asking.
    – WebElaine
    Commented Mar 24, 2017 at 13:21
  • OP is asking to find used/unused WP Template files, which is exactly what this does. Finding template parts and/or includes is not part of this. The reason OP wants to find these is to remove unused files and since files like index.php, header.php shouldn't be deleted anyhow that's not a problem in this scenario.
    – Jebble
    Commented Mar 24, 2017 at 21:39

You could crawl the whole site and match the results for get_included_files() to your template files.


You mean something like this?

$args = array(
    'meta_key' => '_wp_page_template',
    'meta_value' => 'page-special.php'

wp_count_posts( $args );
  • Please edit your answer, and add an explanation: why could that solve the problem?
    – fuxia
    Commented Mar 21, 2017 at 15:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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