7.x field.attach.inc field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $options = array())

Loads fields for the current revisions of a group of entities.

Loads all fields for each entity object in a group of a single entity type. The loaded field values are added directly to the entity objects.

field_attach_load() is automatically called by the default entity controller class, and thus, in most cases, doesn't need to be explicitly called by the entity type module.


$entity_type: The type of $entity; e.g., 'node' or 'user'.

$entities: An array of entities for which to load fields, keyed by entity ID. Each entity needs to have its 'bundle', 'id' and (if applicable) 'revision' keys filled in. The function adds the loaded field data directly in the entity objects of the $entities array.

$age: FIELD_LOAD_CURRENT to load the most recent revision for all fields, or FIELD_LOAD_REVISION to load the version indicated by each entity. Defaults to FIELD_LOAD_CURRENT; use field_attach_load_revision() instead of passing FIELD_LOAD_REVISION.

$options: An associative array of additional options, with the following keys:

  • 'field_id': The field ID that should be loaded, instead of loading all fields, for each entity. Note that returned entities may contain data for other fields, for example if they are read from a cache.
  • 'deleted': If TRUE, the function will operate on deleted fields as well as non-deleted fields. If unset or FALSE, only non-deleted fields are operated on.

Related topics

22 calls to field_attach_load()
comment_reply in modules/comment/comment.pages.inc
This function is responsible for generating a comment reply form. There are several cases that have to be handled, including:
DrupalDefaultEntityController::attachLoad in includes/entity.inc
Attaches data to entities upon loading.
FieldAttachOtherTestCase::testFieldAttachCache in modules/field/tests/field.test
Test field cache.
FieldAttachStorageTestCase::testFieldAttachCreateRenameBundle in modules/field/tests/field.test
Test field_attach_create_bundle() and field_attach_rename_bundle().
FieldAttachStorageTestCase::testFieldAttachDelete in modules/field/tests/field.test
Test field_attach_delete().

... See full list


modules/field/field.attach.inc, line 622
Field attach API, allowing entities (nodes, users, ...) to be 'fieldable'.


