Filter Available Page Templates

When creating a page, WordPress allows you to choose a page template using a drop down list. This list is automatically generated based on the page templates provided by the theme. The standard way to add or remove templates from this list is to create or delete template files in theme. However, there are good reasons to remove a template from the list without deleting the template file itself. Let’s look at a couple of those reasons.

Child Themes

If we’re working with a child theme and we want to remove a template from the list, simply deleting it from the parent theme is only a temporary solution. If the parent theme is updated, the page template file will be reintroduced and appear in the page template list again. The whole goal of a child theme is to avoid modifying the parent theme in any way. So to remove a page template from the list we will want to use the theme_page_templates filter instead. For example, let’s say we’re trying to remove a page template from the parent theme located in a file called full-width.php. Here’s what our filtering function would look like:

function filter_page_templates( $page_templates ) {

	// Removes item from template array.
	unset( $page_templates['full-width.php'] );

	// Returns the updated array.
	return $page_templates;
}
add_filter( 'theme_page_templates', 'filter_page_templates');

Our function accepts one argument. This argument is the array of page templates. This is an associative array. The array keys are the page template file locations and the array values are the page template names. To remove an item from the array, we use the PHP unset() function along with the file name of the template. Next we return the modified $page_templates array. Finally, we add our function to the theme_page_templates filter.

Note: If the template file is located in a subdirectory of the parent theme, the subdirectory name would be required as well. For example.

	// Removes item from template array.
	unset( $page_templates['templates/full-width.php'] );

Now lets look at another reason we might want to filter the page template drop down list (this is the reason I started looking into this).

Template Dependencies

The theme I’m currently working on supports seven different page layouts. There are one column layouts with no sidebars, two column layouts with a content column and a sidebar column, and three column layouts with a content column and two sidebar columns. Each layout has its own page template. However, since my theme is targeted at developers, I want to let the developer decide how many sidebars are available. If a developer only wants to allow a single sidebar, I want to automatically remove the three column page templates from the template list because they require two sidebars. Here’s what my filter looks like:

function filter_page_templates( $page_templates ) {
	global $wp_registered_sidebars;

	if ( ! array_key_exists( 'sidebar-2', $wp_registered_sidebars ) ) {
		unset( $page_templates['page-templates/content-sidebar-sidebar.php'] );
		unset( $page_templates['page-templates/sidebar-sidebar-content.php'] );
		unset( $page_templates['page-templates/sidebar-content-sidebar.php'] );
	}

	return $page_templates;
}
add_filter( 'theme_page_templates', 'filter_page_templates');

First I declare the global variable $wp_registered_sidebars. This variable contains a list of all the registered sidebars. This will allow me to check if the second sidebar has been disabled by the theme developer using my theme.

Note: I tried using is_active_sidebar() first, but that seems to return true for unregistered sidebars that still contain widgets in the database, even though they’re no longer registered or in use.

Next I check if the second sidebar exists in the registered sidebars array. If it’s not there, I unset all the page templates that require that second sidebar. Then I return the newly modified array of page templates and add my function to the theme_page_templates filter. Now the three column page templates only show up if the second sidebar is active.