I created page templates that use the page slug, for example, page-contact.php
, page-gallery.php
etc. or page id, for example, page-2.php
, page-11.php
etc.
How can I move these templates to a subfolder, for example /mytheme/pages/
?
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It only takes a minute to sign up.
Sign up to join this communityI created page templates that use the page slug, for example, page-contact.php
, page-gallery.php
etc. or page id, for example, page-2.php
, page-11.php
etc.
How can I move these templates to a subfolder, for example /mytheme/pages/
?
/YOUR_THEME/page-templates/ will only work for custom page templates assigned on the admin page edit screen, not for page-$slug or page-$id named templates.
The correct filter hook in my view is page_template, but you don't (I assume!) want to throw out any other possible templates for your pages, not least because you're bound to have some pages on your site for which you haven't made a /my-sub-dir/page-$slug.php template file.
The page_template filter hook is called just after WP has found a template for the page using the standard template hierarchy. It would be handy if there was a filter to let you inject your additional template into the right part of the template hierarchy, but in the absence of that we'll need to replicate the search for page templates from WordPress's own get_page_template() function, found in /wp-includes/template.php:
function get_page_template() {
$id = get_queried_object_id();
$template = get_page_template_slug();
$pagename = get_query_var('pagename');
if ( ! $pagename && $id ) {
// If a static page is set as the front page, $pagename will not be set. Retrieve it from the queried object
$post = get_queried_object();
if ( $post )
$pagename = $post->post_name;
}
$templates = array();
if ( $template && 0 === validate_file( $template ) )
$templates[] = $template;
if ( $pagename )
$templates[] = "page-$pagename.php";
if ( $id )
$templates[] = "page-$id.php";
$templates[] = 'page.php';
return get_query_template( 'page', $templates );
}
This function builds an array of possible templates for Pages. get_query_template() then uses locate_template() to run through the array and return the filename of the first template found.
As we can't hook into the list of proposed templates, we'll sadly have to duplicate some of this work.
Here's our own function:
function tbdn_get_page_template() {
$id = get_queried_object_id();
$template = get_page_template_slug();
$pagename = get_query_var('pagename');
if ( ! $pagename && $id ) {
// If a static page is set as the front page, $pagename will not be set. Retrieve it from the queried object
$post = get_queried_object();
if ( $post )
$pagename = $post->post_name;
}
$templates = array();
if ( $template && 0 === validate_file( $template ) )
$templates[] = $template;
// if there's a custom template then still give that priority
if ( $pagename )
$templates[] = "our-sub-dir/page-$pagename.php";
// change the default search for the page-$slug template to use our directory
// you could also look in the theme root directory either before or after this
if ( $id )
$templates[] = "our-sub-dir/page-$id.php";
$templates[] = 'page.php';
/* Don't call get_query_template again!!!
// return get_query_template( 'page', $templates );
We also reproduce the key code of get_query_template() - we don't want to call it or we'll get stuck in a loop .
We can remove lines of code that we know won't apply for pages, leaving us with...
*/
$template = locate_template( $templates );
return $template;
}
add_filter( 'page_template', 'tbdn_get_page_template' );
Caveats:
1 - I haven't tested this, but if you're up to messing around with the template hierarchy then you should certainly be able to follow, test & adjust my code which is mostly copied from WP anyway.
2 - If future core code ever changes the template hierarchy for pages then the code above will go out-of-date.
Parse error: syntax error, unexpected end of file in .../wp-content/themes/language-school/functions.php on line 628
WordPress will recognize template files in /YOUR_THEME/page-templates/: https://developer.wordpress.org/themes/basics/organizing-theme-files/#page-templates-folder
template-%slug%.php
or any other file name except if the file starts with page-
. It could start with page_
for example.
I posted the details on this answer. Here, the CODE is adjusted based on two specific differences of this question:
Move page templates to sub-directory without fall back. For example, it'll check
THEME/sub-directory/page-{slug}.php
, but it'll not checkTHEME/page-{slug}.php
, because that's what the OP asked. However, the option with fallback in the other answer is better, especially in case of child theme (as the parent theme may depend on the fallback).It'll move both
page-{slug}.php
andpage-{id}.php
to the sub-directory.
The best way to move page templates to a sub-directory, say /THEME/page-templates/
, is to use the page_template_hierarchy
filter hook.
Note: the original filter hook is {$type}_template_hierarchy, which becomes
page_template_hierarchy
when$type
ispage
.
<?php
/*
Plugin Name: WPSE Page Template move to Sub Directory
Plugin URI: https://wordpress.stackexchange.com/a/227006/110572
Description: WPSE Page Template move to a Sub Directory
Version: 1.0.0
Author: Fayaz Ahmed
Author URI: https://www.fayazmiraz.com/
*/
// defining the sub-directory so that it can be easily accessed from elsewhere as well.
define( 'WPSE_PAGE_TEMPLATE_SUB_DIR', 'page-templates' );
function wpse227006_page_template_add_subdir( $templates = array() ) {
// Generally this doesn't happen, unless another plugin / theme does modifications
// of their own. In that case, it's better not to mess with it again with our code.
if( empty( $templates ) || ! is_array( $templates ) || count( $templates ) < 3 )
return $templates;
$page_tpl_idx = 0;
$cnt = count( $templates );
if( $templates[0] === get_page_template_slug() ) {
// if there is custom template, then our page-{slug}.php template is at the next index
$page_tpl_idx = 1;
}
// the last one in $templates is page.php, so
// all but the last one in $templates starting from $page_tpl_idx will be moved to sub-directory
for( $i = $page_tpl_idx; $i < $cnt - 1; $i++ ) {
$templates[$i] = WPSE_PAGE_TEMPLATE_SUB_DIR . '/' . $templates[$i];
}
return $templates;
}
// the original filter hook is {$type}_template_hierarchy,
// wihch is located in wp-includes/template.php file
add_filter( 'page_template_hierarchy', 'wpse227006_page_template_add_subdir' );