Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
Let's make a field template and access some date from the entity:
datetime = element['#object'].getCreatedTime|format_date('html_datetime')
That's less than ideal.
Proposed resolution
Provide at least entity
by adding it in template_preprocess_field
$variables['entity'] = $element['#object'];
Remaining tasks
User interface changes
API changes
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#22 | test_accessing_the_original-2761525-22.patch | 12.59 KB | mmbk |
#19 | test_accessing_the_original-2761525-19.patch | 3.45 KB | mmbk |
#9 | accessing_the_original-2761525-9.patch | 9.14 KB | kikoalonsob |
#5 | accessing_the_original-2761525-5.patch | 607 bytes | morsok |
Comments
Comment #2
dawehnerComment #3
dawehnerComment #4
JacineThis would be nice.
A little consistency in the variables available goes a very long way for us. This is especially true because debugging in templates right now is a nightmare, so every little improvement helps.
Comment #5
morsokYeah I think that help ease the pain for themers.
Here's a patch.
Comment #7
joelpittetThis seems to be a nice idea to give access to the template for other fields.
Comment #8
alexpottLet's add tests for this then.
Comment #9
kikoalonsob CreditAttribution: kikoalonsob as a volunteer commentedHere is a more complete patch which alter some field templates too.
How can I add a test for this patch now? It will be my first test so...help is welcome!
Comment #10
OwilliwODon't forget to mark the issue as «needs review» to process tests.
Comment #11
OwilliwOComment #12
Ashley George CreditAttribution: Ashley George at Investis Digital commentedOn my local 8.3.x, I have applied the patch in #9.
In a field.html.twig, I included 'dump(entity)'.
Output of the object was printed to the screen, when viewing a node with fields.
I conclude this is working correctly.
Comment #13
Ashley George CreditAttribution: Ashley George at Investis Digital commentedComment #14
alexpottWe still should have a test for this.
Comment #15
kikoalonsob CreditAttribution: kikoalonsob as a volunteer commentedHow can I test that a variable is available in a template?
Comment #16
joelpittet@kikoalonsob, you can create or mock an node and print it's label with
{{ entity.label }}
in a field template as a possible test and assert the node title is displayed in that field. There are a bunch of examples of this in the existing tests to copy from.Comment #18
nesta_ CreditAttribution: nesta_ at La Drupalera by Emergya commentedadd tag DevDaysSeville
Comment #19
mmbkWith a little help of @webflo : implemented a test for this function
Comment #20
mmbkComment #22
mmbkComment #23
dawehnerComment #25
joelpittetStill applies, seems reasonable to want access to the entity, has tests. I'd RTBC it but there are a few comments needed on the other field templates.
To help find them use these:
Comment #26
derheap CreditAttribution: derheap as a volunteer commentedComment #27
derheap CreditAttribution: derheap as a volunteer commentedI used the find commands and checked the field templates.
Only 2 have no comments:
Test does not need a comment.
The other templates extends the original field.html.twig, so also no comment is needed.
The others are ok:
Comment #28
derheap CreditAttribution: derheap as a volunteer commentedThere are no additional comments necessary.
I talked about it with joelpittet, he agreed to RTBC is. So I put it do RTBC.
Comment #29
derheap CreditAttribution: derheap as a volunteer commentedComment #30
joelpittetThanks for double checking
field--text.html.twig
, I didn't realize they were extending.Comment #31
Wim LeersI see why it can be valuable in some cases. But at the same time, this moves us further away from having simple templates with just the data it needs injected. This patch explicitly adds the ability to easily get data not from the current level, but from the parent level.
If we decide we want this, ok, but we should be conscious about that.
Comment #32
dawehnerWell, in general I believe there will be always some tradeoff between real life usecases and simpleness. If field templates want the full entity they should be able in the theoretical future where they can specify their data dependencies. In that case do we really loose anything, by adding support already?
Comment #33
Wim LeersI agree with you. In the current state of things, this probably makes sense. I just want us to realize there are indirect consequences too, that is all.
Comment #34
catchTagging for a front-end committer to review.
Comment #35
xjmHmm. I kind of feel like accessing the original entity in field templates should be hard, to avoid having business logic in templates?
Edit: I guess this is what #31 is getting at also.
But I'm kind of -1 to this change also.
Comment #36
dawehnerCan I ask the question where business logic actually belongs?
I think this all comes down to the fact that entity/field templates aren't the actual right level of rendering. You want to build components to render stuff and just somehow pass along data to your domain specific component templates. For me at least, if field templates are the place you need to call out to those component templates, using the entity might be needed in that place.
Comment #37
JacineIt seems like these discussion always come back to ease of access to context, which is very important in practice, but is sometimes discounted or overlooked in these discussions. I think the business logic argument is misapplied here. There is *always* going to be a need to derive context and act/theme/style accordingly. If we want to remove the process layer, which is a stated goal in #2702061: Unify & simplify render & theme system: component-based rendering (enables pattern library, style guides, interface previews, client-side re-rendering), I think we need to accept that context is needed, and make it a priority when considering changes.
Here are some real examples of where accessing the parent/child entity has been needed (not all are for fields but the general idea is the same):
Nested Entities Galore
We're dealing with more entity references than ever before, which makes theming harder. What you want to change may require going through 4-6 layers of templates. This is why people are fond of modules like Twig Field Value. Most people don't want to go through all that just to print a field value, and you can't really blame them. Kint and friends are not helpful here, so unless you are very patient and willing to sit there taking shots in the dark for hours (like me), you need to know the magic methods to get anything useful, in a debugger. Most people are sane, and just bypass this all completely, because it's VERY time consuming. And if you question the 4-6 levels of templates, let me give an example of one I'm working on as we speak:
node.html.twig
field--node--field-hero.html.twig
orfield--entity-reference-revisions.html.twig
paragraph--hero.html.twig
field--paragraph--field-video--hero.html.twig
media--youtube.html.twig
*field--media--field-video-url--youtube.html.twig
*container--video-embed-iframe--youtube.html.twig
**video-embed-iframe--youtube.html.twig
**These suggestions need to be customized, they're not specific enough. The Hero context needs to be explicit. Why? Because in the Hero context the video autoplays like a background image via the YouTube API, and in other places, it just needs to be a standard video embed.
**This suggestion has already been customized. However, no other information is available to the the container, so I cannot complete this task without devoting more trial and error time to it, or without backend help. Sigh.
Context of Parent entity, or Field value on Parent Entity
In the same Hero component (paragraph entity), the design calls for using the parent node title in some cases (specifically, the articles vs landing pages). Paragraphs provides access to the parent entity, so the code was simply:
Different Component Templates/Attributes/etc based on Parent/Child
Back to the hero again, some have video media entities attached, others have images. In this case, you nay need to access the parent and the child entities to achieve designs. For example, if the child entity is a video media entity it might need different classes, and/or component template than an image.
Wrapping a Field in a Link to the Parent
Sometimes you just need to wrap an entity reference field in a link to parent entity, INSIDE the field wrapper, not outside. You might say this is the job for a formatter, but I disagree. Formatters only further increase the business logic in templates, because as the template author you've no control over what data structure might be sent to the template, due to options in the UI. They also come with complex caching challenges. A great example of potentially different data structures is a date field. It can be a timestamp, themed via #time, or just #markup. Fatal errors for trying to manipulate what is expected to be a timestamp, but isn't because someone changed the formatter is always fun.
Providing a proper HTML structure
Given a
field_heading
on a Paragraph entity, need to find the depth to give an accurate HTML/outline heading level, e.g.Bingo!
Exactly. I think most people would rather not get down to field templates for theming. We have a responsibility as coders to at least attempt to make our code as simple and readable as possible, but spreading everything out across soooo many templates, is counter to that goal. However, it's not escapable, so for me, it really depends on what kind of field it is. When I can, I do try to do as much as possibly globally for fields, e.g.
field--field-type.html.twig
. That way when I'm working in a parent entity, I can just print, or send it off to a component template as is, because that's easy to read/maintain, etc. However, that doesn't always make sense, and when I do need to get into a field template, I'd agree that accessing parent entity needs to be possible/easy. My point in mentioning this is the Context drives all of this, and context is often really hard. We should try to make it easier instead of harder. Saying this isn't needed to someone working with Drupal templates is sort of like saying you should not be able to have different labels and field settings for a given field that is shared across bundles of the same entity to a backend developer.This ended up being a much longer reply than I anticipated, and I assure you the tone of it is not snarky or anything. I'm just trying to provide some insight into the day-to-day challenges in hopes that we can all just accept that we need context AND business logic, and factor that into the solutions being developed.
And Ultimately, I think the Paragraphs solution, of being able to use
getParentEntity()
is the best one, so if we can do something like that, it'd probably be better.Comment #38
xjmThanks @Jacine, all that context (pun!) is really helpful for understanding this issue.
Comment #39
JacineSure! I'm really glad it's helpful... :o)
Comment #40
star-szrStopping in to weigh in as one of the frontend framework managers:
IMO lack of context is (still) one of the biggest pain points in Drupal theming and something that people run into almost daily. I'm in favour of this change. At a glance, the patch looks reasonable and straightforward but I can't review or test it thoroughly at the moment.
Special thanks to @Jacine for the write up in #37.
Sidenote: I can't find the issue, but at one point during the D8 cycle theme system maintainers had discussed adding a separate $context alongside $variables so that stuff like this could be referenced in preprocess/templates to know where the hell you are in the nesting dolls.
Comment #41
xjm@Cottser, @effulgentsia, and I discussed this issue today and came up with a couple recommendations:
context
array in the variables. Using that pattern will help themers distinguish between information that's part of the current template, and information about what context the template is in to theme it based on that context.core/modules/node/templates/node.html.twig
has some detailed documentation explaining what is and isn't available to do with the node entity there. We should provide similar docs in the field template about the field entity.The patch is failing on a test that was broken in HEAD recently; it looks like it's not getting retested. But since we're updating the patch anyway that is fine.
Thanks everyone for working on this, and for explaining why it's needed.
Comment #43
xjmAdding credit.
Comment #44
xjmOther reviewer credits.
Comment #55
phpsubbarao CreditAttribution: phpsubbarao as a volunteer and at ITT Digital commented{{ element['#object'].getCreatedTime | date('F j, Y') }}
Worked for me.