function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $options = array()) {
  $load_current = $age == FIELD_LOAD_CURRENT;

  // Merge default options.
  $default_options = array(
    'deleted' => FALSE,
  $options += $default_options;

  $info = entity_get_info($entity_type);
  // Only the most current revision of non-deleted fields for cacheable entity
  // types can be cached.
  $cache_read = $load_current && $info['field cache'] && empty($options['deleted']);
  // In addition, do not write to the cache when loading a single field.
  $cache_write = $cache_read && !isset($options['field_id']);

  if (empty($entities)) {

  // Assume all entities will need to be queried. Entities found in the cache
  // will be removed from the list.
  $queried_entities = $entities;

  // Fetch available entities from cache, if applicable.
  if ($cache_read) {
    // Build the list of cache entries to retrieve.
    $cids = array();
    foreach ($entities as $id => $entity) {
      $cids[] = "field:$entity_type:$id";
    $cache = cache_get_multiple($cids, 'cache_field');
    // Put the cached field values back into the entities and remove them from
    // the list of entities to query.
    foreach ($entities as $id => $entity) {
      $cid = "field:$entity_type:$id";
      if (isset($cache[$cid])) {
        foreach ($cache[$cid]->data as $field_name => $values) {
          $entity->$field_name = $values;

  // Fetch other entities from their storage location.
  if ($queried_entities) {
    // The invoke order is:
    // - hook_field_storage_pre_load()
    // - storage backend's hook_field_storage_load()
    // - field-type module's hook_field_load()
    // - hook_field_attach_load()

    // Invoke hook_field_storage_pre_load(): let any module load field
    // data before the storage engine, accumulating along the way.
    $skip_fields = array();
    foreach (module_implements('field_storage_pre_load') as $module) {
      $function = $module . '_field_storage_pre_load';
      $function($entity_type, $queried_entities, $age, $skip_fields, $options);

    $instances = array();

    // Collect the storage backends used by the remaining fields in the entities.
    $storages = array();
    foreach ($queried_entities as $entity) {
      list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
      $instances = _field_invoke_get_instances($entity_type, $bundle, $options);

      foreach ($instances as $instance) {
        $field_name = $instance['field_name'];
        $field_id = $instance['field_id'];
        // Make sure all fields are present at least as empty arrays.
        if (!isset($queried_entities[$id]->{$field_name})) {
          $queried_entities[$id]->{$field_name} = array();
        // Collect the storage backend if the field has not been loaded yet.
        if (!isset($skip_fields[$field_id])) {
          $field = field_info_field_by_id($field_id);
          $storages[$field['storage']['type']][$field_id][] = $load_current ? $id : $vid;

    // Invoke hook_field_storage_load() on the relevant storage backends.
    foreach ($storages as $storage => $fields) {
      $storage_info = field_info_storage_types($storage);
      module_invoke($storage_info['module'], 'field_storage_load', $entity_type, $queried_entities, $age, $fields, $options);

    // Invoke field-type module's hook_field_load().
    $null = NULL;
    _field_invoke_multiple('load', $entity_type, $queried_entities, $age, $null, $options);

    // Invoke hook_field_attach_load(): let other modules act on loading the
    // entity.
    module_invoke_all('field_attach_load', $entity_type, $queried_entities, $age, $options);

    // Build cache data.
    if ($cache_write) {
      foreach ($queried_entities as $id => $entity) {
        $data = array();
        list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
        $instances = field_info_instances($entity_type, $bundle);
        foreach ($instances as $instance) {
          $data[$instance['field_name']] = $queried_entities[$id]->{$instance['field_name']};
        $cid = "field:$entity_type:$id";
        cache_set($cid, $data, 'cache_field');


jamiehollern’s picture

Please note that data returned from field_info_instances can't be directly passed to this function. field_info_instances returns an array of objects with the keys "type", "nid" and "vid". field_attach_load expects an array of arrays with the keys "bundle", "id" and "revision".

jamiehollern’s picture

Actually, I'm talking crap. Ignore the above.

dshumaker’s picture

Hi @jamiehollern,
I landed here because I might be having the same issue you discovered or reported.
In wanting to do a FieldEntityQuery as suggested here and here:

You'll do a FieldEntityQuery and get results that do not contain a bundle specification that field_attach_load expects. So in following the examples in the previous two links I'm getting a
EntityMalformedException: Missing bundle property on entity of type node. in entity_extract_ids() (line 7729 of /var/www/vcd/docroot/includes/common.inc)

And you can't just add the field to the array because it's an array of objects. I know I'm probably still missing something because the other authors got it work but as of yet I don't know what I'm missing and would love to know if you solved your issue as it might be mine as well.

When I do some dd()'s I'm seeing this structure from the result of EntityFieldQuery:

    [node] => Array
            [472] => stdClass Object
                    [nid] => 472
                    [vid] => 472
                    [type] => campaign



and I believe what's necessary is something like this:

    [node] => Array
            [472] => stdClass Object
                    [nid] => 472
                    [vid] => 472
                    [type] => campaign
                    [bundle] => campaign

I wish field_attach_load would be smart enough to know that type is bundle.

dshumaker’s picture

Turns out I didn't need the field_get_items because the field_attach_load was not the problem. I commented out my field_get_items because it was what was causing the MalFormed Exception and the field_attach_load was working just fine.

Hopefully helpful to someone.

cristiroma’s picture

    $fields = field_info_instances('node', 'car');
    $rows = array($nid => (object)array('nid' => $nid, 'vid' => NULL, 'type' => 'car'));
    field_attach_load('node', $rows, FIELD_LOAD_CURRENT, array('field_id' => $fields['field_cubic_capacity']['field_id']));
Gik000’s picture

Void return and no variable passed reference, how this function manage the returning values?
How can amend $entities and return them?

For example

$field_id = NUMERIC FIELD ID
field_attach_load('documents', $docs, FIELD_LOAD_CURRENT, array('field_id' => $field_id));
//here $docs is changed! how come?!

Furthermore I got many fields back, not just the required one, what I expected was an entity with the basic field (id, vid, bundle ...) and the one I passed to the function, but that's not true because I found the whole entity inside $entities['MY INDEX'] after field_attach_load!

I'm perplexed

juampynr’s picture