This issue has gone back-and-forth a few times. Originally, the intent was to allow usage of theme() in templates as opposed to using Twig 'include' directives. However, usage of theme() in a template is an anti-pattern since markup should be pre-generated or a subset of the parent template.

Usage of theme() in templates in core was found to be only 3 instances, in tables and for filter-tips. These instances seemed trivial enough such that the instances could be refactored.

Currently, removal of theme() in the table template is being handled in #1778968: Convert theme_table to Twig, so resulting patches here will likely result in just attending to filter-tips. We may retitle the issue to reflect such.

Original issue summary, wishing to have theme() available in templates

Originally, we had decided to use {% include %} statements for including one template file from within another, but this posed two problems:

1) the path to the include file must be literal. This defeats the purpose of overrides and the theme registry.

2) We were unsure whether to preprocess before including the referenced file.

Instead, we have decided to leave the {% include %} statements as originally intended for twig. when we need to include something literal, without preprocessing, we can. If we need to preprocess variables for that template, we will have to do it ourselves.

We also decided to add the use of theme() from within twig templates. Here, we can call theme functions (that will run preprocess automatically, and respect overrides) directly from within a template.

Comments

jenlampton’s picture

fabianx’s picture

Assigned: Unassigned » fabianx
Status: Closed (duplicate) » Active

No, this is different.

fabianx’s picture

diff --git a/core/lib/Drupal/Core/Template/TwigFactory.php b/core/lib/Drupal/Core/Template/TwigFactory.php
index ef1a40d..91dd369 100644
--- a/core/lib/Drupal/Core/Template/TwigFactory.php
+++ b/core/lib/Drupal/Core/Template/TwigFactory.php
@@ -93,6 +96,7 @@ public static function get() {
 
     // @todo Remove URL function once http://drupal.org/node/1778610 is resolved.
     $twig->addFunction('url', new \Twig_Function_Function('url'));
+    $twig->addFunction('theme', new \Twig_Function_Function('theme'));
     return $twig;
   }
 }

Please apply to front-end.

japerry’s picture

Status: Active » Fixed

Applied to frontend branch

11555f703d690a5b0f3975a7eb7e31fc23da5a4a

c4rl’s picture

Some questions and concerns here. I believe from conversations in IRC earlier this week, we decided that everything sent to a Twig template would be renderable and that Twig template variables should know how to render themselves. Therefore, variable addressability in Twig, by definition, means that it should be renderable, and it is up to the render array to define this structure in an extensible and flexible way.

So, instead of calling theme('node', $node) from Twig, we'd simply be able to do {{ node }} and it would understand. It was via this principle where I started doing some tinkering around here https://gist.github.com/4061841 as a conceptual demo.

Can someone provide some insight here as to why theme function calls should be available via Twig as opposed to having Twig template variables understand their inherent printing method?

fabianx’s picture

This is needed to include another template of your own choice, while calling suggestions, etc. without being dependent that preprocess set things up correctly in a render array.

It completes that {% include is not calling suggestions, pre-process, etc, but rather hard-codes the template to be used.

jenlampton’s picture

@C4rl It would be nice if we could make theme('table') unnecessary from within twig templates, and instead be able to print {{ table }}, but as it is now {{ table }} doesn't exist as a variable for that template, only $header and $rows. Plus, tables are not yet renderable objects. We need to add theme so that our template files can be cleaner and continue working, right now. Plus, it will allow front-end devs to render one template easily within another, even if the module devs didn't prepare renderable objects for the appropriate template file beforehand.

We can, of course, revisit this later after we have all the renderable objects we need. For now this is a great solution. Thanks @FabianX!

I've opened #1848116: Revise usage of {% include %} as a follow-up.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

steveoliver’s picture

Project: » Drupal core
Version: » 8.x-dev
Component: Twig engine (twig_engine branch) » theme system
Assigned: fabianx » steveoliver
Status: Closed (fixed) » Active
StatusFileSize
new551 bytes

Moving this to the core queue from Twig sandbox. Attached patch allows use of theme() within Twig templates.

steveoliver’s picture

Status: Active » Needs review
fabianx’s picture

Title: allow the use of theme() from within templates » Twig: Allow the use of theme() from within templates
Status: Needs review » Needs work
Issue tags: +Twig, +Twig engine

Thanks, steveoliver.

According to the prototype of theme we don't need the arguments by reference, such we can and probably should use:

new \Twig_Function_Function('theme')

steveoliver’s picture

Status: Needs work » Needs review
StatusFileSize
new731 bytes

as per #11

c4rl’s picture

Status: Needs review » Needs work

As expressed in November, I still think this is a bad idea. theme() functions are just (poor) abstractions of nested renderables. A grep for this usage yields the following 3 calls:

./core/themes/stark/templates/filter/filter-guidelines.html.twig:  {{ theme('filter-tips') }}
./core/themes/stark/templates/theme.inc/table.html.twig:        {{ theme('table_cell', cell) }} {# Note: <th> returned by table_cell. #}
./core/themes/stark/templates/theme.inc/table.html.twig:          {{ theme('table_cell', cell) }} {# Note: <td> returned by table_cell. #}

These are minimal, and I think can be removed. Does it seem logical that we can change this issue to simply eliminate the use of theme() in Twig templates and refactor the above instances? What do you guys think?

steveoliver’s picture

This rides the line of where our theme "system" calls something done, vs. done-done*. ;)

I agree, c4rl, we should be done-done by now (within a template).

I see the theme layer(s) as this

1. Theme data (PHP data objects) - theme()
2. Theme object (Twig renderables) - [pre]process()
3. Theme output (HTML markup) - templates

I agree, let's not call theme() in templates.

We really do need these lines drawn. I think c4rl you've got just the right vision on this. I'm in 'just effin' make it work' mode. :)

steveoliver’s picture

*Thanks, sdboyer :)

steveoliver’s picture

Title: Twig: Allow the use of theme() from within templates » Twig: Do not call theme() from within templates
Project: Drupal core »
Version: 8.x-dev »
Component: theme system » Twig engine (twig_engine branch)

Moving this back to the sandbox, where we've been calling theme() within templates, but should stop. :)

steveoliver’s picture

c4rl’s picture

I updated the issue summary here.

steveoliver’s picture

Since we are allowing theme() in templates for the time being, I've fixed various fatal errors related to += / array_merge issues by registering the theme() function as a \Twig_Function_Function rather than a TwigReferenceFunction in git commit 249490c.

c4rl’s picture

Title: Twig: Do not call theme() from within templates » Consider appropriate usage of theme() from within Twig templates
Status: Active » Postponed

Better title. Let's postpone this for now given that we have some disagreement?

fabianx’s picture

c4rl’s picture

Status: Postponed » Fixed

I've updated #1905694: Introduce theme_to_render helper function to reflect that instead of using theme() calls at all, we should use render arrays:


$vars['foo'] = theme('bar', array('baz' => $node));

becomes


$vars['foo'] = array(
  '#theme' => 'bar',
  '#baz' => $node,
);

Marking this one as fixed.

Automatically closed -- issue fixed for 2 weeks with no activity.

Anonymous’s picture

Issue summary: View changes

Updated issue summary to indicate our new direction with this issue.

Project: » Lost & found issues

This issue’s project has disappeared. Most likely, it was a sandbox project, which can be deleted by its maintainer. See the Lost & found issues project page for more details. (The missing project ID was 1750250)