framework icon indicating copy to clipboard operation
framework copied to clipboard

@template directive unexpected behaviour

Open BenceSzalai opened this issue 3 years ago • 1 comments

  • 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 and parts.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 WordPress get_template_part(), however get_template_part( 'example', get_post_type() ) evaluates get_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.

BenceSzalai avatar Oct 25 '20 18:10 BenceSzalai

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.

BenceSzalai avatar Oct 25 '20 18:10 BenceSzalai