From Twig call:

- Add inline_template function to support e.g. #post_render for render arrays with custom one-shot template.

Problem/Motivation

Drillability for Twig is important, but the scope was not clear and how to support #post_render / #theme_wrappers / drupal_render integration.

Proposed resolution

This issue frees drillability to only allow to drill-down by splitting the use case of supporting #post_render / #theme_wrappers and the rest of drupal_render into an inline_template twig tag, by replacing the actual engine render call with a method called on a twig template class.

'#render_function' => array($template, 'magicMethodName'),

Example:

{{ link }}

vs.

{% inline_template link %}
<a href="{{ attributes.href }}">{{ text }}</a>
{% endinline_template %}

Remaining tasks

* Move the #type specific things to a follow-up
** Create the follow-up and make clear what the problems are.

* Fix syntax and make it possible to specify an identifier and an expression, if the expression is a render array, hide and show will work (remove hard-coded "link")
** Like: {% inline_template "link" link %}
** Or like: {% inline_template "link" { '#type': 'link', '#href': 'node', '#title': 'hi' } %}

* Clean-up, docs and get this committed

Done tasks


* Create proof-of-concept by extending macros. This inline templates are added as macros, but internally use a different Twig_Node to call drupal_render instead.
* Extend theme() to allow setting the $render_function used to render the template within the "render variables".

User interface changes

* None.

API changes

* Adding of a new twig tag.

#2008450: Provide for a drillable variable structure in Twig templates

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Fabianx’s picture

Issue tags: +Twig, +theme system cleanup

Tagging

Fabianx’s picture

Status: Active » Needs review
FileSize
1.53 KB

And here is the first part of it:

* Added a key #render_function to support from theme().

That was surprisingly simple.

For non-theme drupal_render still needs a way to "get variable-like output" for things like #type => link.

Fabianx’s picture

And here is a first implementation that can be tested with the following drush script:

$link = array(
  '#type' => 'link',
  '#href' => 'node',
  '#title' => 'foo',
);

$twig = Drupal::service('twig');
$name = 'test-it.html.twig';

print $twig->loadTemplate($name)->render(array('link' => $link, 'foo' => 'wrong output' ));

test-it.html.twig:

{{ link['#href'] }}
{% inline_template link %}
<a href="{{ link.url }}">More text</a>
{% endinline_template %}

Note: The "link" prefix is hardcoded for now.

This really shows that there is a HUGE gap between #type and #theme.

Ideal would be if we could define a #theme => link that is purely internal to Drupal and neither allows theme_link nor templates however and can only be used for inline-templating, because #type obviously has no variables definition / idea at all ... So giving an example as link-type.html.twig.example would be nice.

But it works and is nearer to drillability than we ever have been before.

Status: Needs review » Needs work

The last submitted patch, core-2047263--proof-of-concept-3.diff, failed testing.

Fabianx’s picture

Uhhh, yes.

How to create 115k exceptions with one change :-D.

Put render to the right array ...

Fabianx’s picture

Status: Needs work » Needs review

.

thedavidmeister’s picture

Ideal would be if we could define a #theme => link that is purely internal to Drupal and neither allows theme_link nor templates however and can only be used for inline-templating, because #type obviously has no variables definition / idea at all ... So giving an example as link-type.html.twig.example would be nice.

I think if alters were used instead of the current #pre_render callbacks, and they were expected to build up a #variables array to be used for rendering elements, we wouldn't have such a problem as you could fire all the alters and then use #variables in the inline_template.

Fabianx’s picture

Status: Needs review » Needs work

OMG! I have made drillability for field possible with that for https://github.com/jenlampton/twigified!

( inlining what before was a suggestion for a field )

New plan for this issue:

* Move the #type specific things to a follow-up
** Create the follow-up and make clear what the problems are.

* Fix syntax and make it possible to specify an identifier and an expression, if the expression is a render array, hide and show will work (remove hard-coded "link")
** Like: {% inline_template "link" link %}
** Or like: {% inline_template "link" { '#type': 'link', '#href': 'node', '#title': 'hi' } %}

* Clean-up, docs and get this committed

thedavidmeister’s picture

Minor point, but calling it "#type specific" is a bit misleading as #type just sets defaults, which could be a #theme hook. #type in and of itself causes no problems for drillability or inline templates AFAICS.

The real problem is #pre_render callbacks that partially or completely render markup (usually into #markup) in a single step, with no separation of variable processing and rendering.

thedavidmeister’s picture

Issue summary: View changes

remaining tasks

jenlampton’s picture

Fabianx’s picture

Assigned: Fabianx » Unassigned

no time to finish currently.

Fabianx’s picture

Assigned: Unassigned » Fabianx

Its DrupalCon!

thedavidmeister’s picture

wow, spam. That's something I haven't seen in the issue queue before.

star-szr’s picture

Status: Needs work » Needs review
FileSize
6.33 KB

Rerolled and started to clean up with @Fabianx.

kostask’s picture

Patch to remove the hardcoded 'link' and make inline template work. With help from fabien

rteijeiro’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Core/Template/TwigInlineTemplateTokenParser.php
@@ -0,0 +1,85 @@
+        ¶

Please, remove trailing spaces ;)

rteijeiro’s picture

Issue summary: View changes

Update task to define some things from twig call

markhalliwell’s picture

Status: Needs work » Needs review
sun’s picture

jibran’s picture

Status: Needs review » Needs work

The last submitted patch, 16: core--inline-template--basic.diff, failed testing.

star-szr’s picture

To say the least, a few things have changed:

So I think this really needs an issue summary update to outline the plan here if any.

