Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom templates not loading since latest update #1870

Closed
5 of 6 tasks
vdrnn opened this issue Apr 4, 2017 · 25 comments
Closed
5 of 6 tasks

Custom templates not loading since latest update #1870

vdrnn opened this issue Apr 4, 2017 · 25 comments
Labels

Comments

@vdrnn
Copy link
Contributor

vdrnn commented Apr 4, 2017

Submit a feature request or bug report

Bug report

It looks like after the latest update of sage, the custom templates aren't working anymore. I tested it on two different installations and for both the custom templates don't appear under page attributes. I guess it has something to do with the move of templates/ to resources/views/ and src/ to app/ but unfortunately I wasn't able to figure out where the problem is.

Specifically I'm talking about this template/templates resources/views/template-custom.blade.php

@retlehs retlehs added the bug label Apr 4, 2017
@retlehs
Copy link
Member

retlehs commented Apr 4, 2017

confirmed bug, thanks for reporting

@retlehs
Copy link
Member

retlehs commented Apr 4, 2017

it looks like wordpress hardcodes looking for page templates beyond 1 level deep 😱, see http://wordpress.stackexchange.com/a/250024 / https://github.com/WordPress/WordPress/blob/503d42fe6bcd2f45b3af78657686f8a27ccb0136/wp-includes/class-wp-theme.php#L1034-L1045

from what i can tell so far, we'd have to duplicate the get_post_templates functionality and tell it to search beyond 1 folder deep

...then use the theme_page_templates filter to populate the list of template names & filenames

@Log1x
Copy link
Member

Log1x commented Apr 4, 2017

oh jeeze

@derkjn
Copy link
Contributor

derkjn commented Apr 5, 2017

How about setting the templates in the cache to avoid the issue entirely? Since that method is checking with $post_templates = $this->cache_get( 'post_templates' );?

@retlehs
Copy link
Member

retlehs commented Apr 5, 2017

@derkjn how would the issue be avoided by doing that? that solution still requires duplicating a bunch of functionality in the WP theme class

@derkjn
Copy link
Contributor

derkjn commented Apr 5, 2017

If we preset the list of templates in the cache before wordpress gets to that point, instead of searching for php files in the first level deep, it will return what's in the cache, which basically goes down to accessing the following:

function wp_cache_add( $key, $data, $group = '', $expire = 0 ) {
	global $wp_object_cache;

	return $wp_object_cache->add( $key, $data, $group, (int) $expire );
}

@retlehs
Copy link
Member

retlehs commented Apr 5, 2017

right. where are you getting the list of custom page templates from without duplicating the functionality from the WP theme class?

@derkjn
Copy link
Contributor

derkjn commented Apr 5, 2017

The only thing you need to duplicate is the regexp to parse the files, other than that why not just scandir the templates folder?
Basically you only need the following to feed the cache:

$files = scandir(get_template_directory_uri());
    foreach ( $files as $file => $full_path ) {
        if ( ! preg_match( '|Template Name:(.*)$|mi', file_get_contents( $full_path ), $header ) ) {
            continue;
        }

        $types = array( 'page' );
        if ( preg_match( '|Template Post Type:(.*)$|mi', file_get_contents( $full_path ), $type ) ) {
            $types = explode( ',', _cleanup_header_comment( $type[1] ) );
        }

        foreach ( $types as $type ) {
            $type = sanitize_key( $type );
            if ( ! isset( $post_templates[ $type ] ) ) {
                $post_templates[ $type ] = array();
            }

            $post_templates[ $type ][ $file ] = _cleanup_header_comment( $header[1] );
        }
    }

@retlehs
Copy link
Member

retlehs commented Apr 5, 2017

i mean we're not really avoiding the issue at that point :) i was confused as you made it seem like there was an easier solution. we also need to re-create _cleanup_header_comment as it's not meant to be used outside of core. want to submit a PR?

@derkjn
Copy link
Contributor

derkjn commented Apr 5, 2017

Sorry I was in a bit of a rush and didn't make myself really clear :)
I'll play around with this a bit and see if I can get it to work properly. Once tested I'll post my results here and if we're all happy with it, more than happy to submit a PR :)

@derkjn
Copy link
Contributor

derkjn commented Apr 5, 2017

Alright so after playing with it for a bit I got to this working solution:

add_action('admin_init', function () {
    $templateRoot = trailingslashit(get_template_directory());
    $cache_hash = md5(trailingslashit(dirname($templateRoot)) . basename($templateRoot));
    $post_templates = [];
    $path = $templateRoot . 'resources/views/';
    $files = scandir($path);
    foreach ($files as $file) {
        if (is_dir($path . $file)) {
            continue;
        }
        if (!preg_match('|Template Name:(.*)$|mi', file_get_contents($path . $file), $header)) {
            continue;
        }

        $types = array('page');
        if (preg_match('|Template Post Type:(.*)$|mi', file_get_contents($path . $file), $type)) {
            $types = explode(',', _cleanup_header_comment($type[1]));
        }

        foreach ($types as $type) {
            $type = sanitize_key($type);
            if (!isset($post_templates[$type])) {
                $post_templates[$type] = array();
            }

            $post_templates[$type][$file] = trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $header[1]));
        }
    }
    wp_cache_add('post_templates-' . $cache_hash, $post_templates, 'themes', 1800);
}, 1);

