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.
Related Issues
#2008450: Provide for a drillable variable structure in Twig templates
Comment | File | Size | Author |
---|---|---|---|
#47 | 2047263-47.patch | 5.71 KB | MerryHamster |
#16 | foo.html_.twig_.txt | 207 bytes | kostask |
#16 | t.php_.txt | 346 bytes | kostask |
#15 | 2047263-15.patch | 6.33 KB | star-szr |
#5 | core-2047263--proof-of-concept-5.diff | 8.73 KB | Fabianx |
Comments
Comment #1
Fabianx CreditAttribution: Fabianx commentedTagging
Comment #2
Fabianx CreditAttribution: Fabianx commentedAnd 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.
Comment #3
Fabianx CreditAttribution: Fabianx commentedAnd here is a first implementation that can be tested with the following drush script:
test-it.html.twig:
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.
Comment #5
Fabianx CreditAttribution: Fabianx commentedUhhh, yes.
How to create 115k exceptions with one change :-D.
Put render to the right array ...
Comment #6
Fabianx CreditAttribution: Fabianx commented.
Comment #7
thedavidmeister CreditAttribution: thedavidmeister commentedI 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.
Comment #8
Fabianx CreditAttribution: Fabianx commentedOMG! 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
Comment #9
thedavidmeister CreditAttribution: thedavidmeister commentedMinor 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.
Comment #9.0
thedavidmeister CreditAttribution: thedavidmeister commentedremaining tasks
Comment #10
jenlamptonSee #2009132: Remove #pre_render and #post_render from drupal_render() as it prevents proper Twig drillability
Comment #11
Fabianx CreditAttribution: Fabianx commentedno time to finish currently.
Comment #12
Fabianx CreditAttribution: Fabianx commentedIts DrupalCon!
Comment #14
thedavidmeister CreditAttribution: thedavidmeister commentedwow, spam. That's something I haven't seen in the issue queue before.
Comment #15
star-szrRerolled and started to clean up with @Fabianx.
Comment #16
kostask CreditAttribution: kostask commentedPatch to remove the hardcoded 'link' and make inline template work. With help from fabien
Comment #17
rteijeiro CreditAttribution: rteijeiro commentedPlease, remove trailing spaces ;)
Comment #17.0
rteijeiro CreditAttribution: rteijeiro commentedUpdate task to define some things from twig call
Comment #18
markhalliwell16: core--inline-template--basic.diff queued for re-testing.
Comment #19
sunComment #20
jibran16: core--inline-template--basic.diff queued for re-testing.
Comment #22
star-szrTo 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.
Comment #23
joelpittetClosing 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;)
Comment #24
Fabianx CreditAttribution: Fabianx as a volunteer commentedRe-opening for potential 8.1.x - no API change needed.
Comment #26
Wim LeersIt's not clear to me what we would gain from this. And to repeat @Cottser's crucial point in #22:
Comment #27
Wim LeersFurthermore, this would make Drupal's Twig templates less portable. Restoring the state of #23.
Comment #28
Fabianx CreditAttribution: Fabianx as a volunteer commentedNope, this is something different.
Comment #29
joelpittettemplate_override
maybe to avoid naming collision? @FabianxComment #30
Fabianx CreditAttribution: Fabianx as a volunteer commentedComment #32
Fabianx CreditAttribution: Fabianx as a volunteer commentedI'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:
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.
Comment #33
Fabianx CreditAttribution: Fabianx as a volunteer commentedHere is a first patch that already works using code like this:
--
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
Comment #35
Fabianx CreditAttribution: Fabianx as a volunteer commentedComment #37
Fabianx CreditAttribution: Fabianx as a volunteer commentedComment #38
RainbowArrayDid 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:
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.
Comment #39
cosmicdreams CreditAttribution: cosmicdreams at ICF commentedIn what way is this syntax compatible with Twig's include / with / only syntax? In the above syntax the with / only directives are not used.
Comment #40
Fabianx CreditAttribution: Fabianx as a volunteer commented#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'.
Comment #41
Fabianx CreditAttribution: Fabianx as a volunteer commentedI 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.
but that is less useful obviously without a different scope.
99% can be done without needing extends or whatever, so:
can be implemented purely with blocks.
And if you really need a new template, you can use:
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:
For the 1% case the generated PHP code looks something like:
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.
Comment #45
markhalliwellComment #47
MerryHamster CreditAttribution: MerryHamster at Skilld for Skilld commentedReroll for 8.7.x
Comment #48
MerryHamster CreditAttribution: MerryHamster at Skilld for Skilld commentedComment #50
andypost