5

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/?

  • If you do this you would need al kind of redirects on the server so WP is still able to find the files. Not recommended. – cjbj May 18 '16 at 9:46
  • I hope for some easy and light solution. Costum or WP function for instance. – Den May 18 '16 at 16:45
  • Sorry, there is no easy solution to this one. – cjbj May 18 '16 at 17:57
  • Plugins like WooCommerce, Easy Digital Downloads use custom template loader. I'm not sure, but if you are desperate, have a look into the custom template loader codes and try to find out a way. I'm not sure what I'm suggesting. :( – Mayeenul Islam May 30 '16 at 7:30
  • did you ever find the answers? i need this too – Tintinabulator Zea Dec 20 '18 at 23:23
4

/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.

  • Thanks for answer. You right that i doesn't want to use custom template files, they good, but on this project i need to orginize a lot of different pages and i think, that page-$slug.php it'a a best solution for this. Thanks for code, but wp dont' like than and sayd about error Parse error: syntax error, unexpected end of file in .../wp-content/themes/language-school/functions.php on line 628 – Den May 18 '16 at 16:35
  • I just pasted that function into one of my own themes and I don't get a parse error. Maybe it's elsewhere in your functions.php file? – Andy Macaulay-Brook May 19 '16 at 8:28
  • Separate to your parse issue though, I've realised I didn't add the code line to hook the function into WP so I've edited my answer to include that. – Andy Macaulay-Brook May 19 '16 at 8:34
  • 2
    Andy's answer above is good but it has the wrong callback for add_filter. It should be: add_filter( 'page_template', 'tbdn_get_page_template' ); – Theo Tillotson Jul 15 '17 at 17:57
  • 1
    @Fayaz No, seems fair enough :-) Anything to improve the questions and answers here is fine by me. – Andy Macaulay-Brook Aug 27 '18 at 18:45
1

I posted the details on this answer. Here, the CODE is adjusted based on two specific differences of this question:

  1. Move page templates to sub-directory without fall back. For example, it'll check THEME/sub-directory/page-{slug}.php, but it'll not check THEME/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).

  2. It'll move both page-{slug}.php and page-{id}.php to the sub-directory.


Filter Hook to use:

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 is page.

Sample CODE:

<?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' );
0

WordPress will recognize template files in /YOUR_THEME/page-templates/: https://developer.wordpress.org/themes/basics/organizing-theme-files/#page-templates-folder

  • It's great, but work only with template-%slug%.php files. Now i need to work with a lot of page-%slug%.php files and want to organize them – Den May 18 '16 at 16:29
  • With the name template-%slug%.php or any other file name except if the file starts with page-. It could start with page_ for example. – cybmeta May 31 '16 at 16:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.