(type)_template_hierarchyfilter-hookWP 4.7.0

Allows changing the list of PHP files in the template hierarchy for the current page (the current request).

This is a dynamic hook where (type) can be one of the following:

  • indexindex_template_hierarchy.
  • 404404_template_hierarchy.
  • archivearchive_template_hierarchy.
  • authorauthor_template_hierarchy.
  • categorycategory_template_hierarchy.
  • tagtag_template_hierarchy.
  • taxonomytaxonomy_template_hierarchy.
  • datedate_template_hierarchy.
  • embedembed_template_hierarchy.
  • homehome_template_hierarchy.
  • frontpagefrontpage_template_hierarchy.
  • privacypolicyprivacypolicy_template_hierarchy.
  • pagepage_template_hierarchy.
  • pagedpaged_template_hierarchy.
  • searchsearch_template_hierarchy.
  • singlesingle_template_hierarchy.
  • singularsingular_template_hierarchy.
  • attachmentattachment_template_hierarchy.

The last array element must always be the default template file. For example, it is page.php for the page type, single.php for the singular type, and so on.

Usage

add_filter( '(type)_template_hierarchy', 'wp_kama_type_template_hierarchy_filter' );

/**
 * Function for `(type)_template_hierarchy` filter-hook.
 * 
 * @param string[] $templates A list of template candidates, in descending order of priority.
 *
 * @return string[]
 */
function wp_kama_type_template_hierarchy_filter( $templates ){
	// filter...
	return $templates;
}
$templates(array)

A list of template files in the order in which they should be tried. The first existing file in the list will be used.

The list is an array whose elements contain paths relative to the theme directory. For example, a request for a page post produces the following array:

Array(
	[0] => page-contacts.php
	[1] => page-25.php
	[2] => page.php
)

Examples

#1 Add a custom template file to the hierarchy

Suppose the theme has a tpl directory containing template files. For pages with the my-page and your-page slugs, we need to use the tpl/some-page.php template file. Use the following code:

add_filter( 'page'.'_template_hierarchy', function( $templates ){

	$cur_name = str_replace( [ 'page-', '.php' ], '', $templates[0] );

	$custom_tpls = [
		'my-page' => 'tpl/some-page.php'
		'your-page' => 'tpl/some-page.php'
	];

	if( in_array( $cur_name, array_keys( $custom_tpls ), true ) ){
		array_unshift( $templates, $custom_tpls[ $cur_name ] );
	}

	return $templates;
} );

The tpl/some-page.php file will now appear at the beginning of the theme file hierarchy for page posts. If the file exists in the theme, it will be used as the template for the current page.

#2 Add a custom template file for a custom post type

Suppose we registered the book post type and want the single-page template for this post type to be stored in the theme's templates directory under the name book.php. In other words, templates/book.php should handle the output; if it does not exist, the standard theme file hierarchy should be used.

add_filter( 'single'.'_template_hierarchy', function( $templates ){

	if( is_singular('book') ){
		array_unshift( $templates, 'templates/book.php' );
	}

	return $templates;
} );

#3 Move the entire theme file hierarchy into the templates directory

Make all template files reside in the theme's templates directory instead of the theme root:

$types = [
	'404',
	'archive',
	'author',
	'category',
	'tag',
	'taxonomy',
	'date',
	'embed',
	'home',
	'frontpage',
	'privacypolicy',
	'paged',
	'search',
	'page',
	'single',
	'singular', // include attachments
	'attachment',
	//'index', leave /index.php as is
];

// add a prefix for all template files
foreach( $types as $type ){
	add_filter( "{$type}_template_hierarchy", 'prefix_template_hierarchy', 20 );
}

function prefix_template_hierarchy( $templates ){

	$subfolder = 'templates';

	$type = str_replace( '_template_hierarchy', '', current_filter() );

	// add `taxonomy.php` file after last `category.php` and `tag.php` element.
	if( in_array( $type, [ 'category', 'tag' ] ) ){
		$templates[] = 'taxonomy.php';
	}

	// add global prefix `self::$basedir/` ex: `tpl/`.
	foreach( $templates as $index => $relpath ){

		if( ! str_starts_with( $relpath, "$subfolder/" ) ){
			$templates[ $index ] = "$subfolder/$relpath";
		}
	}

	return $templates;
}

The only exception is index.php, which must remain in the theme root. The example also demonstrates how to determine the current hierarchy type and, for example, add taxonomy.php to the hierarchy for categories and tags. By default, it is absent from the theme file hierarchy, although including it there would be logical.

Standard files such as comments.php, header.php, footer.php, and sidebar.php do not participate in the theme file hierarchy. Handle them separately if you also want them to reside in the templates directory instead of the theme root.

Changelog

Since 4.7.0 Introduced.

Where the hook is called

get_query_template()
(type)_template_hierarchy
wp-includes/template.php 62
$templates = apply_filters( "{$type}_template_hierarchy", $templates );

Where the hook is used in WordPress

Usage not found.