Problem

If you create a template file to theme your field collection field (field--field-my-collection.tpl.php), the tpl cascades through all child fields of that collection.

For example, if you have a collection like:

field-my-collection
-- field-text
-- field-image

and make a template file field--field-my-collection.tpl.php, the fields that are themed will be:

field-my-collection, and
field-text, and
field-image

This is because the field collection name is also the bundle (aka content type) name for collected fields. Drupal's field tpl inheritance from most specific to least is:

  1. field--field-name--content-type.tpl.php
  2. field--field-name.tpl.php
  3. field--content-type.tpl.php
  4. field--field-type.tpl.php

So field--field-my-collection.tpl.php applies to

  1. field--field-name--content-type.tpl.php
  2. field--field-name.tpl.php --- for field-my-collection, and
  3. field--content-type.tpl.php --- for its child fields, field-text and field-image
  4. field--field-type.tpl.php

Expected Behavior would be that you could create a field collection field tpl that will not apply to all children fields.

Workaround

You can create templates for all of the child fields with the pattern field--field-name--content-type.tpl.php. This will override field--content-type.tpl.php.

Proposed Solutions

Rename the field collection bundle to something different than the field collection name.
or
Add a field-collection.tpl.php, so that no one needs to use field--my-field-collection.tpl.php anymore.


Original issue description

If you create a template file to theme the top-level, in-the-node field collection's field (field--your-field-collection.tpl.php, not the field collection itself, field-collection-item--your-field-collection.tpl.php), the field--your-field-collection.tpl.php code is also applied to all of the fields within your field collection.

For instance if you were to have a field--your-field-collection.tpl.php with the code

foreach ($items as $delta => $item) {
  print render($item) . text('foo'); 
} 

every field inside your field collection will also have 'foo' printed after it.
Not sure if this is desired behavior or not.

Comments

RobW’s picture

... and by text('foo') i mean t('foo'). Whoops.

inolen’s picture

Just ran into this today as well, is this intended?

RobW’s picture

If the maintainers don't have a strong bias either way, my opinion is they shouldn't cascade. In general it's bad practice to create templates to restore default behavior, which you have to if your intent is to only override the field collection's theming.

inolen’s picture

RobW, while it's a bad practice, are you saying I should be able to create a template for my sub-fields to restore the default behavior?

For example, I have a field collection field named "foobar" and in there is a field named "image". I have a custom field--field_foobar.tpl.php that is cascading over the theming of the field_image, however, creating a field--field_image.tpl.php doesn't seem to matter (field--field_foobar.tpl.php takes precedence).

fago’s picture

Title: Field--your-field-collection.tpl.php cascades through all field collection fields (bug or desired behavior)? » Field--your-field-collection.tpl.php cascades through all field collection fields

This isn't desired behaviour, thus it sounds like a bug to me. Anyway I'm open to any solution to this, whatever you think is most useful for themers.

>In general it's bad practice to create templates to restore default behavior, which you have to if your intent is to only override the field collection's theming.

That makes sense.

RobW’s picture

Title: Field--your-field-collection.tpl.php cascades through all field collection fields » Field--your-field-collection.tpl.php cascades and overrides all collected field's tpls

>In general it's bad practice to create templates to restore default behavior, which you have to if your intent is to only override the field collection's theming.

Turns out this doesn't work anyway; the field--your-field-collection.tpl overrides all collected fields whether there are per-field tpls or not.

RobW’s picture

In a comment on another post, Joeysantiago pointed out a tpl that provides a workaround for this issue.

In short, you can use field--your-collected-field--your-field-collection.tpl.php. A more complete example with explanation:

  • If you have a collection called field_collection_foo,
  • which contains two fields, collected_1 and collected_2,
  • field--field-collection-foo.tpl.php will theme field_collection_foo, collected_1 and collected_2, overriding any field--collected-1.tpl.php or field--collected-2.tpl.php templates,
  • but field--collected-1--field-collection-foo.tpl.php and field--collected-2--field-collection-foo.tpl.php will override field--field-collection-foo.tpl.php, allowing for per-field theming again.
valderama’s picture