joelpittet’s picture

Status: Needs work » Closed (duplicate)

Closing this to cleanup the queue as a duplicate of macro, while not pretty you can build a macro to pass in a link renderable array or object and theme the properties.

Also, better name may be explode_template or expand_template. inline_template has so many other connotations.

Feel free to re-open if you have a burst of inspiration on this;)

Fabianx’s picture

Title: Provide inline_template tag within Twig » Provide inline_theme tag within Twig
Version: 8.0.x-dev » 8.1.x-dev
Status: Closed (duplicate) » Active

Re-opening for potential 8.1.x - no API change needed.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.0-beta1 was released on March 2, 2016, which means new developments and disruptive changes should now be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Wim Leers’s picture

It's not clear to me what we would gain from this. And to repeat @Cottser's crucial point in #22:

We now have an inline_template render element: https://www.drupal.org/node/2311123

Wim Leers’s picture

Status: Active » Closed (duplicate)

Furthermore, this would make Drupal's Twig templates less portable. Restoring the state of #23.

Fabianx’s picture

Status: Closed (duplicate) » Active

Nope, this is something different.

joelpittet’s picture

template_override maybe to avoid naming collision? @Fabianx

Fabianx’s picture

Title: Provide inline_theme tag within Twig » Provide inline_template_override tag within Twig

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Fabianx’s picture

I've worked out a plan:

- Copy the block tag node (Twig\Node\Twig_Block.php) to a different tag for the inner part
- Create a new node for the direct calling of the function
- Use a closure and pass the parent context as 'parent_context' variable.

Generated PHP code then looks something like:

$self = $this;
print $this->drupalExtension->inlineTemplateOverride($context['some_var'], function($variables) use ($context, $self) {
  $variables['parent_context'] = $context;
  ob_start();
  $self->inlineTemplate_[hash]($variables);
  return ob_end_clean();
}));

A different possibility would be to dynamically return the code of the template (similar to how the other #inline_template works), but that might have caching challenges as it already now is difficult to create all templates in advance.

Fabianx’s picture

Title: Provide inline_template_override tag within Twig » Provide inline_template tag within Twig that inlines a template for usage with a render array
Status: Active » Needs review
FileSize
7.68 KB

Here is a first patch that already works using code like this:

{% inline_template some_entity %}
  Label: {{ label }}
  User: {{ parent_context.some_entity.user }}
{% endinline_template %}

--

Still todo:

- Ensure that exceptions are showing the original source line (non-inlined)
- Ensure that we don't need to pin twig to 1.26.0
- Cleanup
- Tests

Status: Needs review » Needs work

The last submitted patch, 33: provide-2047263-33.patch, failed testing.

Fabianx’s picture

Status: Needs review » Needs work

The last submitted patch, 35: provide-2047263-35.patch, failed testing.

Fabianx’s picture

Status: Needs work » Needs review
RainbowArray’s picture

Did a brief test of this, and it did exactly what I hoped. On the basic page content type, I created a text field named awesome. Then, within the node template, I did the following:

    {% inline_template content.field_awesome %}
      {{ dump() }}
    {% endinline_template %}

That allows me to see the fully preprocess render array for field_awesome, which was previously impossible. Within the inline template, you can now do something like {{ items.0 }} or loop over items. This would allow for full customization of the markup for a child render array, which is hugely useful for component-based theming.

In short, at first glance, this looks fantastic.

cosmicdreams’s picture

In what way is this syntax compatible with Twig's include / with / only syntax? In the above syntax the with / only directives are not used.

Fabianx’s picture

Issue summary: View changes

#39: This issue still needs an IS update, I don't think with and only give much value here, when the full parent context is available as 'parent_context'.

Fabianx’s picture

I am thinking about this some more and there is 2 different things:

One: Being able to include an inline template like possible in render arrays:

e.g.

{% include inline_template('{{ label }}') %}

but that is less useful obviously without a different scope.

99% can be done without needing extends or whatever, so:

{% inline_template field_awesome %}
  Label: {{ label }}
{% endinline_template %}

can be implemented purely with blocks.

And if you really need a new template, you can use:

{% inline_template field_awesome %}
{% filter render_inline_template %}{% verbatim %}
  {% extends 'foo.html.twig' %}
  {% block label %}
  Label: {{ label }}
  {% endblock %}
{%endfilter}{% endverbatim %}
{% endinline_template %}

As that is only for advanced use cases AND the 1-2% case, I feel it is okay to have more verbose syntax for that case.

And more than one verbatim is not supported, period.

For the 99% case the generated PHP code looks like:

function block___internal_[hash]($context, $blocks = array) {
  echo "Label: ";
  echo isset($context['label']) ? $context['label'] : '';
}

For the 1% case the generated PHP code looks something like:

function block___internal_[hash]($context, $blocks = array) {
  echo $this->env->renderInlineTemplate('Label: {{ label }}', $context);
}

The advantage is that the inline_template tag can be a _simple_ callback and advanced functionality is added via composition and not via hacks.

We also no longer need getSource() access then and performance increases slightly.

In the theory case we ever want to support more than one verbatim, we can have the inner verbatims be called verbatim_1, verbatim_2 and replace them per nesting level we are on ... But that can be a follow-up - if ever needed.

So likely good to have parent_context, but also inline_template_level == 1,2,3,4, ...

---

So a full win.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

markhalliwell’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

MerryHamster’s picture

MerryHamster’s picture

Assigned: Fabianx » Unassigned
Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 47: 2047263-47.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

andypost’s picture

Issue tags: -Needs reroll

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.