A better way to theme Field Collections

Field collections are at the same time one of my most favorite and least favorite aspects of working with Drupal 7. Since they are entities they can be extremely powerful and flexible site building tools, and I see lots of unrealized potential in that, on the other hand theming can be tricky and, for lack of better word, generally feels “icky.” There is little documentation online about best practices with almost all links pointing back to this thread on how to theme field collections. The proposed solutions in this thread are a mixed bag — mostly bad — but some that may work, but they certianly don’t follow any best practices in drupal theming. I’ll admit I have shipped field collection theming that, while working, did make me feel “dirty.” Below was a clean solution that — while simple — is maintainable and, hopefully easy to follow.

I created a quick function that pulled out the themed items from the field collection and organized them into an easy to theme array. The theming then felt a lot more natural, like working with a views rows template.

<?php
/**
 * Creates a simple text rows array from a field collections, to be used in a
 * field_preprocess function.
 *
 * @param $vars
 *   An array of variables to pass to the theme template.
 *
 * @param $field_name
 *   The name of the field being altered.
 *
 * @param $field_array
 *   Array of fields to be turned into rows in the field collection.
 */
 
function rows_from_field_collection(&$vars, $field_name, $field_array) {
  $vars['rows'] = array();
  foreach($vars['element']['#items'] as $key => $item) {
    $entity_id = $item['value'];
    $entity = field_collection_item_load($entity_id);
    $wrapper = entity_metadata_wrapper('field_collection_item', $entity);
    $row = array();
    foreach($field_array as $field){
      $row[$field] = $wrapper->$field->value();
    }
    $vars['rows'][] = $row;
  }
 }
}

In this function we pull in the “variables” array from the field template, the field name and an array of fields that we want to extract, and then load them into our own rows array which gets attached to the variables array for use in our template. It uses the entity_metadata_wrapper that is like a swiss army knife of sanity and clean code for Drupal 7. If you aren’t familar with it, start with this documentation page about entity metadata wrappers, and follow up with some quick googling. It’ll make you and your code happy.

Below is the function being called and our custom field template being established. One thing that keeps our code simple is that all fields in the field collection are required eliminating the need to check for the variables existence in the template.

<?php
function THEME_preprocess_field(&$vars, $hook){
  if ($vars['element']['#field_name'] == 'field_achievements') {
    $vars['theme_hook_suggestions'][] = 'field__achievements_collected';
 
    $field_array = array('field_award', 'field_award_presenter','field_year');
    rows_from_field_collection($vars, 'field_achievements', $field_array);
  }
}

Finally below is the field template.

<?php
/**
 *  Field formatter for the field_achievements field collection.
 */
?>
<dl>
  <?php foreach($rows as $row): ?>
    <dt><?php print $row['field_award']; ?></dt>
    <dd><?php print $row['field_award_presenter']; ?></dd>
    <dd><?php print $row['field_year']; ?></dd>
  <?php endforeach; ?>
</dl>

We had a number of fields that were just sets of text data that needed to be output in definition lists. The function could be easily modifed to render the fields instead of just the values by using entity_view(). Next steps for this approach would be to refactor to use entity info to get the fields so that it can be generic and would no longer require the need to pass in the fields that you want.

There is hope for theming within the module itself. There is a promising issue in the queue that looks like it makes the native theming more sane. Since it’s such a big change it doesn’t look likely that it’ll make it into the 1.0 branch, so we may need to wait for the next version before it drops. Perhaps there is space for an add-on contrib module that cleans up the theming.

Mike Minecki is a developer who dabbles in management at Four Kitchens.

Commenting on this Blog post is closed.

Comments

Just today me and a colleague were leading with the same issue. We finally used the same approach with the entity_metadata_wrapper but your solution is more fancy. Thanks for sharing ;)

Thanks! Yeah motivation was literally “I wanna feel good about this when it’s done.”
 :)

Also I hope that other folks won’t have to spend time mucking about and can just take advantage of this.

Mike, great post, your code makes sense to me as a Themer. I think theming Field Collections has been one of the hardest things in Drupal I’ve ever dealt with. My cumulative knowledge comes from that one thread you reference above.

One thing I’ve also struggled with are rendering data parts of Field Collections, i.e. “FID” etc… I opened an issue two months ago on drupal.org but never heard back from the maintainers. Any chance you would have time to take a look sometime? drupal.org/node/1966732 - Thanks and I do understand if you don’t have time.

I know this if off topic but I’m looking into starting my own weblog and was curious what all is required to get setup? I’m assuming having a blog
like yours would cost a pretty penny? I’m not very web smart so I’m not 100% certain.
Any tips or advice would be greatly appreciated. Kudos

Hi,

There are lots of ways to get started with a blog without having any web smarts or developer experience. The first place I would look would be hosted services. If you want to build it on Drupal, which this site is built on Drupal Gardens or if you prefer Wordpress http://wordpress.com/ is a great starting point. Finally a different popular platform is Tumblr. Thank you for your kind words and good luck blogging.

Hi Danny,

To do what you are trying to do I think you could use the function I create to get a set of field collection rows and then access the fid in the $vars[‘rows’] array.

I like this approach for complex scenarios, but if you like Display Suite like I do there is a simpler way.

Override the “field-collection-item.tpl.php” template in your theme, and remove ALL HTML markup in it, so you’re left with only the $content variable.

After that, you can have complete control of the field collection markup, including the wrappers, via Display Suite.

Thanks. I haven’t used Display Suite for a long time. The last time I did I loved it, but everyone else who was on the project was used to doing more “standard” Drupal theming and they found DS to be confusing. I’d love to revisit it on a future project.

Great pointers for theming of field collections. This space is bookmarked now. Thank you for sharing it.

Thank you! Great to hear that this helped you out.

Hi Mike,

Interesting approach… I was looking into the same issue.

Could you please explain the entity_view() solution a bit more?
Because now I’m getting the ‘raw’ values, but not the suffixes for the fields, etc.

Thanks!

Hi,

Sorry it took so long to get back to you for so long. If you want the whole rendered entity you can use entity_view() to get the whole entity rendered in any view mode that is setup. http://drupalcontrib.org/api/drupal/contributions!entity!entity.module/function/entity_view/7

If you want to render an individual field you can use field_view_field(). https://api.drupal.org/api/drupal/modules!field!field.module/function/field_view_field/7

Hi,
I’m having trouble getting this to work. Which files are each of these snippets supposed to go into?

I’m finding that none of the expected variables are available in my theme file.
I’m using a theme file
views-view-field—field-contact.tpl.php
For (as you may have guessed) a field_collection called field_contact.

Inside the file, I can print things like <?php print 'hello' ?> and they appear as expected, but i can’t find any way at all to reference the fields in the field collection.
Have spent the better part of 6 hours on it.

Any help would be appreciated.

Cheers, Chris

Cheers, Chris

Hi Chris,

I’m sorry you are having problems. 6 hours is a long time. Hopefully I can help.

These should go into the template.php for the theme.

Are you setting the field formatter to “fields only”? If so you need to style the template I outline above, not the views-view-field—field-contact.tpl.php

If you have the view mode set correctly the field should be rendered the same in this view and on the entity.

Does that make sense?