thanks a lot RobW, that helped :)

wmostrey’s picture

With the information from #7, isn't this actually a feature that needs more and clearer documentation, instead of this being a bug?

RobW’s picture

I don't think so. For example:

Say you have a node like this:

- Field A
- Field B
- Collection 1
  - Collected Field C
  - Collected Field D

And say you create a field.tpl.php that sets up default html structure for all the fields on your site (A,B,C,D, Collection 1, and everything over the rest of the site). Now you decide you want your field collections to have a slightly different structure, maybe with an image in the corner. Creating a field--collection-1.tpl.php will theme your collection and all child collections, in this example putting an image in the corner of C and D as well. To revert to default behavior, you have to create both field--collected-field-c--field-collection-1.tpl.php and field--collected-field-d--field-collection-1.tpl.php, and use the exact same code as field.tpl.php. If you had ten collected fields, you'd need ten new tpls just to restore default behavior.

This is messy even in this simplified example -- when you add tpls that do more complicated theming with case switches and field type specific code, it becomes a real pain. Hope that helps you understand my point of view.

Sorry, by the way, for my inconsistent example field naming in different posts.

chalee’s picture

+subscribing - This issue is a problem which should be sorted out.

sachbearbeiter’s picture

sub

gazwal’s picture

sub too thx

ufku’s picture

This is because field--BUNDLE.tpl.php overrides field--FIELD-NAME.tpl.php.

For collection field BUNDLE = NODE-TYPE
For sub-fields BUNDLE = COLLECTION-FIELD-NAME

That's why field--COLLECTION-FIELD-NAME.tpl.php overrides field--FIELD-NAME.tpl.php by acting as the BUNDLE of sub-fields.

A workaround without defining template files for each sub-field is to rename field--COLLECTION-FIELD-NAME.tpl.php to field--COLLECTION-FIELD-NAME--NODE-TYPE.tpl.php.

idflood’s picture

thanks RobW and ufku for the workarounds. That helped but it still feels like a bug to me.

ufku’s picture

It's a core bug where field--BUNDLE.tpl.php precedes field--FIELD-NAME.tpl.php.

RobW’s picture

@ufku, is there an issue for this open in the core issue queue? Took a quick look but couldn't find one -- just want to check you haven't seen one, maybe oddly named or as part of another issue, before I create a new core issue.

ufku’s picture

I didn't see either.

RobW’s picture

Posted a core issue at #1367354: [PP-1] The list of theme hook suggestions for "field" is incorrectly ordered and has namespacing collisions. I didn't mention field collection, although you're welcome to, just core-specific reasons to revise the cascade. Thanks for pointing out the technical reason for this bug.

mghatiya’s picture

I am lost. I have seen good number of threads talking about similar things, but can't get my thing to work.

I have a field collection called "field_result_row" which has fields called "field_rank", "field_direction", "field_team_num" and a field which is a field collection in itself called "field_team_members"

I have created "field--field-result-row.tpl.php" . Is this name correct? Right now this is just a copy of original "field-collection-item.tpl.php" found in field_collection module

My "print render($content); " is not printing anything. So I thought I tried adding following items:

print_r ($content); 
print $title;
var_dump(get_defined_vars());

But none of these worked. print_r printed nothing. I am getting error for title saying "undefined variable". and when I put var_dump, I am just getting the white screen.

When I just removed all of these and just added "print ("Test");", the "Test" was printed for all the fields of the collection.

Can someone please give me exact steps with file names etc. as per my field names to clarify things? What I just want to theme is that I want all the fields of the field items to appear in one line. By default they are coming in different lines.
I am sorry I might seem to demand too much, but when someone says create a file with name "your-field-collection-item.tpl.php", it becomes very ambiguous to me as to whether to use underscore or hyphen, whether to add that -- or not, etc.

Thanks so much for reading till here and helping :)

RobW’s picture

mghatiya, here's some brief pointers that hopefully will help you out.

In Drupal 7, double dashes are used between every distinct part of a tpl.php name. Single dashes are used just as you have used them, to make field names, content type names, etc., with more than one word. Example: field--field-name--content-type.tpl.php. Check here for examples.

