From f96c141f5aa99ed414eba4e0a520e5b4d9f91b76 Mon Sep 17 00:00:00 2001
From: Dries Buytaert <dries@buytaert.net>
Date: Mon, 22 Jun 2009 09:10:07 +0000
Subject: [PATCH] - Patch #409750 by yched et al: overhaul and extend node
 build modes.

---
 modules/blog/blog.module               |   8 +-
 modules/book/book.module               |  30 ++++--
 modules/comment/comment.module         |  14 +--
 modules/field/field.api.php            |   6 +-
 modules/field/field.attach.inc         |  12 +--
 modules/field/field.default.inc        |  35 ++-----
 modules/field/field.module             |  16 ++-
 modules/field/modules/text/text.module |  13 +--
 modules/field/theme/field.tpl.php      |   2 +-
 modules/forum/forum.module             |  12 +--
 modules/node/node.api.php              |  29 +++---
 modules/node/node.module               | 133 ++++++++++---------------
 modules/node/node.pages.inc            |   8 +-
 modules/node/node.test                 |   7 +-
 modules/node/node.tpl.php              |   3 +-
 modules/node/tests/node_test.module    |   6 +-
 modules/poll/poll.module               |   6 +-
 modules/search/search.api.php          |   6 +-
 modules/statistics/statistics.module   |   4 +-
 modules/system/system.api.php          |   7 +-
 modules/taxonomy/taxonomy.module       |   8 +-
 modules/translation/translation.module |   2 +-
 modules/trigger/trigger.module         |   4 +-
 modules/upload/upload.module           |  12 +--
 modules/upload/upload.test             |   2 +-
 modules/user/user.module               |   1 -
 26 files changed, 171 insertions(+), 215 deletions(-)

