Steve Taylor photo

How to restrict a WordPress page template to one page

WordPress page templates (now applicable to any post type) are designed to be re-used for any number of pages. However, sometimes I want there to be a template that only gets used once. It is possible to tie a template to a specific page by using the page-{slug}.php or page-{id}.php template naming patterns, but slugs and IDs can sometimes be unstable (e.g. across different environments). How to use a template and make sure it only gets used once? As with most cats, there’s probably many ways to skin this one. But here’s one way.

First we need a function to get the ID of the page currently set to the template, if any.

function slt_get_template_page_id( $template ) {
	$page_id = null;

	$pages = get_posts( array(
		'post_type'			=> 'page',
		'posts_per_page'	=> 1,
		'fields'			=> 'ids',
		'meta_key'			=> '_wp_page_template',
		'meta_value'		=> $template
	));

	if ( $pages ) :
		$page_id = $pages[0];
	endif;

	return $page_id;
}

Now we hook into the theme_{$post_type}_templates filter which controls the templates available in the Page attributes drop-down:

add_filter( 'theme_page_templates', 'slt_theme_page_templates', 10, 3 );
function slt_theme_page_templates( $templates, $theme, $post ) {
	$template = 'page_my-template.php';

	$template_page_id = slt_get_template_page_id( $template );
	if ( $template_page_id && ! empty( $post ) && ( $template_page_id != $post->ID ) ) :
		unset( $templates[ $template ] );
	endif;

	return $templates;
}

This checks if there’s already a page set to the template. If there is (and we’re not dealing with that page!), the template is removed from the options.

NB: As is often the case, Quick Edit scuppers things slightly. If necessary, there are ways of disabling Quick Edit completely. Suggestions for making the above theme_page_templates filter work properly for Quick Edit are welcome. The issues seems to be that $post isn’t passed through.

One comment

Leave a comment

Your email address will not be published. Required fields are marked *