Labs

By John Ennew | 31st January 2012

Accessing field data in code for Drupal 7

This blog post is about the possible ways to access field data attached to an entity in code.

After loading an entity, such as a node, any fields are attached to the node object as arrays. For example, below is part of a loaded node object:

object(stdClass)#217 (29) {
  ["vid"]=>
  string(1) "1"
  ["uid"]=>
  string(1) "1"
  ["title"]=>
  string(24) "My example node"
  ["body"]=>
  array(1) {
    ["und"]=>
    array(1) {
      [0]=>
      array(5) {
        ["value"]=>
        string(38) "Here is some example text"
        ["summary"]=>
        string(0) ""
        ["format"]=>
        string(13) "filtered_html"
        ["safe_value"]=>
        string(46) "<p>Here is some example text</p>"
        ["safe_summary"]=>
        string(0) ""
      }
    }
  }
}

Here we see the body field as an array attached to the node. To read the value of the data stored in the body text we might access it directly via it's "und" language element:

  $body_text = $node->body['und'][0]['value'];

Or, more correctly:

  $body_text = $node->body[LANGUAGE_NONE][0]['value'];

However, this approach does not work in all cases as the 'und' key will change if the locale module is enabled. For English language sites this will be 'en'. In multi language sites there may be a number of different keys. We need a way of identifying the language the current user has selected and always read that key.

One approach is the field_get_items() function. This returns just the array of values for the user's configured language.

  $body_values = field_get_items('node', $node, 'body');
  $body_text = $body_values[0]['value'];

This works fine and gets round the language problem but it doesn't provide very clean code. Imagine if you needed to read more than one field, you would need to run this for each field...

  $body_values = field_get_items('node', $node, 'body');
  $body_text = $body_values[0]['value'];
  $some_taxonomy_values = field_get_items('node', $node, 'field_taxonomy_a');
  $some_taxonomy_term = taxonomy_term_load($some_taxonomy_values[0]['tid']);

There is another method provided by the entity api module called entity_metadata_wrapper. This returns an object of type EntityMetadataWrapper. This docs for this make it look complicated but that's because it is very powerful and lets you traverse all entity types in a variety of ways. For our purposes here though we need only know the general pattern for accessing entity fields.

Now, in one line we can get the value of the body text field on a node.

  $body_text = entity_metadata_wrapper('node', $node)->body->value();

Another example allows us to load a full taxonomy_term entity from a term reference field on the node in one line. This doesn't just return the term tid but the fully loaded term object.

  $some_taxonomy_term = entity_metadata_wrapper('node', $node)->field_taxonomy_a->value();

Indeed this would work for any node referenced by a entityreference field on a node

  $other_node = entity_metadata_wrapper('node', $node)->field_some_entityref->value();

Looping through multiple fields via entity_metadata_wrapper

When you access a field via the metadata wrapper, it is an object which is returned and this object extends the PHP iterator interfaces which allows looping over the elements of multiple fields.

  $wrapper = entity_metadata_wrapper('node', $node); 
  foreach ($wrapper->field_taxonomy_a->value() as $taxonomy) {
    // $taxonomy is a fully loaded taxonomy entity.   
  }  

Note that a field might be setup to have either 1 or multiple values. The type of value returned by the function $wrapper->field_taxonomy_a->value() will change depending on each of these cases. In the case that it can only have 1 value, then that value is returned. If it can have multiple values, an array is returned. For the empty cases, where no term is selected, a multiple field will return an empty array, a single value field will return NULL.

Modifying an entity through entity_metadata_wrapper

The wrapper object doesn't just make it easy to read data from an entity, it also provides a standard way of modifying an entity. In the simple case, suppose you would like to change the title of a node.

	$wrapper = entity_metadata_wrapper('node', $node);
	$wrapper->title = 'My new title';
	$wrapper->save();
        node_save($node);

This doesn't add much to the usual node_save procedure but the process is now the same for all entities, no need for different function names for different entity types. However, it becomes more powerful when editing fields. For example, to change the body text ...

	$wrapper = entity_metadata_wrapper('node', $node);
	$wrapper->body = array(
	  'value' => 'My new body text value',
	  'format' => 'filtered_html',
    );
	$wrapper->save();
        node_save($node);

You can make several modifications to fields of a node using the same wrapper before finally calling node_save.

Comments

Thanks for this awesome tutorial :)

Little correction $wrapper-save(); will be $wrapper->save();
Nothing big :) Thanks again

John Ennew's picture
John Ennew
John Ennew

Thanks for your comment! All corrected.

Add new comment