diff --git a/modules/blog/blog.module b/modules/blog/blog.module
index 900e0930ab85..f99657f8332d 100644
--- a/modules/blog/blog.module
+++ b/modules/blog/blog.module
@@ -79,7 +79,7 @@ function blog_form($node, $form_state) {
 /**
  * Implement hook_view().
  */
-function blog_view($node, $teaser) {
+function blog_view($node, $build_mode) {
   if ((bool)menu_get_object()) {
     // Breadcrumb navigation.
     drupal_set_breadcrumb(array(l(t('Home'), NULL), l(t('Blogs'), 'blog'), l(t("!name's blog", array('!name' => $node->name)), 'blog/' . $node->uid)));
@@ -88,10 +88,10 @@ function blog_view($node, $teaser) {
 }
 
 /**
- * Implement hook_node_view.
+ * Implement hook_node_view().
  */
-function blog_node_view($node, $teaser = FALSE) {
-  if ($node->build_mode != NODE_BUILD_RSS) {
+function blog_node_view($node, $build_mode = 'full') {
+  if ($build_mode != 'rss') {
     if ($node->type == 'blog' && arg(0) != 'blog' || arg(1) != $node->uid) {
       $links['blog_usernames_blog'] = array(
         'title' => t("!username's blog", array('!username' => $node->name)),
diff --git a/modules/book/book.module b/modules/book/book.module
index c17e45199de9..8eba4dee8674 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -63,11 +63,11 @@ function book_perm() {
 /**
  * Inject links into $node as needed.
  */
-function book_node_view_link($node, $teaser) {
+function book_node_view_link($node, $build_mode) {
   $links = array();
 
   if (isset($node->book['depth'])) {
-    if (!$teaser) {
+    if ($build_mode == 'full') {
       $child_type = variable_get('book_child_type', 'book');
       if ((user_access('add content to books') || user_access('administer book outlines')) && node_access('create', $child_type) && $node->status == 1 && $node->book['depth'] < MENU_MAX_DEPTH) {
         $links['book_add_child'] = array(
@@ -184,6 +184,19 @@ function book_init() {
   drupal_add_css(drupal_get_path('module', 'book') . '/book.css');
 }
 
+/**
+ * Implement hook_field_build_modes().
+ */
+function book_field_build_modes($obj_type) {
+  $modes = array();
+  if ($obj_type == 'node') {
+    $modes = array(
+      'print' => t('Print'),
+    );
+  }
+  return $modes;
+}
+
 /**
  * Implement hook_block_list().
  */
@@ -705,9 +718,9 @@ function book_node_load($nodes, $types) {
 /**
  * Implement hook_node_view().
  */
-function book_node_view($node, $teaser) {
-  if (!$teaser) {
-    if (!empty($node->book['bid']) && $node->build_mode == NODE_BUILD_NORMAL) {
+function book_node_view($node, $build_mode) {
+  if ($build_mode == 'full') {
+    if (!empty($node->book['bid']) && empty($node->in_preview)) {
       $node->content['book_navigation'] = array(
         '#markup' => theme('book_navigation', $node->book),
         '#weight' => 100,
@@ -715,8 +728,8 @@ function book_node_view($node, $teaser) {
     }
   }
 
-  if ($node->build_mode != NODE_BUILD_RSS) {
-    book_node_view_link($node, $teaser);
+  if ($build_mode != 'rss') {
+    book_node_view_link($node, $build_mode);
   }
 }
 
@@ -1035,8 +1048,7 @@ function book_export_traverse($tree, $visit_func) {
  *   The HTML generated for the given node.
  */
 function book_node_export($node, $children = '') {
-  $node->build_mode = NODE_BUILD_PRINT;
-  $node = node_build_content($node, FALSE, FALSE);
+  $node = node_build_content($node, 'print');
   $node->rendered = drupal_render($node->content);
 
   return theme('book_node_export_html', $node, $children);
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index 3e64620c2d99..c1fd811c5b53 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -457,13 +457,13 @@ function theme_comment_block() {
 }
 
 /**
- * An implementation of hook_node_view().
+ * Implement hook_node_view().
  */
-function comment_node_view($node, $teaser) {
+function comment_node_view($node, $build_mode) {
   $links = array();
 
   if ($node->comment) {
-    if ($node->build_mode == NODE_BUILD_RSS) {
+    if ($build_mode == 'rss') {
       if ($node->comment != COMMENT_NODE_HIDDEN) {
         // Add a comments RSS element which is a URL to the comments of this node.
         $node->rss_elements[] = array(
@@ -472,7 +472,7 @@ function comment_node_view($node, $teaser) {
         );
       }
     }
-    else if ($teaser) {
+    elseif ($build_mode == 'teaser') {
       // Main page: display the number of comments that have been posted.
       if (user_access('access comments')) {
         if (!empty($node->comment_count)) {
@@ -548,7 +548,7 @@ function comment_node_view($node, $teaser) {
     );
 
     // Append the list of comments to $node->content for node detail pages.
-    if ($node->comment && (bool)menu_get_object() && $node->build_mode != NODE_BUILD_PREVIEW) {
+    if ($node->comment && (bool)menu_get_object() && empty($node->in_preview)) {
       $node->content['comments'] = array(
         '#markup' => comment_render($node),
         '#sorted' => TRUE,
@@ -1016,7 +1016,7 @@ function comment_save($edit) {
 /**
  * Implement hook_link().
  */
-function comment_link($type, $object, $teaser) {
+function comment_link($type, $object, $build_mode) {
   if ($type == 'comment') {
     $links = comment_links($object, FALSE);
     return $links;
@@ -2032,7 +2032,7 @@ function template_preprocess_comment_folded(&$variables) {
       $variables['classes_array'][] = 'comment-new';
     }
   }
-  
+
 }
 
 /**
diff --git a/modules/field/field.api.php b/modules/field/field.api.php
index 24f5e583947c..4accf941f309 100644
--- a/modules/field/field.api.php
+++ b/modules/field/field.api.php
@@ -657,10 +657,10 @@ function hook_field_attach_delete_revision($obj_type, $object) {
  *   The type of $object; e.g. 'node' or 'user'.
  * @param $object
  *   The object with fields to render.
- * @param $teaser
- *   Whether to display the teaser only, as on the main page.
+ * @param $build_mode
+ *   Build mode, e.g. 'full', 'teaser'...
  */
-function hook_field_attach_view_alter($output, $obj_type, $object, $teaser) {
+function hook_field_attach_view_alter($output, $obj_type, $object, $build_mode) {
 }
 
 /**
diff --git a/modules/field/field.attach.inc b/modules/field/field.attach.inc
index db5c599351a4..523855793223 100644
--- a/modules/field/field.attach.inc
+++ b/modules/field/field.attach.inc
@@ -149,7 +149,7 @@ class FieldQueryException extends FieldException {}
  *   The fully formed $obj_type object.
  * @param $a
  *   - The $form in the 'form' operation.
- *   - The value of $teaser in the 'view' operation.
+ *   - The value of $build_mode in the 'view' operation.
  *   - Otherwise NULL.
  * @param $b
  *   - The $form_state in the 'submit' operation.
@@ -883,19 +883,19 @@ function field_attach_query_revisions($field_name, $conditions, $result_format =
  *   The type of $object; e.g. 'node' or 'user'.
  * @param $object
  *   The object with fields to render.
- * @param $teaser
- *   Whether to display the teaser only, as on the main page.
+ * @param $build_mode
+ *   Build mode, e.g. 'full', 'teaser'...
  * @return
  *   A structured content array tree for drupal_render().
  */
-function field_attach_view($obj_type, $object, $teaser = FALSE) {
+function field_attach_view($obj_type, $object, $build_mode = 'full') {
   // Let field modules sanitize their data for output.
   _field_invoke('sanitize', $obj_type, $object);
 
-  $output = _field_invoke_default('view', $obj_type, $object, $teaser);
+  $output = _field_invoke_default('view', $obj_type, $object, $build_mode);
 
   // Let other modules make changes after rendering the view.
-  drupal_alter('field_attach_view', $output, $obj_type, $object, $teaser);
+  drupal_alter('field_attach_view', $output, $obj_type, $object, $build_mode);
 
   return $output;
 
diff --git a/modules/field/field.default.inc b/modules/field/field.default.inc
index f6069367607b..f0bcc4dc3f94 100644
--- a/modules/field/field.default.inc
+++ b/modules/field/field.default.inc
@@ -76,8 +76,8 @@ function field_default_insert($obj_type, $object, $field, $instance, &$items) {
  *     '#field_name' => 'field_name',
  *     '#object' => $object,
  *     '#object_type' => $obj_type,
- *     // Value of the $teaser param of hook_node('view').
- *     '#teaser' => $teaser,
+ *     // Value of the $build_mode param of hook_node('view').
+ *     '#build_mode' => $build_mode,
  *     'items' =>
  *       0 => array(
  *         '#item' => $items[0],
@@ -112,27 +112,14 @@ function field_default_insert($obj_type, $object, $field, $instance, &$items) {
  *     ),
  *   );
  */
-function field_default_view($obj_type, $object, $field, $instance, $items, $teaser) {
+function field_default_view($obj_type, $object, $field, $instance, $items, $build_mode) {
   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'];
+  $display = isset($instance['display'][$build_mode]) ? $instance['display'][$build_mode] : $instance['display']['full'];
   // Ensure we have a valid formatter and formatter settings.
   $display = _field_get_formatter($display, $field);
 
@@ -141,7 +128,7 @@ function field_default_view($obj_type, $object, $field, $instance, $items, $teas
     $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) {
+    if ($build_mode == 'search_index') {
       $label_display = 'hidden';
     }
 
@@ -157,7 +144,7 @@ function field_default_view($obj_type, $object, $field, $instance, $items, $teas
       '#title' => check_plain(t($instance['label'])),
       '#access' => field_access('view', $field),
       '#label_display' => $label_display,
-      '#teaser' => $teaser,
+      '#build_mode' => $build_mode,
       '#single' => $single,
       'items' => array(),
     );
@@ -196,7 +183,7 @@ function field_default_view($obj_type, $object, $field, $instance, $items, $teas
       'field' => $element,
       '#weight' => $instance['weight'],
       '#post_render' => array('field_wrapper_post_render'),
-      '#context' => $context,
+      '#build_mode' => $build_mode,
     );
 
     $addition = array($field['field_name'] => $wrapper);
@@ -209,7 +196,7 @@ function field_default_view($obj_type, $object, $field, $instance, $items, $teas
  */
 function field_wrapper_post_render($content, $element) {
   $instance = field_info_instance($element['#field_name'], $element['#bundle']);
-  if (theme('field_exclude', $content, $instance, $element['#context'])) {
+  if (theme('field_exclude', $content, $instance, $element['#build_mode'])) {
     return '';
   }
   return $content;
@@ -231,10 +218,10 @@ function field_wrapper_post_render($content, $element) {
  *   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) {
+function theme_field_exclude($content, $object, $build_mode) {
   if (empty($object['display'])
-    || empty($object['display'][$context])
-    || empty($object['display'][$context]['exclude'])) {
+    || empty($object['display'][$build_mode])
+    || empty($object['display'][$build_mode]['exclude'])) {
     return FALSE;
   }
   else {
diff --git a/modules/field/field.module b/modules/field/field.module
index f518169f975d..ef1fb1e5d2e8 100644
--- a/modules/field/field.module
+++ b/modules/field/field.module
@@ -482,8 +482,7 @@ function field_format($obj_type, $object, $field, $item, $formatter_name = NULL,
  * $FIELD_NAME_rendered variables instead.
  *
  * By default, the field is displayed using the settings defined for the
- * 'full' or 'teaser' contexts (depending on the value of the $teaser param).
- * Set $node->build_mode to a different value to use a different context.
+ * 'full' or 'teaser' contexts (depending on the value of the $build_mode param).
  *
  * Different settings can be specified by adjusting $field['display'].
  *
@@ -492,19 +491,16 @@ function field_format($obj_type, $object, $field, $item, $formatter_name = NULL,
  * @param $object
  *   The object containing the field to display. Must at least contain the id key,
  *   revision key (if applicable), bundle key, and the field data.
- * @param $teaser
- *   Similar to hook_node('view')
+ * @param $build_mode
+ *   Build mode, e.g. 'full', 'teaser'...
  * @return
  *   The themed output for the field.
  */
-function field_view_field($obj_type, $object, $field, $instance, $teaser = FALSE) {
+function field_view_field($obj_type, $object, $field, $instance, $build_mode = 'full') {
   $output = '';
   if (isset($object->$field['field_name'])) {
     $items = $object->$field['field_name'];
 
-    // Use 'full'/'teaser' if not specified otherwise.
-    $object->build_mode = isset($object->build_mode) ? $object->build_mode : NODE_BUILD_NORMAL;
-
     // One-field equivalent to _field_invoke('sanitize').
     $function = $field['module'] . '_field_sanitize';
     if (drupal_function_exists($function)) {
@@ -512,7 +508,7 @@ function field_view_field($obj_type, $object, $field, $instance, $teaser = FALSE
       $object->$field['field_name'] = $items;
     }
 
-    $view = field_default_view($obj_type, $object, $field, $instance, $items, $teaser);
+    $view = field_default_view($obj_type, $object, $field, $instance, $items, $build_mode);
     // TODO : what about hook_field_attach_view ?
 
     // field_default_view() adds a wrapper to handle variables and 'excluded'
@@ -594,7 +590,7 @@ function template_preprocess_field(&$variables) {
     $variables['items'][0]['view'] = drupal_render_children($element, array('items'));
   }
 
-  $variables['teaser'] = $element['#teaser'];
+  $variables['build_mode'] = $element['#build_mode'];
   $variables['page'] = (bool)menu_get_object();
 
   $field_empty = TRUE;
diff --git a/modules/field/modules/text/text.module b/modules/field/modules/text/text.module
index 00ba52017870..fe6e1da80981 100644
--- a/modules/field/modules/text/text.module
+++ b/modules/field/modules/text/text.module
@@ -176,12 +176,10 @@ function text_field_load($obj_type, $objects, $field, $instances, &$items) {
         // handled by text_field_sanitize().
         $format = $item['format'];
         if (filter_format_allowcache($format)) {
-          // TODO D7 : this code is really node-related.
-          $check = is_null($object) || (isset($object->build_mode) && $object->build_mode == NODE_BUILD_PREVIEW);
           $lang = isset($object->language) ? $object->language : $language->language;
-          $items[$id][$delta]['safe'] = isset($item['value']) ? check_markup($item['value'], $format, $lang, $check, FALSE) : '';
+          $items[$id][$delta]['safe'] = isset($item['value']) ? check_markup($item['value'], $format, $lang, FALSE, FALSE) : '';
           if ($field['type'] == 'text_with_summary') {
-            $items[$id][$delta]['safe_summary'] = isset($item['summary']) ? check_markup($item['summary'], $format, $lang, $check, FALSE) : '';
+            $items[$id][$delta]['safe_summary'] = isset($item['summary']) ? check_markup($item['summary'], $format, $lang, FALSE, FALSE) : '';
           }
         }
       }
@@ -209,12 +207,10 @@ function text_field_sanitize($obj_type, $object, $field, $instance, &$items) {
     if (!isset($items[$delta]['safe'])) {
       if (!empty($instance['settings']['text_processing'])) {
         $format = $item['format'];
-        // TODO D7 : this code is really node-related.
-        $check = is_null($object) || (isset($object->build_mode) && $object->build_mode == NODE_BUILD_PREVIEW);
         $lang = isset($object->language) ? $object->language : $language->language;
-        $items[$delta]['safe'] = isset($item['value']) ? check_markup($item['value'], $format, $lang, $check) : '';
+        $items[$delta]['safe'] = isset($item['value']) ? check_markup($item['value'], $format, $lang, FALSE) : '';
         if ($field['type'] == 'text_with_summary') {
-          $items[$delta]['safe_summary'] = isset($item['summary']) ? check_markup($item['summary'], $format, $lang, $check) : '';
+          $items[$delta]['safe_summary'] = isset($item['summary']) ? check_markup($item['summary'], $format, $lang, FALSE) : '';
         }
       }
       else {
@@ -770,3 +766,4 @@ function theme_text_textarea_with_summary($element) {
     return $element['#children'];
   }
 }
+
diff --git a/modules/field/theme/field.tpl.php b/modules/field/theme/field.tpl.php
index 037d4380cdeb..efa629da1b20 100644
--- a/modules/field/theme/field.tpl.php
+++ b/modules/field/theme/field.tpl.php
@@ -9,7 +9,7 @@
  * - $object: The object to which the field is attached.
  * - $field: The field array.
  * - $items: An array of values for each item in the field array.
- * - $teaser: Whether this is displayed as a teaser.
+ * - $build_mode: Build mode, e.g. 'full', 'teaser'...
  * - $page: Whether this is displayed as a page.
  * - $field_name: The field name.
  * - $field_type: The field type.
diff --git a/modules/forum/forum.module b/modules/forum/forum.module
index a65762d0c2a1..ef5c9517a12f 100644
--- a/modules/forum/forum.module
+++ b/modules/forum/forum.module
@@ -187,7 +187,7 @@ function _forum_node_check_node_type($node, $vocabulary) {
 /**
  * Implement hook_node_view().
  */
-function forum_node_view($node, $teaser) {
+function forum_node_view($node, $build_mode) {
   $vid = variable_get('forum_nav_vocabulary', 0);
   $vocabulary = taxonomy_vocabulary_load($vid);
   if (_forum_node_check_node_type($node, $vocabulary)) {
@@ -212,7 +212,7 @@ function forum_node_view($node, $teaser) {
       }
       drupal_set_breadcrumb($breadcrumb);
 
-      if (!$teaser) {
+      if ($build_mode == 'full') {
         $node->content['forum_navigation'] = array(
           '#markup' => theme('forum_topic_navigation', $node),
           '#weight' => 100,
@@ -642,7 +642,7 @@ function forum_get_forums($tid = 0) {
     $query->join('node_comment_statistics', 'ncs', 'n.nid = ncs.nid');
     $query->join('users', 'u2', 'ncs.last_comment_uid = u2.uid');
     $query->addExpression('IF (ncs.last_comment_uid != 0, u2.name, ncs.last_comment_name)', 'last_comment_name');
-    
+
     $topic = $query
       ->fields('ncs', array('last_comment_timestamp', 'last_comment_uid'))
       ->condition('n.status', 1)
@@ -651,7 +651,7 @@ function forum_get_forums($tid = 0) {
       ->addTag('node_access')
       ->execute()
       ->fetchObject();
-    
+
     $last_post = new stdClass();
     if (!empty($topic->last_comment_timestamp)) {
       $last_post->timestamp = $topic->last_comment_timestamp;
@@ -724,14 +724,14 @@ function forum_get_topics($tid, $sortby, $forum_per_page) {
     ->orderByHeader($forum_topic_list_header)
     ->orderBy('n.created', 'DESC')
     ->limit($forum_per_page);
-    
+
   $count_query = db_select('node', 'n');
   $count_query->join('taxonomy_term_node', 'r', 'n.vid = r.vid AND r.tid = :tid', array(':tid' => $tid));
   $count_query->addExpression('COUNT(*)');
   $count_query
     ->condition('n.status', 1)
     ->addTag('node_access');
-    
+
   $query->setCountQuery($count_query);
   $result = $query->execute();
   $topics = array();
diff --git a/modules/node/node.api.php b/modules/node/node.api.php
index 66630b7d015c..37a83dc00a1a 100644
--- a/modules/node/node.api.php
+++ b/modules/node/node.api.php
@@ -474,10 +474,10 @@ function hook_node_validate($node, $form) {
  * will be called after hook_view(). The structure of $node->content is a
  * renderable array as expected by drupal_render().
  *
- * When $node->build_mode is NODE_BUILD_RSS modules can also add extra RSS
- * elements and namespaces to $node->rss_elements and $node->rss_namespaces
- * respectively for the RSS item generated for this node. For details on how
- * this is used @see node_feed()
+ * When $build_mode is 'rss', modules can also add extra RSS elements and
+ * namespaces to $node->rss_elements and $node->rss_namespaces respectively for
+ * the RSS item generated for this node.
+ * For details on how this is used @see node_feed()
  *
  * @see taxonomy_node_view()
  * @see upload_node_view()
@@ -485,10 +485,10 @@ function hook_node_validate($node, $form) {
  *
  * @param $node
  *   The node the action is being performed on.
- * @param $teaser
- *   The $teaser parameter from node_build().
+ * @param $build_mode
+ *   The $build_mode parameter from node_build().
  */
-function hook_node_view($node, $teaser) {
+function hook_node_view($node, $build_mode) {
   $node->content['my_additional_field'] = array(
     '#value' => $additional_field,
     '#weight' => 10,
@@ -510,10 +510,10 @@ function hook_node_view($node, $teaser) {
  *
  * @param $node
  *   The node the action is being performed on.
- * @param $teaser
- *   The $teaser parameter from node_build().
+ * @param $build_mode
+ *   The $build_mode parameter from node_build().
  */
-function hook_node_build_alter($node, $teaser) {
+function hook_node_build_alter($node, $build_mode) {
   // Check for the existence of a field added by another module.
   if (isset($node->content['an_additional_field'])) {
     // Change its weight.
@@ -855,7 +855,7 @@ function hook_update($node) {
  *
  * Changes made to the $node object within a hook_validate() function will
  * have no effect. The preferred method to change a node's content is to use
- * hook_node_presave() instead. If it is really necessary to change 
+ * hook_node_presave() instead. If it is really necessary to change
  * the node at the validate stage, you can use function form_set_value().
  *
  * For a detailed usage example, see node_example.module.
@@ -877,9 +877,8 @@ function hook_validate($node, &$form) {
  *
  * @param $node
  *   The node to be displayed.
- * @param $teaser
- *   Whether we are to generate a "teaser" or summary of the node, rather than
- *   display the whole thing.
+ * @param $build_mode
+ *   Build mode, e.g. 'full', 'teaser'...
  * @return
  *   $node. The passed $node parameter should be modified as necessary and
  *   returned so it can be properly presented. Nodes are prepared for display
@@ -894,7 +893,7 @@ function hook_validate($node, &$form) {
  *
  * For a detailed usage example, see node_example.module.
  */
-function hook_view($node, $teaser = FALSE) {
+function hook_view($node, $build_mode = 'full') {
   if ((bool)menu_get_object()) {
     $breadcrumb = array();
     $breadcrumb[] = array('path' => 'example', 'title' => t('example'));
diff --git a/modules/node/node.module b/modules/node/node.module
index ad7bedbe5656..b416dd4056a0 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -15,36 +15,6 @@
  */
 define('NODE_NEW_LIMIT', REQUEST_TIME - 30 * 24 * 60 * 60);
 
-/**
- * Node is being built before being viewed normally.
- */
-define('NODE_BUILD_NORMAL', 0);
-
-/**
- * Node is being built before being previewed.
- */
-define('NODE_BUILD_PREVIEW', 1);
-
-/**
- * Node is being built before being indexed by search module.
- */
-define('NODE_BUILD_SEARCH_INDEX', 2);
-
-/**
- * Node is being built before being displayed as a search result.
- */
-define('NODE_BUILD_SEARCH_RESULT', 3);
-
-/**
- * Node is being built before being displayed as part of an RSS feed.
- */
-define('NODE_BUILD_RSS', 4);
-
-/**
- * Node is being built before being printed.
- */
-define('NODE_BUILD_PRINT', 5);
-
 /**
  * Implement hook_help().
  */
@@ -181,13 +151,14 @@ function node_field_build_modes($obj_type) {
     $modes = array(
       'teaser' => t('Teaser'),
       'full' => t('Full node'),
-      NODE_BUILD_RSS => t('RSS'),
-      NODE_BUILD_PRINT => t('Print'),
+      'rss' => t('RSS'),
     );
+    // Search integration is provided by node.module, so search-related
+    // build-modes for nodes are defined here and not in search.module.
     if (module_exists('search')) {
       $modes += array(
-        NODE_BUILD_SEARCH_INDEX => t('Search Index'),
-        NODE_BUILD_SEARCH_RESULT => t('Search Result'),
+        'search_index' => t('Search Index'),
+        'search_result' => t('Search Result'),
       );
     }
   }
@@ -1107,22 +1078,22 @@ function node_delete_multiple($nids) {
  *
  * @param $node
  *   A node array or node object.
- * @param $teaser
- *   Whether to display the teaser only or the full form.
+ * @param $build_mode
+ *   Build mode, e.g. 'full', 'teaser'...
  *
  * @return
  *   An array as expected by drupal_render().
  */
-function node_build($node, $teaser = FALSE) {
+function node_build($node, $build_mode = 'full') {
   $node = (object)$node;
 
-  $node = node_build_content($node, $teaser);
+  $node = node_build_content($node, $build_mode);
 
   $build = $node->content;
   $build += array(
     '#theme' => 'node',
     '#node' => $node,
-    '#teaser' => $teaser,
+    '#build_mode' => $build_mode,
   );
   return $build;
 }
@@ -1130,52 +1101,49 @@ function node_build($node, $teaser = FALSE) {
 /**
  * Builds a structured array representing the node's content.
  *
- * The content built for the node will vary depending on the $node->build_mode
- * attribute.  The node module defines a set of common build mode constants:
- *   - NODE_BUILD_NORMAL: Node is being built to be viewed normally.
- *   - NODE_BUILD_PREVIEW: Node is being built to be previewed.
- *   - NODE_BUILD_SEARCH_INDEX: Node is being built to be indexed for search.
- *   - NODE_BUILD_SEARCH_RESULT: Node is being built as a search result.
- *   - NODE_BUILD_RSS: Node is being built to be displayed in an RSS feed.
- *
- * The default mode is NODE_BUILD_NORMAL, which will be used if
- * $node->build_mode is not set.
- *
- * When defining an additional build mode constant in a contributed module,
- * the suggested standard is to use the unix timestamp of when you write the
- * code to minimize the likelihood of two modules using the same value.
+ * The content built for the node (field values, comments, file attachments or
+ * other node components) will vary depending on the $build_mode parameter.
+ *
+ * Drupal core defines the following build modes for nodes, with the following
+ * default use cases:
+ *   - full (default): node is being displayed on its own page (node/123)
+ *   - teaser: node is being displayed on the default home page listing, on
+ *     taxonomy listing pages, or on blog listing pages.
+ *   - rss: node displayed in an RSS feed.
+ *   If search.module is enabled:
+ *   - search_index: node is being indexed for search.
+ *   - search_result: node is being displayed as a search result.
+ *   If book.module is enabled:
+ *   - print: node is being displayed in print-friendly mode.
+ * Contributed modules might define additional build modes, or use existing
+ * build modes in additional contexts.
  *
  * @param $node
  *   A node object.
- * @param $teaser
- *   Whether to display the teaser only, as on the main page.
+ * @param $build_mode
+ *   Build mode, e.g. 'full', 'teaser'...
  *
  * @return
- *   An structured array containing the individual elements
+ *   A structured array containing the individual elements
  *   of the node's content.
  */
-function node_build_content($node, $teaser = FALSE) {
-  // The build mode identifies the target for which the node is built.
-  if (!isset($node->build_mode)) {
-    $node->build_mode = NODE_BUILD_NORMAL;
-  }
-
+function node_build_content($node, $build_mode = 'full') {
   // The 'view' hook can be implemented to overwrite the default function
   // to display nodes.
   if (node_hook($node, 'view')) {
-    $node = node_invoke($node, 'view', $teaser);
+    $node = node_invoke($node, 'view', $build_mode);
   }
 
   // Build fields content.
   if (empty($node->content)) {
     $node->content = array();
   };
-  $node->content += field_attach_view('node', $node, $teaser);
+  $node->content += field_attach_view('node', $node, $build_mode);
 
   // Always display a read more link on teasers because we have no way
   // to know when a teaser view is different than a full view.
   $links = array();
-  if ($teaser) {
+  if ($build_mode == 'teaser') {
     $links['node_readmore'] = array(
       'title' => t('Read more'),
       'href' => 'node/' . $node->nid,
@@ -1188,10 +1156,10 @@ function node_build_content($node, $teaser = FALSE) {
   );
 
   // Allow modules to make their own additions to the node.
-  module_invoke_all('node_view', $node, $teaser);
+  module_invoke_all('node_view', $node, $build_mode);
 
   // Allow modules to modify the structured node.
-  drupal_alter('node_build', $node, $teaser);
+  drupal_alter('node_build', $node, $build_mode);
 
   return $node;
 }
@@ -1215,7 +1183,7 @@ function node_show($node, $message = FALSE) {
   node_tag_new($node->nid);
 
   // For markup consistency with other pages, use node_build_multiple() rather than node_build().
-  return node_build_multiple(array($node), FALSE);
+  return node_build_multiple(array($node), 'full');
 }
 
 /**
@@ -1227,13 +1195,15 @@ function node_show($node, $message = FALSE) {
  *
  * The $variables array contains the following arguments:
  * - $node
- * - $teaser
+ * - $build_mode
  * - $page
  *
  * @see node.tpl.php
  */
 function template_preprocess_node(&$variables) {
-  $variables['teaser'] = $variables['elements']['#teaser'];
+  $variables['build_mode'] = $variables['elements']['#build_mode'];
+  // Provide a distinct $teaser boolean.
+  $variables['teaser'] = $variables['build_mode'] == 'teaser';
   $variables['node'] = $variables['elements']['#node'];
   $node = $variables['node'];
 
@@ -1243,7 +1213,7 @@ function template_preprocess_node(&$variables) {
   $variables['title']     = check_plain($node->title);
   $variables['page']      = (bool)menu_get_object();
 
-  if ($node->build_mode == NODE_BUILD_PREVIEW) {
+  if (!empty($node->in_preview)) {
     unset($node->content['links']);
   }
 
@@ -1480,8 +1450,7 @@ function node_search($op = 'search', $keys = NULL) {
       foreach ($find as $item) {
         // Render the node.
         $node = node_load($item->sid);
-        $node->build_mode = NODE_BUILD_SEARCH_RESULT;
-        $node = node_build_content($node, FALSE, FALSE);
+        $node = node_build_content($node, 'search_result');
         $node->rendered = drupal_render($node->content);
 
         // Fetch comments for snippet.
@@ -1626,11 +1595,11 @@ function theme_node_search_admin($form) {
 /**
  * Implement hook_link().
  */
-function node_link($type, $node = NULL, $teaser = FALSE) {
+function node_link($type, $node, $build_mode) {
   $links = array();
 
   if ($type == 'node') {
-    if ($teaser == 1) {
+    if ($build_mode == 'teaser') {
       $links['node_read_more'] = array(
         'title' => t('Read more'),
         'href' => "node/$node->nid",
@@ -1932,7 +1901,6 @@ function node_feed($nids = FALSE, $channel = array()) {
   foreach ($nodes as $node) {
     $item_text = '';
 
-    $node->build_mode = NODE_BUILD_RSS;
     $node->link = url("node/$node->nid", array('absolute' => TRUE));
     $node->rss_namespaces = array();
     $node->rss_elements = array(
@@ -1943,7 +1911,7 @@ function node_feed($nids = FALSE, $channel = array()) {
 
     // The node gets built and modules add to or modify $node->rss_elements
     // and $node->rss_namespaces.
-    $node = node_build_content($node, $teaser);
+    $node = node_build_content($node, 'rss');
 
     if (!empty($node->rss_namespaces)) {
       $namespaces = array_merge($namespaces, $node->rss_namespaces);
@@ -1981,17 +1949,17 @@ function node_feed($nids = FALSE, $channel = array()) {
  *
  * @param $nodes
  *   An array of nodes as returned by node_load_multiple().
- * @param $teaser
- *   Display nodes into teaser view or full view.
+ * @param $build_mode
+ *   Build mode, e.g. 'full', 'teaser'...
  * @param $weight
  *   An integer representing the weight of the first node in the list.
  * @return
  *   An array in the format expected by drupal_render().
  */
-function node_build_multiple($nodes, $teaser = TRUE, $weight = 0) {
+function node_build_multiple($nodes, $build_mode = 'teaser', $weight = 0) {
   $build = array();
   foreach ($nodes as $node) {
-    $build['nodes'][$node->nid] = node_build($node, $teaser);
+    $build['nodes'][$node->nid] = node_build($node, $build_mode);
     $build['nodes'][$node->nid]['#weight'] = $weight;
     $weight++;
   }
@@ -2084,8 +2052,7 @@ function _node_index_node($node) {
   variable_set('node_cron_last', $node->changed);
 
   // Render the node.
-  $node->build_mode = NODE_BUILD_SEARCH_INDEX;
-  $node = node_build_content($node, FALSE, FALSE);
+  $node = node_build_content($node, 'search_index');
   $node->rendered = drupal_render($node->content);
 
   $text = '<h1>' . check_plain($node->title) . '</h1>' . $node->rendered;
diff --git a/modules/node/node.pages.inc b/modules/node/node.pages.inc
index ee362cbf60b4..185160e086ac 100644
--- a/modules/node/node.pages.inc
+++ b/modules/node/node.pages.inc
@@ -123,7 +123,7 @@ function node_form(&$form_state, $node) {
     node_object_prepare($node);
   }
   else {
-    $node->build_mode = NODE_BUILD_PREVIEW;
+    $node->in_preview = TRUE;
   }
 
   // Set the id and identify this as a node edit form.
@@ -351,7 +351,7 @@ function node_preview($node) {
     // Previewing alters $node so it needs to be cloned.
     if (!form_get_errors()) {
       $cloned_node = clone $node;
-      $cloned_node->build_mode = NODE_BUILD_PREVIEW;
+      $cloned_node->in_preview = TRUE;
       $output = theme('node_preview', $cloned_node);
     }
     drupal_set_title(t('Preview'), PASS_THROUGH);
@@ -373,8 +373,8 @@ function theme_node_preview($node) {
 
   $preview_trimmed_version = FALSE;
 
-  $trimmed = drupal_render(node_build(clone $node, TRUE));
-  $full = drupal_render(node_build($node, FALSE));
+  $trimmed = drupal_render(node_build(clone $node, 'teaser'));
+  $full = drupal_render(node_build($node, 'full'));
 
   // Do we need to preview trimmed version of post as well as full version?
   if ($trimmed != $full) {
diff --git a/modules/node/node.test b/modules/node/node.test
index 152a1353b279..246f9b2c4286 100644
--- a/modules/node/node.test
+++ b/modules/node/node.test
@@ -519,11 +519,11 @@ class NodeRSSContentTestCase extends DrupalWebTestCase {
 
     $this->drupalGet('rss.xml');
 
-    // Check that content added in NODE_BUILD_RSS appear in RSS feed.
+    // Check that content added in 'rss' build mode appear in RSS feed.
     $rss_only_content = t('Extra data that should appear only in the RSS feed for node !nid.', array('!nid' => $node->nid));
     $this->assertText($rss_only_content, t('Node content designated for RSS appear in RSS feed.'));
 
-    // Check that content added in build modes other than NODE_BUILD_RSS doesn't
+    // Check that content added in build modes other than 'rss' doesn't
     // appear in RSS feed.
     $non_rss_content = t('Extra data that should appear everywhere except the RSS feed for node !nid.', array('!nid' => $node->nid));
     $this->assertNoText($non_rss_content, t('Node content not designed for RSS doesn\'t appear in RSS feed.'));
@@ -537,7 +537,8 @@ class NodeRSSContentTestCase extends DrupalWebTestCase {
     $this->assertRaw(format_xml_elements(array($test_element)), t('Extra RSS elements appear in RSS feed.'));
     $this->assertRaw($test_ns, t('Extra namespaces appear in RSS feed.'));
 
-    // Check that content added in NODE_BUILD_RSS doesn't appear when viewing node.
+    // Check that content added in 'rss' build mode doesn't appear when
+    // viewing node.
     $this->drupalGet("node/$node->nid");
     $this->assertNoText($rss_only_content, t('Node content designed for RSS doesn\'t appear when viewing node.'));
   }
diff --git a/modules/node/node.tpl.php b/modules/node/node.tpl.php
index 49979a22de42..fc4255f43e44 100644
--- a/modules/node/node.tpl.php
+++ b/modules/node/node.tpl.php
@@ -51,7 +51,8 @@
  * - $id: Position of the node. Increments each time it's output.
  *
  * Node status variables:
- * - $teaser: Flag for the teaser state.
+ * - $build_mode: Build mode, e.g. 'full', 'teaser'...
+ * - $teaser: Flag for the teaser state (shortcut for $build_mode == 'teaser').
  * - $page: Flag for the full page state.
  * - $promote: Flag for front page promotion state.
  * - $sticky: Flags for sticky post setting.
diff --git a/modules/node/tests/node_test.module b/modules/node/tests/node_test.module
index fd0fca70724f..dc354ff806d7 100644
--- a/modules/node/tests/node_test.module
+++ b/modules/node/tests/node_test.module
@@ -10,8 +10,8 @@
 /**
  * Implement hook_node_view().
  */
-function node_test_node_view($node, $teaser) {
-  if ($node->build_mode == NODE_BUILD_RSS) {
+function node_test_node_view($node, $build_mode) {
+  if ($build_mode == 'rss') {
     // Add RSS elements and namespaces when building the RSS feed.
     $node->rss_elements[] = array(
       'key' => 'testElement',
@@ -26,7 +26,7 @@ function node_test_node_view($node, $teaser) {
     );
   }
 
-  if ($node->build_mode != NODE_BUILD_RSS) {
+  if ($build_mode != 'rss') {
     // Add content that should NOT be displayed in the RSS feed.
     $node->content['extra_non_feed_content'] = array(
       '#markup' => '<p>' . t('Extra data that should appear everywhere except the RSS feed for node !nid.', array('!nid' => $node->nid)) . '</p>',
diff --git a/modules/poll/poll.module b/modules/poll/poll.module
index e59b5971cce1..ed1b4e90b3f1 100644
--- a/modules/poll/poll.module
+++ b/modules/poll/poll.module
@@ -584,7 +584,7 @@ function poll_block_latest_poll_view($node) {
 /**
  * Implement hook_view().
  */
-function poll_view($node, $teaser = FALSE) {
+function poll_view($node, $build_mode = 'full') {
   global $user;
   $output = '';
 
@@ -592,7 +592,7 @@ function poll_view($node, $teaser = FALSE) {
     $node->content['poll_view_voting'] = drupal_get_form('poll_view_voting', $node);
   }
   else {
-    $node->content['poll_view_results'] = array('#markup' => poll_view_results($node, $teaser));
+    $node->content['poll_view_results'] = array('#markup' => poll_view_results($node, $build_mode));
   }
   return $node;
 }
@@ -712,7 +712,7 @@ function template_preprocess_poll_vote(&$variables) {
 /**
  * Generates a graphical representation of the results of a poll.
  */
-function poll_view_results($node, $teaser, $block = FALSE) {
+function poll_view_results($node, $build_mode, $block = FALSE) {
   // Count the votes and find the maximum
   $total_votes = 0;
   $max_votes = 0;
diff --git a/modules/search/search.api.php b/modules/search/search.api.php
index 417ea7d0ef54..03a0016d3c90 100644
--- a/modules/search/search.api.php
+++ b/modules/search/search.api.php
@@ -171,8 +171,7 @@ function hook_search($op = 'search', $keys = NULL) {
       foreach ($find as $item) {
         // Build the node body.
         $node = node_load($item->sid);
-        $node->build_mode = NODE_BUILD_SEARCH_RESULT;
-        $node = node_build_content($node, FALSE, FALSE);
+        $node = node_build_content($node, 'search_result');
         $node->body = drupal_render($node->content);
 
         // Fetch comments for snippet.
@@ -257,8 +256,7 @@ function hook_update_index() {
     variable_set('node_cron_last', $node->changed);
 
     // Render the node.
-    $node->build_mode = NODE_BUILD_SEARCH_INDEX;
-    $node = node_build_content($node, FALSE, FALSE);
+    $node = node_build_content($node, 'search_index');
     $node->rendered = drupal_render($node->content);
 
     $text = '<h1>' . check_plain($node->title) . '</h1>' . $node->rendered;
diff --git a/modules/statistics/statistics.module b/modules/statistics/statistics.module
index 393a9754a2e8..4cf85b935f5f 100644
--- a/modules/statistics/statistics.module
+++ b/modules/statistics/statistics.module
@@ -103,8 +103,8 @@ function statistics_perm() {
 /**
  * Implement hook_node_view().
  */
-function statistics_node_view($node, $teaser) {
-  if ($node->build_mode != NODE_BUILD_RSS) {
+function statistics_node_view($node, $build_mode) {
+  if ($build_mode != 'rss') {
     $links = array();
     if (user_access('view post access counter')) {
       $statistics = statistics_get($node->nid);
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index c8d07cd77c07..776d92c7bc94 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -437,14 +437,13 @@ function hook_image_toolkits() {
  *   - comment: Links to be placed below a comment being viewed.
  * @param $object
  *   A comment object.
- * @param $teaser
- *   A 0/1 flag depending on whether the node is
- *   displayed with its teaser or its full form.
+ * @param $build_mode
+ *   Build mode for the node, e.g. 'full', 'teaser'...
  * @return
  *   An array of the requested links.
  *
  */
-function hook_link($type, $object, $teaser = FALSE) {
+function hook_link($type, $object, $build_mode) {
   $links = array();
 
   if ($type == 'comment') {
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index 4c669c099a12..d14496c27e23 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -66,14 +66,14 @@ function taxonomy_theme() {
 }
 
 /**
- * An implementation of hook_node_view().
+ * Implement hook_node_view().
  */
-function taxonomy_node_view($node) {
+function taxonomy_node_view($node, $build_mode) {
   if (empty($node->taxonomy)) {
     return;
   }
 
-  if ($node->build_mode == NODE_BUILD_RSS) {
+  if ($build_mode == 'rss') {
     // Provide category information for RSS feeds.
     foreach ($node->taxonomy as $term) {
       $node->rss_elements[] = array(
@@ -87,7 +87,7 @@ function taxonomy_node_view($node) {
     $links = array();
 
     // If previewing, the terms must be converted to objects first.
-    if ($node->build_mode == NODE_BUILD_PREVIEW) {
+    if (!empty($node->in_preview)) {
       $node->taxonomy = taxonomy_preview_terms($node);
     }
 
diff --git a/modules/translation/translation.module b/modules/translation/translation.module
index 4b9dbecd73c7..b2e1ed9f3327 100644
--- a/modules/translation/translation.module
+++ b/modules/translation/translation.module
@@ -167,7 +167,7 @@ function translation_form_alter(&$form, &$form_state, $form_id) {
  * Display translation links with native language names, if this node
  * is part of a translation set.
  */
-function translation_node_view($node, $teaser = FALSE) {
+function translation_node_view($node, $build_mode) {
   if (isset($node->tnid) && $translations = translation_node_get_translations($node->tnid)) {
     // Do not show link to the same node.
     unset($translations[$node->language]);
diff --git a/modules/trigger/trigger.module b/modules/trigger/trigger.module
index 68ef220c9f8c..00e732ab4391 100644
--- a/modules/trigger/trigger.module
+++ b/modules/trigger/trigger.module
@@ -245,8 +245,8 @@ function _trigger_node($node, $op, $a3 = NULL, $a4 = NULL) {
 /**
  * Implement hook_node_view().
  */
-function trigger_node_view($node, $teaser) {
-  _trigger_node($node, 'view', $teaser);
+function trigger_node_view($node, $build_mode) {
+  _trigger_node($node, 'view', $build_mode);
 }
 
 /**
diff --git a/modules/upload/upload.module b/modules/upload/upload.module
index c54297a41b98..86ed1ba3e5b2 100644
--- a/modules/upload/upload.module
+++ b/modules/upload/upload.module
@@ -58,7 +58,7 @@ function upload_perm() {
 /**
  * Inject links into $node for attachments.
  */
-function upload_node_links($node, $teaser) {
+function upload_node_links($node, $build_mode) {
   $links = array();
 
   // Display a link with the number of attachments
@@ -337,14 +337,14 @@ function upload_node_load($nodes, $types) {
 /**
  * Implement hook_node_view().
  */
-function upload_node_view($node, $teaser) {
+function upload_node_view($node, $build_mode) {
   if (!isset($node->files)) {
     return;
   }
 
-  if (user_access('view uploaded files') && $node->build_mode != NODE_BUILD_RSS) {
+  if (user_access('view uploaded files') && $build_mode != 'rss') {
     if (count($node->files)) {
-      if (!$teaser) {
+      if ($build_mode == 'full') {
         // Add the attachments list to node body with a heavy weight to ensure
         // they're below other elements.
         $node->content['files'] = array(
@@ -354,12 +354,12 @@ function upload_node_view($node, $teaser) {
         );
       }
       else {
-        upload_node_links($node, $teaser);
+        upload_node_links($node, $build_mode);
       }
     }
   }
 
-  if ($node->build_mode == NODE_BUILD_RSS) {
+  if ($build_mode == 'rss') {
     // Add the first file as an enclosure to the RSS item. RSS allows only one
     // enclosure per item. See: http://en.wikipedia.org/wiki/RSS_enclosure
     foreach ($node->files as $file) {
diff --git a/modules/upload/upload.test b/modules/upload/upload.test
index 7c07c516d67f..124c9bbd8516 100644
--- a/modules/upload/upload.test
+++ b/modules/upload/upload.test
@@ -64,7 +64,7 @@ class UploadTestCase extends DrupalWebTestCase {
 
     // Assure that the attachment link appears on teaser view and has correct count.
     $node = node_load($node->nid);
-    $teaser = drupal_render(node_build($node, TRUE));
+    $teaser = drupal_render(node_build($node, 'teaser'));
     $this->assertTrue(strpos($teaser, format_plural(2, '1 attachment', '@count attachments')), 'Attachments link found on node teaser.');
 
     // Fetch db record and use fid to rename and delete file.
diff --git a/modules/user/user.module b/modules/user/user.module
index c0ff8defa6bf..7c182a561c07 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -2047,7 +2047,6 @@ function user_build_content(&$account) {
 
   // Build fields content.
   // TODO D7 : figure out where exactly this needs to go
-  // TODO D7 : $page / $teaser ??
   $account->content += field_attach_view('user', $account);
 
   user_module_invoke('view', $edit, $account);
-- 
GitLab