Creating page-templates directory breaks everything!

When a page is assigned to a template, this template selection is saved in the post meta table under the key _wp_page_template. These template values are as follow

  • default if no page template in explicitely set

  • {$template}.php for templates in root

  • subfolder/{$template}.php for templates in a subfolder where subfolder should be the name of the subfolder

is_page_template() explicitely compares the value from the template name passed to it to the value stored in _wp_page_template. Note, the page template is returned by get_page_template_slug() inside is_page_template(). If these two values don’t match, false is returned

Example:

If we have a template called template.php we would match that with is_page_template( 'template.php' ), because the value of _wp_page_template for the specific page will be template.php.

When we move this template to a subfolder called subfolder and reassign the page template to the page, the value of _wp_page_template will be
subfolder/template.php, abviously which will fail is_page_template( 'template.php' ) because 'template.php' !== 'subfolder/template.php'

You will need to manually adjust your conditional statement to is_page_template( 'subfolder/template.php ) to match up with the move to subfolders as there are no filters that I can see to safely change this.

EDIT from comments

  1. Change the structure aka move templates to directiory

As you already explained, moving templates to a subfolder breaks the current structures

  1. Reassign page templates

You will need to reassign pages to the correct template again. If you move templates (our example is template.php being moved into subfolder) into a subfolder, the value of _wp_page_template does not change. The old value (which is template.php in our example) remains in db. With this in mind, it is very easy to bulk update all pages and reassigning the correct page template to a page.

All we need to do is to get the old value from db and then resaving the value with subfolder/ appended to the old template name. I have written a small action to achieve this, no you do not need to do it manually anymore ;-). All you need to do is to add an array of page names which you have moved to the value parameter in the meta_query , this will get all pages which have those old templates assigned to them, then you simply append subfolder/ to the template names and resave them.

As the action runs on admin_init, all you need to do is, load any admin page once, and your done., After that you can remove the function. Just one note before running the action, make double sure all values are correct before you run the action as it alters values in the db. Also have a backup of the db stored somewhere

add_action( 'admin_init', function ()
{
    // Get all pages in order to change the template paths to subfolder
    $args = [
        'post_type'      => 'page',
        'posts_per_page' => -1,
        'fields'         => 'ids',
        'meta_query'     => [
            [
                'key' => '_wp_page_template',
                'value' => ['template.php'] // Set all the templates you have moved into an array
            ]
        ]
    ];
    $q = get_posts( $args );

    if ( !$q )
        return;

    foreach ( $q as $id ) {
        // Get the current template name saved
        $template = get_post_meta( $id, '_wp_page_template', true );
        // The name of the subfolder with trailing slash
        $subfolder_name="subfolder/";
        // Update the templates to add the subfolder name. Change name as needed
        update_post_meta( 
            $id, // Page ID
            '_wp_page_template', //Meta key under which the page template name is saved
            $subfolder_name . $template, //the new value of the template name, in this case subfolder/{$template}.php
            $template // Old value of the template name
        );
    }
});
  1. Add page-templates/ path to every is_page_template() to my every code?

That is correct. There is unfortunately no other way to to this. You can bulk update this in your theme if you have a good code editor

I wasn’t sure about the 3. step because what I read from article was that WP “knows” by default if templates are in page-templates/ directory

WordPress does not know that. Another wrong in the codex, one again. WordPress uses the value stored in _wp_page_template to load the correct template from either root or a subfolder according to the value returned. Without knowing the value of _wp_page_template, WordPress will not know which template was assigned to the page and where to look for the template. template.php means the page template is in root, subfolder/template.php means the template is in the subfolder calles subfolder.

You can check out how templates are loaded for pages by looking at the source code for get_page_template()