Background
In https://www.lullabot.com/articles/level-your-twiggery, @hawkeye.twolf laid out a method for creating an |as()
twig filter that "adds template suggestions to a render array"
With this, the Twig code for wrapping the body
field in a <details>
element can be shortened to just {{ content.body|as('details') }}
, along with a new template, field--details.html.twig
, that adds the <details>
markup. “How is this different/better” you might be asking “than just using the standard field-name template suggestion, field--node--body--article
?” Three main reasons:
- Naming the template in a generic way leaves it available for use by other fields. If you have another field that needs the same customization, you no longer have to resort to various forms of chicanery, like copy/pasting the original template into an exact but renamed duplicate, Twig
extends
ing an otherwise-unrelated file, or symlinking one template to another. - For experienced Drupal developers, the idea of template suggestions and their naming scheme might seem obvious. But to an outsider reviewing the Article’s node template, the source of the
<details>
wrapper around the body field may prove arcane. The addition of|as('details')
makes the code more readable and adds semantic meaning to the source. - Keeps front-end logic in the front-end. Normally, you would implement
hook_theme_suggestions_alter()
in a theme or module file to make unrelated fields use the same template. While there’s nothing wrong with this approach, it creates a dependency on PHP skills for any developer wishing to work on the front-end. The|as
filter allows front-end developers to stay out of the PHP if they want to.
Task
I'd like to move this filter into Drupal core!
Discussion
I've discussed this with the @lauriii. He seemed excited about getting this in, and doesn't anticipate this being unrealistic for Drupal 10. I've also talked to @hawkeye.twolf, who said he has some updated code samples and seems willing to help!
Lets do this! ⚡️
Release highlight
New Twig |add_suggestion
filter for adding a theme suggestion without having to write PHP. See https://www.drupal.org/node/3301862 for details.
Comment | File | Size | Author |
---|---|---|---|
#21 | mikes-as-test.txt | 11.7 KB | mherchel |
Issue fork drupal-3301373
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
mherchelComment #4
mherchelCrediting @hawkeye.twolf
Comment #5
hawkeye.twolfComment #6
hawkeye.twolfInitial implementation pushed to the fork. Needs tests.
Comment #9
lauriiiComment #10
hawkeye.twolfWhat do you think about adding a second parameter to inject a class to the attributes? I find that’s often needed in order to easily make use of the template suggestion. I.e., I want something to display with the markup and a component-specific class, like this:
In this example, the list template can be more easily reused because we get both the list markup and a class to adjust styling for the specific placement.
Do you think this is something desirable and worth trying to add it in still?
Comment #11
mherchel➕💯 to this!
It's good that you've actually used this before. It totally makes sense that you'd want to inject one or more classes.
Comment #12
mherchelCreated followup #3301853: Create twig filters: |add_class and |set_attribute to address the option of passing down a CSS class.
Comment #13
mherchelSetting to needs work because tests are failing.
Comment #14
lauriiiFixed the failing test
Comment #15
lauriiiChange record exists
Comment #16
ckrinaJust jumping here to mention that this was implemented on a client project we're working on right now with @hawkeye.twolf and it really helped reducing the number of templates needed. Although the most important benefit for me is that it keeps as much logic as possible in the component itself.
Comment #17
mherchelNote that this issue is affected by #2118743: Twig debug output does not display all suggestions when an array of theme hooks is passed to #theme, which causes the template suggestions to not output to HTML comments when Twig debug is enabled.
Comment #18
hudriI'd like to add another point why this is a great idea:
In our case we have one common override template for a certain number of fields. This template could not be distinguished by common template suggestions based on entity type, bundle or field name. So this led to a weird situation where we had one
shared_special_field_template.html.twig
containing the actual templateand about 30-40
field--node--FIELDNAME--BUNDLE.html.twig
templates containing onlyWith the proposed
|as
filter we could have used the node template and spared all the dummy extend templates.Comment #19
mherchelUnfortunately, something's broken. I can reproduce a WSOD with the error message below if the field that has an
|as
filter is not in the{{ content }}
Steps to reproduce
field_details
node--article.html.twig
(note this will apply to all view modes){{ content.field_details|as('test') }}
Error
Comment #20
hawkeye.twolfThank you for catching that, @mherchel! I was being overly strict in the function declaration. I've pushed a change to allow NULL values, so missing content should no longer throw an error. I also added test coverage for the fix. Please re-test with your example when you get a chance, thank you!
Comment #21
mherchelThis is sooo awesome!
Marking this as RTBC! I found a couple interesting notes, but after talking to Hawkeye, we think they're OK.
Things to note
{{ content.field_myfield|as('Mike-Herchel') }}
, it will NOT load afield--mike-herchel.html.twig
file{{ content.field_myfield|as('mike-herchel') }}
will NOT load afield--myfield--mike-herchel.html.twig
.field_test
and I passed in atest
argument like{{ content.field_test|as('test') }}
. It loaded up thefield–field_test.html.twig
file (note the underscores) that I had created.Things I tested
{{ content.field_test|as('not-here') }}
{{ content.field_test|as('mike-herchel') }}
this loads the field--mike-herchel.html.twig file{{ content.field_test|as('mike_herchel') }}
this loads the field--mike-herchel.html.twig file{{ content.field_test|render|as('xx') }}
Things I did not test
I didn’t test entities besides nodes.
Note that I'm attaching a patch with a number of test cases and templates in case myself or someone else wants to do more manual testing.
Comment #22
alexpott@lauriii asked me to have a look at this issue.
This is a really neat idea. I like how it puts the themer in more control and makes certain theming task less complex and easier to learn and do.
The current MR has really nice test coverage of all the logic in the function. Nice.
I chatted to @lauriii about the semantic-ness of
as
as a filter name. We agreed that this is really nice for someone that does not know much about how Drupal themes work. But, on the other hand, it does not help them really understand what is going on under-the-hood. One option would be to alias theas
filter toaddSuggestion
so then we can be semantic for people who do have this type of knowledge of the theme system. I would also suggest renaming the function to addThemeSuggestion() as that is what it is doing.The only awkwardness I see in the current patch is were you have multiple theme suggestions... in the test case we have:
This seems quite tricky if
kitten__stripy__cute
does not exist butkitten__cute
andkitten__stripy
do. I’m not sure what I’d expect to happen. One on hand, I can imagine being given a task to add stripy kitten template to a theme which haskitten
andkitten__cute
templates already and so I’d add akitten__stripy
template and then be surprised when it doesn’t work everywhere. But, as @lauriii pointed out to me, he expect that if I have called|as('cute')
in a template that I wouldn’t accidentally override that by adding a theme suggestion forstripy
.I think this could be mitigated completely if we only added a single theme suggestion based on the base theme hook. (@lauriii thinks this might be quite hard to do). Then again, maybe this append to everything is quite powerful.
Also one fun thing is that filters can be chained...
field|as(‘details’)|as(‘more_details’)
- I'm also not sure how I feel about this especially in light of the append this to every suggestion appraoch.Comment #23
mherchelI'm not opposed to renaming the filter to
addSuggestion
. You're right that it gives people a helpful gleam of what's happening under the hood. That might cause them to think, "Huh... I wonder if there's other ways to add suggestions?" It would also help with the search-ability of the term when people are looking for support via Google, et al.Comment #24
alexpott@mherchel my suggestion is that both
|as
and|addSuggestion
work.Comment #25
mherchelOne of the concerns that I have about having two filters (or whatever) doing the same thing is that it can be confusing to a newbie developer
Their (potential) thoughts:
There's also the "searchability" issue. If someone is searching for the
|as
filter, they won't find stack overflow answers that include the| addSuggestion
filter.IMHO, we should only have one name for this filter.
Comment #26
mherchelDiscussed this in person at DrupalCon Prague with @andy_blum, @ckrina, @alexpott.
We came to the conclusion to use
add_suggestion
only, as this gives insight to front-end developers on what his happening under the hood. We don't want to "muddy the waters" with an alias of this suggestion just yet.Comment #27
mherchelSetting this back to Needs Work. We need to rename the filter.
Comment #28
hawkeye.twolfFilter renamed from
|as
to|add_suggestion
. Thanks @mherchel @andy_blum @ckrina and @alexpott!@alexpott, thank you for bringing up the concerns about adding the suggestion to every theme hook, very happy to have additional input! Here's some context from Slack where Lauri and I discussed this question and ended up going with "add to every suggestion". Please let me know if you have additional thoughts or if you end up agreeing with the current approach so we can mark this issue back to RTBC. Thank you! 🙏🏻
Comment #29
mherchelChanges look good. Gave it a run-through again, and it works as expected. Thanks @hawkeye.twolf!
Comment #30
alexpottOnce the CR https://www.drupal.org/node/3301862 is updated for the new name and has something about #28 then I think we're good to go. It's important the CR documents how it affects all existing theme suggestions and talks about the precedence stuff.
Comment #31
alexpottDiscussed with @lauriii and we agreed that as a pure addition this can go into 10.0.0 and be there from the beginning of Drupal 10.
Can someone add a release notes section?
Committed and pushed d985697c26 to 10.1.x and 75f7ef8b29 to 10.0.x. Thanks!
Comment #34
lauriii