Index: modules/block/block.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.admin.inc,v
retrieving revision 1.58
diff -u -p -r1.58 block.admin.inc
--- modules/block/block.admin.inc	30 Sep 2009 13:09:29 -0000	1.58
+++ modules/block/block.admin.inc	11 Oct 2009 03:57:56 -0000
@@ -36,46 +36,45 @@ function block_admin_display_form($form,
   $form['#action'] = arg(4) ? url('admin/structure/block/list/' . $theme_key) : url('admin/structure/block');
   $form['#tree'] = TRUE;
 
-  foreach ($blocks as $i => $block) {
-    $key = $block['module'] . '_' . $block['delta'];
-    $form[$key]['module'] = array(
+  foreach ($blocks as $block) {
+    $form[$block['block_id']]['block_instance_id'] = array(
       '#type' => 'value',
-      '#value' => $block['module'],
+      '#value' => $block['instances'][$theme_key]['block_instance_id'],
     );
-    $form[$key]['delta'] = array(
+    $form[$block['block_id']]['status'] = array(
       '#type' => 'value',
-      '#value' => $block['delta'],
+      '#value' => $block['status'],
     );
-    $form[$key]['info'] = array(
+    $form[$block['block_id']]['info'] = array(
       '#markup' => check_plain($block['info']),
     );
-    $form[$key]['theme'] = array(
+    $form[$block['block_id']]['theme'] = array(
       '#type' => 'hidden',
       '#value' => $theme_key,
     );
-    $form[$key]['weight'] = array(
+    $form[$block['block_id']]['weight'] = array(
       '#type' => 'weight',
-      '#default_value' => $block['weight'],
+      '#default_value' => $block['instances'][$theme_key]['weight'],
       '#delta' => $weight_delta,
     );
-    $form[$key]['region'] = array(
+    $form[$block['block_id']]['region'] = array(
       '#type' => 'select',
-      '#default_value' => $block['region'],
+      '#default_value' => $block['instances'][$theme_key]['region'],
       '#options' => $block_regions,
     );
-    $form[$key]['configure'] = array(
+    $form[$block['block_id']]['configure'] = array(
       '#markup' => l(t('configure'),
-      'admin/structure/block/configure/' . $block['module'] . '/' . $block['delta']),
+      'admin/structure/block/configure/' . $block['block_id']),
     );
     if ($block['module'] == 'block') {
-      $form[$key]['delete'] = array(
+      $form[$block['block_id']]['delete'] = array(
         '#markup' => l(t('delete'),
-        'admin/structure/block/delete/' . $block['delta']),
+        'admin/structure/block/delete/' . $block['block_id']),
       );
     }
   }
   // Do not allow disabling the main system content block.
-  unset($form['system_main']['region']['#options'][BLOCK_REGION_NONE]);
+  unset($form[block_entity_id('system', 'main')]['region']['#options'][BLOCK_REGION_NONE]);
 
   $form['submit'] = array(
     '#type' => 'submit',
@@ -89,20 +88,19 @@ function block_admin_display_form($form,
  * Process main blocks administration form submissions.
  */
 function block_admin_display_form_submit($form, &$form_state) {
-  foreach ($form_state['values'] as $block) {
-    $block['status'] = (int) ($block['region'] != BLOCK_REGION_NONE);
-    $block['region'] = $block['status'] ? $block['region'] : '';
-    db_update('block')
-      ->fields(array(
-        'status' => $block['status'],
-        'weight' => $block['weight'],
-        'region' => $block['region'],
-      ))
-      ->condition('module', $block['module'])
-      ->condition('delta', $block['delta'])
-      ->condition('theme', $block['theme'])
-      ->execute();
+  foreach ($form_state['values'] as $block_id => $instance) {
+    $new_status = (int) ($instance['region'] != BLOCK_REGION_NONE);
+    if ($new_status != $instance['status']) {
+      db_update('block')
+        ->fields(array('status' => $new_status))
+        ->condition('block_id', $block_id)
+        ->execute();
+    }
+
+    $instance['region'] = $new_status ? $instance['region'] : BLOCK_REGION_NONE;
+    block_instance_save($instance);
   }
+
   drupal_set_message(t('The block settings have been updated.'));
   cache_clear_all();
 }
@@ -129,11 +127,11 @@ function _block_compare($a, $b) {
     return $status;
   }
   // Sort by region (in the order defined by theme .info file).
-  if ((!empty($a['region']) && !empty($b['region'])) && ($place = ($regions[$a['region']] - $regions[$b['region']]))) {
+  if (((isset($a['instances'][$theme_key]) && !empty($a['instances'][$theme_key]['region'])) && (isset($b['instances'][$theme_key]) && !empty($b['instances'][$theme_key]['region']))) && ($place = ($regions[$a['instances'][$theme_key]['region']] - $regions[$b['instances'][$theme_key]['region']]))) {
     return $place;
   }
   // Sort by weight.
-  $weight = $a['weight'] - $b['weight'];
+  $weight = $a['instances'][$theme_key]['weight'] - $b['instances'][$theme_key]['weight'];
   if ($weight) {
     return $weight;
   }
@@ -144,43 +142,44 @@ function _block_compare($a, $b) {
 /**
  * Menu callback; displays the block configuration form.
  */
-function block_admin_configure($form, &$form_state, $module = NULL, $delta = 0) {
+function block_admin_configure($form, &$form_state, $block) {
+  $form['block_id'] = array(
+    '#type' => 'value',
+    '#value' => (isset($block->block_id)) ? $block->block_id : NULL,
+  );
   $form['module'] = array(
     '#type' => 'value',
-    '#value' => $module,
+    '#value' => $block->module,
   );
   $form['delta'] = array(
     '#type' => 'value',
-    '#value' => $delta,
+    '#value' => isset($block->delta) ? $block->delta : NULL,
   );
 
-  $edit = db_query("SELECT pages, visibility, custom, title FROM {block} WHERE module = :module AND delta = :delta", array(
-    ':module' => $module,
-    ':delta' => $delta,
-  ))->fetchAssoc();
-
   $form['block_settings'] = array(
     '#type' => 'fieldset',
     '#title' => t('Block specific settings'),
     '#collapsible' => TRUE,
+    '#weight' => field_attach_extra_weight($block->block_machine_name, 'block_settings'),
   );
   $form['block_settings']['title'] = array(
     '#type' => 'textfield',
     '#title' => t('Block title'),
     '#maxlength' => 64,
-    '#description' => $module == 'block' ? t('The title of the block as shown to the user.') : t('Override the default title for the block. Use <em>&lt;none&gt;</em> to display no title, or leave blank to use the default block title.'),
-    '#default_value' => $edit['title'],
+    '#description' => $block->module == 'block' ? t('The title of the block as shown to the user.') : t('Override the default title for the block. Use <em>&lt;none&gt;</em> to display no title, or leave blank to use the default block title.'),
+    '#default_value' => isset($block->title) ? $block->title : '',
     '#weight' => -18,
   );
 
   // Allow the user to define this block's region directly
-  $form['regions'] = array(
+  $form['instances'] = array(
     '#type' => 'fieldset',
     '#title' => t('Region settings'),
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
     '#description' => t('Specify in which region this block is displayed.'),
     '#tree' => TRUE,
+    '#weight' => field_attach_extra_weight($block->block_machine_name, 'instances'),
   );
 
   $theme_default = variable_get('theme_default', 'garland');
@@ -189,13 +188,9 @@ function block_admin_configure($form, &$
   foreach (list_themes() as $theme_key => $theme) {
     // Only display enabled themes
     if ($theme->status) {
-      $region = db_query("SELECT region FROM {block} WHERE module = :module AND delta = :delta AND theme = :theme", array(
-        ':module' => $module,
-        ':delta' => $delta,
-        ':theme' => $theme_key,
-      ))->fetchField();
-  
-      $form['regions'][$theme_key] = array(
+      $region = (isset($block->instances[$theme_key]['region'])) ? $block->instances[$theme_key]['region'] : NULL;
+
+      $form['instances'][$theme_key]['region'] = array(
         '#type' => 'select',
         '#title' => t('!theme region', array('!theme' => $theme->info['name'])),
         '#default_value' => (!empty($region) ? $region : BLOCK_REGION_NONE),
@@ -203,20 +198,38 @@ function block_admin_configure($form, &$
         '#expandable' => ($theme_key !== $theme_default),
         '#weight' => ($theme_key == $theme_default ? 9 : 10),
       );
+      $form['instances'][$theme_key]['block_instance_id'] = array(
+        '#type' => 'value',
+        '#value' => (isset($block->instances[$theme_key]['block_instance_id'])) ? $block->instances[$theme_key]['block_instance_id'] : NULL,
+      );
+      $form['instances'][$theme_key]['theme'] = array(
+        '#type' => 'value',
+        '#value' => $theme_key,
+      );
+      $form['instances'][$theme_key]['weight'] = array(
+        '#type' => 'value',
+        '#value' => (isset($block->instances[$theme_key]['weight'])) ? $block->instances[$theme_key]['weight'] : 0,
+      );
     }
   }
 
   // Module-specific block configurations.
-  if ($settings = module_invoke($module, 'block_configure', $delta)) {
+  if ($settings = module_invoke($block->module, 'block_configure', $block->delta)) {
     foreach ($settings as $k => $v) {
       $form['block_settings'][$k] = $v;
     }
   }
 
   // Get the block subject for the page title.
-  $info = module_invoke($module, 'block_info');
-  if (isset($info[$delta])) {
-    drupal_set_title(t("'%name' block", array('%name' => $info[$delta]['info'])), PASS_THROUGH);
+  $info = module_invoke($block->module, 'block_info');
+  if (isset($info[$block->delta])) {
+    drupal_set_title(t("'%name' block", array('%name' => $info[$block->delta]['info'])), PASS_THROUGH);
+  }
+
+  // Attach fields.
+  if (isset($block->block_id)) {
+    //field_attach_load('block', array($block->block_id => $block));
+    field_attach_form('block', $block, $form, $form_state);
   }
 
   $form['page_vis_settings'] = array(
@@ -224,13 +237,17 @@ function block_admin_configure($form, &$
     '#title' => t('Page specific visibility settings'),
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
+    '#weight' => field_attach_extra_weight($block->block_machine_name, 'page_vis_settings'),
   );
 
   $access = user_access('use PHP for settings');
-  if ($edit['visibility'] == 2 && !$access) {
+  if (isset($block->visibility) && $block->visibility == 2 && !$access) {
     $form['page_vis_settings'] = array();
     $form['page_vis_settings']['visibility'] = array('#type' => 'value', '#value' => 2);
-    $form['page_vis_settings']['pages'] = array('#type' => 'value', '#value' => $edit['pages']);
+    $form['page_vis_settings']['pages'] = array(
+      '#type' => 'value',
+      '#value' => isset($block->pages) ? $block->pages : '',
+    );
   }
   else {
     $options = array(t('Every page except those specified below.'), t('Only the pages specified below.'));
@@ -244,27 +261,25 @@ function block_admin_configure($form, &$
       '#type' => 'radios',
       '#title' => t('Show block on specific pages'),
       '#options' => $options,
-      '#default_value' => $edit['visibility'],
+      '#default_value' => isset($block->visibility) ? $block->visibility : NULL,
     );
     $form['page_vis_settings']['pages'] = array(
       '#type' => 'textarea',
       '#title' => t('Pages'),
-      '#default_value' => $edit['pages'],
+      '#default_value' => isset($block->pages) ? $block->pages : '',
       '#description' => $description,
     );
   }
 
   // Role-based visibility settings.
-  $default_role_options = db_query("SELECT rid FROM {block_role} WHERE module = :module AND delta = :delta", array(
-    ':module' => $module,
-    ':delta' => $delta,
-  ))->fetchCol();
+  $default_role_options = (isset($block->roles)) ? $block->roles : array();
   $role_options = db_query('SELECT rid, name FROM {role} ORDER BY name')->fetchAllKeyed();
   $form['role_vis_settings'] = array(
     '#type' => 'fieldset',
     '#title' => t('Role specific visibility settings'),
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
+    '#weight' => field_attach_extra_weight($block->block_machine_name, 'role_vis_settings'),
   );
   $form['role_vis_settings']['roles'] = array(
     '#type' => 'checkboxes',
@@ -275,15 +290,13 @@ function block_admin_configure($form, &$
   );
 
   // Content type specific configuration.
-  $default_type_options = db_query("SELECT type FROM {block_node_type} WHERE module = :module AND delta = :delta", array(
-    ':module' => $module,
-    ':delta' => $delta,
-  ))->fetchCol();
+  $default_type_options = (isset($block->node_types)) ? $block->node_types : array();
   $form['content_type_vis_settings'] = array(
     '#type' => 'fieldset',
     '#title' => t('Content type specific visibility settings'),
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
+    '#weight' => field_attach_extra_weight($block->block_machine_name, 'content_type_vis_settings'),
   );
   $form['content_type_vis_settings']['types'] = array(
     '#type' => 'checkboxes',
@@ -299,6 +312,7 @@ function block_admin_configure($form, &$
     '#title' => t('User specific visibility settings'),
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
+    '#weight' => field_attach_extra_weight($block->block_machine_name, 'user_vis_settings'),
   );
   $form['user_vis_settings']['custom'] = array(
     '#type' => 'radios',
@@ -309,12 +323,13 @@ function block_admin_configure($form, &$
       t('Hide this block by default but let individual users show it.')
     ),
     '#description' => t('Allow individual users to customize the visibility of this block in their account settings.'),
-    '#default_value' => $edit['custom'],
+    '#default_value' => isset($block->custom) ? $block->custom : NULL,
   );
 
   $form['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Save block'),
+    '#weight' => 99,
   );
 
   return $form;
@@ -322,70 +337,67 @@ function block_admin_configure($form, &$
 
 function block_admin_configure_validate($form, &$form_state) {
   if ($form_state['values']['module'] == 'block') {
-    $custom_block_exists = (bool) db_query_range('SELECT 1 FROM {block_custom} WHERE bid <> :bid AND info = :info', 0, 1, array(
-      ':bid' => $form_state['values']['delta'],
+    $custom_block_exists = (bool) db_query_range('SELECT 1 FROM {block_custom} WHERE block_id <> :block_id AND info = :info', 0, 1, array(
+      ':block_id' => $form_state['values']['block_id'],
       ':info' => $form_state['values']['info'],
     ))->fetchField();
     if (empty($form_state['values']['info']) || $custom_block_exists) {
       form_set_error('info', t('Please ensure that each block description is unique.'));
     }
   }
+
+  $block = (object) $form_state['values'];
+  $block->block_machine_name = $block->module . ':' . $block->delta;
+  field_attach_form_validate('block', $block, $form, $form_state);
 }
 
 function block_admin_configure_submit($form, &$form_state) {
   if (!form_get_errors()) {
-    db_update('block')
-      ->fields(array(
-        'visibility' => (int) $form_state['values']['visibility'],
-        'pages' => trim($form_state['values']['pages']),
-        'custom' => (int) $form_state['values']['custom'],
-        'title' => $form_state['values']['title'],
-      ))
-      ->condition('module', $form_state['values']['module'])
-      ->condition('delta', $form_state['values']['delta'])
-      ->execute();
+    $block = $form_state['values'];
+
+    $block['block_machine_name'] = $block['module'] . ':' . $block['delta'];
+    $block = (object) $block;
+    field_attach_submit('block', $block, $form, $form_state);
+    field_attach_presave('block', $block);
+    $block = (array) $block;
+
+    // Make sure status = 1 any theme has the block in a valid region.
+    foreach ($block['instances'] as $instance) {
+      if ($instance['region'] != BLOCK_REGION_NONE) {
+        $block['status'] = 1;
+        break;
+      }
+    }
+
+    block_save($block);
 
     db_delete('block_role')
-      ->condition('module', $form_state['values']['module'])
-      ->condition('delta', $form_state['values']['delta'])
+      ->condition('block_id', $block['block_id'])
       ->execute();
-    $query = db_insert('block_role')->fields(array('rid', 'module', 'delta'));
+    $query = db_insert('block_role')->fields(array('block_id', 'rid'));
     foreach (array_filter($form_state['values']['roles']) as $rid) {
       $query->values(array(
         'rid' => $rid,
-        'module' => $form_state['values']['module'],
-        'delta' => $form_state['values']['delta'],
+        'block_id' => $block['block_id'],
       ));
     }
     $query->execute();
 
     db_delete('block_node_type')
-      ->condition('module', $form_state['values']['module'])
-      ->condition('delta', $form_state['values']['delta'])
+      ->condition('block_id', $block['block_id'])
       ->execute();
-    $query = db_insert('block_node_type')->fields(array('type', 'module', 'delta'));
+    $query = db_insert('block_node_type')->fields(array('type', 'block_id'));
     foreach (array_filter($form_state['values']['types']) as $type) {
       $query->values(array(
         'type' => $type,
-        'module' => $form_state['values']['module'],
-        'delta' => $form_state['values']['delta'],
+        'block_id' => $block['block_id'],
       ));
     }
     $query->execute();
 
-    // Store regions per theme for this block
-    foreach ($form_state['values']['regions'] as $theme => $region) {
-      db_merge('block')
-        ->key(array('theme' => $theme, 'delta' => $form_state['values']['delta'], 'module' => $form_state['values']['module']))
-        ->fields(array(
-          'region' => $region,
-          'pages' => trim($form_state['values']['pages']),
-          'status' => (int) ($region != BLOCK_REGION_NONE),
-        ))
-        ->execute();
-    }
+    field_attach_update('block', (object) $block);
 
-    module_invoke($form_state['values']['module'], 'block_save', $form_state['values']['delta'], $form_state['values']);
+    module_invoke($form_state['values']['module'], 'block_save', $form_state['values']['delta'], $block);
     drupal_set_message(t('The block configuration has been saved.'));
     cache_clear_all();
     $form_state['redirect'] = 'admin/structure/block';
@@ -395,8 +407,25 @@ function block_admin_configure_submit($f
 /**
  * Menu callback: display the custom block addition form.
  */
-function block_add_block_form($form, &$form_state) {
-  return block_admin_configure($form, $form_state, 'block', NULL);
+function block_add_block_form(&$form_state) {
+  $block = array(
+    'block_machine_name' => 'block_0',
+    'module' => 'block',
+    'delta' => NULL,
+  );
+
+  $form = block_admin_configure(array(), $form_state, (object) $block);
+  // When creating a new custom block the Field API bundle for the block and
+  // block_body field have not been created yet. Collect input for the
+  // block_body field here and place it in the new Field API field once it has
+  // been created.
+  $form['block_body'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Block body'),
+    '#text_format' => filter_default_format(),
+    '#required' => TRUE,
+  );
+  return $form;
 }
 
 function block_add_block_form_validate($form, &$form_state) {
@@ -411,64 +440,80 @@ function block_add_block_form_validate($
  * Save the new custom block.
  */
 function block_add_block_form_submit($form, &$form_state) {
-  $delta = db_insert('block_custom')
+  $block = $form_state['values'];
+  block_save($block);
+
+  // Update the {block}.delta to match the block_id.
+  db_update('block')
+    ->fields(array('delta' => $block['block_id']))
+    ->condition('block_id', $block['block_id'])
+    ->execute();
+
+  db_insert('block_custom')
     ->fields(array(
-      'body' => $form_state['values']['body'],
+      'block_id' => $block['block_id'],
       'info' => $form_state['values']['info'],
-      'format' => $form_state['values']['body_format'],
     ))
     ->execute();
 
-  $query = db_insert('block')->fields(array('visibility', 'pages', 'custom', 'title', 'module', 'theme', 'status', 'weight', 'delta', 'cache'));
-  foreach (list_themes() as $key => $theme) {
-    if ($theme->status) {
-      $query->values(array(
-        'visibility' => (int) $form_state['values']['visibility'],
-        'pages' => trim($form_state['values']['pages']),
-        'custom' => (int) $form_state['values']['custom'],
-        'title' => $form_state['values']['title'], 
-        'module' => $form_state['values']['module'],
-        'theme' => $theme->name, 
-        'status' => 0,
-        'weight' => 0,
-        'delta' => $delta, 
-        'cache' => DRUPAL_NO_CACHE,
-      ));
-    }
-  }
-  $query->execute();
-
-  $query = db_insert('block_role')->fields(array('rid', 'module', 'delta'));
+  $query = db_insert('block_role')->fields(array('rid', 'block_id'));
   foreach (array_filter($form_state['values']['roles']) as $rid) {
     $query->values(array(
       'rid' => $rid,
-      'module' => $form_state['values']['module'],
-      'delta' => $delta,
+      'block_id' => $block['block_id']
     ));
   }
   $query->execute();
 
-  $query = db_insert('block_node_type')->fields(array('type', 'module', 'delta'));
+  $query = db_insert('block_node_type')->fields(array('type', 'block_id'));
   foreach (array_filter($form_state['values']['types']) as $type) {
     $query->values(array(
       'type' => $type,
-      'module' => $form_state['values']['module'],
-      'delta' => $delta,
+      'block_id' => $form_state['block_id'],
     ));
   }
   $query->execute();
-  
-  // Store regions per theme for this block
-  foreach ($form_state['values']['regions'] as $theme => $region) {
-    db_merge('block')
-      ->key(array('theme' => $theme, 'delta' => $delta, 'module' => $form_state['values']['module']))
-      ->fields(array(
-        'region' => $region,
-        'pages' => trim($form_state['values']['pages']),
-        'status' => (int) ($region != BLOCK_REGION_NONE),
-      ))
-      ->execute();
+
+  // Create the 'block_body' field if it doesn't already exist.
+  $field = field_info_field('block_body');
+  if (empty($field)) {
+    $field = array(
+      'field_name' => 'block_body',
+      'type' => 'text_long',
+    );
+    field_create_field($field);
   }
+  
+  // Attach an instance of the 'block_body' field to the new block bundle.
+  $instance = array(
+    'field_name' => 'block_body',
+    'bundle' => 'block:' . $block['block_id'],
+    'label' => t('Block body'),
+    'description' => t('The content of the block as shown to the user.'),
+    'required' => TRUE,
+    'settings' => array('text_processing' => 1),
+    'widget' => array(
+      'type' => 'text_textarea',
+      'label' => t('Block body'),
+    ),
+    'display' => array(
+      'full' => array('label' => 'hidden'),
+    ),
+  );
+  field_create_instance($instance);
+
+  // Move the content from the temporary block_body field to the new Field API
+  // block_body field.
+  $block['block_machine_name'] = 'block:' . $block['block_id'];
+  $block['block_body'] = array(
+    FIELD_LANGUAGE_NONE => array(
+      0 => array(
+        'value' => $form_state['values']['block_body'],
+        'format' => $form_state['values']['block_body_format'],
+      ),
+    ),
+  );
+  field_attach_insert('block', (object) $block);
 
   drupal_set_message(t('The block has been created.'));
   cache_clear_all();
@@ -478,12 +523,16 @@ function block_add_block_form_submit($fo
 /**
  * Menu callback; confirm deletion of custom blocks.
  */
-function block_custom_block_delete($form, &$form_state, $bid = 0) {
-  $custom_block = block_custom_block_get($bid);
-  $form['info'] = array('#type' => 'hidden', '#value' => $custom_block['info'] ? $custom_block['info'] : $custom_block['title']);
-  $form['bid'] = array('#type' => 'hidden', '#value' => $bid);
+function block_custom_block_delete($form, &$form_state, $block) {
+  if ($block->module != 'block') {
+    drupal_set_message(t('The block %block can not be deleted. To remove this block disable the %module module', array('%block' => $block->info, '%module' => $block->module)), 'warning');
+    drupal_goto('admin/structure/block');
+  }
+
+  $form['info'] = array('#type' => 'hidden', '#value' => $block->info ? $block->info : $block->info);
+  $form['block_id'] = array('#type' => 'hidden', '#value' => $block->block_id);
 
-  return confirm_form($form, t('Are you sure you want to delete the block %name?', array('%name' => $custom_block['info'])), 'admin/structure/block', '', t('Delete'), t('Cancel'));
+  return confirm_form($form, t('Are you sure you want to delete the block %name?', array('%name' => $block->info)), 'admin/structure/block', '', t('Delete'), t('Cancel'));
 }
 
 /**
@@ -491,11 +540,10 @@ function block_custom_block_delete($form
  */
 function block_custom_block_delete_submit($form, &$form_state) {
   db_delete('block_custom')
-    ->condition('bid', $form_state['values']['bid'])
+    ->condition('block_id', $form_state['values']['block_id'])
     ->execute();
   db_delete('block')
-    ->condition('module', 'block')
-    ->condition('delta', $form_state['values']['bid'])
+    ->condition('block_id', $form_state['values']['block_id'])
     ->execute();
   drupal_set_message(t('The block %name has been removed.', array('%name' => $form_state['values']['info'])));
   cache_clear_all();
Index: modules/block/block.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.install,v
retrieving revision 1.33
diff -u -p -r1.33 block.install
--- modules/block/block.install	29 Sep 2009 15:13:54 -0000	1.33
+++ modules/block/block.install	11 Oct 2009 03:57:57 -0000
@@ -11,9 +11,9 @@
  */
 function block_schema() {
   $schema['block'] = array(
-    'description' => 'Stores block settings, such as region and visibility settings.',
+    'description' => 'Stores block settings, such as visibility settings.',
     'fields' => array(
-      'bid' => array(
+      'block_id' => array(
         'type' => 'serial',
         'not null' => TRUE,
         'description' => 'Primary Key: Unique block ID.',
@@ -32,13 +32,6 @@ function block_schema() {
         'default' => '0',
         'description' => 'Unique ID for block within a module.',
       ),
-      'theme' => array(
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'The theme under which the block settings apply.',
-      ),
       'status' => array(
         'type' => 'int',
         'not null' => TRUE,
@@ -46,20 +39,6 @@ function block_schema() {
         'size' => 'tiny',
         'description' => 'Block enabled status. (1 = enabled, 0 = disabled)',
       ),
-      'weight' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'tiny',
-        'description' => 'Block weight within region.',
-      ),
-      'region' => array(
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'Theme region within which the block is set.',
-      ),
       'custom' => array(
         'type' => 'int',
         'not null' => TRUE,
@@ -94,29 +73,66 @@ function block_schema() {
         'description' => 'Binary flag to indicate block cache mode. (-1: Do not cache, 1: Cache per role, 2: Cache per user, 4: Cache per page, 8: Block cache global) See BLOCK_CACHE_* constants in block.module for more detailed information.',
       ),
     ),
-    'primary key' => array('bid'),
+    'primary key' => array('block_id'),
     'unique keys' => array(
-      'tmd' => array('theme', 'module', 'delta'),
+      'bmd' => array('block_id', 'module', 'delta'),
     ),
     'indexes' => array(
-      'list' => array('theme', 'status', 'region', 'weight', 'module'),
+      'list' => array('status', 'module'),
     ),
   );
 
-  $schema['block_role'] = array(
-    'description' => 'Sets up access permissions for blocks based on user roles',
+  $schema['block_instance'] = array(
+    'description' => 'Stores block intance information for themes and regions.',
     'fields' => array(
-      'module' => array(
+      'block_instance_id' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Primary key: Unique block instance ID',
+      ),
+      'block_id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Block ID from {blocks}',
+      ),
+      'theme' => array(
         'type' => 'varchar',
         'length' => 64,
         'not null' => TRUE,
-        'description' => "The block's origin module, from {block}.module.",
+        'default' => '',
+        'description' => 'The theme under which the block settings apply.',
       ),
-      'delta' => array(
+      'region' => array(
         'type' => 'varchar',
-        'length' => 32,
+        'length' => 64,
         'not null' => TRUE,
-        'description' => "The block's unique delta within module, from {block}.delta.",
+        'default' => '',
+        'description' => 'Theme region within which the block is set.',
+      ),
+      'weight' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'Block weight within region.',
+      ),
+    ),
+    'primary key' => array('block_instance_id'),
+    'indexes' => array(
+      'list' => array('theme', 'region', 'weight'),
+    ),
+  );
+
+  $schema['block_role'] = array(
+    'description' => 'Sets up access permissions for blocks based on user roles',
+    'fields' => array(
+      'block_id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Block ID from {blocks}',
       ),
       'rid' => array(
         'type' => 'int',
@@ -125,7 +141,7 @@ function block_schema() {
         'description' => "The user's role ID from {users_roles}.rid.",
       ),
     ),
-    'primary key' => array('module', 'delta', 'rid'),
+    'primary key' => array('block_id', 'rid'),
     'indexes' => array(
       'rid' => array('rid'),
     ),
@@ -134,17 +150,11 @@ function block_schema() {
   $schema['block_node_type'] = array(
     'description' => 'Sets up display criteria for blocks based on content types',
     'fields' => array(
-      'module' => array(
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-        'description' => "The block's origin module, from {block}.module.",
-      ),
-      'delta' => array(
-        'type' => 'varchar',
-        'length' => 32,
+      'block_id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
         'not null' => TRUE,
-        'description' => "The block's unique delta within module, from {block}.delta.",
+        'description' => 'Block ID from {blocks}',
       ),
       'type' => array(
         'type' => 'varchar',
@@ -153,7 +163,7 @@ function block_schema() {
         'description' => "The machine-readable name of this type from {node_type}.type.",
       ),
     ),
-    'primary key' => array('module', 'delta', 'type'),
+    'primary key' => array('block_id', 'type'),
     'indexes' => array(
       'type' => array('type'),
     ),
@@ -162,18 +172,12 @@ function block_schema() {
   $schema['block_custom'] = array(
     'description' => 'Stores contents of custom-made blocks.',
     'fields' => array(
-      'bid' => array(
-        'type' => 'serial',
+      'block_id' => array(
+        'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
         'description' => "The block's {block}.bid.",
       ),
-      'body' => array(
-        'type' => 'text',
-        'not null' => FALSE,
-        'size' => 'big',
-        'description' => 'Block contents.',
-      ),
       'info' => array(
         'type' => 'varchar',
         'length' => 128,
@@ -181,18 +185,10 @@ function block_schema() {
         'default' => '',
         'description' => 'Block description.',
       ),
-      'format' => array(
-        'type' => 'int',
-        'size' => 'small',
-        'not null' => TRUE,
-        'default' => 0,
-        'description' => "Block body's {filter_format}.format; for example, 1 = Filtered HTML.",
-      )
     ),
     'unique keys' => array(
-      'info' => array('info'),
+      'bi' => array('block_id', 'info'),
     ),
-    'primary key' => array('bid'),
   );
 
   $schema['cache_block'] = drupal_get_schema_unprocessed('system', 'cache');
@@ -264,3 +260,216 @@ function block_update_7001() {
 
   db_create_table('block_node_type', $schema['block_node_type']);
 }
+
+/**
+ * Refactor {block} table to {block} and {block_instance} and add a unique ID
+ * for every block.
+ */
+function block_update_7002() {
+  // Create the new {block_instance} table.
+  $schema['block_instance'] = array(
+    'description' => 'Stores block intance information for themes and regions.',
+    'fields' => array(
+      'block_instance_id' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Primary key: Unique block instance ID',
+      ),
+      'block_id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Block ID from {blocks}',
+      ),
+      'theme' => array(
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The theme under which the block settings apply.',
+      ),
+      'region' => array(
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Theme region within which the block is set.',
+      ),
+      'weight' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'Block weight within region.',
+      ),
+    ),
+    'primary key' => array('block_instance_id'),
+    'unique keys' => array(
+      'btr' => array('block_id', 'theme', 'region'),
+    ),
+    'indexes' => array(
+      'list' => array('theme', 'region', 'weight'),
+    ),
+  );
+  db_create_table('block_instance', $schema['block_instance']);
+
+  // Rename {block}.bid to {block}.block_id and adjust keys and indexes.
+  db_drop_unique_key('block', 'tmd');
+  db_drop_index('block', 'list');
+  db_change_field('block', 'bid', 'block_id',
+    array(
+      'type' => 'serial',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'description' => 'Primary Key: Unique block ID.'
+    ),
+    array(
+      'unique keys' => array(
+        'bmd' => array('block_id', 'module', 'delta'),
+      ),
+      'indexes' => array(
+        'list' => array('status', 'module'),
+      ),
+    )
+  );
+
+  $result = db_query('SELECT * FROM {block}');
+  $blocks = array();
+  // Copy data from {block} table to new {block_instance} table. Re-use
+  // block_id for blocks with the same module/delta and keep track of used
+  // block_id so we can remove the old rows.
+  foreach ($result as $block) {
+    if (isset($blocks[$block->module . ':' . $block->delta])) {
+      $block->block_id = $blocks[$block->module . ':' . $block->delta];
+    }
+    db_query("INSERT INTO {block_instance} (block_id, theme, region, weight) VALUES (" . $block->block_id . ", '" . $block->theme . "', '" . $block->region . "', " . $block->weight . ")");
+    $blocks[$block->module . ':' . $block->delta] = $block->block_id;
+  }
+
+  // Replace module/delta columns with block_id column on {block_role} and
+  // {block_node_type} tables.
+  db_drop_primary_key('block_role');
+  db_add_field('block_role', 'block_id',
+    array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'description' => 'Block ID from {blocks}',
+      'initial' => 0
+    ),
+    array(
+      'primary key' => array('block_id', 'rid'),
+    )
+  );
+  db_drop_primary_key('block_node_type');
+  db_add_field('block_node_type', 'block_id',
+    array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'description' => 'Block ID from {blocks}',
+      'initial' => 0
+    ),
+    array(
+      'primary key' => array('block_id', 'type'),
+    )
+  );
+  foreach ($blocks as $key => $block_id) {
+    list($module, $delta) = explode(':', $key);
+    db_query("UPDATE {block_role} SET block_id = " . $block_id . " WHERE module = '" . $module . "' AND delta = '" . $delta . "'");
+    db_query("UPDATE {block_node_type} SET block_id = " . $block_id . " WHERE module = '" . $module . "' AND delta = '" . $delta . "'");
+  }
+
+  // Remove unused columns from {block_role} and {block_node_type}.
+  db_drop_field('block_role', 'module');
+  db_drop_field('block_role', 'delta');
+  db_drop_field('block_node_type', 'module');
+  db_drop_field('block_node_type', 'delta');
+
+  // Replace {block_custom}.bid with {block_custom}.block_id.
+  db_add_field('block_custom', 'block_id',
+    array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'description' => "The block's {block}.bid.",
+      'default' => 0,
+    )
+  );
+  $result = db_query("SELECT * FROM {block} WHERE module='block'");
+  foreach ($result as $block) {
+    if ($blocks[$block->module . ':' . $block->delta] == $block->block_id) {
+      db_query("UPDATE {block_custom} SET block_id = " . $block->block_id . " WHERE bid = " . $block->delta);
+      db_query("UPDATE {block} SET delta = " . $block->block_id . " WHERE block_id = " . $block->block_id);
+    }
+  }
+  db_drop_field('block_custom', 'bid');
+
+  // Any block that is not in $blocks is now a duplicate and can be removed.
+  db_delete('block')
+    ->condition('block_id', $blocks, 'NOT IN')
+    ->execute();
+
+  // Remove columns from {block} that are now in {block_instance}.
+  db_drop_field('block', 'theme');
+  db_drop_field('block', 'region');
+  db_drop_field('block', 'weight');
+}
+
+/**
+ * Convert custom block body to a field.
+ */
+function block_update_7003() {
+  // Create the 'block_body' field if it doesn't already exist.
+  $field = field_info_field('block_body');
+  if (empty($field)) {
+    $field = array(
+      'field_name' => 'block_body',
+      'type' => 'text_long',
+    );
+    field_create_field($field);
+  }
+
+  // Attach an instance of the 'block_body' field to all custom blocks.
+  $custom_blocks = db_query('SELECT * FROM {block_custom}');
+  foreach ($custom_blocks as $block) {
+    // Create a new bundle for the block
+    field_attach_create_bundle('block:' . $block->block_id);
+
+    $instance = array(
+      'field_name' => 'block_body',
+      'bundle' => 'block:' . $block->block_id,
+      'label' => t('Block body'),
+      'description' => t('The content of the block as shown to the user.'),
+      'required' => TRUE,
+      'settings' => array('text_processing' => 1),
+      'widget' => array(
+        'type' => 'text_textarea',
+        'label' => t('Block body'),
+      ),
+      'display' => array(
+        'full' => array('label' => 'hidden'),
+      ),
+    );
+    field_create_instance($instance);
+
+    // Move the block body to the new 'block_body' field.
+    $block->block_machine_name = 'block:' . $block->block_id;
+    $block->block_body = array(
+      FIELD_LANGUAGE_NONE => array(
+        0 => array(
+          'value' => $block->body,
+          'format' => $block->format,
+        ),
+      ),
+    );
+    // This is a core update and no contrib modules are enabled yet, so we can
+    // assume default field storage for a faster update.
+    field_sql_storage_field_storage_write('block', $block, FIELD_STORAGE_INSERT, array());
+  }
+
+  // Remove the now-obsolete body info from block_custom.
+  db_drop_field('block_custom', 'body');
+  db_drop_field('block_custom', 'format');
+}
Index: modules/block/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.module,v
retrieving revision 1.386
diff -u -p -r1.386 block.module
--- modules/block/block.module	10 Oct 2009 21:39:01 -0000	1.386
+++ modules/block/block.module	11 Oct 2009 03:57:58 -0000
@@ -91,18 +91,18 @@ function block_menu() {
     'type' => MENU_CALLBACK,
     'file' => 'block.admin.inc',
   );
-  $items['admin/structure/block/configure'] = array(
+  $items['admin/structure/block/configure/%block'] = array(
     'title' => 'Configure block',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('block_admin_configure'),
+    'page arguments' => array('block_admin_configure', 4),
     'access arguments' => array('administer blocks'),
     'type' => MENU_CALLBACK,
     'file' => 'block.admin.inc',
   );
-  $items['admin/structure/block/delete'] = array(
+  $items['admin/structure/block/delete/%block'] = array(
     'title' => 'Delete block',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('block_custom_block_delete'),
+    'page arguments' => array('block_custom_block_delete', 4),
     'access arguments' => array('administer blocks'),
     'type' => MENU_CALLBACK,
     'file' => 'block.admin.inc',
@@ -156,16 +156,116 @@ function _block_custom_theme($theme = NU
 }
 
 /**
+ * Implement hook_entity_info().
+ */
+function block_entity_info() {
+  $return = array(
+    'block' => array(
+      'label' => t('Block'),
+      'controller class' => 'BlockController',
+      'base table' => 'block',
+      'fieldable' => TRUE,
+      'object keys' => array(
+        'id' => 'block_id',
+        'bundle' => 'block_machine_name',
+      ),
+      'bundle keys' => array(
+        'bundle' => 'block_machine_name',
+      ),
+      'bundles' => array(),
+    ),
+  );
+
+  $blocks = db_query('SELECT block_id, module, delta FROM {block}');
+  foreach ($blocks as $block) {
+    $return['block']['bundles'][$block->module . ':' . $block->delta] = array(
+      'label' => $block->module . '_' . $block->delta,
+      'admin' => array(
+        'path' => 'admin/structure/block/configure/%block',
+        'real path' => 'admin/structure/block/configure/' . $block->block_id,
+        'access arguments' => array('administer blocks'),
+        'bundle argument' => 4,
+      ),
+    );
+  }
+
+  return $return;
+}
+
+/**
+ * Implement hook_field_build_modes().
+ */
+function block_field_build_modules($obj_type) {
+  $modes = array();
+  if ($obj_type == 'block') {
+    $modes = array(
+      'full' => t('Block'),
+    );
+  }
+  return $modes;
+}
+
+/**
+ * Implement hook_field_extra_fields().
+ */
+function block_field_extra_fields($bundle) {
+  $args = explode(':', $bundle);
+  $module = (isset($args[0])) ? $args[0] : NULL;
+  $delta = (isset($args[1])) ? $args[1] : NULL;
+  $is_block = block_entity_id($module, $delta);
+
+  if ($is_block) {
+    $extra = array();
+    $extra['block_settings'] = array(
+      'label' => t('Block settings'),
+      'description' => t('Block specific settings'),
+      'weight' => -10,
+    );
+    $extra['module_content'] = array(
+      'label' => t('Module content'),
+      'description' => t('Any content provided by the implementing module'),
+      'weight' => 0,
+    );
+    $extra['instances'] = array(
+      'label' => t('Region settings'),
+      'description' => t('Specify in which region this block is displayed.'),
+      'weight' => 30,
+    );
+    $extra['page_vis_settings'] = array(
+      'label' => t('Page visibility settings'),
+      'description' => t('Page specific visibility settings'),
+      'weight' => 31,
+    );
+    $extra['role_vis_settings'] = array(
+      'label' => t('Role visibility settings'),
+      'description' => t('Role specific visibility settings'),
+      'weight' => 32,
+    );
+    $extra['content_type_vis_settings'] = array(
+      'label' => t('Content type visibility settings'),
+      'description' => t('Show block for specific content types'),
+      'weight' => 33,
+    );
+    $extra['user_vis_settings'] = array(
+      'label' => t('User visibility settings'),
+      'description' => t('User specific visibility settings'),
+      'weight' => 34,
+    );
+    return $extra;
+  }
+}
+
+/**
  * Implement hook_block_info().
  */
 function block_block_info() {
   $blocks = array();
 
-  $result = db_query('SELECT bid, info FROM {block_custom} ORDER BY info');
+  $result = db_query('SELECT block_id, info FROM {block_custom} ORDER BY info');
   foreach ($result as $block) {
-    $blocks[$block->bid]['info'] = $block->info;
+    $blocks[$block->block_id]['info'] = $block->info;
     // Not worth caching.
-    $blocks[$block->bid]['cache'] = DRUPAL_NO_CACHE;
+    $blocks[$block->block_id]['cache'] = DRUPAL_NO_CACHE;
   }
   return $blocks;
 }
@@ -174,7 +274,7 @@ function block_block_info() {
  * Implement hook_block_configure().
  */
 function block_block_configure($delta = 0) {
-  $custom_block = array('format' => filter_default_format());
+  $custom_block = array();
   if ($delta) {
     $custom_block = block_custom_block_get($delta);
   }
@@ -182,6 +282,17 @@ function block_block_configure($delta = 
 }
 
 /**
+ * Implement hook_block_load().
+ */
+function block_block_load($blocks) {
+  foreach ($blocks as $block_id => $block) {
+    if ($block->module == 'block' && $custom_block = block_custom_block_get($block_id)) {
+      $blocks[$block_id]->info = $custom_block['info'];
+    }
+  }
+}
+
+/**
  * Implement hook_block_save().
  */
 function block_block_save($delta = 0, $edit = array()) {
@@ -190,13 +301,11 @@ function block_block_save($delta = 0, $e
 
 /**
  * Implement hook_block_view().
- *
- * Generates the administrator-defined blocks for display.
  */
-function block_block_view($delta = 0, $edit = array()) {
-  $block = db_query('SELECT body, format FROM {block_custom} WHERE bid = :bid', array(':bid' => $delta))->fetchObject();
-  $data['content'] = check_markup($block->body, $block->format, '', TRUE);
-  return $data;
+function block_block_view($delta = 0) {
+  // All custom block content is handled by the field API, so return an empty
+  // array here.
+  return array('content' => array());
 }
 
 /**
@@ -237,6 +346,21 @@ function block_page_build(&$page) {
 }
 
 /**
+ * Implement hook_modules_enabled().
+ */
+function block_modules_enabled($modules) {
+  // When a new module that provides a block is enabled we need to make sure
+  // that the block is saved to the database and given a block_id.
+  foreach ($modules as $module) {
+    if (function_exists($module . '_block_info')) {
+      _block_rehash();
+      drupal_flush_all_caches();
+      break;
+    }
+  }
+}
+
+/**
  * Get a renderable array of a region containing all enabled blocks.
  *
  * @param $region
@@ -271,14 +395,18 @@ function _block_rehash() {
 
   drupal_theme_initialize();
 
+  $block_ids = db_select('block', 'b')
+    ->fields('b', array('block_id'))
+    ->execute()
+    ->fetchCol();
+  $existing_blocks = block_load_multiple($block_ids);
+
   $old_blocks = array();
-  $result = db_query("SELECT * FROM {block} WHERE theme = :theme", array(':theme' => $theme_key));
-  foreach ($result as $old_block) {
-    $old_block = is_object($old_block) ? get_object_vars($old_block) : $old_block;
-    $old_blocks[$old_block['module']][$old_block['delta']] = $old_block;
+  foreach ($existing_blocks as $block) {
+    $old_blocks[$block->module][$block->delta] = $block;
   }
-
   $blocks = array();
+
   // Valid region names for the theme.
   $regions = system_region_list($theme_key);
 
@@ -289,39 +417,54 @@ function _block_rehash() {
         if (empty($old_blocks[$module][$delta])) {
           // If it's a new block, add identifiers.
           $block['module'] = $module;
-          $block['delta']  = $delta;
-          $block['theme']  = $theme_key;
+          $block['delta'] = $delta;
+          $block['instances'] = array(
+            $theme_key => array(
+              'theme' => $theme_key,
+              'region' => isset($block['region']) ? $block['region'] : BLOCK_REGION_NONE,
+              'weight' => isset($block['weight']) ? $block['weight'] : NULL,
+            )
+          );
           if (!isset($block['pages'])) {
             // {block}.pages is type 'text', so it cannot have a
             // default value, and not null, so we need to provide
             // value if the module did not.
             $block['pages']  = '';
           }
-          // Add defaults and save it into the database.
-          drupal_write_record('block', $block);
-          // Set region to none if not enabled.
-          $block['region'] = $block['status'] ? $block['region'] : BLOCK_REGION_NONE;
+
+          block_save($block);
+
           // Add to the list of blocks we return.
-          $blocks[] = $block;
+          $blocks[$block['block_id']] = $block;
         }
         else {
           // If it's an existing block, database settings should overwrite
-          // the code. But aside from 'info' everything that's definable in
-          // code is stored in the database and we do not store 'info', so we
-          // do not need to update the database here.
+          // the code.
+          // If the block does not have an instance for the selected theme create one now.
+          if (!isset($old_blocks[$module][$delta]->instances[$theme_key])) {
+            $instance = array(
+              'block_id' => $old_blocks[$module][$delta]->block_id,
+              'theme' => $theme_key,
+              'region' => BLOCK_REGION_NONE,
+            );
+            drupal_write_record('block_instance', $instance);
+            $old_blocks[$module][$delta]->instances[$theme_key] = $instance;
+          }
           // Add 'info' to this block.
-          $old_blocks[$module][$delta]['info'] = $block['info'];
+          $old_blocks[$module][$delta]->info = $block['info'];
           // If the region name does not exist, disable the block and assign it to none.
-          if (!empty($old_blocks[$module][$delta]['region']) && !isset($regions[$old_blocks[$module][$delta]['region']])) {
-            drupal_set_message(t('The block %info was assigned to the invalid region %region and has been disabled.', array('%info' => $old_blocks[$module][$delta]['info'], '%region' => $old_blocks[$module][$delta]['region'])), 'warning');
-            $old_blocks[$module][$delta]['status'] = 0;
-            $old_blocks[$module][$delta]['region'] = BLOCK_REGION_NONE;
+          if ($old_blocks[$module][$delta]->instances[$theme_key]['region'] != BLOCK_REGION_NONE && !isset($regions[$old_blocks[$module][$delta]->instances[$theme_key]['region']])) {
+            drupal_set_message(t('The block %info was assigned to the invalid region %region and has been disabled.', array('%info' => $old_blocks[$module][$delta]->info, '%region' => $old_blocks[$module][$delta]->instances[$theme_key]['region'])), 'warning');
+            $old_blocks[$module][$delta]->status = 0;
+            $old_blocks[$module][$delta]->instances[$theme_key]['region'] = BLOCK_REGION_NONE;
+            $block = (array) $old_blocks[$module][$delta];
+            block_save($block);
           }
           else {
-            $old_blocks[$module][$delta]['region'] = $old_blocks[$module][$delta]['status'] ? $old_blocks[$module][$delta]['region'] : BLOCK_REGION_NONE;
+            $old_blocks[$module][$delta]->instances[$theme_key]['region'] = $old_blocks[$module][$delta]->instances[$theme_key]['region'] ? $old_blocks[$module][$delta]->instances[$theme_key]['region'] : BLOCK_REGION_NONE;
           }
           // Add this block to the list of blocks we return.
-          $blocks[] = $old_blocks[$module][$delta];
+          $blocks[$old_blocks[$module][$delta]->block_id] = (array) $old_blocks[$module][$delta];
           // Remove this block from the list of blocks to be deleted.
           unset($old_blocks[$module][$delta]);
         }
@@ -333,9 +476,7 @@ function _block_rehash() {
   foreach ($old_blocks as $module => $old_module_blocks) {
     foreach ($old_module_blocks as $delta => $block) {
       db_delete('block')
-        ->condition('module', $module)
-        ->condition('delta', $delta)
-        ->condition('theme', $theme_key)
+        ->condition('block_id', $block->block_id)
         ->execute();
     }
   }
@@ -355,39 +496,23 @@ function _block_rehash() {
  *   - body: Block contents.
  *   - format: Filter ID of the filter format for the body.
  */
-function block_custom_block_get($bid) {
-  return db_query("SELECT * FROM {block_custom} WHERE bid = :bid", array(':bid' => $bid))->fetchAssoc();
+function block_custom_block_get($block_id) {
+  return db_query("SELECT * FROM {block_custom} WHERE block_id = :block_id", array(':block_id' => $block_id))->fetchAssoc();
 }
 
 /**
  * Define the custom block form.
  */
 function block_custom_block_form($edit = array()) {
-  $edit += array(
-    'info' => '',
-    'body' => '',
-  );
   $form['info'] = array(
     '#type' => 'textfield',
     '#title' => t('Block description'),
-    '#default_value' => $edit['info'],
+    '#default_value' => isset($edit['info']) ? $edit['info'] : '',
     '#maxlength' => 64,
     '#description' => t('A brief description of your block. Used on the <a href="@overview">blocks administration page</a>.', array('@overview' => url('admin/structure/block'))),
     '#required' => TRUE,
     '#weight' => -19,
   );
-  $form['body_field']['#weight'] = -17;
-  $form['body_field']['body'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Block body'),
-    '#default_value' => $edit['body'],
-    '#text_format' => isset($edit['format']) ? $edit['format'] : filter_default_format(),
-    '#rows' => 15,
-    '#description' => t('The content of the block as shown to the user.'),
-    '#required' => TRUE,
-    '#weight' => -17,
-    '#access' => filter_access(filter_format_load($edit['format'])),
-  );
 
   return $form;
 }
@@ -408,11 +533,9 @@ function block_custom_block_form($edit =
 function block_custom_block_save($edit, $delta) {
   db_update('block_custom')
     ->fields(array(
-      'body' => $edit['body'],
       'info' => $edit['info'],
-      'format' => $edit['body_format'],
     ))
-    ->condition('bid', $delta)
+    ->condition('block_id', $edit['block_id'])
     ->execute();
   return TRUE;
 }
@@ -424,16 +547,16 @@ function block_form_user_profile_form_al
   if ($form['#user_category'] == 'account') {
     $account = $form['#user'];
     $rids = array_keys($account->roles);
-    $result = db_query("SELECT DISTINCT b.* FROM {block} b LEFT JOIN {block_role} r ON b.module = r.module AND b.delta = r.delta WHERE b.status = 1 AND b.custom <> 0 AND (r.rid IN (:rids) OR r.rid IS NULL) ORDER BY b.weight, b.module", array(':rids' => $rids));
+    $block_ids = db_query('SELECT b.block_id FROM {block} b LEFT JOIN {block_role} r ON b.block_id = r.block_id WHERE b.status = 1 AND b.custom <> 0 AND (r.rid IN (:rids) OR r.rid IS NULL) ORDER BY b.module', array(':rids' => $rids))->fetchAssoc();
+    $blocks = block_load_multiple($block_ids);
 
-    $blocks = array();
-    foreach ($result as $block) {
+    foreach ($blocks as $block) {
       $data = module_invoke($block->module, 'block_info');
       if ($data[$block->delta]['info']) {
-        $blocks[$block->module][$block->delta] = array(
+        $form['block'][$block->block_id] = array(
           '#type' => 'checkbox',
           '#title' => check_plain($data[$block->delta]['info']),
-          '#default_value' => isset($account->block[$block->module][$block->delta]) ? $account->block[$block->module][$block->delta] : ($block->custom == 1),
+          '#default_value' => isset($account->block[$block->block_id]) ? $account->block[$block->block_id] : ($block->custom == 1),
         );
       }
     }
@@ -476,7 +599,7 @@ function block_system_themes_form_submit
     }
     if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] !== variable_get('admin_theme', 0)) {
       // If we're changing themes, make sure the theme has its blocks initialized.
-      $has_blocks = (bool) db_query_range('SELECT 1 FROM {block} WHERE theme = :theme', 0, 1, array(':theme' => $form_state['values']['admin_theme']))->fetchField();
+      $has_blocks = (bool) db_query_range('SELECT 1 FROM {block_instance} WHERE theme = :theme', 0, 1, array(':theme' => $form_state['values']['admin_theme']))->fetchField();
       if (!$has_blocks) {
         block_theme_initialize($form_state['values']['admin_theme']);
       }
@@ -497,19 +620,23 @@ function block_system_themes_form_submit
  */
 function block_theme_initialize($theme) {
   // Initialize theme's blocks if none already registered.
-  $has_blocks = (bool) db_query_range('SELECT 1 FROM {block} WHERE theme = :theme', 0, 1, array(':theme' => $theme))->fetchField();
+  $has_blocks = (bool) db_query_range('SELECT 1 FROM {block_instance} WHERE theme = :theme', 0, 1, array(':theme' => $theme))->fetchField();
   if (!$has_blocks) {
     $default_theme = variable_get('theme_default', 'garland');
     $regions = system_region_list($theme);
-    $result = db_query("SELECT * FROM {block} WHERE theme = :theme", array(':theme' => $default_theme), array('fetch' => PDO::FETCH_ASSOC));
-    foreach ($result as $block) {
+    $block_ids = db_select('block', 'b')
+      ->fields('b', array('block_id'))
+      ->execute()
+      ->fetchCol();
+    $blocks = block_load_multiple($block_ids);
+    foreach ($blocks as $block) {
       // If the region isn't supported by the theme, assign the block to the theme's default region.
-      if (!array_key_exists($block['region'], $regions)) {
-        $block['region'] = system_default_region($theme);
+      if (!array_key_exists($block->instances[$default_theme]['region'], $regions)) {
+        $block->instances[$theme]['region'] = system_default_region($theme);
       }
-      $block['theme'] = $theme;
-      unset($block['bid']);
-      drupal_write_record('block', $block);
+      $block->instances[$theme]['theme'] = $theme;
+      $block = (array) $block;
+      block_save($block);
     }
   }
 }
@@ -548,30 +675,207 @@ function block_list($region) {
 }
 
 /**
+ * Given a module and delta return the unique ID for a block.
+ *
+ * @param $module
+ *   Name of the module that implements the block.
+ * @param $delta
+ *   Unique ID of the block within the defining module.
+ *
+ * @return
+ *   The numeric entity ID of the block or FALSE if there is no matching block.
+ *   Resuts are statically cached.
+ */
+function block_entity_id($module, $delta) {
+  $block_ids = &drupal_static(__FUNCTION__);
+
+  if (empty($block_ids)) {
+    $block_ids = array();
+    $blocks = db_query('SELECT block_id, module, delta FROM {block}');
+    foreach ($blocks as $block) {
+      $block_ids[$block->module . ':' . $block->delta] = $block->block_id;
+    }
+  }
+
+  return (isset($block_ids[$module . ':' . $delta])) ? $block_ids[$module . ':' . $delta] : NULL;
+}
+
+/**
+ * Load a block object from the database.
+ *
+ * @param $block_id
+ *   The block_id of the block to load.
+ * @param $reset
+ *   Whether to reset the block_load_multiple cache.
+ * @return
+ *   A block object.
+ */
+function block_load($block_id, $reset = FALSE) {
+  $block = block_load_multiple(array($block_id), array(), $reset);
+  return $block ? $block[$block_id] : FALSE;
+}
+
+/**
+ * Load block entities from the database.
+ *
+ * This function should be used whenever you need to load more than one block
+ * from the database. Blocks are loaded into memory and will not require
+ * database access if loaded again during the same page request.
+ *
+ * @see entity_load()
+ *
+ * @param $block_ids
+ *   An array of block IDs.
+ * @param $conditions
+ *   An array of conditions on the {block} table in the form 'field' => $value.
+ * @param $reset
+ *   Whether to reset the internal block_load cache.
+ *
+ * @return
+ *   An array of block objects indexed by block_id.
+ */
+function block_load_multiple($block_ids = array(), $conditions = array(), $reset = FALSE) {
+  return entity_load('block', $block_ids, $conditions, $reset);
+}
+
+/**
+ * Save changes to a block or add a new block and related instances.
+ *
+ * @param $block
+ *   The $block object to be saved. If $block->block_id is omitted a new node
+ *   will be added.
+ */
+function block_save(&$block) {
+  // Check for an existing block with the same module and delta.
+  $block['block_id'] = isset($block['block_id']) ? $block['block_id'] : block_entity_id($block['module'], $block['delta']);
+
+  // Add defaults and save it into the database.
+  $update = (isset($block['block_id'])) ? 'block_id' : FALSE;
+  drupal_write_record('block', $block, $update);
+
+  // Add defaults and save each instance into the database.
+  if (isset($block['instances']) && is_array($block['instances'])) {
+    foreach ($block['instances'] as $key => $instance) {
+      $instance['block_id'] = $block['block_id'];
+      block_instance_save($instance);
+      $block['instances'][$key] = $instance;
+    }
+  }
+
+  // Create a Field API bundle for the block.
+  if (!$update) {
+    field_attach_create_bundle($block['module'] . ':' . $block['delta']);
+  }
+
+  // Clear the page and block caches.
+  cache_clear_all();
+  // Flush the static cache mapping module:delta to a block_id.
+  drupal_static_reset('block_entity_id');
+}
+
+/**
+ * Save changes to an instances or add a new one.
+ *
+ * @param $instances
+ *   A block instance array.
+ */
+function block_instance_save(&$instance) {
+  $instance['theme'] = (isset($instance['theme'])) ? $instance['theme'] : variable_get('theme_default', 'garland');
+  $instance['region'] = (isset($instance['region'])) ? $instance['region'] : BLOCK_REGION_NONE;
+  $update = (isset($instance['block_instance_id'])) ? 'block_instance_id' : NULL;
+  drupal_write_record('block_instance', $instance, $update);
+}
+
+/**
+ * Controller class for blocks.
+ *
+ * This extends the DrupalDefaultEntityController class, adding required
+ * special handling for block objects.
+ */
+class BlockController extends DrupalDefaultEntityController {
+  protected function buildQuery() {
+    parent::buildQuery();
+    $this->query->leftJoin('block_role', 'br', 'base.block_id = br.block_id');
+    $this->query->addField('br', 'rid');
+    $this->query->leftJoin('block_node_type', 'bnt', 'base.block_id = bnt.block_id');
+    $this->query->addField('bnt', 'type');
+  }
+
+  protected function attachLoad(&$records) {
+    // Combine multiple rows that represent the same block from the leftJoin
+    // into a single record.
+    foreach ($records as $record) {
+      if (isset($record->rid)) {
+        $roles[$record->block_id][$record->rid] = $record->rid;
+        unset($record->rid);
+        $record->roles = $roles[$record->block_id];
+      }
+      elseif (!isset($record->roles)) {
+        $record->roles = array();
+      }
+
+      if (isset($record->type)) {
+        $node_types[$record->block_id][$record->type] = $record->type;
+        unset($record->type);
+        $record->node_types = $node_types[$record->block_id];
+      }
+      elseif (!isset($record->nodes)) {
+        $record->node_types = array();
+      }
+      $queried_blocks[$record->block_id] = $record;
+    }
+    $records = $queried_blocks;
+
+    // Load instance information for each block and assign a
+    // block_machine_name.
+    foreach ($records as $record) {
+      $instances = db_query('SELECT block_instance_id, theme, region, weight FROM {block_instance} WHERE block_id = :block_id', array(':block_id' => $record->block_id), array('fetch' => PDO::FETCH_ASSOC));
+      if ($instances) {
+        foreach ($instances as $instance) {
+          $record->instances[$instance['theme']] = $instance;
+        }
+      }
+      $record->block_machine_name = $record->module . ':' . $record->delta;
+    }
+
+    parent::attachLoad($records);
+  }
+}
+
+/**
  * Load blocks information from the database.
  */
 function _block_load_blocks() {
   global $theme_key;
 
   $query = db_select('block', 'b');
+  $query->join('block_instance', 'bi', 'bi.block_id = b.block_id');
   $result = $query
     ->fields('b')
-    ->condition('b.theme', $theme_key)
+    ->fields('bi')
+    ->condition('bi.theme', $theme_key)
     ->condition('b.status', 1)
-    ->orderBy('b.region')
-    ->orderBy('b.weight')
+    ->orderBy('bi.region')
+    ->orderBy('bi.weight')
     ->orderBy('b.module')
     ->addTag('block_load')
-    ->execute();
+    ->execute()
+    ->fetchCol();
+
+  $block_info = block_load_multiple($result);
 
-  $block_info = $result->fetchAllAssoc('bid');
   // Allow modules to modify the block list.
   drupal_alter('block_info', $block_info);
 
   $blocks = array();
   foreach ($block_info as $block) {
+    // Simplify the block structure for theming.
+    $block->theme = $block->instances[$theme_key]['theme'];
+    $block->region = $block->instances[$theme_key]['region'];
+    $block->weight = $block->instances[$theme_key]['weight'];
     $blocks[$block->region]["{$block->module}_{$block->delta}"] = $block;
   }
+
   return $blocks;
 }
 
@@ -584,22 +888,8 @@ function _block_load_blocks() {
 function block_block_info_alter(&$blocks) {
   global $user, $theme_key;
 
-  // Build an array of roles for each block.
-  $block_roles = array();
-  $result = db_query('SELECT module, delta, rid FROM {block_role}');
-  foreach ($result as $record) {
-    $block_roles[$record->module][$record->delta][] = $record->rid;
-  }
-
-  // Build an array of node types for each block.
-  $block_node_types = array();
-  $result = db_query('SELECT module, delta, type FROM {block_node_type}');
-  foreach ($result as $record) {
-    $block_node_types[$record->module][$record->delta][] = $record->type;
-  }
-
   foreach ($blocks as $key => $block) {
-    if ($block->theme != $theme_key || $block->status != 1) {
+    if (!isset($block->instances[$theme_key]) || $block->status != 1) {
       // This block was added by a contrib module, leave it in the list.
       continue;
     }
@@ -607,7 +897,7 @@ function block_block_info_alter(&$blocks
     // If a block has no roles associated, it is displayed for every role.
     // For blocks with roles associated, if none of the user's roles matches
     // the settings from this block, remove it from the block list.
-    if (isset($block_roles[$block->module][$block->delta]) && !array_intersect($block_roles[$block->module][$block->delta], array_keys($user->roles))) {
+    if (count($block->roles) && !array_intersect($block->roles, array_keys($user->roles))) {
       // No match.
       unset($blocks[$key]);
       continue;
@@ -616,11 +906,11 @@ function block_block_info_alter(&$blocks
     // If a block has no node types associated, it is displayed for every type.
     // For blocks with node types associated, if the node type does not match
     // the settings from this block, remove it from the block list.
-    if (isset($block_node_types[$block->module][$block->delta])) {
+    if (count($block->node_types)) {
       $node = menu_get_object();
       if (!empty($node)) {
         // This is a node or node edit page.
-        if (!in_array($node->type, $block_node_types[$block->module][$block->delta])) {
+        if (!in_array($node->type, $block->node_types)) {
           // This block should not be displayed for this node type.
           unset($blocks[$key]);
           continue;
@@ -628,7 +918,7 @@ function block_block_info_alter(&$blocks
       }
       elseif (arg(0) == 'node' && arg(1) == 'add' && in_array(arg(2), array_keys(node_type_get_types()))) {
         // This is a node creation page
-        if (!in_array(arg(2), $block_node_types[$block->module][$block->delta])) {
+        if (!in_array(arg(2), $block->node_types)) {
           // This block should not be displayed for this node type.
           unset($blocks[$key]);
           continue;
@@ -643,8 +933,8 @@ function block_block_info_alter(&$blocks
 
     // Use the user's block visibility setting, if necessary.
     if ($block->custom != 0) {
-      if ($user->uid && isset($user->block[$block->module][$block->delta])) {
-        $enabled = $user->block[$block->module][$block->delta];
+      if ($user->uid && isset($user->block[$block->block_id])) {
+        $enabled = $user->block[$block->block_id];
       }
       else {
         $enabled = ($block->custom == 1);
@@ -723,11 +1013,25 @@ function _block_render_blocks($region_bl
           $block->$k = $v;
         }
       }
-      if (isset($block->content) && $block->content) {
-        // Normalize to the drupal_render() structure.
-        if (is_string($block->content)) {
-          $block->content = array('#markup' => $block->content);
-        }
+
+      // Normalize to the drupal_render() structure.
+      if (!empty($block->content) && is_string($block->content)) {
+        $block->content = array('#markup' => $block->content);
+      }
+      else if (!empty($block->content) && is_array($block->content)) {
+        // If a module provides the conent in a drupal_render() structure move
+        // the module provided content into a child array so it does not get
+        // overwritten when we attach the Fields API content.
+        $block->content = array('module_content' => $block->content);
+        $block->content['module_content']['#weight'] = field_attach_extra_weight($block->block_machine_name, 'module_content');
+      }
+      else {
+        $block->content = array();
+      }
+
+      $block->content += field_attach_view('block', $block, 'full');
+
+      if (!empty($block->content)) {
         // Override default block title if a custom display title is present.
         if ($block->title) {
           // Check plain here to allow module generated titles to keep any
@@ -833,26 +1137,18 @@ function block_user_role_delete($role) {
 }
 
 /**
- * Implement hook_filter_format_delete().
- */
-function block_filter_format_delete($format, $fallback) {
-  db_update('block_custom')
-    ->fields(array('format' => $fallback->format))
-    ->condition('format', $format->format)
-    ->execute();
-}
-
-/**
  * Implement hook_menu_delete().
  */
 function block_menu_delete($menu) {
+  $block_id = block_entity_id('menu', $menu['menu_name']);
   db_delete('block')
-    ->condition('module', 'menu')
-    ->condition('delta', $menu['menu_name'])
+    ->condition('block_id', $block_id)
+    ->execute();
+  db_delete('block_instance')
+    ->condition('block_id', $block_id)
     ->execute();
   db_delete('block_role')
-    ->condition('module', 'menu')
-    ->condition('delta', $menu['menu_name'])
+    ->condition('block_id', $block_id)
     ->execute();
 }
 
@@ -871,7 +1167,7 @@ function block_form_system_performance_s
   );
 
   // Check if the "Who's online" block is enabled.
-  $online_block_enabled = db_query_range("SELECT 1 FROM {block} b WHERE module = 'user' AND delta = 'online' AND status = 1", 0, 1)->fetchField();
+  $online_block_enabled = db_query_range("SELECT 1 FROM {block} b WHERE module = 'user' AND delta = 'online' AND status = 1", 0, 1, array())->fetchField();
 
   // If the "Who's online" block is enabled, append some descriptive text to
   // the end of the form description.
Index: modules/block/block.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.test,v
retrieving revision 1.28
diff -u -p -r1.28 block.test
--- modules/block/block.test	5 Oct 2009 02:43:01 -0000	1.28
+++ modules/block/block.test	11 Oct 2009 03:57:58 -0000
@@ -41,26 +41,27 @@ class BlockTestCase extends DrupalWebTes
     $custom_block = array();
     $custom_block['info'] = $this->randomName(8);
     $custom_block['title'] = $this->randomName(8);
-    $custom_block['body'] = $this->randomName(32);
+    $custom_block['block_body'] = $this->randomName(32);
     $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
 
     // Confirm that the custom block has been created, and then query the created bid.
     $this->assertText(t('The block has been created.'), t('Custom block successfully created.'));
-    $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
+    $block_id = db_query("SELECT block_id FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
 
     // Check to see if the custom block was created by checking that it's in the database..
-    $this->assertNotNull($bid, t('Custom block found in database'));
+    $this->assertNotNull($block_id, t('Custom block found in database'));
 
     // Check if the block can be moved to all availble regions.
+    $custom_block['block_id'] = $block_id;
     $custom_block['module'] = 'block';
-    $custom_block['delta'] = $bid;
+    $custom_block['delta'] = $block_id;
     foreach ($this->regions as $region) {
       $this->moveBlockToRegion($custom_block, $region);
     }
 
     // Delete the created custom block & verify that it's been deleted and no longer appearing on the page.
     $this->clickLink(t('delete'));
-    $this->drupalPost('admin/structure/block/delete/' . $bid, array(), t('Delete'));
+    $this->drupalPost('admin/structure/block/delete/' . $block_id, array(), t('Delete'));
     $this->assertRaw(t('The block %title has been removed.', array('%title' => $custom_block['info'])), t('Custom block successfully deleted.'));
     $this->assertNoText(t($custom_block['title']), t('Custom block no longer appears on page.'));
   }
@@ -73,14 +74,14 @@ class BlockTestCase extends DrupalWebTes
     $custom_block = array();
     $custom_block['info'] = $this->randomName(8);
     $custom_block['title'] = $this->randomName(8);
-    $custom_block['body'] = '<h1>Full HTML</h1>';
-    $custom_block['body_format'] = 2;
+    $custom_block['block_body'] = '<h1>Full HTML</h1>';
+    $custom_block['block_body_format'] = 2;
     $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
 
     // Set the created custom block to a specific region.
-    $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
+    $block_id = db_query("SELECT block_id FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
     $edit = array();
-    $edit['block_' . $bid . '[region]'] = $this->regions[1]['name'];
+    $edit[$block_id . '[region]'] = $this->regions[1]['name'];
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
 
     // Confirm that the custom block is being displayed using configured text format.
@@ -90,9 +91,9 @@ class BlockTestCase extends DrupalWebTes
     // but can still submit the form without errors.
     $block_admin = $this->drupalCreateUser(array('administer blocks'));
     $this->drupalLogin($block_admin);
-    $this->drupalGet('admin/structure/block/configure/block/' . $bid);
+    $this->drupalGet('admin/structure/block/configure/block/' . $block_id);
     $this->assertNoText(t('Block body'));
-    $this->drupalPost('admin/structure/block/configure/block/' . $bid, array(), t('Save block'));
+    $this->drupalPost('admin/structure/block/configure/block/' . $block_id, array(), t('Save block'));
     $this->assertNoText(t('Please ensure that each block description is unique.'));
 
     // Confirm that the custom block is still being displayed using configured text format.
@@ -112,12 +113,12 @@ class BlockTestCase extends DrupalWebTes
     $custom_block = array();
     $custom_block['info'] = $this->randomName(8);
     $custom_block['title'] = $title;
-    $custom_block['body'] = $this->randomName(32);
+    $custom_block['block_body'] = $this->randomName(32);
     $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
     
-    $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
+    $block_id = db_query("SELECT block_id FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
     $block['module'] = 'block';
-    $block['delta'] = $bid;
+    $block['delta'] = $block_id;
     $block['title'] = $title;
 
     // Set the block to be hidden on any user path, and to be shown only to
@@ -125,9 +126,10 @@ class BlockTestCase extends DrupalWebTes
     $edit = array();
     $edit['pages'] = 'user*';
     $edit['roles[2]'] = TRUE;
-    $this->drupalPost('admin/structure/block/configure/' . $block['module'] . '/' . $block['delta'], $edit, t('Save block'));
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, $edit, t('Save block'));
 
     // Move block to the first sidebar.
+    $block['block_id'] = $block_id;
     $this->moveBlockToRegion($block, $this->regions[1]);
 
     $this->drupalGet('');
@@ -153,24 +155,26 @@ class BlockTestCase extends DrupalWebTes
     $block['title'] = $this->randomName(8);
 
     // Set block title to confirm that interface works and override any custom titles.
-    $this->drupalPost('admin/structure/block/configure/' . $block['module'] . '/' . $block['delta'], array('title' => $block['title']), t('Save block'));
+    $block_id = block_entity_id($block['module'], $block['delta']);
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, array('title' => $block['title']), t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block title set.'));
-    $bid = db_query("SELECT bid FROM {block} WHERE module = :module AND delta = :delta", array(
+    $block_id = db_query("SELECT block_id FROM {block} WHERE module = :module AND delta = :delta", array(
       ':module' => $block['module'],
       ':delta' => $block['delta'],
     ))->fetchField();
 
     // Check to see if the block was created by checking that it's in the database.
-    $this->assertNotNull($bid, t('Block found in database'));
+    $this->assertNotNull($block_id, t('Block found in database'));
 
     // Check if the block can be moved to all availble regions.
+    $block['block_id'] = $block_id;
     foreach ($this->regions as $region) {
       $this->moveBlockToRegion($block, $region);
     }
 
     // Set the block to the disabled region.
     $edit = array();
-    $edit[$block['module'] . '_' . $block['delta'] . '[region]'] = '-1';
+    $edit[$block_id . '[region]'] = '-1';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
 
     // Confirm that the block was moved to the proper region.
@@ -178,16 +182,16 @@ class BlockTestCase extends DrupalWebTes
     $this->assertNoText(t($block['title']), t('Block no longer appears on page.'));
 
     // Confirm that the regions xpath is not availble
-    $xpath = '//div[@id="block-block-' . $bid . '"]/*';
+    $xpath = '//div[@id="block-block-' . $block_id . '"]/*';
     $this->assertNoFieldByXPath($xpath, FALSE, t('Custom block found in no regions.'));
 
     // For convenience of developers, put the navigation block back.
     $edit = array();
-    $edit[$block['module'] . '_' . $block['delta'] . '[region]'] = $this->regions[1]['name'];
+    $edit[$block_id . '[region]'] = $this->regions[1]['name'];
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertText(t('The block settings have been updated.'), t('Block successfully move to first sidebar region.'));
 
-    $this->drupalPost('admin/structure/block/configure/' . $block['module'] . '/' . $block['delta'], array('title' => 'Navigation'), t('Save block'));
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, array('title' => 'Navigation'), t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block title set.'));
   }
 
@@ -199,7 +203,7 @@ class BlockTestCase extends DrupalWebTes
 
     // Set the created block to a specific region.
     $edit = array();
-    $edit[$block['module'] . '_' . $block['delta'] . '[region]'] = $region['name'];
+    $edit[$block['block_id'] . '[region]'] = $region['name'];
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
 
     // Confirm that the block was moved to the proper region.
@@ -256,25 +260,22 @@ class NewDefaultThemeBlocks extends Drup
     $this->drupalLogin($admin_user);
 
     // Ensure no other theme's blocks are in the block table yet.
-    $count = db_query_range("SELECT 1 FROM {block} WHERE theme NOT IN ('garland', 'seven')", 0, 1)->fetchField();
+    $count = db_query_range("SELECT 1 FROM {block_instance} WHERE theme NOT IN ('garland', 'seven')", 0, 1)->fetchField();
     $this->assertFalse($count, t('Only Garland and Seven have blocks.'));
 
     // Populate list of all blocks for matching against new theme.
     $blocks = array();
-    $result = db_query("SELECT * FROM {block} WHERE theme = 'garland'");
+    $result = db_query("SELECT b.* FROM {block} b INNER JOIN {block_instance} bi ON bi.block_id = b.block_id WHERE bi.theme = 'garland'");
     foreach ($result as $block) {
-      // $block->theme and $block->bid will not match, so remove them.
-      unset($block->theme, $block->bid);
-      $blocks[$block->module][$block->delta] = $block;
+      $blocks[$block->block_id] = $block;
     }
 
     // Turn on the Stark theme and ensure that it contains all of the blocks
     // that Garland did.
     $this->drupalPost('admin/appearance', array('theme_default' => 'stark'), t('Save configuration'));
-    $result = db_query("SELECT * FROM {block} WHERE theme='stark'");
+    $result = db_query("SELECT b.* FROM {block} b INNER JOIN {block_instance} bi ON bi.block_id = b.block_id WHERE bi.theme='stark'");
     foreach ($result as $block) {
-      unset($block->theme, $block->bid);
-      $this->assertEqual($blocks[$block->module][$block->delta], $block, t('Block %name matched', array('%name' => $block->module . '-' . $block->delta)));
+      $this->assertEqual($blocks[$block->block_id], $block, t('Block %name matched', array('%name' => $block->module . '-' . $block->delta)));
     }
   }
 }
Index: modules/blog/blog.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/blog/blog.test,v
retrieving revision 1.19
diff -u -p -r1.19 blog.test
--- modules/blog/blog.test	11 Oct 2009 03:07:16 -0000	1.19
+++ modules/blog/blog.test	11 Oct 2009 03:57:59 -0000
@@ -62,7 +62,8 @@ class BlogTestCase extends DrupalWebTest
     $this->drupalLogin($this->big_user);
     // Enable the recent blog block.
     $edit = array();
-    $edit['blog_recent[region]'] = 'sidebar_second';
+    $block_id = block_entity_id('blog', 'recent');
+    $edit[$block_id . '[region]'] = 'sidebar_second';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertResponse(200);
 
Index: modules/book/book.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/book/book.test,v
retrieving revision 1.17
diff -u -p -r1.17 book.test
--- modules/book/book.test	11 Oct 2009 03:07:17 -0000	1.17
+++ modules/book/book.test	11 Oct 2009 03:57:59 -0000
@@ -215,12 +215,13 @@ class BookBlockTestCase extends DrupalWe
 
   function testBookNavigationBlock() {
     // Set block title to confirm that the interface is availble.
-    $this->drupalPost('admin/structure/block/configure/book/navigation', array('title' => $this->randomName(8)), t('Save block'));
+    $block_id = block_entity_id('book', 'navigation');
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, array('title' => $this->randomName(8)), t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
 
     // Set the block to a region to confirm block is availble.
     $edit = array();
-    $edit['book_navigation[region]'] = 'footer';
+    $edit[$block_id . '[region]'] = 'footer';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));
   }
Index: modules/comment/comment.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.test,v
retrieving revision 1.47
diff -u -p -r1.47 comment.test
--- modules/comment/comment.test	8 Oct 2009 08:16:54 -0000	1.47
+++ modules/comment/comment.test	11 Oct 2009 03:58:00 -0000
@@ -720,8 +720,9 @@ class CommentBlockFunctionalTest extends
     $this->drupalLogin($this->admin_user);
 
     // Set the block to a region to confirm block is available.
+    $block_id = block_entity_id('comment', 'recent');
     $edit = array(
-      'comment_recent[region]' => 'sidebar_first',
+      $block_id . '[region]' => 'sidebar_first',
     );
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertText(t('The block settings have been updated.'), t('Block saved to first sidebar region.'));
@@ -731,7 +732,7 @@ class CommentBlockFunctionalTest extends
       'title' => $this->randomName(),
       'comment_block_count' => 2,
     );
-    $this->drupalPost('admin/structure/block/configure/comment/recent', $block, t('Save block'));
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, $block, t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block saved.'));
 
     // Add some test comments, one without a subject.
@@ -760,7 +761,7 @@ class CommentBlockFunctionalTest extends
     $block = array(
       'comment_block_count' => 10,
     );
-    $this->drupalPost('admin/structure/block/configure/comment/recent', $block, t('Save block'));
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, $block, t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block saved.'));
 
     // Post an additional comment.
Index: modules/filter/filter.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.test,v
retrieving revision 1.45
diff -u -p -r1.45 filter.test
--- modules/filter/filter.test	11 Oct 2009 03:07:18 -0000	1.45
+++ modules/filter/filter.test	11 Oct 2009 03:58:02 -0000
@@ -1130,8 +1130,8 @@ class FilterHooksTestCase extends Drupal
   }
 
   function setUp() {
-    parent::setUp('block', 'filter_test');
-    $admin_user = $this->drupalCreateUser(array('administer filters', 'administer blocks'));
+    parent::setUp('filter_test');
+    $admin_user = $this->drupalCreateUser(array('administer filters', 'administer nodes', 'administer comments'));
     $this->drupalLogin($admin_user);
   }
 
@@ -1157,29 +1157,30 @@ class FilterHooksTestCase extends Drupal
     $this->assertRaw(t('The text format %format has been updated.', array('%format' => $name)), t('Format successfully updated.'));
     $this->assertText('hook_filter_format_update invoked.', t('hook_filter_format_update() was invoked.'));
 
-    // Add a new custom block.
-    $custom_block = array();
-    $custom_block['info'] = $this->randomName(8);
-    $custom_block['title'] = $this->randomName(8);
-    $custom_block['body'] = $this->randomName(32);
-    // Use the format created.
-    $custom_block['body_format'] = $format;
-    $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
-    $this->assertText(t('The block has been created.'), t('New block successfully created.'));
-
-    // Verify the new block is in the database.
-    $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
-    $this->assertNotNull($bid, t('New block found in database'));
+
+    // Create a node and post a comment to it using the format created.
+    $node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_OPEN));
+    $this->assertTrue($node, t('Article node created.'));
+    $edit = array();
+    $edit['subject'] = $this->randomName(8);
+    $edit['comment'] = $this->randomName(32);
+    $edit['comment_format'] = $format;
+    $this->drupalPost('node/' . $node->nid, $edit, t('Save'));
+    $this->assertText($edit['subject'], t('Comment created.'));
+
+    // Verify the new comment is in the database.
+    $cid = db_query("SELECT cid FROM {comment} WHERE nid = :nid AND subject = :subject", array(':nid' => $node->nid, ':subject' => $edit['subject']))->fetchField();
+    $this->assertNotNull($cid, t('New comment found in database'));
 
     // Delete the text format.
     $this->drupalPost('admin/config/content/formats/' . $format . '/delete', array(), t('Delete'));
     $this->assertRaw(t('Deleted text format %format.', array('%format' => $name)), t('Format successfully deleted.'));
     $this->assertText('hook_filter_format_delete invoked.', t('hook_filter_format_delete() was invoked.'));
 
-    // Verify that the deleted format was replaced with the fallback format.
-    $current_format = db_select('block_custom', 'b')
-      ->fields('b', array('format'))
-      ->condition('bid', $bid)
+    // Verify that the deleted format was replaced with the default format.
+    $current_format = db_select('comment', 'c')
+      ->fields('c', array('format'))
+      ->condition('cid', $cid)
       ->execute()
       ->fetchField();
     $this->assertEqual($current_format, filter_fallback_format(), t('Deleted text format replaced with the fallback format.'));
Index: modules/forum/forum.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.test,v
retrieving revision 1.34
diff -u -p -r1.34 forum.test
--- modules/forum/forum.test	11 Oct 2009 03:07:18 -0000	1.34
+++ modules/forum/forum.test	11 Oct 2009 03:58:02 -0000
@@ -81,14 +81,14 @@ class ForumTestCase extends DrupalWebTes
 
     // Enable the active forum block.
     $edit = array();
-    $edit['forum_active[region]'] = 'sidebar_second';
+    $edit[block_entity_id('forum', 'active') . '[region]'] = 'sidebar_second';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertResponse(200);
     $this->assertText(t('The block settings have been updated.'), t('Active forum topics forum block was enabled'));
 
     // Enable the new forum block.
     $edit = array();
-    $edit['forum_new[region]'] = 'sidebar_second';
+    $edit[block_entity_id('forum', 'new') . '[region]'] = 'sidebar_second';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertResponse(200);
     $this->assertText(t('The block settings have been updated.'), t('[New forum topics] Forum block was enabled'));
Index: modules/locale/locale.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.test,v
retrieving revision 1.43
diff -u -p -r1.43 locale.test
--- modules/locale/locale.test	11 Oct 2009 03:07:18 -0000	1.43
+++ modules/locale/locale.test	11 Oct 2009 03:58:04 -0000
@@ -1067,7 +1067,7 @@ class LanguageSwitchingFunctionalTest ex
   function testLanguageBlock() {
     // Enable the language switching block.
     $edit = array(
-      'locale_language[region]' => 'sidebar_first',
+      block_entity_id('locale', 'language') . '[region]' => 'sidebar_first',
     );
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
 
Index: modules/menu/menu.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.test,v
retrieving revision 1.24
diff -u -p -r1.24 menu.test
--- modules/menu/menu.test	11 Oct 2009 03:07:18 -0000	1.24
+++ modules/menu/menu.test	11 Oct 2009 03:58:04 -0000
@@ -154,10 +154,18 @@ class MenuTestCase extends DrupalWebTest
     $this->drupalGet('admin/structure/menu');
     $this->assertText($title, 'Menu created');
 
+    // After creating a custom menu there is also a new block provided by menu
+    // that has not been saved to the {block} table yet. Save the new block and
+    // flush the block_entity_id cache so that the remainder of the tests can
+    // use the new block.
+    _block_rehash();
+    drupal_static_reset('block_entity_id');
+
     // Enable the custom menu block.
     $menu_name = 'menu-' . $menu_name; // Drupal prepends the name with 'menu-'.
     $edit = array();
-    $edit['menu_' . $menu_name . '[region]'] = 'sidebar_first';
+    $block_id = block_entity_id('menu', $menu_name);
+    $edit[$block_id . '[region]'] = 'sidebar_first';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertResponse(200);
     $this->assertText(t('The block settings have been updated.'), t('Custom menu block was enabled'));
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	11 Oct 2009 03:58:06 -0000
@@ -490,12 +490,13 @@ class NodeBlockTestCase extends DrupalWe
 
   function testSearchFormBlock() {
     // Set block title to confirm that the interface is availble.
-    $this->drupalPost('admin/structure/block/configure/node/syndicate', array('title' => $this->randomName(8)), t('Save block'));
+    $block_id = block_entity_id('node', 'syndicate');
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, array('title' => $this->randomName(8)), t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
 
     // Set the block to a region to confirm block is availble.
     $edit = array();
-    $edit['node_syndicate[region]'] = 'footer';
+    $edit[$block_id . '[region]'] = 'footer';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));
   }
Index: modules/poll/poll.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/poll/poll.test,v
retrieving revision 1.24
diff -u -p -r1.24 poll.test
--- modules/poll/poll.test	11 Oct 2009 03:07:19 -0000	1.24
+++ modules/poll/poll.test	11 Oct 2009 03:58:06 -0000
@@ -260,12 +260,13 @@ class PollBlockTestCase extends PollTest
 
   function testRecentBlock() {
     // Set block title to confirm that the interface is available.
-    $this->drupalPost('admin/structure/block/configure/poll/recent', array('title' => $this->randomName(8)), t('Save block'));
+    $block_id = block_entity_id('poll', 'recent');
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, array('title' => $this->randomName(8)), t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
 
     // Set the block to a region to confirm block is available.
     $edit = array();
-    $edit['poll_recent[region]'] = 'footer';
+    $edit[$block_id . '[region]'] = 'footer';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));
 
Index: modules/profile/profile.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/profile/profile.test,v
retrieving revision 1.21
diff -u -p -r1.21 profile.test
--- modules/profile/profile.test	5 Oct 2009 01:18:25 -0000	1.21
+++ modules/profile/profile.test	11 Oct 2009 03:58:06 -0000
@@ -314,12 +314,13 @@ class ProfileBlockTestCase extends Drupa
 
   function testAuthorInformationBlock() {
     // Set block title to confirm that the interface is availble.
-    $this->drupalPost('admin/structure/block/configure/profile/author-information', array('title' => $this->randomName(8)), t('Save block'));
+    $block_id = block_entity_id('profile', 'author-information');
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, array('title' => $this->randomName(8)), t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
 
     // Set the block to a region to confirm block is availble.
     $edit = array();
-    $edit['profile_author-information[region]'] = 'footer';
+    $edit[$block_id . '[region]'] = 'footer';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));
   }
Index: modules/search/search.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.test,v
retrieving revision 1.38
diff -u -p -r1.38 search.test
--- modules/search/search.test	11 Oct 2009 03:07:19 -0000	1.38
+++ modules/search/search.test	11 Oct 2009 03:58:06 -0000
@@ -404,12 +404,13 @@ class SearchBlockTestCase extends Drupal
 
   function testSearchFormBlock() {
     // Set block title to confirm that the interface is availble.
-    $this->drupalPost('admin/structure/block/configure/search/form', array('title' => $this->randomName(8)), t('Save block'));
+    $block_id = block_entity_id('search', 'form');
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, array('title' => $this->randomName(8)), t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
 
     // Set the block to a region to confirm block is availble.
     $edit = array();
-    $edit['search_form[region]'] = 'footer';
+    $edit[$block_id . '[region]'] = 'footer';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));
   }
@@ -420,7 +421,8 @@ class SearchBlockTestCase extends Drupal
   function testBlock() {
     // Enable the block, and place it in the 'content' region so that it isn't
     // hidden on 404 pages.
-    $edit = array('search_form[region]' => 'content');
+    $block_id = block_entity_id('search', 'form');
+    $edit = array($block_id . '[region]' => 'content');
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
 
     // Test a normal search via the block form, from the front page.
@@ -434,7 +436,7 @@ class SearchBlockTestCase extends Drupal
 
     // Test a search from the block when it doesn't appear on the search page.
     $edit = array('pages' => 'search');
-    $this->drupalPost('admin/structure/block/configure/search/form', $edit, t('Save block'));
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, $edit, t('Save block'));
     $this->drupalPost('node', $terms, t('Search'));
     $this->assertText('Your search yielded no results');
   }
Index: modules/system/system.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.test,v
retrieving revision 1.83
diff -u -p -r1.83 system.test
--- modules/system/system.test	11 Oct 2009 03:07:20 -0000	1.83
+++ modules/system/system.test	11 Oct 2009 03:58:07 -0000
@@ -565,7 +565,7 @@ class AccessDeniedTestCase extends Drupa
     // Log back in, set the custom 403 page to /user and remove the block
     $this->drupalLogin($this->admin_user);
     variable_set('site_403', 'user');
-    $this->drupalPost('admin/structure/block', array('user_login[region]' => '-1'), t('Save blocks'));
+    $this->drupalPost('admin/structure/block', array(block_entity_id('user', 'login') . '[region]' => '-1'), t('Save blocks'));
 
     // Check that we can log in from the 403 page.
     $this->drupalLogout();
@@ -895,12 +895,13 @@ class SystemBlockTestCase extends Drupal
    */
   function testPoweredByBlock() {
     // Set block title and some settings to confirm that the interface is availble.
-    $this->drupalPost('admin/structure/block/configure/system/powered-by', array('title' => $this->randomName(8), 'color' => 'powered-black', 'size' => '135x42'), t('Save block'));
+    $block_id = block_entity_id('system', 'powered-by');
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, array('title' => $this->randomName(8), 'color' => 'powered-black', 'size' => '135x42'), t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
 
     // Set the powered-by block to the footer region.
     $edit = array();
-    $edit['system_powered-by[region]'] = 'footer';
+    $edit[$block_id . '[region]'] = 'footer';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));
 
@@ -909,7 +910,7 @@ class SystemBlockTestCase extends Drupal
 
     // Set the block to the disabled region.
     $edit = array();
-    $edit['system_powered-by[region]'] = '-1';
+    $edit[$block_id . '[region]'] = '-1';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
 
     // Confirm that the block is hidden.
@@ -917,9 +918,9 @@ class SystemBlockTestCase extends Drupal
 
     // For convenience of developers, set the block to it's default settings.
     $edit = array();
-    $edit['system_powered-by[region]'] = 'footer';
+    $edit[$block_id . '[region]'] = 'footer';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
-    $this->drupalPost('admin/structure/block/configure/system/powered-by', array('title' => '', 'color' => 'powered-blue', 'size' => '80x15'), t('Save block'));
+    $this->drupalPost('admin/structure/block/configure/' . $block_id, array('title' => '', 'color' => 'powered-blue', 'size' => '80x15'), t('Save block'));
   }
 
 }
Index: profiles/default/default.install
===================================================================
RCS file: /cvs/drupal/drupal/profiles/default/default.install,v
retrieving revision 1.9
diff -u -p -r1.9 default.install
--- profiles/default/default.install	8 Oct 2009 07:58:47 -0000	1.9
+++ profiles/default/default.install	11 Oct 2009 03:58:08 -0000
@@ -9,113 +9,125 @@
 function default_install() {
 
   // Enable some standard blocks.
-  $values = array(
+  $blocks = array(
     array(
       'module' => 'system',
       'delta' => 'main',
-      'theme' => 'garland',
       'status' => 1,
-      'weight' => 0,
-      'region' => 'content',
-      'pages' => '',
-      'cache' => -1,
-    ),
-    array(
-      'module' => 'search',
-      'delta' => 'form',
-      'theme' => 'garland',
-      'status' => 1,
-      'weight' => -1,
-      'region' => 'sidebar_first',
       'pages' => '',
       'cache' => -1,
+      'instances' => array(
+        array(
+          'theme' => 'garland',
+          'region' => 'content',
+          'weight' => 0,
+        ),
+        array(
+          'theme' => 'seven',
+          'region' => 'content',
+          'weight' => 0,
+        ),
+      ),
     ),
     array(
       'module' => 'user',
       'delta' => 'login',
-      'theme' => 'garland',
       'status' => 1,
-      'weight' => 0,
-      'region' => 'sidebar_first',
       'pages' => '',
       'cache' => -1,
+      'instances' => array(
+        array(
+          'theme' => 'garland',
+          'region' => 'sidebar_first',
+          'weight' => 0,
+        ),
+        array(
+          'theme' => 'seven',
+          'region' => 'content',
+          'weight' => 10,
+        ),
+      ),
     ),
     array(
       'module' => 'system',
       'delta' => 'navigation',
-      'theme' => 'garland',
       'status' => 1,
-      'weight' => 0,
-      'region' => 'sidebar_first',
       'pages' => '',
       'cache' => -1,
+      'instances' => array(
+        array(
+          'theme' => 'garland',
+          'region' => 'sidebar_first',
+          'weight' => 0,
+        ),
+      ),
     ),
     array(
       'module' => 'system',
       'delta' => 'management',
-      'theme' => 'garland',
-      'status' => 1,
-      'weight' => 1,
-      'region' => 'sidebar_first',
-      'pages' => '',
-      'cache' => -1,
-    ),
-    array(
-      'module' => 'system',
-      'delta' => 'powered-by',
-      'theme' => 'garland',
       'status' => 1,
-      'weight' => 10,
-      'region' => 'footer',
       'pages' => '',
       'cache' => -1,
+      'instances' => array(
+        array(
+          'theme' => 'garland',
+          'region' => 'sidebar_first',
+          'weight' => 1,
+        ),
+      ),
     ),
     array(
-      'module' => 'system',
-      'delta' => 'help',
-      'theme' => 'garland',
+      'module' => 'search',
+      'delta' => 'form',
       'status' => 1,
-      'weight' => 0,
-      'region' => 'help',
       'pages' => '',
       'cache' => -1,
+      'instances' => array(
+        array(
+          'theme' => 'garland',
+          'region' => 'sidebar_first',
+          'weight' => -1,
+        )
+      ),
     ),
     array(
       'module' => 'system',
-      'delta' => 'main',
-      'theme' => 'seven',
+      'delta' => 'powered-by',
       'status' => 1,
-      'weight' => 0,
-      'region' => 'content',
       'pages' => '',
       'cache' => -1,
+      'instances' => array(
+        array(
+          'theme' => 'garland',
+          'region' => 'footer',
+          'weight' => 10,
+        ),
+      ),
     ),
     array(
       'module' => 'system',
       'delta' => 'help',
-      'theme' => 'seven',
-      'status' => 1,
-      'weight' => 0,
-      'region' => 'help',
-      'pages' => '',
-      'cache' => -1,
-    ),
-    array(
-      'module' => 'user',
-      'delta' => 'login',
-      'theme' => 'seven',
       'status' => 1,
-      'weight' => 10,
-      'region' => 'content',
       'pages' => '',
       'cache' => -1,
+      'instances' => array(
+        array(
+          'theme' => 'garland',
+          'region' => 'help',
+          'weight' => 0,
+        ),
+        array(
+          'theme' => 'seven',
+          'region' => 'help',
+          'weight' => 0,
+        ),
+      ),
     ),
   );
-  $query = db_insert('block')->fields(array('module', 'delta', 'theme', 'status', 'weight', 'region', 'pages', 'cache'));
-  foreach ($values as $record) {
-    $query->values($record);
+
+  foreach ($blocks as $block) {
+    block_save($block);
   }
-  $query->execute();
 
   // Insert default user-defined node types into the database. For a complete
   // list of available node type attributes, refer to the node type API
