From 6a13eb22fc5c7c2a27d6c18e8ec99493f1566350 Mon Sep 17 00:00:00 2001
From: Dries Buytaert <dries@buytaert.net>
Date: Sat, 12 Dec 2009 20:16:03 +0000
Subject: [PATCH] - Patch #657828 by yched: make hook_field_formatter() act on
 all field values.

---
 modules/field/field.api.php                | 82 ++++++++++------------
 modules/field/field.attach.inc             | 10 +--
 modules/field/field.default.inc            | 53 +++++++-------
 modules/field/field.info.inc               | 19 -----
 modules/field/modules/list/list.module     | 27 +++----
 modules/field/modules/number/number.module | 34 ++++-----
 modules/field/modules/text/text.module     | 38 +++++-----
 modules/field/tests/field_test.field.inc   | 24 +++----
 modules/field/theme/field.tpl.php          | 20 +++---
 modules/file/file.field.inc                | 29 ++++----
 modules/image/image.field.inc              | 30 ++++----
 modules/taxonomy/taxonomy.module           | 46 ++++++------
 12 files changed, 192 insertions(+), 220 deletions(-)

diff --git a/modules/field/field.api.php b/modules/field/field.api.php
index 4e1481a8634b..af76ecf6c112 100644
--- a/modules/field/field.api.php
+++ b/modules/field/field.api.php
@@ -711,30 +711,16 @@ function hook_field_widget_error($element, $error) {
  *   - settings: An array whose keys are the names of the settings available
  *     for the formatter type, and whose values are the default values for
  *     those settings.
- *   - behaviors: (optional) An array describing behaviors of the formatter.
- *     - multiple values:
- *       FIELD_BEHAVIOR_DEFAULT (default) if the formatter displays one single
- *       field value (most common case). The formatter theme will be invoked
- *       iteratively on each of the field valies.
- *       FIELD_BEHAVIOR_CUSTOM if one single invocation of the formatter theme
- *       takes care of displaying all the field values. Examples: points on a
- *       generated graph picture, a Google map, a single link to a popup...
  */
 function hook_field_formatter_info() {
   return array(
     'text_default' => array(
       'label' => t('Default'),
       'field types' => array('text', 'text_long', 'text_with_summary'),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
-      ),
     ),
     'text_plain' => array(
       'label' => t('Plain text'),
       'field types' => array('text', 'text_long', 'text_with_summary'),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
-      ),
     ),
 
     // The text_trimmed formatter displays the trimmed version of the
@@ -745,9 +731,6 @@ function hook_field_formatter_info() {
     'text_trimmed' => array(
       'label' => t('Trimmed'),
       'field types' => array('text', 'text_long', 'text_with_summary'),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
-      ),
     ),
 
     // The 'summary or trimmed' field formatter for text_with_summary
@@ -757,9 +740,6 @@ function hook_field_formatter_info() {
     'text_summary_or_trimmed' => array(
       'label' => t('Summary or trimmed'),
       'field types' => array('text_with_summary'),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
-      ),
     ),
   );
 }
