Author image
Senior Developer

Rendering Drupal 7 fields (the right way)

The short answer.

Use field_view_field()!

The long answer.

Drupal 7 brought us Entities, and with them the powerful Field API for 'storing, loading, editing, and rendering field data.' attached to them. If you're managing everything through 'manage fields' and 'manage display' tabs of your content type, then every part of that process is rather wonderfully taken care of for you.

We often, however, come across the need to render a field outside the context of it's entity. A common example might include rendering a node's author in a sidebar block. Sure, modules like Panels and CCK Blocks will do this for you, but doing it manually is actually not that hard.

You may well have seen (or written!) code that looks something like this:

// This is WRONG example.
$block['content'] = $node->field_name['und'][0]['safe_value'];

Poking around the node object for the value you wanted to print was fairly common in Drupal 6, and the 'safe_value' sounds like it's been sanitised, right? What's wrong with that? Oh, Let me count the ways.

  1. Firstly, the ['und'] element is part of the field localisation in Drupal 7 (see this article from Gábor Hojtsy for more on that); directly accessing that value will cause issues in any kind of multi-lingual environment. Boo.
  2. By accessing the field value directly you miss out on any theming that might come courtesy of the normal field markup.
  3. The [0][safe_value] explicitly accesses the first value of the field - if you wanted every value from a multi-value field you'd need to do some sort of loop.
  4. Some fields (such as node references) won't have a safe_value element, only a value - which can easily be printed without thought for sanitisation. This is dangerous, not because node reference fields contain dangerous data (they're just a nid), but because it's not a helpful habit to get into, especially for new developers. Other fields types 'value' may well be highly dangerous.

Happily, field_view_field() comes the rescue!

$output = field_view_field('node', $node, 'field_name');

That will return the sanitised (fixing #4), rendered field in its entirety (fixing #3), in the current language (fixing #1) and in render-array form, so you'll get all the associated markup (fixing #2). Win! It will use the sites language fallback logic if the field has no values available for the current language. You can also pass an array of formatter options or specify a view mode as an optional argument. Nice. And doesn't it just feel better?

Bonus extra tips

Suppose you do just want a single value, and none of 'that crufty field markup' anyway? Well there are two api functions to help you out here. Firstly, we have field_get_items(): which returns a field items in the right language (again, you can specify a language if you need). You can poke around in there and get at the raw data, perhaps for using in some server-side logic or if you want to do something exotic like printing an image field's alt text somewhere else. Do be aware though, that you're dealing with raw user input here and will need to do the proper sanitisation before using these values, else you risk introducing security vulnerabilities.

Better yet, there's another handy field API function, field_view_value(), for when you want to render a single field value, which has all the right sanitisation built right in. It also uses field formatters, which is lovely. It takes a single field value taken from the array returned by field_view_value(). Here's an example:

$node = node_load($nid);
$field = field_get_items('node', $node, 'field_name');
$output = field_view_value('node', $node, 'field_name', $field[$delta]);

Where $delta is the field value you want. On a single value field this would be 0. Simples.

And just for fun, here's a final example of passing in some formatter options to specify an imagecache preset, and make the field link to the node. This would work the same for both field_view_value() and field_view_field().

$node = node_load($nid);
$image = field_get_items('node', $node, 'field_image');
$output = field_view_value('node', $node, 'field_image', $image[0], array(
  'type' => 'image',
  'settings' => array(
    'image_style' => 'thumbnail',
    'image_link' => 'content',
  ),
));

This Rocks.

There you have it. Certainly for the example use case of the 'field-as-a-block' the Field API makes this really nice, clean and simple. We're dealing with render arrays, so it's all lovely and alterable right up to point render() is called in a template file. And using field_view_field() and field_view_value() for rendering output also means that proper sanitisation is done for you. Brilliant.

Comments

Wouldn't it be easier to use View and override with row style tpl?

You could also use entity API to achive this:

$object = entity_metadata_wrapper('node', $node);
$field = $object->field_yourfield->value();

Hi Jessica,

It all depends on what you're trying to achieve and where you're working (in code/in the UI). Sure, you can do the basic example of 'node author info in a sidebar' either with panels and a view block or in Drupal 7 just with views (with a contextual filter like this) - this post was more for when you find yourself in code and needing to render a field.

As a complete NUG, I am thinking this is the path I need to explore to get the existing 'product information' targets in Ubercart to appear as options in the 'Legend' in FEEDS mapping for csv. If this is no the case, an email with some guidance would be greatly appreciated. But please use small words.

Thanx! Definitely an interesting article. I stumbled upon this accidentily, but so much it opened my eyes!

Thanks for the explanation. Just what I was googling for. And from what I can tell, you are correct: this is the *right* way.

This is a great tip. I also suggest readers go check out the *brand new* field extraction module, which will allow you do to all kinds of crazy-cool things to get the values of fields without dealing with language, etc.

http://drupal.org/project/1158878

After hours spent trying to figure out the proper way to format I ran across your site.
Changing [0]['view'] and variations to ['und'][0]['safe_value'] made everything finally work - so simple. Thanks

Hi Rick,

I fear you may have skipped most of the article - some rather crucial information followed the first code block; namely, why that was an example of the wrong way to do it in Drupal 7! Read on for what we think is the right way. Sorry for the confusion there. I've added a comment to the code to highlight this fact.

This I think is what I need to put in place for my situation. I am looking alter the formatting of my taxonomy terms. I would like to display the tags like such: tag \ tag \ tag

They are currently displaying like so: tag,tag,tag,

This field lives in the node and has a field name of field_tags... but where i am confused is how I can have the system display these terms in this format?

Thanks

Hi Matt,

For that you want to read our other article about creating new field formatters, it's quite simple, and will be mostly copy/pasting from the taxonomy_reference formatters I expect, good luck!

Hi Matt, actually you might just want to use the Taxonomy Formatter project.

Comments on this article are now closed, if you want to give us feeback you can use our contact form instead.