field_name when we return from _field_invoke_default(). // TODO D7: Allow the values to be form_altered to another location, like we // do for the form definition ($form['#fields'][$field_name]['form_path']) ? if (isset($form_state['values'][$field['field_name']])) { $items = $form_state['values'][$field['field_name']]; // Remove the 'value' of the 'add more' button. unset($items[$field['field_name'] . '_add_more']); // TODO: the above should be moved to validate time (and values saved back // using form_set_value() ), so that hook_field_validate() works on clean data. // Not sure we'll want what's below in validate too. // Reorder items to account for drag-n-drop reordering. if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) { $items = _field_sort_items($field, $items); } // Filter out empty values. $items = field_set_empty($field, $items); // _field_invoke() does not add back items for fields not present in the // original $object, so add them manually. $object->{$field['field_name']} = $items; } else { // The form did not include this field, for instance because of access // rules: make sure any existing value for the field stays unchanged. unset($object->{$field['field_name']}); } } /** * The 'view' operation constructs the $object in a way that you can use * drupal_render() to display the formatted output for an individual field. * i.e. print drupal_render($object->content['field_foo']); * * The code supports both single value formatters, which theme an individual * item value, and multiple value formatters, which theme all values for the * field in a single theme. The multiple value formatters could be used, for * instance, to plot field values on a single map or display them in a graph. * Single value formatters are the default, multiple value formatters can be * designated as such in formatter_info(). * * The $object array will look like: * $object->content['field_foo']['wrapper'] = array( * '#type' => 'field', * '#title' => 'label' * '#field_name' => 'field_name', * '#object' => $object, * '#object_type' => $obj_type, * // Value of the $teaser param of hook_nodeapi('view'). * '#teaser' => $teaser, * 'items' => * 0 => array( * '#item' => $items[0], * // Only for 'single-value' formatters * '#theme' => $theme, * '#field_name' => 'field_name', * '#bundle' => $bundle, * '#formatter' => $formatter_name, * '#settings' => $formatter_settings, * '#object' => $object, * '#object_type' => $obj_type, * '#delta' => 0, * ), * 1 => array( * '#item' => $items[1], * // Only for 'single-value' formatters * '#theme' => $theme, * '#field_name' => 'field_name', * '#bundle' => $bundle_name, * '#formatter' => $formatter_name, * '#settings' => $formatter_settings, * '#object' => $object, * '#object_type' => $obj_type, * '#delta' => 1, * ), * // Only for 'multiple-value' formatters * '#theme' => $theme, * '#field_name' => 'field_name', * '#bundle' => $bundle_name, * '#formatter' => $formatter_name, * '#settings' => $formatter_settings, * ), * ); */ function field_default_view($obj_type, $object, $field, $instance, $items, $teaser) { list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object); $addition = array(); // Entities without build modes should provide a 'full' context. // NODE_BUILD_NORMAL is 0, and ('whatever' == 0) is TRUE, so we need a ===. if (!isset($object->build_mode)) { $context = 'full'; } elseif ($object->build_mode === NODE_BUILD_NORMAL || $object->build_mode == NODE_BUILD_PREVIEW) { $context = $teaser ? 'teaser' : 'full'; } else { $context = $object->build_mode; } // If we don't have specific settings for the current build_mode, we use the // (required) 'full' build_mode. $display = isset($instance['display'][$context]) ? $instance['display'][$context] : $instance['display']['full']; // Ensure we have a valid formatter and formatter settings. $display = _field_get_formatter($display, $field); if ($display['type'] && $display['type'] !== 'hidden') { $theme = 'field_formatter_' . $display['type']; $single = (field_behaviors_formatter('multiple values', $display) == FIELD_BEHAVIOR_DEFAULT); $label_display = $display['label']; if (isset($object->build_mode) && $object->build_mode == NODE_BUILD_SEARCH_INDEX) { $label_display = 'hidden'; } $info = array( '#field_name' => $field['field_name'], '#bundle' => $bundle, '#object' => $object, '#object_type' => $obj_type, ); $element = $info + array( '#type' => 'field', '#title' => check_plain(t($instance['label'])), '#access' => field_access('view', $field), '#label_display' => $label_display, '#teaser' => $teaser, '#single' => $single, 'items' => array(), ); // Fill-in items. foreach ($items as $delta => $item) { $element['items'][$delta] = array( '#item' => $item, '#weight' => $delta, ); } // Append formatter information either on each item ('single-value' formatter) // or at the upper 'items' level ('multiple-value' formatter) $format_info = $info + array( '#formatter' => $display['type'], '#settings' => $display['settings'], '#theme' => $theme, ); if ($single) { foreach ($items as $delta => $item) { $element['items'][$delta] += $format_info; $element['items'][$delta]['#item']['#delta'] = $delta; } } else { $element['items'] += $format_info; } // The wrapper lets us get the themed output for the whole field // to populate the $FIELD_NAME_rendered variable for templates, // and hide it from the $content variable if needed. // See 'preprocess' op and theme_content_field_wrapper()? $wrapper = $info + array( 'field' => $element, '#weight' => $instance['weight'], '#post_render' => array('field_wrapper_post_render'), '#context' => $context, ); $addition = array($field['field_name'] => $wrapper); } return $addition; } /** * Hide excluded fields from the $content variable in templates. */ function field_wrapper_post_render($content, $element) { $instance = field_info_instance($element['#field_name'], $element['#bundle']); if (theme('field_exclude', $content, $instance, $element['#context'])) { return ''; } return $content; } /** * 'Theme' function for a field's addition to the combined template output, * i.e. the node's $content or the user's $user_profile value. * This allows more flexibility in templates : you can use custom markup * around a few specific fields, and print the rest normally. * * This is a theme function, so it can be overridden in different * themes to produce different results. * * The html for individual fields and groups are available in the * $FIELD_NAME_rendered and $GROUP_NAME_rendered variables. * * @return * Whether or not the field's content is to be added in this context. * Uses the 'exclude' value from the field's display settings. */ function theme_field_exclude($content, $object, $context) { if (empty($object['display']) || empty($object['display'][$context]) || empty($object['display'][$context]['exclude'])) { return FALSE; } else { return TRUE; } } function field_default_preprocess($obj_type, $object, $field, $instance, &$items) { return array( $field['field_name'] . '_rendered' => isset($object->content[$field['field_name']]['#children']) ? $object->content[$field['field_name']]['#children'] : '', ); } function field_default_prepare_translation($obj_type, $object, $field, $instance, &$items) { $addition = array(); if (isset($object->translation_source->$field['field_name'])) { $addition[$field['field_name']] = $object->translation_source->$field['field_name']; } return $addition; }