@@ -827,46 +807,60 @@ function hook_field_formatter_prepare_view($obj_type, $objects, $field, $instanc
  *   The field instance.
  * @param $langcode
  *   The language associated to $items.
- * @param $display
- *   The display settings to use, as found in the 'display' entry of instance
- *   definitions.
  * @param $items
  *   Array of values for this field.
- * @param $delta
+ * @param $display
+ *   The display settings to use, as found in the 'display' entry of instance
+ *   definitions. The array notably contains the following keys and values;
+ *   - type: The name of the formatter to use.
+ *   - settings: The array of formatter settings.
  *
  * @return
+ *   A renderable array for the $items, as an array of child elements keyed
+ *   by numeric indexes starting from 0.
  */
-function hook_field_formatter($obj_type, $object, $field, $instance, $langcode, $display, $items, $delta) {
+function hook_field_formatter($obj_type, $object, $field, $instance, $langcode, $items, $display) {
+  $element = array();
   $settings = $display['settings'];
 
   switch ($display['type']) {
-    case 'field_test_default':
-      // Sample code for a 'single' formatter, displaying one single field
-      // value (the hook_field_formatter_info() entry uses
-      // 'multiple values' = FIELD_BEHAVIOR_DEFAULT).
-      $item = $items[$delta];
-      $result = array(
-        '#markup' => $item['value'],
-      );
+    case 'sample_field_formatter_simple':
+      // Common case: each value is displayed individually in a sub-element
+      // keyed by delta. The field.tpl.php template specifies the markup
+      // wrapping each value.
+      foreach ($items as $delta => $item) {
+        $element[$delta] = array('#markup' => $settings['some_setting'] . $item['value']);
+      }
       break;
 
-    case 'field_test_multiple':
-      // Sample code for a 'multiple' formatter, displaying all the field
-      // values (the hook_field_formatter_info() entry uses
-      // 'multiple values' = FIELD_BEHAVIOR_CUSTOM).
-      $array = array();
+    case 'sample_field_formatter_themeable':
+      // More elaborate formatters can defer to a theme function for easier
+      // customization.
       foreach ($items as $delta => $item) {
-        $array[] = $delta .':'. $item['value'];
+        $element[$delta] = array(
+          '#theme' => 'mymodule_theme_sample_field_formatter_themeable',
+          '#data' => $item['value'],
+          '#some_setting' => $settings['some_setting'],
+        );
       }
-      $result = array(
-        '#markup' => implode('|', $array),
+      break;
+
+    case 'sample_field_formatter_combined':
+      // Some formatters might need to display all values within a single piece
+      // of markup.
+      $rows = array();
+      foreach ($items as $delta => $item) {
+        $rows[] = array($delta, $item['value']);
+      }
+      $element[0] = array(
+        '#theme' => 'table',
+        '#header' => array(t('Delta'), t('Value')),
+        '#rows' => $rows,
       );
       break;
   }
 
-  return array(
-    '#markup' => $output,
-  );
+  return $element;
 }
 
 /**
diff --git a/modules/field/field.attach.inc b/modules/field/field.attach.inc
index 7daca8468fc6..1b55180cdb17 100644
--- a/modules/field/field.attach.inc
+++ b/modules/field/field.attach.inc
@@ -1134,15 +1134,7 @@ function field_attach_prepare_view($obj_type, $objects, $build_mode = 'full') {
  *     '#formatter' => the name of the formatter,
  *     '#items' => the field values being displayed,
  *     // The element's children are the formatted values returned by
- *     // hook_field_formatter(), keyed by delta.
- *     0 => array(
- *       // Renderable array for value 0, or for all values if the formatter
- *       // is 'multiple-values'.
- *     ),
- *     1 => array(
- *       // Renderable array for value 1 (only for 'single-value' formatters).
- *     ),
- *     // ...
+ *     // hook_field_formatter().
  *   ),
  * );
  * @endcode
diff --git a/modules/field/field.default.inc b/modules/field/field.default.inc
index b86f8b222ad1..7ab203d1455e 100644
--- a/modules/field/field.default.inc
+++ b/modules/field/field.default.inc
@@ -90,44 +90,41 @@ function field_default_view($obj_type, $object, $field, $instance, $langcode, $i
   list($id, $vid, $bundle) = entity_extract_ids($obj_type, $object);
 
   $addition = array();
-  $display = $instance['display'][$build_mode];
 
+  $display = $instance['display'][$build_mode];
   if ($display['type'] !== 'hidden') {
+    // We never want to index fields labels.
     if ($build_mode == 'search_index') {
       $display['label'] = 'hidden';
     }
 
-    $element = array(
-      '#theme' => 'field',
-      '#weight' => $display['weight'],
-      '#title' => t($instance['label']),
-      '#access' => field_access('view', $field, $obj_type, $object),
-      '#label_display' => $display['label'],
-      '#build_mode' => $build_mode,
-      '#language' => $langcode,
-      '#field_name' => $field['field_name'],
-      '#field_type' => $field['type'],
-      '#object_type' => $obj_type,
-      '#bundle' => $bundle,
-      '#object' => $object,
-      '#items' => $items,
-      '#formatter' => $display['type'],
-    );
-
     // Calling the formatter function through module_invoke() can have a
     // performance impact on pages with many fields and values.
-    $formatter_function = $display['module'] . '_field_formatter';
-    if (field_behaviors_formatter('multiple values', $display) == FIELD_BEHAVIOR_DEFAULT) {
-      foreach ($items as $delta => $item) {
-        $element[$delta] = $formatter_function($obj_type, $object, $field, $instance, $langcode, $display, $items, $delta);
-        $element[$delta]['#weight'] = $delta;
-      }
-    }
-    else {
-      $element[0] = $formatter_function($obj_type, $object, $field, $instance, $langcode, $display, $items, 0);
+    $function = $display['module'] . '_field_formatter';
+    if (function_exists($function)) {
+      $elements = $function($obj_type, $object, $field, $instance, $langcode, $items, $display);
     }
 
-    $addition = array($field['field_name'] => $element);
+    if ($elements) {
+      $info = array(
+        '#theme' => 'field',
+        '#weight' => $display['weight'],
+        '#title' => t($instance['label']),
+        '#access' => field_access('view', $field, $obj_type, $object),
+        '#label_display' => $display['label'],
+        '#build_mode' => $build_mode,
+        '#language' => $langcode,
+        '#field_name' => $field['field_name'],
+        '#field_type' => $field['type'],
+        '#object_type' => $obj_type,
+        '#bundle' => $bundle,
+        '#object' => $object,
+        '#items' => $items,
+        '#formatter' => $display['type']
+      );
+
+      $addition[$field['field_name']] = array_merge($info, $elements);
+    }
   }
 
   return $addition;
diff --git a/modules/field/field.info.inc b/modules/field/field.info.inc
index 13d5030f7100..e4df3a391c6c 100644
--- a/modules/field/field.info.inc
+++ b/modules/field/field.info.inc
@@ -326,25 +326,6 @@ function field_behaviors_widget($op, $instance) {
   return isset($info['behaviors'][$op]) ? $info['behaviors'][$op] : FIELD_BEHAVIOR_DEFAULT;
 }
 
-/**
- * Determines the behavior of a formatter with respect to an operation.
- *
- * @param $op
- *   The name of the operation. Currently supported: 'multiple values'.
- * @param $display
- *   The $instance['display'][$build_mode] array.
- *
- * @return
- *   One of these values:
- *   - FIELD_BEHAVIOR_NONE: Do nothing for this operation.
- *   - FIELD_BEHAVIOR_CUSTOM: Use the formatter's callback function.
- *   - FIELD_BEHAVIOR_DEFAULT: Use field module default behavior.
- */
-function field_behaviors_formatter($op, $display) {
-  $info = field_info_formatter_types($display['type']);
-  return isset($info['behaviors'][$op]) ? $info['behaviors'][$op] : FIELD_BEHAVIOR_DEFAULT;
-}
-
 /**
  * Returns information about field types from hook_field_info().
  *
diff --git a/modules/field/modules/list/list.module b/modules/field/modules/list/list.module
index b52dfd40b128..0b8496f44e60 100644
--- a/modules/field/modules/list/list.module
+++ b/modules/field/modules/list/list.module
@@ -300,27 +300,30 @@ function list_field_formatter_info() {
 /**
  * Implements hook_field_formatter().
  */
-function list_field_formatter($object_type, $object, $field, $instance, $langcode, $display, $items, $delta) {
-  $value = $items[$delta]['value'];
+function list_field_formatter($object_type, $object, $field, $instance, $langcode, $items, $display) {
+  $element = array();
 
   switch ($display['type']) {
     case 'list_default':
       $allowed_values = list_allowed_values($field);
-      if (isset($allowed_values[$value])) {
-        $output = $allowed_values[$value];
-      }
-      else {
-        // If no match was found in allowed values, fall back to the key.
-        $output = $value;
+      foreach ($items as $delta => $item) {
+        if (isset($allowed_values[$item['value']])) {
+          $output = $allowed_values[$item['value']];
+        }
+        else {
+          // If no match was found in allowed values, fall back to the key.
+          $output = $value;
+        }
+        $element[$delta] = array('#markup' => $output);
       }
       break;
 
     case 'list_key':
-      $output = $value;
+      foreach ($items as $delta => $item) {
+        $element[$delta] = array('#markup' => $item['value']);
+      }
       break;
   }
 
-  return array(
-    '#markup' => $output,
-  );
+  return $element;
 }
diff --git a/modules/field/modules/number/number.module b/modules/field/modules/number/number.module
index 710d82e5487c..5c03db5a59c3 100644
--- a/modules/field/modules/number/number.module
+++ b/modules/field/modules/number/number.module
@@ -242,34 +242,34 @@ function number_field_formatter_info() {
 /**
  * Implements hook_field_formatter().
  */
-function number_field_formatter($object_type, $object, $field, $instance, $langcode, $display, $items, $delta) {
-  $value = $items[$delta]['value'];
+function number_field_formatter($object_type, $object, $field, $instance, $langcode, $items, $display) {
+  $element = array();
+  $settings = $display['settings'];
 
   switch ($display['type']) {
     case 'number_integer':
     case 'number_decimal':
-      $settings = $display['settings'];
-      if (empty($value) && $value !== '0') {
-        return '';
-      }
-      $output = number_format($value, $settings['scale'], $settings['decimal_separator'], $settings['thousand_separator']);
-      if ($settings['prefix_suffix']) {
-        $prefixes = isset($instance['settings']['prefix']) ? array_map('field_filter_xss', explode('|', $instance['settings']['prefix'])) : array('');
-        $suffixes = isset($instance['settings']['suffix']) ? array_map('field_filter_xss', explode('|', $instance['settings']['suffix'])) : array('');
-        $prefix = (count($prefixes) > 1) ? format_plural($value, $prefixes[0], $prefixes[1]) : $prefixes[0];
-        $suffix = (count($suffixes) > 1) ? format_plural($value, $suffixes[0], $suffixes[1]) : $suffixes[0];
-        $output = $prefix . $output . $suffix;
+      foreach ($items as $delta => $item) {
+        $output = number_format($item['value'], $settings['scale'], $settings['decimal_separator'], $settings['thousand_separator']);
+        if ($settings['prefix_suffix']) {
+          $prefixes = isset($instance['settings']['prefix']) ? array_map('field_filter_xss', explode('|', $instance['settings']['prefix'])) : array('');
+          $suffixes = isset($instance['settings']['suffix']) ? array_map('field_filter_xss', explode('|', $instance['settings']['suffix'])) : array('');
+          $prefix = (count($prefixes) > 1) ? format_plural($item['value'], $prefixes[0], $prefixes[1]) : $prefixes[0];
+          $suffix = (count($suffixes) > 1) ? format_plural($item['value'], $suffixes[0], $suffixes[1]) : $suffixes[0];
+          $output = $prefix . $output . $suffix;
+        }
+        $element[$delta] = array('#markup' => $output);
       }
       break;
 
     case 'number_unformatted':
-      $output = $value;
+      foreach ($items as $delta => $item) {
+        $element[$delta] = array('#markup' => $item['value']);
+      }
       break;
   }
 
-  return array(
-    '#markup' => $output,
-  );
+  return $element;
 }
 
 /**
diff --git a/modules/field/modules/text/text.module b/modules/field/modules/text/text.module
index 97b71571f284..06609fcd96b4 100644
--- a/modules/field/modules/text/text.module
+++ b/modules/field/modules/text/text.module
@@ -251,37 +251,43 @@ function text_field_formatter_info() {
 /**
  * Implements hook_field_formatter().
  */
-function text_field_formatter($object_type, $object, $field, $instance, $langcode, $display, $items, $delta) {
-  $item = $items[$delta];
+function text_field_formatter($object_type, $object, $field, $instance, $langcode, $items, $display) {
+  $element = array();
 
   switch ($display['type']) {
     case 'text_default':
     case 'text_trimmed':
-      $output = _text_sanitize($instance, $langcode, $item, 'value');
-      if ($display['type'] == 'text_trimemd') {
-        $output = text_summary($output, $instance['settings']['text_processing'] ? $item['format'] : NULL);
+      foreach ($items as $delta => $item) {
+        $output = _text_sanitize($instance, $langcode, $item, 'value');
+        if ($display['type'] == 'text_trimemd') {
+          $output = text_summary($output, $instance['settings']['text_processing'] ? $item['format'] : NULL);
+        }
+        $element[$delta] = array('#markup' => $output);
       }
       break;
 
     case 'text_summary_or_trimmed':
-      if (!empty($item['summary'])) {
-        $output = _text_sanitize($instance, $langcode, $item, 'summary');
-      }
-      else {
-        $output = _text_sanitize($instance, $langcode, $item, 'value');
-        $size = variable_get('teaser_length_' . $instance['bundle'], 600);
-        $output = text_summary($output, $instance['settings']['text_processing'] ? $item['format'] : NULL, $size);
+      foreach ($items as $delta => $item) {
+        if (!empty($item['summary'])) {
+          $output = _text_sanitize($instance, $langcode, $item, 'summary');
+        }
+        else {
+          $output = _text_sanitize($instance, $langcode, $item, 'value');
+          $size = variable_get('teaser_length_' . $instance['bundle'], 600);
+          $output = text_summary($output, $instance['settings']['text_processing'] ? $item['format'] : NULL, $size);
+        }
+        $element[$delta] = array('#markup' => $output);
       }
       break;
 
     case 'text_plain':
-      $output = strip_tags($item['value']);
+      foreach ($items as $delta => $item) {
+        $element[$delta] = array('#markup' => strip_tags($item['value']));
+      }
       break;
   }
 
-  return array(
-    '#markup' => $output,
-  );
+  return $element;
 }
 
 /**
diff --git a/modules/field/tests/field_test.field.inc b/modules/field/tests/field_test.field.inc
index 5097a3357a9c..89def7e10688 100644
--- a/modules/field/tests/field_test.field.inc
+++ b/modules/field/tests/field_test.field.inc
@@ -211,9 +211,6 @@ function field_test_field_formatter_info() {
       'settings' => array(
         'test_formatter_setting_multiple' => 'dummy test string',
       ),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
-      ),
     ),
     'field_test_needs_additional_data' => array(
       'label' => t('Tests hook_field_formatter_prepare_view()'),
@@ -246,32 +243,33 @@ function field_test_field_formatter_prepare_view($obj_type, $objects, $field, $i
 /**
  * Implements hook_field_formatter().
  */
-function field_test_field_formatter($object_type, $object, $field, $instance, $langcode, $display, $items, $delta) {
+function field_test_field_formatter($object_type, $object, $field, $instance, $langcode, $items, $display) {
+  $element = array();
   $settings = $display['settings'];
 
   switch ($display['type']) {
     case 'field_test_default':
-      $item = $items[$delta];
-      $output = $settings['test_formatter_setting'] . '|' . $item['value'];
+      foreach ($items as $delta => $item) {
+        $element[$delta] = array('#markup' => $settings['test_formatter_setting'] . '|' . $item['value']);
+      }
       break;
 
     case 'field_test_needs_additional_data':
-      $item = $items[$delta];
-      $output = $settings['test_formatter_setting_additional'] . '|' . $item['value'] . '|' . $item['additional_formatter_value'];
+      foreach ($items as $delta => $item) {
+        $element[$delta] = array('#markup' => $settings['test_formatter_setting_additional'] . '|' . $item['value'] . '|' . $item['additional_formatter_value']);
+      }
       break;
 
     case 'field_test_multiple':
       $array = array();
       foreach ($items as $delta => $item) {
-        $array[] = $delta .':'. $item['value'];
+        $array[] = $delta . ':' . $item['value'];
       }
-      $output = $settings['test_formatter_setting_multiple'] . '|' . implode('|', $array);
+      $element[0] = array('#markup' => $settings['test_formatter_setting_multiple'] . '|' . implode('|', $array));
       break;
   }
 
-  return array(
-    '#markup' => $output,
-  );
+  return $element;
 }
 
 /**
diff --git a/modules/field/theme/field.tpl.php b/modules/field/theme/field.tpl.php
index a35fd7615835..1c8be235da23 100644
--- a/modules/field/theme/field.tpl.php
+++ b/modules/field/theme/field.tpl.php
@@ -38,15 +38,13 @@
  * @see template_preprocess_field()
  */
 ?>
-<?php if ($items) : ?>
-  <div class="field <?php print $classes; ?> clearfix"<?php print $attributes; ?>>
-    <?php if (!$label_hidden) : ?>
-      <div class="field-label"<?php print $title_attributes; ?>><?php print $label ?>:&nbsp;</div>
-    <?php endif; ?>
-    <div class="field-items"<?php print $content_attributes; ?>>
-      <?php foreach ($items as $delta => $item) : ?>
-        <div class="field-item <?php print $delta % 2 ? 'odd' : 'even'; ?>"<?php print $item_attributes[$delta]; ?>><?php print render($item); ?></div>
-      <?php endforeach; ?>
-    </div>
+<div class="field <?php print $classes; ?> clearfix"<?php print $attributes; ?>>
+  <?php if (!$label_hidden) : ?>
+    <div class="field-label"<?php print $title_attributes; ?>><?php print $label ?>:&nbsp;</div>
+  <?php endif; ?>
+  <div class="field-items"<?php print $content_attributes; ?>>
+    <?php foreach ($items as $delta => $item) : ?>
+      <div class="field-item <?php print $delta % 2 ? 'odd' : 'even'; ?>"<?php print $item_attributes[$delta]; ?>><?php print render($item); ?></div>
+    <?php endforeach; ?>
   </div>
-<?php endif; ?>
+</div>
diff --git a/modules/file/file.field.inc b/modules/file/file.field.inc
index 7470d3d1e615..456598606e2a 100644
--- a/modules/file/file.field.inc
+++ b/modules/file/file.field.inc
@@ -373,9 +373,6 @@ function file_field_formatter_info() {
     'file_table' => array(
       'label' => t('Table of files'),
       'field types' => array('file'),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
-      ),
     ),
     'file_url_plain' => array(
       'label' => t('URL to file'),
@@ -846,33 +843,35 @@ function theme_file_upload_help($variables) {
 /**
  * Implements hook_field_formatter().
  */
-function file_field_formatter($obj_type, $object, $field, $instance, $langcode, $display, $items, $delta) {
-  $item = $items[$delta];
+function file_field_formatter($obj_type, $object, $field, $instance, $langcode, $items, $display) {
+  $element = array();
 
   switch ($display['type']) {
     case 'file_default':
-      $result = array(
-        '#theme' => 'file_link',
-        '#file' => (object) $item,
-      );
+      foreach ($items as $delta => $item) {
+        $element[$delta] = array(
+          '#theme' => 'file_link',
+          '#file' => (object) $item,
+        );
+      }
       break;
 
     case 'file_url_plain':
-      $result = array(
-        '#markup' => empty($item['uri']) ? '' : file_create_url($item['uri']),
-      );
+      foreach ($items as $delta => $item) {
+        $element[$delta] = array('#markup' => empty($item['uri']) ? '' : file_create_url($item['uri']));
+      }
       break;
 
     case 'file_table':
-      // Multiple formatter, dealing with all $items.
-      $result = array(
+      // Display all values in a single element..
+      $element[0] = array(
         '#theme' => 'file_formatter_table',
         '#items' => $items,
       );
       break;
   }
 
-  return $result;
+  return $element;
 }
 
 /**
diff --git a/modules/image/image.field.inc b/modules/image/image.field.inc
index 3ab6f7090299..f52193cb99ad 100644
--- a/modules/image/image.field.inc
+++ b/modules/image/image.field.inc
@@ -450,31 +450,37 @@ function image_field_formatter_info() {
 /**
  * Implements hook_field_formatter().
  */
-function image_field_formatter($obj_type, $object, $field, $instance, $langcode, $display, $items, $delta) {
-  $item = $items[$delta];
-  $image_style = '';
-  $path = '';
+function image_field_formatter($obj_type, $object, $field, $instance, $langcode, $items, $display) {
+  $element = array();
 
-  // Check if this requires a particular image style.
+  // Check if the formatter involves a particular image style.
   $matches = array();
   if (preg_match('/__([a-z0-9_]+)/', $display['type'], $matches)) {
     $image_style = $matches[1];
   }
 
+  // Check if the formatter involves a link.
   if (strpos($display['type'], 'image_link_content') === 0) {
     list($id) = entity_extract_ids($obj_type, $object);
     $path = $obj_type . '/' . $id;
   }
   elseif (strpos($display['type'], 'image_link_file') === 0) {
-    $path = file_create_url($item['uri']);
+    $link_file = TRUE;
   }
 
-  return array(
-    '#theme' => 'image_formatter',
-    '#item' => $item,
-    '#image_style' => $image_style,
-    '#path' => $path,
-  );
+  foreach ($items as $delta => $item) {
+    if (isset($link_file)) {
+      $path = file_create_url($item['uri']);
+    }
+    $element[$delta] = array(
+      '#theme' => 'image_formatter',
+      '#item' => $item,
+      '#image_style' => isset($image_style) ? $image_style : '',
+      '#path' => isset($path) ? $path : '',
+    );
+  }
+
+   return $element;
 }
 
 /**
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index 1eb295d39021..a15e7b4ba37c 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -1087,16 +1087,10 @@ function taxonomy_field_formatter_info() {
     'taxonomy_term_link' => array(
       'label' => t('Link'),
       'field types' => array('taxonomy_term'),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
-      ),
     ),
     'taxonomy_term_plain' => array(
       'label' => t('Plain text'),
       'field types' => array('taxonomy_term'),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
-      ),
     ),
   );
 }
@@ -1104,34 +1098,38 @@ function taxonomy_field_formatter_info() {
 /**
  * Implements hook_field_formatter().
  */
-function taxonomy_field_formatter($object_type, $object, $field, $instance, $langcode, $display, $items, $delta) {
-  $item = $items[$delta];
+function taxonomy_field_formatter($object_type, $object, $field, $instance, $langcode, $items, $display) {
+  $element = array();
 
   switch ($display['type']) {
     case 'taxonomy_term_link':
-      // @todo Remove this when "node_build() does not call
-      // field_attach_prepare_view()" bug is fixed.
-      // See http://drupal.org/node/493314.
-      if (!isset($item['taxonomy_term'])) {
-        $item['taxonomy_term'] = taxonomy_term_load($item['tid']);
+      foreach ($items as $delta => $item) {
+        // @todo Remove this when "node_build() does not call
+        // field_attach_prepare_view()" bug is fixed.
+        // See http://drupal.org/node/493314.
+        if (!isset($item['taxonomy_term'])) {
+          $item['taxonomy_term'] = taxonomy_term_load($item['tid']);
+        }
+        $term = $item['taxonomy_term'];
+        $element[$delta] = array(
+          '#type' => 'link',
+          '#title' => $term->name,
+          '#href' => 'taxonomy/term/' . $term->tid,
+        );
       }
-      $term = $item['taxonomy_term'];
-      $result = array(
-        '#type' => 'link',
-        '#title' => $term->name,
-        '#href' => 'taxonomy/term/' . $term->tid,
-      );
       break;
 
     case 'taxonomy_term_plain':
-      $term = $item['taxonomy_term'];
-      $result = array(
-        '#markup' => check_plain($term->name),
-      );
+      foreach ($items as $delta => $item) {
+        $term = $item['taxonomy_term'];
+        $element[$delta] = array(
+          '#markup' => check_plain($term->name),
+        );
+      }
       break;
   }
 
-  return $result;
+  return $element;
 }
 
 /**
-- 
GitLab