Postponed on #3159050: Allow deprecating theme suggestions

Problem/Motivation

Currently, core has 4 theme hook suggestions for the "field" theme hook:

field--[field-type].tpl.php
field--[field-name].tpl.php
field--[bundle].tpl.php 
field--[field-name]--[bundle].tpl.php

Note: that the field name is prefixed with the name of the module providing the field, which usally means “field-” is prefixed to the field name. Also, note that the "bundle" is a sub-type of an entity, e.g. “content types” are bundles since an "article" is a bundle of the node entity.

The theme hook suggestions are supposed to be in order of specificity. With least specific suggestions appearing first in the list. Suggestions at the end of the list override suggestions earlier in the list.

Unfortunately, the field--[field-name].tpl.php and field--[bundle].tpl.php suggestions are in the wrong order. A specific field should take precedence over "any field attached to this bundle". A fix for this should be backported to D7.

We also have a namespacing issue. If the same name is used for the bundle name or the field name or the field type, it can cause unintended issues. For example, if a user creates an "image" content type there will be a namespace collision with any fields that are the "image" field type; field--[field-type] and field--[bundle] would both be field--image. If a themer wanted to use a theme hook suggestion for all image-type fields (perfectly reasonable!), they would also accidentally trigger the bundle-based suggestion on all fields attached to the image content type (perfectly horrible!)

Proposed resolution

Fix the order of specificity for theme hook suggestions, namely:

field--[field-type].tpl.php
field--[bundle].tpl.php 
field--[field-name].tpl.php
field--[field-name]--[bundle].tpl.php

Come up with a way to properly namespace theme hook suggestions so that bundle-based suggestions don't conflict with type-based suggestions. Note that field names are currently prefixed with the name of the module implementing the field, which almost universally means a field name is prefixed with "field-".

Remaining tasks

  1. Reach consensus that this is the correct order of specificity. Done.
  2. Reach consensus on a namespacing fix.
  3. Write a Drupal 8 patch.
  4. Backporting the namespacing fix would break D7 themes in the wild, so its not backportable. But, the order of specificity fix should be backported to D7.
  5. Workaround

    See here for a workaround that provides a solution for adding theme suggestions for fields based on display mode: https://drupal.stackexchange.com/questions/201210/field-template-for-dis...

Issue fork drupal-1367354

Command icon 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

RobW’s picture

Issue summary: View changes

Edited for clarity.

RobW’s picture

Some additional notes and usage example:

On a second look what I said before -- "If very specific code is needed for both bundle fields and specific fields, the same amount of corrective field--FIELD-NAME--BUNDLE.tpl's will be required no matter the override order" -- is true in many cases, in others FIELD-NAME taking priority over BUNDLE could result in easier to maintain, DRYer code.

Given the structure:

node type one
- field a
- field b
- field c

node type two
- field a
- field d
- field e

...let's say "field a" is a user reference that should display an image of the user along with their name, so some custom code is written in field--field-a.tpl.php. Let's also say that for whatever reason we need wrapper divs on all fields in node type two. With the current cascade, creating a general-case field--two.tpl.php, which contains field.tpl.php code with the addition of a wrapper div will absolutely require field--field-a--two.tpl.php to re-establish the custom picture and name code.

If we re-order the cascade as suggested here, a themer could decide if the custom field (field a) needs the wrapper div, or if maybe it already has markup that could function similarly, or if they should include a wrapper across the board in field--field-a.tpl.php, ensuring that there is only one theme file to edit for that particular field.

The point is a general tpl referring to multiple tpls of different types in a bundle/node-type should not override a specific tpl referring to the smallest unit displayable, just that field. If the cascade were switched, options would exists for less repetitive, easier to manage code where currently there are none.

alexiswatson’s picture

Agree with the general concept here. The specificity outlined in #0 (asserting that bundles are less specific than fields) seems far more intuitive. Any other thoughts?

johnalbin’s picture

