Index: modules/field/field.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/field.api.php,v
retrieving revision 1.42
diff -u -p -r1.42 field.api.php
--- modules/field/field.api.php	14 Oct 2009 14:55:12 -0000	1.42
+++ modules/field/field.api.php	15 Oct 2009 03:30:24 -0000
@@ -35,7 +35,7 @@ function hook_field_extra_fields($bundle
   $extra = array();
 
   if ($type = node_type_get_type($bundle)) {
-    if ($type->has_title) {
+    if (field_info_instance('title', $type->type) === NULL) {
       $extra['title'] = array(
         'label' => $type->title_label,
         'description' => t('Node module element.'),
Index: modules/node/content_types.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/content_types.inc,v
retrieving revision 1.97
diff -u -p -r1.97 content_types.inc
--- modules/node/content_types.inc	14 Oct 2009 01:01:54 -0000	1.97
+++ modules/node/content_types.inc	15 Oct 2009 03:30:25 -0000
@@ -132,25 +132,6 @@ function node_type_form($form, &$form_st
     '#collapsible' => TRUE,
     '#group' => 'additional_settings',
   );
-  $form['submission']['title_label'] = array(
-    '#title' => t('Title field label'),
-    '#type' => 'textfield',
-    '#default_value' => $type->title_label,
-    '#required' => TRUE,
-  );
-  if (!$type->has_title) {
-    // Avoid overwriting a content type that intentionally does not have a
-    // title field.
-    $form['submission']['title_label']['#attributes'] = array('disabled' => 'disabled');
-    $form['submission']['title_label']['#description'] = t('This content type does not have a title field.');
-    $form['submission']['title_label']['#required'] = FALSE;
-  }
-  $form['submission']['body_label'] = array(
-    '#title' => t('Body field label'),
-    '#type' => 'textfield',
-    '#default_value' => isset($type->body_label) ? $type->body_label : '',
-    '#description' => t('To remove the body field, remove text and leave blank.'),
-  );
   $form['submission']['node_preview'] = array(
     '#type' => 'radios',
     '#title' => t('Preview before submitting'),
@@ -305,13 +286,6 @@ function node_type_form_submit($form, &$
 
   $type->description = $form_state['values']['description'];
   $type->help = $form_state['values']['help'];
-  $type->title_label = $form_state['values']['title_label'];
-  $type->body_label = $form_state['values']['body_label'];
-
-  // title_label is required in core; has_title will always be true, unless a
-  // module alters the title field.
-  $type->has_title = ($type->title_label != '');
-  $type->has_body = ($type->body_label != '');
 
   $type->base = !empty($form_state['values']['base']) ? $form_state['values']['base'] : 'node_content';
   $type->custom = $form_state['values']['custom'];
Index: modules/node/node.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.api.php,v
retrieving revision 1.39
diff -u -p -r1.39 node.api.php
--- modules/node/node.api.php	10 Oct 2009 21:39:03 -0000	1.39
+++ modules/node/node.api.php	15 Oct 2009 03:30:35 -0000
@@ -596,14 +596,6 @@ function hook_node_build_alter($node, $b
  *   - "description": a brief description of the node type. Required.
  *   - "help": help information shown to the user when creating a node of
  *      this type.. Optional (defaults to '').
- *   - "has_title": boolean indicating whether or not this node type has a title
- *      field. Optional (defaults to TRUE).
- *   - "title_label": the label for the title field of this content type.
- *      Optional (defaults to 'Title').
- *   - "has_body": boolean indicating whether or not this node type has a body
- *      field. Optional (defaults to TRUE).
- *   - "body_label": the label for the body field of this content type. Optional
- *      (defaults to 'Body').
  *   - "locked": boolean indicating whether the administrator can change the
  *      machine name of this type. FALSE = changable (not locked),
  *      TRUE = unchangable (locked). Optional (defaults to TRUE).
@@ -792,26 +784,15 @@ function hook_prepare($node) {
  *   edit form.
  *
  * The submit and preview buttons, taxonomy controls, and administrative
- * accoutrements are displayed automatically by node.module. This hook
- * needs to return the node title, the body text area, and fields
- * specific to the node type.
+ * accoutrements are displayed automatically by node.module. Node title and
+ * body fields are handled by the Field API, so this hook does not need to
+ * describe them. It only needs to return elements specific to the node type.
  *
  * For a detailed usage example, see node_example.module.
  */
 function hook_form($node, $form_state) {
   $type = node_type_get_type($node);
 
-  $form['title'] = array(
-    '#type' => 'textfield',
-    '#title' => check_plain($type->title_label),
-    '#required' => TRUE,
-  );
-  $form['body'] = array(
-    '#type' => 'textarea',
-    '#title' => check_plain($type->body_label),
-    '#rows' => 20,
-    '#required' => TRUE,
-  );
   $form['field1'] = array(
     '#type' => 'textfield',
     '#title' => t('Custom field'),
Index: modules/node/node.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.install,v
retrieving revision 1.33
diff -u -p -r1.33 node.install
--- modules/node/node.install	11 Oct 2009 03:07:18 -0000	1.33
+++ modules/node/node.install	15 Oct 2009 03:30:57 -0000
@@ -288,34 +288,6 @@ function node_schema() {
         'not null' => TRUE,
         'size' => 'medium',
       ),
-      'has_title' => array(
-        'description' => 'Boolean indicating whether this type uses the {node}.title field.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'size' => 'tiny',
-      ),
-      'title_label' => array(
-        'description' => 'The label displayed for the title field on the edit form.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'has_body' => array(
-        'description' => 'Boolean indicating whether this type has the body field attached.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'size' => 'tiny',
-      ),
-      'body_label' => array(
-        'description' => 'The label displayed for the body field on the edit form.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
       'custom' => array(
         'description' => 'A boolean indicating whether this type is defined by a module (FALSE) or by a user via Add content type (TRUE).',
         'type' => 'int',
@@ -426,7 +398,8 @@ function node_update_7005() {
 }
 
 /**
- * Convert body and teaser from node properties to fields, and migrate status/comment/promote and sticky columns to the {node_revision} table.
+ * Convert title, body, and teaser from node properties to fields, and migrate
+ * status, comment, promote, and sticky columns to the {node_revision} table.
  */
 function node_update_7006(&$context) {
   $context['#finished'] = 0;
@@ -438,10 +411,26 @@ function node_update_7006(&$context) {
   if (!isset($context['total'])) {
     // Initial invocation.
 
-    // Re-save node types to create title and body field instances.
+    // Create title and body field instances for each node type.
+    $default_instances = node_type_default_fields();
     foreach ($node_types as $type => $info) {
-      if ($info->has_title || $info->has_body) {
-        node_type_save($info);
+      if ($info->has_title) {
+        $instance = field_info_instance('title', $type);
+        if (empty($instance)) {
+          $instance = $default_instances['title'];
+          $instance['bundle'] = $type;
+          $instance['label'] = $info->title_label;
+          field_create_instance($instance);
+        }
+      }
+      if ($info->has_body) {
+        $instance = field_info_instance('body', $type);
+        if (empty($instance)) {
+          $instance = $default_instances['body'];
+          $instance['bundle'] = $type;
+          $instance['label'] = $info->body_label;
+          field_create_instance($instance);
+        }
       }
     }
 
@@ -536,9 +525,15 @@ function node_update_7006(&$context) {
       db_drop_field('node_revision', 'teaser');
       db_drop_field('node_revision', 'format');
 
+      // Remove node properties that descrbe titles and bodies.
+      db_drop_field('node_type', 'has_title');
+      db_drop_field('node_type', 'title_label');
+      db_drop_field('node_type', 'has_body');
+      db_drop_field('node_type', 'body_label');
+
       // We're done.
       $context['#finished'] = 1;
-      return t("!number node body and teaser properties migrated to the 'body' field.", array('!number' => $context['total']));
+      return t("!number node title, body, and teaser properties migrated to 'title' and 'body' fields.", array('!number' => $context['total']));
     }
   }
 }
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1145
diff -u -p -r1.1145 node.module
--- modules/node/node.module	11 Oct 2009 03:07:18 -0000	1.1145
+++ modules/node/node.module	15 Oct 2009 03:31:11 -0000
@@ -473,10 +473,6 @@ function node_type_save($info) {
     'type' => (string) $type->type,
     'name' => (string) $type->name,
     'base' => (string) $type->base,
-    'has_title' => (int) $type->has_title,
-    'title_label' => (string) $type->title_label,
-    'has_body' => (int) $type->has_body,
-    'body_label' => (string) $type->body_label,
     'description' => (string) $type->description,
     'help' => (string) $type->help,
     'custom' => (int) $type->custom,
@@ -493,7 +489,6 @@ function node_type_save($info) {
     if (!empty($type->old_type) && $type->old_type != $type->type) {
       field_attach_rename_bundle($type->old_type, $type->type);
     }
-    node_configure_fields($type);
     module_invoke_all('node_type_update', $type);
     $status = SAVED_UPDATED;
   }
@@ -504,7 +499,13 @@ function node_type_save($info) {
       ->execute();
 
     field_attach_create_bundle($type->type);
-    node_configure_fields($type);
+
+    // Add default fields.
+    $default_instances = node_type_default_fields($type);
+    foreach ($default_instances as $instance) {
+      field_create_instance($instance);
+    }
+
     module_invoke_all('node_type_insert', $type);
     $status = SAVED_NEW;
   }
@@ -516,106 +517,6 @@ function node_type_save($info) {
 }
 
 /**
- * Manage the field(s) for a node type.
- *
- * Currently, the node module manages a single Field API field,
- * 'body'.  If $type->has_body is true, this function ensures the
- * 'body' field exists and creates an instance of it for the bundle
- * $type->type (e.g. 'page', 'story', ...).  If $type->has_body is
- * false, this function removes the instance (if it exists) for the
- * 'body' field on $type->type.
- */
-function node_configure_fields($type) {
-   // Add or remove the body field, as needed.
-  $field = field_info_field('body');
-  $instance = field_info_instance('body', $type->type);
-  if ($type->has_body) {
-    if (empty($field)) {
-      $field = array(
-        'field_name' => 'body',
-        'type' => 'text_with_summary',
-      );
-      $field = field_create_field($field);
-    }
-    if (empty($instance)) {
-      $instance = array(
-        'field_name' => 'body',
-        'bundle' => $type->type,
-        'label' => $type->body_label,
-        'widget_type' => 'text_textarea_with_summary',
-        'settings' => array('display_summary' => TRUE),
-
-        // Define default formatters for the teaser and full view.
-        'display' => array(
-          'full' => array(
-            'label' => 'hidden',
-            'type' => 'text_default',
-          ),
-          'teaser' => array(
-            'label' => 'hidden',
-            'type' => 'text_summary_or_trimmed',
-          ),
-        ),
-      );
-      field_create_instance($instance);
-    }
-    else {
-      $instance['label'] = $type->body_label;
-      $instance['settings']['display_summary'] = TRUE;
-      field_update_instance($instance);
-    }
-  }
-  elseif (!empty($instance)) {
-    field_delete_instance($instance);
-  }
-
-  if ($type->has_title) {
-    // Add the title field if not present.
-    $field = field_info_field('title');
-    $instance = field_info_instance('title', $type->type);
-
-    if (empty($field)) {
-      $field = array(
-        'field_name' => 'title',
-        'type' => 'text',
-      );
-      $field = field_create_field($field);
-    }
-    if (empty($instance)) {
-      $weight = -5;
-      $instance = array(
-        'field_name' => 'title',
-        'bundle' => $type->type,
-        'label' => $type->title_label,
-        'widget_type' => 'text',
-        'widget' => array(
-          'weight' => $weight,
-        ),
-        'required' => TRUE,
-        'locked' => TRUE,
-        'display' => array(
-          'full' => array(
-            'label' => 'hidden',
-            'type' => 'text_default',
-            'weight' => $weight,
-          ),
-          'teaser' => array(
-            'label' => 'hidden',
-            'type' => 'text_default',
-            'weight' => $weight,
-          ),
-        ),
-      );
-      field_create_instance($instance);
-    }
-    else {
-      $instance['label'] = $type->title_label;
-      field_update_instance($instance);
-    }
-  }
-}
-
-/**
  * Deletes a node type from the database.
  *
  * @param $type
@@ -722,10 +623,6 @@ function node_type_set_defaults($info = 
     $type->base = '';
     $type->description = '';
     $type->help = '';
-    $type->has_title = 1;
-    $type->has_body = 1;
-    $type->title_label = t('Title');
-    $type->body_label = t('Body');
     $type->custom = 0;
     $type->modified = 0;
     $type->locked = 1;
@@ -737,19 +634,97 @@ function node_type_set_defaults($info = 
   foreach ($info as $key => $data) {
     $new_type->$key = $data;
   }
-  // If the type has no title or body, set an empty label.
-  if (!$new_type->has_title) {
-    $new_type->title_label = '';
-  }
-  if (!$new_type->has_body) {
-    $new_type->body_label = '';
-  }
   $new_type->orig_type = isset($info['type']) ? $info['type'] : '';
 
   return $new_type;
 }
 
 /**
+ * Ensure that default node fields exist, and return instance arrays.
+ *
+ * If no $type is provided, this will ensure that the default fields (title and
+ * body) exist, and return instance arrays with 'bundle' set to NULL.
+ *
+ * @param $type
+ *   A node type object.
+ *
+ * @return
+ *   An array of the two default field instances for nodes: 'title' and 'body'.
+ */
+function node_type_default_fields($type = NULL) {
+  if ($type === NULL) {
+    $type->type = NULL;
+  }
+
+  // Make sure that the default fields exist.
+  $field = field_info_field('title');
+  if (empty($field)) {
+    $field = array(
+      'field_name' => 'title',
+      'type' => 'text',
+    );
+    $field = field_create_field($field);
+  }
+  $field = field_info_field('body');
+  if (empty($field)) {
+    $field = array(
+      'field_name' => 'body',
+      'type' => 'text_with_summary',
+    );
+    $field = field_create_field($field );
+  }
+
+  // Default field instances.
+  $weight = -5;
+  $default_instances = array(
+    'title' => array(
+      'field_name' => 'title',
+      'bundle' => $type->type,
+      'label' => t('Title'),
+      'widget_type' => 'text',
+      'widget' => array(
+        'weight' => $weight,
+      ),
+      'required' => TRUE,
+      'locked' => TRUE,
+      'display' => array(
+        'full' => array(
+          'label' => 'hidden',
+          'type' => 'text_default',
+          'weight' => $weight,
+        ),
+        'teaser' => array(
+          'label' => 'hidden',
+          'type' => 'text_default',
+          'weight' => $weight,
+        ),
+      ),
+    ),
+    'body' => array(
+      'field_name' => 'body',
+      'bundle' => $type->type,
+      'label' => t('Body'),
+      'widget_type' => 'text_textarea_with_summary',
+      'settings' => array('display_summary' => TRUE),
+
+      // Define default formatters for the teaser and full view.
+      'display' => array(
+        'full' => array(
+          'label' => 'hidden',
+          'type' => 'text_default',
+        ),
+        'teaser' => array(
+          'label' => 'hidden',
+          'type' => 'text_summary_or_trimmed',
+        ),
+      ),
+    ),
+  );
+
+  return $default_instances;
+}
+
+/**
  * Determine whether a node hook exists.
  *
  * @param $node
Index: modules/node/node.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.test,v
retrieving revision 1.47
diff -u -p -r1.47 node.test
--- modules/node/node.test	11 Oct 2009 03:07:18 -0000	1.47
+++ modules/node/node.test	15 Oct 2009 03:31:20 -0000
@@ -879,39 +879,20 @@ class NodeTypeTestCase extends DrupalWeb
     $this->assertRaw('Title', t('Title field was found.'));
     $this->assertRaw('Full text', t('Body field was found.'));
 
-    // Rename the title field and remove the body field.
-    $edit = array(
-      'title_label' => 'Foo',
-      'body_label' => '',
-    );
-    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
-    field_info_cache_clear();
-
-    $this->assertFalse(field_info_instance('body', 'page'), t('Body field was removed.'));
-    $this->drupalGet('node/add/page');
-    $this->assertRaw('Foo', t('New title label was displayed.'));
-    $this->assertNoRaw('Title', t('Old title label was not displayed.'));
-    $this->assertNoRaw('Full text', t('Body field was not found.'));
-
-    // Add the body field again and change the name, machine name and description.
+    // Change the name, machine name and description.
     $edit = array(
       'name' => 'Bar',
       'type' => 'bar',
       'description' => 'Lorem ipsum.',
-      'body_label' => 'Baz',
     );
     $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
     field_info_cache_clear();
 
-    $instance = field_info_instance('body', 'bar');
-    $this->assertEqual($instance['label'], 'Baz', t('Body field was added.'));
     $this->drupalGet('node/add');
     $this->assertRaw('Bar', t('New name was displayed.'));
     $this->assertRaw('Lorem ipsum', t('New description was displayed.'));
     $this->clickLink('Bar');
     $this->assertEqual(url('node/add/bar', array('absolute' => TRUE)), $this->getUrl(), t('New machine name was used in URL.'));
-    $this->assertRaw('Foo', t('Title field was found.'));
-    $this->assertRaw('Full text', t('Body field was found.'));
   }
 }
 