Your field--field-result-row.tpl.php is correct if you are trying to theme the whole field collection, and as noted in this issue, all the field in it identically. If you want all of the collected fields to appear on the same line, you might try leaving the field collection alone and theming each individual field, replacing the surrounding divs with spans or some other appropriate inline markup. Your tpls would be field--field-rank--field-result-row.tpl.php, and so on. An even simpler option, if you consider the current formatting semantic, is to leave all the tpls at their defaults and style the fields with css. Some well placed display:inline; or float:left; would probably work.

For debugging I recommend you download the Devel module if you haven't already. The devel render tab will give you access to all of your node variables, and dpm($content) will give you the content array in a nice click-to-expand list. Good luck!

mghatiya’s picture

Thanks for the reply Rob. I'll try it the css way. Will install the Devel module too. I have heard of it, but just that I have observed that adding more modules just slows down drupal and I am wary to add another. But somehow every solution in Drupal points to installing another module :)

But I am still not clear why would print $content or print_r $content will not print anything. As soon as I stop using this tpl file and resort to default, all values are printed, so it is not an issue of display of field being set as hidden. Same is case of why the variable $title is being reported as undeclared. These are all the variables mentioned in the default tpl given with the module.

RobW’s picture

Issue summary: View changes

Embetterized the summary.

RobW’s picture

Issue summary: View changes

tiny edit

RobW’s picture

I think we can leave bundle names alone: creating a field-collection.tpl should fix this, since there will no longer be a reason to use field--field-collection-name.tpls. Progress in #1157794: Move markup to template files and improve theming in new 2.x branch.

RobW’s picture

Issue summary: View changes

removing incorrect formatting

RobW’s picture

While working on the tpl patch, I was thinking about this and maybe I was wrong in #23. Even with a field-collection.tpl, child field collections will still have the issue unless we rename the bundle.

e.g.:

field_my_collection
-- field_some_field
-- field_child_collection

field-collection--field-my-collection.tpl.php will apply to field_my_collection, not apply to field_some_field, and will apply to field_child_collection since field_my_collection is it's bundle.

So do we want to rename all field collection bundles something different than the field name? Maybe "collection-field-my-collection"? Other suggestions?

If maintainers are for renaming the bundle I will write the patch.

remaye’s picture

I tried the solution proposed on #7 and could'nt make it work :
- first I created "field--collected-n--field-collection-foo.tpl.php" for each fields of my collection field and it worked : all fields are correctly overriden within the field collection
- then I created a "field--field-collection-foo.tpl.php" using the "field-collection-item.tpl.php" found in the field_collection module, and then the field collection became blank, the $content variable is not even present at the template level.

Unlike mghatiya in #20, if I print "Test" in the "field--field-collection-foo.tpl.php" (and disable "field--collected-x--field-collection-foo.tpl.php") it just prints "Test" one time, not in each fields, just as if the template was not cascaded through the fields as suggest this thread.

I'm confused of what is going on, any idea of what I'm doing wrong ?
Thanks for your time.

RobW’s picture

The field--field-collection-foo.tpl.php should be based on field.tpl, not field-collection-item.tpl. Field.tpl is basically a wrapper template that will contain all field collection items, where field-collection-item is the tpl for each individual field collection instance.

remaye’s picture

Thank you Rob for you quick answer and your pertinence, that was it !
Now works as expected and workaround #7 is fine.
Thanks !

RobW’s picture

No problem, thanks for the thorough bug report.

JohnAlbin’s picture

Thanks for tracking this down, everyone! I've posted a Drupal core patch over at #1367354: [PP-1] The list of theme hook suggestions for "field" is incorrectly ordered and has namespacing collisions

stevetweeddale’s picture

I am understanding this correctly, that even if #1367354: [PP-1] The list of theme hook suggestions for "field" is incorrectly ordered and has namespacing collisions were to get committed, there would still be confusion when using field collection? Because the bundle is the same as field name? So would there still be cause to namespace the field collection bundle?

RobW’s picture

@steve, correct.

JohnAlbin’s picture