Any feedback is most welcome. If accepted I'm happy to open a PR with it :)

@ciromattia
Copy link
Contributor

The following line
$post_templates[$type][$file] = trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $header[1]));
should be changed to
$post_templates[$type][$full_path] = trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $header[1]));
to maintain coherence with wordpress' internal way of setting post template meta - and because changing it to a numerical id breaks ACF way of setting the rule for Page Templates.

@derkjn
Copy link
Contributor

derkjn commented Apr 5, 2017

Thanks @ciromattia for pointing that out, code updated 😄

@kimhf
Copy link
Contributor

kimhf commented Apr 6, 2017

I get a lot of notices with that code.

Could you change
foreach ($files as $file => $full_path) {
to something like

foreach ($files as $file) {
  if ( is_dir( $path . $file ) ) {
    continue;
  }

and just rename $full_path to $file?

@ciromattia
Copy link
Contributor

@Kimers what kind of notices?

@kimhf
Copy link
Contributor

kimhf commented Apr 6, 2017

Warning: file_get_contents(resources/views/.): failed to open stream: Permission denied in app\filters.php

Warning: file_get_contents(resources/views/..): failed to open stream: Permission denied in app\filters.php

Warning: file_get_contents(resources/views/layouts): failed to open stream: Permission denied in app\filters.php

Warning: file_get_contents(resources/views/partials): failed to open stream: Permission denied in app\filters.php

Other then this it seems to work just fine.

@ciromattia
Copy link
Contributor

Strange, are you sure your directories have 755 permissions?

@kimhf
Copy link
Contributor

kimhf commented Apr 6, 2017

Have no idea, it is on a WAMP local server, not sure it is even possible to manage permissions that apache would recognize with that or how to set that up. It does not have an issue with the php files, just the folders and "." and ".." (not sure what those are). Seem to me the issue is that we can't just assume that we can use file_get_contents() on everything scandir() returns. The trick for me seems to be to filter out everything else then those php files. is_dir() seems to return true on the "." and ".." and the two folders.

@andrewklau
Copy link
Contributor

andrewklau commented Apr 6, 2017

Including @Kimers changes will introduce a new problem for undefined $full_path variable on child templates

Also the above method breaks child pages that use the js router
ie. a page parent->child used to run JS that was in Parent.js however now the body classes are:

page-template page-template-parent page-template-views page-template-template-languages-blade page-template-parentviewstemplate-languages-blade-php page page-id-72 page-child parent-pageid-67 child

Although perhaps something that could be fixed here instead https://github.com/roots/sage/blob/master/app/filters.php#L8

@andrewklau
Copy link
Contributor

andrewklau commented Apr 6, 2017

This seems to be a temporary fix for the parent class but probably not the ideal approach:

global $post;
parents = get_post_ancestors($post->ID);
$id = ($parents) ? $parents[count($parents)-1]: $post->ID;
$parent = get_post($id);
$classes[] = $parent->post_name;

@derkjn
Copy link
Contributor

derkjn commented Apr 6, 2017

Thanks for the feedback everyone!
@andrewklau I just tested this but I correctly get the class page-parent in my templates as before the folder restructure, so not sure where your problem is originating. The one you posted is the child page classlist which is not supposed to have the page-parent class, but only a reference to the parent id (parent-pageid-67 in your example).

Updated the hook to exclude directories as well 😄

@alexkerber
Copy link

Any update with this bug? :/

@vdrnn
Copy link
Contributor Author

vdrnn commented Apr 13, 2017

@alexkerber there is a pull request waiting to get merged to master. If you need it now, just get the code from the pull request and implement it yourself real quick, that should solve the problem: https://github.com/roots/sage/pull/1876/files

@rutger1140
Copy link

I can confirm it works smoothly with Bedrock and Valet 👌

QWp6t added a commit that referenced this issue Apr 14, 2017
* Resolves issue with WP only looking one-level deep for templates #1870
* get_template_dir() and related functions now point to sage/resources
* Use collect() when assembling views paths
QWp6t added a commit that referenced this issue Apr 14, 2017
* Resolves issue with WP only looking one-level deep for templates #1870
* get_template_dir() and related functions now point to sage/resources
* Use collect() when assembling views paths
* Update tree in README
QWp6t added a commit that referenced this issue Apr 14, 2017
* Resolves issue with WP only looking one-level deep for templates #1870
* get_template_dir() and related functions now point to sage/resources
* Use collect() when assembling views paths
* Update tree in README
QWp6t added a commit that referenced this issue Apr 14, 2017
* Resolves issue with WP only looking one-level deep for templates #1870
* get_template_dir() and related functions now point to sage/resources
* Use collect() when assembling views paths
* Update tree in README
QWp6t added a commit that referenced this issue Apr 16, 2017
* Resolves issue with WP only looking one-level deep for templates #1870
* get_template_dir() and related functions now point to sage/resources
* Use collect() when assembling views paths
* Update tree in README
@retlehs
Copy link
Member

retlehs commented Apr 16, 2017

fixed by #1877

@retlehs retlehs closed this as completed Apr 16, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants