Which WordPress Pages Use This Template? The Answer Is in _wp_page_template

The page template is the one we pick when we are editing a page in the right sidebar, under the Template section. The Pages screen itself never shows which page template is being used for which page. If we have assigned the Full Width template to some pages in Theme A and we switch to Theme B, the pages would be there on the Full Width template. This could be a problem if the theme we are switching to doesn’t have the same template. So where does the choice live? How do we query it? How do we fix it?

What is a page template?

In WordPress, every page of our site is rendered through one or the other template file. The question arises, how does WordPress know which file to use for which page? The answer to this is simple -> Hierarchy.

For example, let’s take a page with the slug our-team -> The page for this slug would be rendered through the following files:

  • page-our-team.php
  • page-21.php -> if the ID of the page is 21
  • page.php
  • singular.php
  • index.php

Some of these files may not be there, and that’s perfectly fine. WordPress will just use the file placed below that in the hierarchy.

There’s also a way to create custom page templates, we can create a PHP file and add a Template Name: header to it, then we can use the Page Template feature in the editor to select it. We can also add the Template Post Type: header in it and it would be accessible for all the post types specified in it.

Block themes provide an option in the theme.json file to define the customTemplates where it would fetch the theme template files from the templates/ directory.

In the Site Editor when we are creating custom templates they are saved as wp_template posts.

Where is the choice stored?

The choice we get in the editor is to set the Page Template to a specific value, that value is stored under the post meta row with the key _wp_page_template and the value is the file path for the template like templates/full-width.php.

In case of block themes, the value is a block template slug instead of a file path.

default or empty value -> The page will use the default template for the post type.

get_page_template_slug() would read this value and the REST API would provide it under the template field.

When we go to the Pages list, we see a table with columns like title, author, comments, date etc. But we do not see a column for template.

To find out which pages are using the Full Width template we must open each page one by one and check its Template panel for the value.

This is practically not possible, for e.g. a user with 500 pages -> he would need 500 tabs open to check if they are on Full Width.

How do we query it ourselves?

SQL command for getting all the rows in wp_postmeta where meta_key = '_wp_page_template':

SELECT * FROM `wp_postmeta` WHERE `meta_key` = '_wp_page_template';

To get the count of every page template being used, we can add GROUP BY meta_value with COUNT(*):

SELECT COUNT(*), `meta_value` FROM `wp_postmeta` WHERE `meta_key` = '_wp_page_template' GROUP BY `meta_value`;

The output we are getting is the raw file paths for the page templates, not the template names. Also this would not give us a sign for which template the theme no longer has.

The table prefix may not be wp_, we can check it in our wp-config.php file, the prefix is stored under the variable $table_prefix.

WP-CLI provides a command wp post list. To get the list of pages using a certain template file, we can use the command:

wp post list --post_type=page --meta_key=_wp_page_template --meta_value=<file>

We can also add the --fields=ID,post_title to get only the ID and the title of the page.

We can also add extra --<field>=<value> arguments to this which would be considered as query variables in the WP_Query.

How does a template go missing?

There can be various reasons for the page template to break, or for it to no longer be available in the Page Template menu.

  • The theme switch, the templates from the old theme are gone.
  • Child theme has been removed or replaced
  • The template file has been renamed or deleted in a deploy
  • We have deleted a custom template created via Site Editor
  • The Template Post Type: value has been changed
  • The plugin that added the template has been deactivated
  • The parent theme has been updated and template file has been dropped

In all of the above cases, _wp_page_template keeps the value as the one we set previously.

What do visitors see?

The function get_page_template() would return the file found under the page’s own template first, and then goes on with the following order if the file is not found.

  • page-{slug}.php
  • page-{id}.php
  • page.php
  • singular.php
  • index.php

Block themes also use this same type of logic to load their template, they also use the function resolve_block_template() to resolve the template, and internally they follow the same list as above.

The page is still loaded, just the layout changes, the content stays the same. We do not get any notice in wp-admin that our page is loading the default layout instead of the chosen one, there’s also no log entry for the same.

This is not a bug, this is a feature.

What happens on save?

The block editor does save through the REST API. But we can also see from check_template() that, if the template is the same as it is now, it will always allow it no matter if the theme dropped it or not -> this is the reason the dead value for the template survives saves.

If we try to do the same with the wp_insert_post() / wp_update_post() function with an unknown page_template:

  • If $wp_error is true -> we would get the error invalid_page_template, with the message Invalid page template.
  • If $wp_error is false -> the meta would be quietly set to default

Fixing pages by hand

If we want to change the page template for a single page, we can directly do it in the editor or the Quick Edit mode on the page.

We can use the wp post list command to get a list of pages and then use the --format=ids to only get the post IDs.

We can shell loop over those IDs and run the wp post meta update <id> _wp_page_template default to set the page template for all those pages to default.

Before we switch to a new theme, we can list all the templates the new theme offers us.

We can then compare this with the values in use in our site, and we can map each of the old templates to a new one and switch them.

If there is no corresponding template, we can also set it to default -> which would let the WordPress page template hierarchy decide which template file to load.

Axle Page Template Usage

We have added a Template column to the Pages list, this would display the template assigned to the page.

If we click a template name from this column it would take us to the page where all the pages using that particular template would be listed.

Above this list we have a filter to select every template with the count of pages using it.

The count inside the parentheses is used to denote the number of times the template is being used, if the number is 0 that means the template is not being used anywhere on the site.

We can also sort the pages on the basis of template.

Missing templates are shown in red text.

There is an additional section under Appearance > Axle Page Template Usage which provides us a screen with every template and the count of pages using that template on a single screen.

There is also a button available to remove every page from a template in a single action.

We can reassign all the missing page templates to the default template with a single command:

wp axle-page-template-usage reassign missing default

Checking a theme before switching

We can pick an installed theme that is not active and run the check on that.

It would list us all the pages and posts that would lose their template when switching to the theme we picked.

The report groups the pages and posts by template, and also adds the count for the same.

We can then pick a replacement template from the list provided for every missing template, they are default preselected.

After we are done picking all the replacements, we can save the plan.

When we activate the theme, it will run all the changes on the site, 500 per request. The rest of the tasks will be completed in the background. -> We will be given a notice and can also undo the changes afterwards.

The check only reads the information and does nothing to the posts or pages until we activate the theme.

We can use the below command to check the page template usage for a theme:

wp axle-page-template-usage check-theme <theme>

Template history

Every template change on a page is recorded: the page where the change was made, the old template, the new template, who made the change, when the change was made.

There are several sources of changes, for example the editor, Quick Edit, the Move button, switching between themes, WP-CLI.

We can filter the template history records on the basis of the page, source, user who made the change, the template and the date.

We can undo one change at a time as long as the page still has that template assigned to it. We can undo a whole batch of changes as well.

Template history only keeps the record of the latest 10,000 changes and deletes the entries after 1 year. If we activate it today, it would not have any record of the previous template changes.

Template history data is stored in its own table named {prefix}axle_ptu_history.

Getting it

The counts are produced by a single grouped query for all the used templates and it is cached for up to 1 hour.

We can download the zip from axlewp.com/plugins/axle-page-template-usage.

We can also find a guide for it on axlewp.com/docs/axle-page-template-usage.

We can also try the plugin out in the browser itself -> try.axlewp.com/axle-page-template-usage

This plugin is free and open sourced under the GPL and there is no pro version or any kind of tracking.