Yeah. The only good work-around is to add a preprocess function to check if the field's name is the name of the collection and then set a custom theme hook suggestion.

function THEMENAME_preprocess_field(&$variables, $hook) {
  if ($variables['element']['#field_name'] == 'NAME_OF_COLLECTION') {
    $variables['theme_hook_suggestions'][] = 'field__custom_suggestion';
  }
}

To fix this problem altogether, should field collection name its bundles "collection-FIELDNAME"?

RobW’s picture

That's my suggestion (I might have mentioned it somewhere in the comments above).

RobW’s picture

Issue summary: View changes

revised solutions and added original summary

bradallenfisher’s picture

Semester -> Field Collection
-- Semester Label -> Text Field
-- Course Row -> Field Collection
---- Credits -> Text Field
---- Course Details -> Field Collection -> Machine Name = field_course_details
------ Course Name and Link -> Link Field -> Machine Name = field_course_name_and_link
------ Course Notes -> Text Field
------ Course Requirements -> Select Field

I know this is an old thread. However when deeper nesting is involved such as above, how can i get more specific with my tpl files. I would like to use a tpl file for Course Name and Link.

So far the tpl i can get to fire is:
field--field-course-details.tpl.php which affects all the fields below it as pointed out in this thread. However, what i expected to work is field--field-course-name-and-link--field-course-details.tpl.php but it doesn't. ? Any ideas. drush cc all multiple times.

bradallenfisher’s picture

I was able to come to a solution on this. however, it is icky :)

Basically you create the parent collection tpl file and add the desire markup or logic.
In my case above i created field--field-course-details.tpl.php and it overrode all child fields.
So i created field--field-course-requirements--field-course-details.tpl which is one of the child fields but i used the default field.tpl.php to "undo" my changes from the inheritance.
YUK. but it works for me until there is a better way.

thanks for this thread... I am going to investigate a way to handle this in a function next.

leanderl’s picture

Thanks for posting this info everyone involved. I ran into this, but it took me several hours to realise that it was the module that was behaving in an unexpected way and not a problem with my implementation of tpl:s in Drupal.

I really find this module useful, perhaps there could be a more clear statement about this "cascading" behaviour in the documentation or in the read-me file? And info about how to address it by "overriding the override". Once you know what's going on, it's a lot easier to tackle.

Ronino’s picture

I solved this for all cases with a preprocess function in my template.php to remove that malicious theme hook suggestion:

function THEME_preprocess_field(&$variables, $hook) {
  if ($variables['element']['#entity_type'] == 'field_collection_item') {
    // Check if the bundle name (i.e. the field collection field name) is
    // among the theme hook suggestions.
    $index = array_search('field__' . $variables['element']['#bundle'],
      $variables['theme_hook_suggestions']);

    // Remove the bundle theme hook suggestion.
    if ($index !== false) {
      unset($variables['theme_hook_suggestions'][$index]);
    }
  }
}
RumpledElf’s picture

Apparently this is still an issue in 7.28

Having issues getting the name to hit only the field collection on a vocabulary ...

field--field-collection-name--vocabulary-name.tpl.php

It doesn't work just with taxonomy-term.

lcampanis’s picture

With version 7.x-1.0-beta7, still facing some serious issues in how the templates are processed for BUNDLE.

For some peculiar reason field--my-collection--node-type.tpl.php (or bundle) just doesn't work! I reversed, added all templates, just nothing.
Anything with bundle just won't process as a template at all. Note that all suggestions are in the array and you would expect them to process in order.

