diff --git a/fe_block.module b/fe_block.module
index 91826b9..dffb554 100644
--- a/fe_block.module
+++ b/fe_block.module
@@ -1,6 +1,16 @@
 <?php
 
 /**
+ * @file
+ * Provide features components for exporting core blocks and settings.
+ */
+
+/**
+ * Version number for the current fe_block export definition.
+ */
+define('FE_BLOCK_VERSION', '2.0');
+
+/**
  * Implements hook_features_api().
  */
 function fe_block_features_api() {
@@ -31,7 +41,7 @@ function fe_block_features_api() {
 function fe_block_settings_features_export_options() {
   $options = array();
 
-  $blocks = _block_rehash();
+  $blocks = _fe_block_get_blocks();
   usort($blocks, '_fe_block_compare');
 
   foreach ($blocks as $block) {
@@ -81,192 +91,441 @@ function fe_block_settings_features_export($data, &$export, $module_name = '') {
  * Implements hook_features_export_render().
  */
 function fe_block_settings_features_export_render($module_name = '', $data) {
-  global $custom_theme, $theme_key;
-  drupal_theme_initialize();
-  $backup = array($custom_theme, $theme_key);
-
-  $component = 'fe_block_settings';
-  $default_hook = 'default_' . $component;
-  $theme_default = variable_get('theme_default', 'garland');
-  $themes = list_themes();
-
   $code = array();
   $code[] = '  $export = array();';
   $code[] = '';
 
-  // Provide backwards compatibility.
-  $code[] = '  $export[\'version\'] = \'1.0\';';
+  // The way the blocks are exported has changed throughout the history of the
+  // module. We provide an export format version string to provide backwards
+  // compatibility. Note that it is ok to use the array key "version" here.
+  // Block ids always have a '-' in their string.
+  $code[] = '  $export[\'version\'] = \'' . FE_BLOCK_VERSION . '\';';
   $code[] = '';
 
-  // Retrieve node type visibility settings.
-  $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] = TRUE;
+  // Get a list of all active themes to cycle through.
+  $themes = _fe_block_get_active_themes();
+
+  // Retrieve block settings for all blocks in all active themes.
+  $blocks = array();
+  foreach ($themes as $theme) {
+    $blocks[$theme] = _fe_block_info_by_theme($theme);
   }
 
-  // Filter all blocks, keeping only the ones that will be exported.
-  $blocks = _block_rehash();
-  usort($blocks, '_fe_block_compare');
-  foreach ($blocks as $key => $block) {
-    $block_id = _fe_block_build_id($block);
-    if (empty($block_id) || !in_array($block_id, $data)) {
-      unset($blocks[$key]);
+  // We use the first theme's block settings as master settings. Some settings
+  // are specific to each theme, but these are processed later in the loop.
+  $default_theme = reset($themes);
+
+  // We try to build an export for each defined data element.
+  foreach ($data as $name) {
+    // Check if the block still exists in the block definitions.
+    if (!empty($blocks[$default_theme][$name])) {
+      $block = $blocks[$default_theme][$name];
+
+      // We start to build the export object for this block.
+      // First we retrieve data that is valid for any theme.
+      $export_block = _fe_block_get_global_settings($block);
+      // Ensure core custom block export keys are transformed.
+      $export_block = _fe_block_prepare_custom_blocks_for_export($export_block);
+      // Add node type settings.
+      $export_block['node_types'] = _fe_block_get_block_node_types($block);
+      // @todo: Add role visibility settings.
+      // Add theme specific settings for every active theme.
+      $export_block['themes'] = array();
+      foreach ($themes as $theme) {
+        $export_block['themes'][$theme] = _fe_block_get_theme_specific_settings($blocks[$theme][$name]);
+      }
+
+      // Sort export array keys.
+      ksort($export_block);
+
+      // Export to code.
+      $code[] = '  $export[\'' . $name . '\'] = ' . features_var_export($export_block, '  ') . ';';
+      // Add an empty line.
+      $code[] = '';
     }
   }
 
-  // Export theme independent visibility settings.
-  $code[] = '  // Theme independent visibility settings.';
+  $code[] = '  return $export;';
+  $code = implode("\n", $code);
 
-  $visibility = array();
-  foreach ($blocks as $block) {
-    $block_id = _fe_block_build_id($block);
-    $visibility[$block_id]['module'] = $block['module'];
-    // Use machine name with boxes.
-    if ($block['module'] == 'block') {
-      $visibility[$block_id]['machine_name'] = fe_block_get_machine_name($block['delta']);
-    }
-    else {
-      $visibility[$block_id]['delta'] = $block['delta'];
+  return array('default_fe_block_settings' => $code);
+}
+
+/**
+ * Returns the block definitions for a specific theme.
+ *
+ * @param string $theme
+ *   Machine name of the theme.
+ *
+ * @return array
+ *   Array of block definitions.
+ */
+function _fe_block_info_by_theme($theme) {
+  $blocks = array();
+  foreach (_fe_block_get_blocks($theme) as $block) {
+    // Blocks are only valid for export if we got a machine name for them.
+    if ($id = _fe_block_build_id($block)) {
+      $blocks[$id] = $block;
     }
+  }
+  // Sort blocks by keys to get a consistent order.
+  ksort($blocks);
+  return $blocks;
+}
+
+/**
+ * Retrieve the global (non-theme-specific) part of a block definition.
+ *
+ * @param array $block
+ *   A block definition.
+ *
+ * @return array
+ *   The block definition filtered on non-theme-specific settings.
+ */
+function _fe_block_get_global_settings($block) {
+  $theme_specific_defaults = _fe_block_theme_specific_defaults();
+  // Filter on any keys other than the theme specific ones.
+  $return = array_diff_key($block, $theme_specific_defaults);
+
+  // Remove the serial.
+  if (isset($return['bid'])) {
+    unset($return['bid']);
+  }
+  // Remove the info from hook_block_info().
+  if (isset($return['info'])) {
+    unset($return['info']);
+  }
 
-    // Export node type visibility.
-    $visibility[$block_id]['node_type'] = !empty($block_node_types[$block['module']][$block['delta']]) ? $block_node_types[$block['module']][$block['delta']] : array();
+  return $return;
+}
 
-    // @todo export role visibility.
+/**
+ * Helper to prepare a core custom block for export.
+ *
+ * Replaces the block delta that is used by the core block module with a unique
+ * machine name.
+ *
+ * @param array $block
+ *   Block definition - can be only part of the original definition.
+ *
+ * @return array
+ *   Altered block array.
+ */
+function _fe_block_prepare_custom_blocks_for_export($block) {
+  if ($block['module'] == 'block') {
+    $block['machine_name'] = fe_block_get_machine_name($block['delta']);
+    unset($block['delta']);
   }
+  return $block;
+}
 
-  // Sort the array and remove empty values.
-  _features_sanitize($visibility);
+/**
+ * Helper function. Prepares an exported core custom block for import.
+ *
+ * @param array $block
+ *   Block definition from the import code.
+ *
+ * @return array
+ *   Altered array with machine_name replaced by delta.
+ */
+function _fe_block_prepare_custom_blocks_for_import($block) {
+  if ($block['module'] == 'block') {
+    $block['delta'] = fe_block_get_bid($block['machine_name'], TRUE);
+    unset($block['machine_name']);
+  }
+  return $block;
+}
 
-  $code[] = '  $export[\'visibility\'] = ' . features_var_export($visibility, '  ') . ';';
-  $code[] = '';
+/**
+ * Helper function to get the theme specific settings for a block.
+ *
+ * @param array $block
+ *   A single block definition.
+ *
+ * @return array
+ *   A filtered block definition with only theme-specific settings.
+ */
+function _fe_block_get_theme_specific_settings($block) {
+  $defaults = _fe_block_theme_specific_defaults();
+  $settings = array_intersect_key($block, $defaults);
+  // Region.
+  if ($settings['region'] == BLOCK_REGION_NONE) {
+    $settings['status'] = 0;
+    $settings['region'] = '';
+  }
+  ksort($settings);
+  return $settings;
+}
 
-  // Export theme specific settings.
-  foreach ($themes as $_theme_key => $theme) {
-    if ($_theme_key == $theme_default || !empty($theme->status)) {
-      $code[] = '  // Exported block settings for ' . $theme->info['name'] . '.';
-      $code[] = '  $theme = array();';
-      $code[] = '';
+/**
+ * Helper function for filtering theme specific settings.
+ *
+ * @see _fe_block_get_global_settings()
+ * @see _fe_block_get_theme_specific_settings()
+ *
+ * @return array
+ *   An array of default settings, keyed by name.
+ */
+function _fe_block_theme_specific_defaults() {
+  return array(
+    'theme' => '',
+    'status' => '',
+    'weight' => 0,
+    'region' => '',
+  );
+}
+
+/**
+ * Get node type visibility settings for the specified block.
+ *
+ * @param array $block
+ *   Block definition array.
+ *
+ * @return array
+ *   Array of node types associated with the block.
+ */
+function _fe_block_get_block_node_types($block) {
+  $query = db_select('block_node_type', 'bnt')
+    ->condition('module', $block['module'])
+    ->condition('delta', $block['delta'])
+    ->fields('bnt', array('type'))
+    ->orderBy('bnt.type', 'ASC');
+  return $query->execute()->fetchCol();
+}
 
-      // Get the block list for the current theme.
-      $custom_theme = $theme_key = $_theme_key;
-      $blocks = _block_rehash();
-      usort($blocks, '_fe_block_compare');
+/**
+ * Returns the blocks currently exported by modules.
+ *
+ * Derived from _block_rehash().
+ *
+ * @param $theme
+ *   The theme to retrieve blocks for. If not provided, defaults to the
+ *   currently used theme.
+ *
+ * @return
+ *   Blocks currently exported by modules.
+ */
+function _fe_block_get_blocks($theme = NULL) {
+  global $theme_key;
+  $blocks = &drupal_static(__FUNCTION__);
 
-      foreach ($blocks as $block) {
-        unset($block['bid'], $block['info']);
-        $block_id = _fe_block_build_id($block);
-        if (empty($block_id)) {
-          continue;
+  drupal_theme_initialize();
+  if (!isset($theme)) {
+    // If theme is not specifically set, rehash for the current theme.
+    $theme = $theme_key;
+  }
+  if (!isset($blocks[$theme])) {
+    $regions = system_region_list($theme);
+
+    // These are the blocks defined by code and modified by the database.
+    $current_blocks = array();
+    // These are {block}.bid values to be kept.
+    $bids = array();
+    $or = db_or();
+    // Gather the blocks defined by modules.
+    foreach (module_implements('block_info') as $module) {
+      $module_blocks = module_invoke($module, 'block_info');
+      foreach ($module_blocks as $delta => $block) {
+        // Compile a condition to retrieve this block from the database.
+        $condition = db_and()
+          ->condition('module', $module)
+          ->condition('delta', $delta);
+        $or->condition($condition);
+        // Add identifiers.
+        $block['module'] = $module;
+        $block['delta']  = $delta;
+        $block['theme']  = $theme;
+        $current_blocks[$module][$delta] = $block;
+      }
+    }
+    // Retrieve database settings for all blocks that are defined by modules.
+    $code_blocks = $current_blocks;
+    $database_blocks = db_select('block', 'b')
+      ->fields('b')
+      ->condition($or)
+      ->condition('theme', $theme)
+      ->execute();
+    foreach ($database_blocks as $block) {
+      // Preserve info which is not in the database.
+      $block->info = $current_blocks[$block->module][$block->delta]['info'];
+      // The cache mode can only by set from hook_block_info(), so that has
+      // precedence over the database's value.
+      if (isset($current_blocks[$block->module][$block->delta]['cache'])) {
+        $block->cache = $current_blocks[$block->module][$block->delta]['cache'];
+      }
+      // Blocks stored in the database override the blocks defined in code.
+      $current_blocks[$block->module][$block->delta] = get_object_vars($block);
+      // Preserve this block.
+      $bids[$block->bid] = $block->bid;
+    }
+    drupal_alter('block_info', $current_blocks, $theme, $code_blocks);
+    foreach ($current_blocks as $module => $module_blocks) {
+      foreach ($module_blocks as $delta => $block) {
+        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']  = '';
         }
-        if (in_array($block_id, $data)) {
-          // Use machine name with boxes.
-          if ($block['module'] == 'block') {
-            $block['machine_name'] = fe_block_get_machine_name($block['delta']);
-            unset($block['delta']);
-          }
-          // Region.
-          if ($block['region'] == BLOCK_REGION_NONE) {
-            $block['status'] = 0;
-            $block['region'] = '';
-          }
-
-          $code[] = '  $theme[\'' . $block_id . '\'] = ' . features_var_export($block, '  ') . ';';
-          $code[] = '';
+        // Make sure weight is set.
+        if (!isset($block['weight'])) {
+          $block['weight'] = 0;
         }
+        // Disable blocks that are not assigned to a region in the theme.
+        if (!empty($block['region']) && $block['region'] != BLOCK_REGION_NONE && !isset($regions[$block['region']]) && $block['status'] == 1) {
+          // Disabled modules are moved into the BLOCK_REGION_NONE later so no
+          // need to move the block to another region.
+          $block['status'] = 0;
+        }
+        // Set region to none if not enabled and make sure status is set.
+        if (empty($block['status'])) {
+          $block['status'] = 0;
+          $block['region'] = BLOCK_REGION_NONE;
+        }
+        // Add to the list of blocks we return.
+        $blocks[$theme][] = $block;
       }
-
-      $code[] = '  $export[\'theme\'][\'' . $_theme_key . '\'] = $theme;';
-      $code[] = '';
     }
   }
+  return $blocks[$theme];
+}
 
-  // Only return for enabled themes and the default theme.
-  $code[] = '  $theme_default = variable_get(\'theme_default\', \'bartik\');';
-  $code[] = '  $themes = list_themes();';
-  $code[] = '  foreach ($export[\'theme\'] as $theme_key => $settings) {';
-  $code[] = '    if ($theme_key != $theme_default && empty($themes[$theme_key]->status)) {';
-  $code[] = '      unset($export[\'theme\'][$theme_key]);';
-  $code[] = '    }';
-  $code[] = '  }';
-  $code[] = '  return $export;';
-  $code = implode("\n", $code);
-
-  list($custom_theme, $theme_key) = $backup;
-  return array($default_hook => $code);
+/**
+ * Returns a list of machine names of active themes.
+ *
+ * @return array
+ *   An array of theme machine names.
+ */
+function _fe_block_get_active_themes() {
+  $theme_names = array();
+  foreach (list_themes() as $machine_name => $theme) {
+    if (!empty($theme->status)) {
+      $theme_names[] = $machine_name;
+    }
+  }
+  sort($theme_names);
+  return $theme_names;
 }
 
 /**
  * Implements hook_features_revert().
  */
 function fe_block_settings_features_revert($module_name = NULL) {
-  global $custom_theme, $theme_key;
+
   $component = 'fe_block_settings';
   $defaults = features_get_default($component, $module_name);
   if (empty($defaults)) {
     return;
   }
 
-  // Provide backwards compatibility with the old export format that only
-  // supported theme specific settings.
-  if ($new_format = (isset($defaults['version']) && $defaults['version'] == '1.0')) {
-    $themes = $defaults['theme'];
-  }
-  else {
-    $themes = $defaults;
-  }
+  // We remove the version, as we now want to deal with actual block settings.
+  unset($defaults['version']);
 
-  // Revert theme specific settings.
-  foreach ($themes as $_theme_key => $theme) {
-    $custom_theme = $theme_key = $_theme_key;
-    _block_rehash();
+  $themes_rehashed = array();
+  $active_themes = _fe_block_get_active_themes();
+  // The fallback theme for theme specific settings.
+  $theme_default = variable_get('theme_default', 'bartik');
 
-    foreach ($theme as $block) {
-      // Convert machine name back to bid.
-      if ($block['module'] == 'block') {
-        $block['delta'] = fe_block_get_bid($block['machine_name'], TRUE);
-      }
+  foreach ($defaults as $block) {
+    // Core custom blocks are prepared with a delta value.
+    $block = _fe_block_prepare_custom_blocks_for_import($block);
 
-      drupal_write_record('block', $block, array('module', 'delta', 'theme'));
-    }
-  }
+    // Remove the additional settings from the block array, to process them
+    // later. We explicitely set NULL, if no setting was given in the defaults.
+    $block_themes = $block['themes'];
+    $block_node_types = isset($block['node_types']) ? $block['node_types'] : NULL;
+    unset($block['themes']);
+    unset($block['node_types']);
+
+    // Restore theme specific settings for every active theme.
+    foreach ($active_themes as $theme) {
 
-  // Revert node type visibility settings. These have been introduced with the
-  // new export format.
-  if ($new_format) {
-    foreach ($defaults['visibility'] as $block) {
-      // Convert machine name back to bid.
-      if ($block['module'] == 'block') {
-        $block['delta'] = fe_block_get_bid($block['machine_name']);
+      // Rehash if we did not yet.
+      if (empty($themes_rehashed[$theme])) {
+        _block_rehash($theme);
+        $themes_rehashed[$theme] = TRUE;
       }
 
-      db_delete('block_node_type')
-        ->condition('module', $block['module'])
-        ->condition('delta', $block['delta'])
-        ->execute();
-      if (!empty($block['node_type'])) {
-        $query = db_insert('block_node_type')->fields(array('type', 'module', 'delta'));
-        foreach ($block['node_type'] as $type => $value) {
-          if ($value) {
-            $query->values(array(
-              'type' => $type,
-              'module' => $block['module'],
-              'delta' => isset($block['delta']) ? $block['delta'] : 0,
-            ));
-          }
-        }
-        $query->execute();
+      // Get the theme specific setting for the active theme.
+      if (isset($block_themes[$theme])) {
+        $key = $theme;
       }
+      // Or fallback on the default theme.
+      elseif (isset($block_themes[$theme_default])) {
+        $key = $theme_default;
+      }
+      // Or fallback on the first available theme spec.
+      else {
+        $key = key($block_themes);
+      }
+
+      // Write block settings.
+      $write = array_merge($block, $block_themes[$key]);
+      drupal_write_record('block', $write, array('module', 'delta', 'theme'));
+    }
+    // Ensure global settings.
+    _fe_block_settings_update_global_settings($block);
+
+    // Set node type settings
+    // (only if there were some defined, to avoid overwriting not yet exported
+    // data).
+    if (isset($block_node_types)) {
+      _fe_block_settings_update_block_node_type_settings($block, $block_node_types);
     }
   }
-  // Clear block cache
+
+  // Clear block cache.
   cache_clear_all(NULL, 'cache_block');
 
   return TRUE;
 }
 
 /**
+ * Helper to update global block settings for a specific block.
+ *
+ * @param array $block
+ *   block definition
+ */
+function _fe_block_settings_update_global_settings($block) {
+  $globals = _fe_block_get_global_settings($block);
+  db_update('block')
+    ->fields($globals)
+    ->condition('module', $block['module'])
+    ->condition('delta', $block['delta'])
+    ->execute();
+}
+
+/**
+ * Helper to update node type settings for a given block.
+ *
+ * @param array $block
+ *   block definition
+ * @param array $node_types
+ *   array of node types
+ */
+function _fe_block_settings_update_block_node_type_settings($block, $node_types) {
+
+  // First delete the old node type settings.
+  db_delete('block_node_type')
+    ->condition('module', $block['module'])
+    ->condition('delta', $block['delta'])
+    ->execute();
+
+  if (!empty($node_types)) {
+    $insert = db_insert('block_node_type')
+      ->fields(array('module', 'delta', 'type'));
+    foreach ($node_types as $type) {
+      $insert->values(array(
+        'module' => $block['module'],
+        'delta' => $block['delta'],
+        'type' => $type,
+      ));
+    }
+    $insert->execute();
+  }
+}
+
+/**
  * Implements hook_features_disable_feature().
  *
  * @param $module
@@ -614,7 +873,7 @@ function fe_block_get_bid($machine_name, $reset = FALSE) {
  * Generate block ID.
  */
 function _fe_block_build_id($block) {
-  if (empty($block['module']) || (empty($block['delta']) && !is_numeric($block['delta'])) ) {
+  if (empty($block['module']) || (empty($block['delta']) && !is_numeric($block['delta']))) {
     return NULL;
   }
   if ($block['module'] == 'block') {
@@ -670,3 +929,121 @@ function _fe_block_save_box($settings = array()) {
 
   return $settings;
 }
+
+/**
+ * Implements hook_module_implements_alter().
+ */
+function fe_block_module_implements_alter(&$implementations, $hook) {
+  if ($hook == 'default_fe_block_settings_alter') {
+    // Ensure fe_block is the first imlementation to be called, so we can
+    // convert to the newest format.
+    $group = $implementations['fe_block'];
+    unset($implementations['fe_block']);
+    $rest = array_reverse($implementations, TRUE);
+    $rest['fe_block'] = $group;
+    $implementations = array_reverse($rest, TRUE);
+  }
+}
+
+/**
+ * Implements hook_default_fe_block_settings_alter().
+ */
+function fe_block_default_fe_block_settings_alter(&$defaults) {
+  // Convert the settings in the newest format.
+  $defaults = _fe_block_settings_convert($defaults);
+}
+
+
+/**
+ * Helper function to convert an older export into the new format.
+ *
+ * @param array $defaults
+ *   array of fe_block_settings definition.
+ *
+ * @return array
+ *   array of current fe_block_settings definition
+ */
+function _fe_block_settings_convert($defaults) {
+
+  $version = (isset($defaults['version'])) ? $defaults['version'] : 0;
+
+  // Directly return if the version is the current one.
+  if ($version == FE_BLOCK_VERSION) {
+    return $defaults;
+  }
+  elseif ($version == '1.0') {
+
+    // We try to get the default theme for the global definitions, else we take
+    // the first.
+    $theme_default = variable_get('theme_default', 'bartik');
+    if (!isset($defaults['theme'][$theme_default])) {
+      $theme_default = key($defaults['theme']);
+    }
+
+    $blocks = array();
+    // We get the basic blocks from the visibility array.
+    foreach ($defaults['visibility'] as $block_id => $base) {
+      $node_types = array();
+      if (isset($base['node_type'])) {
+        // Node types were specified in node_type => TRUE/FALSE. Now we simply
+        // list the selected node types.
+        $node_types = array_keys(array_filter($base));
+        unset($base['node_type']);
+      }
+
+      $block = $base;
+      $block['node_types'] = $node_types;
+
+      // Global settings.
+      $globals = _fe_block_get_global_settings($defaults['theme'][$theme_default][$block_id]);
+      $block = array_merge($globals, $block);
+
+      // Build theme specific array.
+      $block['themes'] = array();
+      foreach ($defaults['theme'] as $theme => $items) {
+        $block['themes'][$theme] = _fe_block_get_theme_specific_settings($items[$block_id]);
+      }
+      $blocks[$block_id] = $block;
+    }
+    // Set current version so we can compare it with current version defaults.
+    $blocks['version'] = FE_BLOCK_VERSION;
+    return $blocks;
+  }
+  // The oldest version.
+  // There we got an array of themes that holded the block settings.
+  elseif ($version == 0) {
+
+    // We try to get the default theme for the global definitions, else we take
+    // the first.
+    $theme_default = variable_get('theme_default', 'bartik');
+    if (!isset($defaults[$theme_default])) {
+      $theme_default = key($defaults);
+    }
+
+    $blocks = array();
+    foreach ($defaults as $theme => $items) {
+      foreach ($items as $block_id => $item) {
+
+        // Avoid php notices.
+        if (!isset($blocks[$block_id])) {
+          $blocks[$block_id] = array(
+            'themes' => array(),
+          );
+        }
+
+        // Set theme specific settings.
+        $blocks[$block_id]['themes'][$theme] = _fe_block_get_theme_specific_settings($item);
+
+        // We add the global settings for the default theme.
+        if ($theme == $theme_default) {
+          $globals = _fe_block_get_global_settings($item);
+          $blocks[$block_id] = array_merge($blocks[$block_id], $globals);
+        }
+      }
+    }
+    // Set current version so we can compare it with current version defaults.
+    $blocks['version'] = FE_BLOCK_VERSION;
+
+    return $blocks;
+  }
+}
