framework
framework copied to clipboard
@template directive unexpected behaviour
- Themosis Version: 2.0.5
- WordPress Version: 5.5.1 (irrelevant)
- PHP Version: 7.2.32
Description
The documentation and the PHPDoc examples suggest that @template
directive can be efficiently used to include different variants of other views using a syntax of @template('parts.content', get_post_type())
, however this is misleading in a sense due to the way blade templates are compiled and cached.
Steps to reproduce
- Create a template and use
@template('parts.content', get_post_type())
in it. - Create two views as suggested by the documentation:
parts.content-page
andparts.content-post
. - Flush the blade cache under
storage/framework/views/blade
. - Open a Page, and see the Page rendered using
parts.content-page
. - Open a Post, and see the Post rendered using
parts.content-page
as well. - Flush the blade cache under
storage/framework/views/blade
. - Open a Post, and see the Post rendered using
parts.content-post
. - Open a Page, and see the Page rendered using
parts.content-post
as well.
Expected behavior
- Opening a Post, should cause the Post to be rendered using
parts.content-post
. - Opening a Page, should cause the Post to be rendered using
parts.content-page
.
Additional details
The issue is that when the main template is compiled the actual value of get_post_type()
gets hard coded into the cached php file under storage/framework/views/blade
. So if the first opened resource was a Page, the compiled template will look for parts.content-page
until the cache is flushed.
The issue is two-fold:
- The documentation suggests that using
get_post_type()
makes the inclusion of the parts dynamic, comparable to WordPressget_template_part()
, howeverget_template_part( 'example', get_post_type() )
evaluatesget_post_type()
every time as opposed to@template
. - The actual code of
@template
deliberately calls the function passed as the second argument and compiles the template using the return value, instead of compiling it in a way that would keep the second argument as a function call to be reevaluated on every render.
A fix can be achieved by replacing this line with:
$args[1] = "'.{$args[1]}().'";
This achieves that the compiled blade template would always call the second argument, if that is a function, instead of calling it once and reusing the return value for all future renders.
Let me know if you'd like a PR for that.