The way I got around it is by working with view modes instead. (I honestly don't know why one works and not the other)

function HOOK_preprocess_field(&$vars) {
  if($vars['element']['#field_name'] == "my_collection") {
    $vars['theme_hook_suggestions'] = array('field__my_collection__' . $vars['element']['#view_mode']);
  }
}

That will give you field--my-collection--full.tpl.php, full being the name of your view mode under Display settings for that node type.

skribbz14’s picture

Ronino's work in the THEME_preprocess_field() did it for me as well. Thanks a lot!

graper’s picture

I know that this is an old issue, but I found something that I know will help a lot of people with this. I had turned on theme debug mode and found the suggestions that are uses for each field and the children of a collection.

I have a content type named "Procedures" (machine_name:procedure)
in procedures I have a field collection named "Tools Required" (field_tools_required).
inside the collection are 2 fields, and image field named "Image" and a text field named "Description".
The first template file I created followed the same convention as some of the other files, field--field-tools-required.tpl.php. This lead me to here because I too had the same issue of the file be used for the collection and each child field.

I saw some of the work that others had done and as I tracked through the theming and files, I thought it appeared that the file wasn't being provided as a "hook", so I started tracking how to work with theme hooks. That got me to a page to turn on Theme debug mode at https://www.drupal.org/node/223440.

With debug mode on I found that the collection and the child theme are being given the same exact file name suggestions for the theme as one of the suggestions. I also saw other suggestions, so I change the collection to use field--field-tools-required--procedure.tpl.php and that stopped cascading to the child fields.
Instead of using the same collection only template file, I can now use the field--image--field-tools-required.tpl.php named files. This means you don't have to preprocess the field and remove a suggestion.

Hope this is understandable and helps others.

Graper.

jwilson3’s picture

@Graper, unfortunately, your comment left me confused. What is field--field-parts-included-procedure.tpl.php coming from? Your content type name is "Procedures", so I'm having trouble following the mappings of this suggestion... and then at the end, you refer to field--my-field--my-collection.tpl.php instead of following through with the example you setup.

It would be helpful if you could stick to the concrete example you have for your solution, in order to understand it more clearly. Thanks.

graper’s picture

@jwilson

Thank you for catching my mistakes. I edited my original post to keep the proper convention. I am working on a node type that has multiple collections so I got things a bit mixed up.

the my-field--my-collection was supposed to be a generic naming convention. sorry about that I changed it also since there seemed to be some confusion on it. Hope this helps.

jwilson3’s picture

Thanks for the fix. Interesting solution.

efpapado’s picture

Please take a look at https://www.drupal.org/node/715160

I implemented hook_preprocess_field(), where I added
$vars['theme_hook_suggestions'][] = 'field__custom_template_name';

and then I implemented hook_theme_registry_alter() as it is described at the link, and I managed to have my custom template for field collection without problems.

I hope it helps.

yugi’s picture

The solution suggested by @graper is really helpful and does not require any preprocess or changing theme suggestions.
Basically, you can create a template file followed by the content type that contains the field collection, something in the form of field--[field-collection]--[content-type].tpl.php.

ronigal’s picture

Thanks graper

jimkeller’s picture

Possibly a simpler solution, although possibly brittle if you need to use the word 'collection' anywhere else in your template suggestions:

in THEME_preprocess_field:

  if ( !empty($vars['element']['#field_type']) ) {
    if ( $vars['element']['#field_type'] != 'field_collection' ) {
      foreach( $vars['theme_hook_suggestions'] as $index => $suggestion ) {
        if ( strpos($suggestion, 'collection') !== false ) {
          //
          // If it looks like we have a template suggestion for a field collection, but we're not actually in a field collection,
          // unset that suggestion.
          //
          unset($vars['theme_hook_suggestions'][$index]);
        }
      }
    }
  }
rajveergangwar’s picture

I got the solution from https://www.drupal.org/node/1187990#comment-4699320

Explain:

If your field collection name is XYZ and filed under XYZ is ABC then filed tpl should be

field--ABC--XYZ.tpl

If your field collection name is FIELD_XYZ_MODE and filed under XYZ is FIELD_ABC_DEF then filed tpl should be

field--FIELD_ABC_DEF--FIELD_XYZ_MODE.tpl

Tim Banks’s picture

The template suggestion Documentation suggests a similar solution to #39 but that a cleaner way to add to the array would be:
$variables['theme_hook_suggestions'][] = 'hook__suggestion';

So a complete example would look like:

function YOURTHEME_preprocess_field(&$vars) {
  if ($vars['element']['#field_name'] == 'FIELD_COLLECTION_FIELD_NAME') {
    $vars['theme_hook_suggestions'][] = 'YOUR_TEMPLATE_NAME';
  }
}