StatusFileSize
new614 bytes

Here's a patch for D7. Rolling one for D8 now.

johnalbin’s picture

Status: Active » Needs review
StatusFileSize
new634 bytes

Here's the patch for D8.

RobW’s picture

Wooo! Thanks for giving this some attention.

At this point existing modules and themes are relying on the current cascade, so I don't think it's a good idea to change this in D7. As a default in D8 it's great. Thoughts?

RobW’s picture

Status: Needs review » Reviewed & tested by the community

Minor change that's working fine for me, so RTBC.

catch’s picture

Status: Reviewed & tested by the community » Needs review

If this isn't backportable, do we want to look at namespacing these - so field-bundle-$bundle.tpl.php to avoid conflicts between field and bundle names?

RobW’s picture

Catch, are you suggesting that for D7 or D8?

Namespacing the template suggestions in field.module will fix conflicts where a field and bundle have the same name (like in field collection: #1137024-24: Field--your-field-collection.tpl.php cascades and overrides all collected field's tpls), but won't help with other module's template suggestions (like when entity view mode or DS adds a view mode template suggestion).

I was thinking about fixing this in field collection by namespacing the bundle itself; the field's machine name would stay {field-name}, but the bundle name would become bundle-{field-name}. We could open an issue to fix all conflicts across Drupal by namespacing the bundle and view mode machine names, or ask all modules and theme developers to follow a namespaced template pattern (field--{field name}--bundle-{bundle-name}--view-mode-{view mode name}.tpl).

[Edit] Replaced my pre-caffeinated thoughts with something more coherent.

johnalbin’s picture

StatusFileSize
new641 bytes

So I looked at the theme hook suggestions created for Drupal's default image field:

field__image
field__article
field__field_image
field__field_image__article

field__image appears to be the name of the field. BUT it's actually the field type. Prefixing it so it's "field__type_image" makes a lot of sense to avoid this confusion.

field__article is the bundle the field is attached to. We should prefix it to avoid namespace conflicts. But using "field__bundle_article" exposes the confusing "bundle" word to themers. Not good. However, we can use the entity_type to prefix the bundle name so it makes better sense. e.g. "field__node_article". (Field collection's bundle suggestions would then look like "field__field_collection_field_name", I believe.)

Hmm…Actually, I can't think of an actual use-case to have a bundle-specific theme hook suggestion. “I want to override the markup for all fields in the exact same way on the article content type.” Seriously. Why? How about we remove that entire suggestion and if a themer wants such an obscure edge case, they can just add one in the usual way.

So this patch would make the example above be:

field__type_image
field__field_image
field__field_image__article

RobW’s picture

Writing a full treatment of this issue has been on my to do list for months but I keep putting it off. Having bundle specific field templates becomes a little more reasonable when you are fielding non-node entities, e.g., simplifying HTML structure or adding a class on fields in a file entity or field collection that are themselves going to be wrapped in normal field markup at the node level.

Namespace collisions are even more likey if view modes or displays (or any additional user named variable) get added to the template suggestions. I can imagine someone (who should probably plan a little better) having a slideshow view mode, a slideshow node type, and a slideshow file type. We should probably rename this issue to prevent template name variable namespace collisions (please someone reword that so it's somewhat readable by humans) or open a new issue to cover it.

And I think prefixing is the best fix, even if it has the potential to create ridiculously long file names. I suppose we could introduce a shorthand like f-fieldname--t-entity-type--v-viewmode.tpl.

Status: Needs review » Needs work

The last submitted patch, 1367354-9-field-theme-hook-suggestion.patch, failed testing.

alexiswatson’s picture

@10 - It sounds like there are in fact two issues - one for the specificity (this issue) and another to handle namespacing. I wonder if conflating the two will cause more problems down the road, but I do see the value in tackling the latter, even if we don't change the title of this issue.

johnalbin’s picture

Title: field--BUNDLE.tpl.php takes priority over field--FIELD-NAME.tpl.php, although the latter is more specific » The list of theme hook suggestions for "field" is incorrectly ordered and has namespacing collisions
StatusFileSize
new614 bytes

@10 - It sounds like there are in fact two issues - one for the specificity (this issue) and another to handle namespacing.

Yes, we are conflating the two issues. But I think its easy to address them both in this issue. And Catch asked about it. And my general rule is “KEEP THE DRUPAL 8 CORE COMMITTER HAPPY.” :-D Also, while it would technically be faster to separate the two, the bug in Drupal 7 is not urgent and the bug fix patch wouldn't even fix the main issue people are experiencing with the Field Collections module (which is how I got here.)

The fix for the specificity is straight-forward. That part of this issue is totally back-portable. In fact, I'll upload the D7 patch for this right now so people can see it.

The namespacing issue requires that we change the names of the theme hook suggestions. That is totally not backportable as it would break the theme hook suggestions that people are using now.

Having bundle specific field templates becomes a little more reasonable when you are fielding non-node entities, e.g., simplifying HTML structure or adding a class on fields in a file entity or field collection that are themselves going to be wrapped in normal field markup at the node level.

“more reasonable” isn't a specific use-case. :-D Maybe I need to ask a more specific question: What specific use case can you describe where you want the exact same wrapping markup around each field on a file entity or on a field collection?

I've worked with the field collection module A LOT and I love it, but I would never want the same wrapping markup around each field in a collection since they each usually have their own semantics. And given how much I've used this module and how I've never needed such functionality, I would argue that its an uncommon edge case so we shouldn't be providing it by default. Let the user add that suggestion if they need it. After all, we don't provide suggestions for display modes.

Namespace collisions are even more likey if view modes or displays (or any additional user named variable) get added to the template suggestions. I can imagine someone (who should probably plan a little better) having a slideshow view mode, a slideshow node type, and a slideshow file type.

Or worse: an image field type called "image" in an "image" field collection on an "image" content type with an "image" display mode on image.com.

I would prefer to limit the number of suggestions to those most likely (the 3 that I mention in comment #9).

  • field__type_TYPE
  • field__[field_name] (Note that the field name is prefixed with the module providing the field, which is usually the "field" module.)
  • field__[field_name]__[bundle] (For field's attached to nodes, this means the bundle is the node type.)

And I think we should just leave the rest for a themer to implement. Rather then add display modes in the form of field__[field_name]__display_[display_mode] to the mix too.

Note: for the third theme hook suggestion, we could namespace the bundle by prefixing with the name of the entity. So __node_article, but I think that would give us __user_user since user entity's don't have bundles. And I feel STRONGLY that we shouldn't use the word "bundle" anywhere in our theme hook suggestions.

We should probably rename this issue to prevent template name variable namespace collisions (please someone reword that so it's somewhat readable by humans) or open a new issue to cover it.

Done! :-)

alexiswatson’s picture

Yes, we are conflating the two issues. But I think its easy to address them both in this issue. And Catch asked about it. And my general rule is “KEEP THE DRUPAL 8 CORE COMMITTER HAPPY.” :-D

If the consensus here is to tackle it in the same issue, I'm willing to run with it. :]

What specific use case can you describe where you want the exact same wrapping markup around each field on a file entity or on a field collection?

Playing the devil's advocate here (assuming I've parsed this out correctly), but consider the case of minimizing markup for performance reasons. It wouldn't be terribly hard to imagine a scenario in which two or three fields belonging to a simple collection happens to have the same lightweight wrapping markup, if you don't want or need any measure of control after that.

I would prefer to limit the number of suggestions to those most likely (the 3 that I mention in comment #9).

Agreed, and that list looks sane. Themers who need the extra control can still alter template suggestions as needed. Not sure yet how I feel about the actual conventions, have to mull it over a bit.

alexiswatson’s picture

Issue summary: View changes

refined issue explanation.

johnalbin’s picture

Status: Needs work » Needs review
StatusFileSize
new1.53 KB

While everyone is mulling over the list I outlined in comment #13, here's a re-rolled patch that implements that list.

Note that I had to update Bartik to use the updated theme hook suggestion name for taxonomy terms; otherwise, tests broke. :-)

johnalbin’s picture

Issue summary: View changes

Include namespacing issue in summary

Status: Needs review » Needs work

The last submitted patch, 15: 1367354-15-field-theme-hook-suggestion.patch, failed testing.

andypost’s picture

Patch outdated, seems duplicated issue #2229355: Field template suggestions are colliding

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

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should 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.

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

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should 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.

catch’s picture

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

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should 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.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should 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.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should 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.

joelpittet’s picture

Status: Needs work » Closed (outdated)

Looks like different approaches tackled this.

hongpong’s picture

Issue summary: View changes

I found a solution for adding theme suggestions for fields based on display mode here: https://drupal.stackexchange.com/questions/201210/field-template-for-dis... ... adding this here since this is a prominent search result.

catch’s picture

Version: 8.5.x-dev » 8.9.x-dev
Status: Closed (outdated) » Needs work

The precedence order is still an issue, bundle name comes before field name in https://api.drupal.org/api/drupal/core!modules!system!system.module/func...

This might be a duplicate of #2831144: [policy] Bundle / field name / view mode theme suggestions can conflict, but re-opening for now.

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

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

darvanen’s picture

Title: The list of theme hook suggestions for "field" is incorrectly ordered and has namespacing collisions » [PP-1] The list of theme hook suggestions for "field" is incorrectly ordered and has namespacing collisions
Version: 9.2.x-dev » 9.4.x-dev
Issue summary: View changes
Issue tags: +Bug Smash Initiative
Parent issue: #2831144: [policy] Bundle / field name / view mode theme suggestions can conflict » #3159050: Allow deprecating theme suggestions
Related issues: +#2824566: Cannot name a field 'comment'

Triaging a collection of related issues as part of the Bug Smash Initiative, I'm going to favour this issue as it is the oldest and has some attempts at work to fix.

Closing as duplicate of this issue in order of creation:

Postponing on #3159050: Allow deprecating theme suggestions as it will not be possible to deploy any work done here without a way to deprecate old template suggestions.

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.

catch’s picture

Title: [PP-1] The list of theme hook suggestions for "field" is incorrectly ordered and has namespacing collisions » The list of theme hook suggestions for "field" is incorrectly ordered and has namespacing collisions

Unpostponed finally.

#3536196: Investigate preprocess_field in the comment module was dealing with this problem, and we can tidy up that preprocess implementation here probably.

berdir’s picture

This is a lot trickier than the views issue we we just deprecated the suggestions completely. Order in general is not something we can *directly* provide BC for, but we might not actually need to...

The issue summary is very old, unsurprisingly and outdated. multiple entries are no longer there like that, specifically not bundle-only suggestions.

This is the current list:

$suggestions[] = 'field__' . $element['#field_type'];
$suggestions[] = 'field__' . $element['#field_name'];
$suggestions[] = 'field__' . $element['#entity_type'] . '__' . $element['#bundle'];
$suggestions[] = 'field__' . $element['#entity_type'] . '__' . $element['#field_name'];
$suggestions[] = 'field__' . $element['#entity_type'] . '__' . $element['#field_name'] . '__' . $element['#bundle'];

(note: this is reversed as the last entry is the most specific)

one issue that's easy to resolve is $suggestions[] = 'field__' . $element['#field_name'];, field names are no longer global, so this should not be a thing and we can deprecate this. field type is global and then unique but also least specific, that's fine. However, because we only deprecate the suggestions here, you will only be able to rely on the field type once the field name suggestion is actually removed (D13). Including in core. One option is that we introduce a prefix for the field type and make that $suggestions[] = 'field__type_' . $element['#field_type'];. But this would force everyone to rename their field type specific templates.

This also solves all order problems. entity type + field name is more specific than entity type + bundle.

The next problem is the conflict of entity type + field name/bundle, meaning a field name and bundle of the same name. That seems less common but possible. I wonder if we should just straight up deprecate entity type + bundle. Is it really a common use case to have a template for *all* fields of a given bundle? If someone wants that, they could still introduce that on their own again.

Alternatively, we need to introduce prefixes for these two, so $suggestions[] = 'field__' . $element['#entity_type'] . '__bundle_' . $element['#bundle'];. This is what #2831144: [policy] Bundle / field name / view mode theme suggestions can conflict was discussing. Which I think is not a duplicate but a parent/meta issue of this and the entity one. Either for both bundle and field or one only bundle, as that's likely far less used.

berdir’s picture

Status: Needs work » Needs review

Created an MR as a starting point.

After looking at this, I'm proposing to *not* deprecate and rename field--FIELDNAME.html.twig. That would require us to rename several existing templates, specifically field__comment.html.twig in comment module and it's 10 overrides and the new specific preprocess function and that seems like way more trouble than it's worth. That just means we can only remove that extra check in #3536196: Investigate preprocess_field in the comment module in D13, but I can very much live with that.

The MR should fail with deprecations on field--comment-body.html.twig in olivero, all others are field type specific or entity type prefixed I think.

berdir’s picture

Well, my suggestion didn't account for the fact that the default field name of the comment field in \Drupal\comment\Tests\CommentTestTrait::addDefaultCommentField() is 'comment', which is exactly what triggers the conflict. it's a comment field, so it's not broken, but of course the deprecation doesn't make a difference between that.

And actually, the default comment field in standard install profile is comment too.

Might need to rename the field type based suggestion after all...

berdir’s picture

I had an idea that I'm not sure is a good one, but it seems to work. Basically, I was thinking that we add some magic to the deprecation logic and if we discover a deprecated suggestion and the next in line is identical, we just skip to that. This means we basically assume that field--comment.html.twig is meant to be about the field type.

I can't think of an edge case where this would be a problem right now, but there might be?

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new1.38 KB

The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

catch’s picture

#38 sounds like a very nice way of handling this, but I also am unsure whether there's going to be weird edge cases. However even if there are, it might be less disruptive than a complex renaming situation overall.

berdir’s picture

Status: Needs work » Needs review

All remaining deprecations were triggered by field--comment-body.html.twig in olivero, renamed that, so if the RNG gods are with us, this might be green.

berdir’s picture

Well, this is awkward, I learned something today. And I keep running into problems here.

By renaming field--comment-body.html.twig to field--comment--comment-body.html.twig, what happens is that this is now triggering preprocess_field_comment functions.

The actual theme suggestions have no assumptions about depth and hierarchy, it's just first match in reverse order wins. Turns out that preprocess discovery doesn't work like that at all. It splits up the template name by "--" and then assumes that earlier parts are it's parents/hierarchy and should be called too. So because the entity type is comment, and the field type is comment, we're running into a different kind of collision.

I've added a workaround to the olivero preprocess, which is essentially the same as comment already has. This is an existing issue and not caused by this directly (except that you have to name your template now in a way to trigger this) But it also kind of defeats the purpose of this issue.

Makes me wonder if we maybe went too far in our approach to preprocess functions and whether it was a good idea to support preprocess for theme suggestions. But that's unlikely to change.

The only other options is that we do in fact rename the field--$type suggestion to field-type-$type. But that's going to cause so many BC issues (preprocess_comment will stop working).

catch’s picture

#3533198: [Meta] Make Drupal the first "design-system native" CMS + Unify & simplify render & theme systems has on its list getting rid of theme suggestions altogether. I'm not really sure how that fits into things but just noting that they potentially could end up on their way out.

smustgrave’s picture

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

Can we add a test case of the collision please.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.