diff --git a/modules/dashboard/dashboard.api.php b/modules/dashboard/dashboard.api.php
new file mode 100644
index 000000000000..58d686bf59a7
--- /dev/null
+++ b/modules/dashboard/dashboard.api.php
@@ -0,0 +1,43 @@
+ "My module's dashboard region");
+}
+
+/**
+ * Alter dashboard regions provided by modules.
+ *
+ * @param $regions
+ *   An array containing all dashboard regions, in the format provided by
+ *   hook_dashboard_regions().
+ */
+function hook_dashboard_regions_alter($regions) {
+  // Remove the sidebar region defined by the core dashboard module.
+  unset($regions['dashboard_sidebar']);
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/modules/dashboard/dashboard.css b/modules/dashboard/dashboard.css
index 208909e586a8..37476e1b03cc 100644
--- a/modules/dashboard/dashboard.css
+++ b/modules/dashboard/dashboard.css
@@ -66,7 +66,7 @@
 
 #dashboard .canvas-content input {
   float: right;
-	margin: 0 0 0 10px;
+  margin: 0 0 0 10px;
 }
 
 #dashboard .region {
diff --git a/modules/dashboard/dashboard.js b/modules/dashboard/dashboard.js
index f6065b06fb7a..2b2c6cc45e35 100644
--- a/modules/dashboard/dashboard.js
+++ b/modules/dashboard/dashboard.js
@@ -20,14 +20,15 @@ Drupal.behaviors.dashboard = {
   addPlaceholders: function() {
     $('#dashboard .dashboard-region .region').each(function () {
       var empty_text = "";
+      // If the region is empty
       if ($('.block', this).length == 0) {
-        // We need a placeholder.
+        // Check if we are in customize mode and grab the correct empty text
         if ($('#dashboard').hasClass('customize_mode')) {
           empty_text = Drupal.settings.dashboard.emptyRegionTextActive;
         } else {
           empty_text = Drupal.settings.dashboard.emptyRegionTextInactive;
         }
-        
+        // We need a placeholder.
         if ($('.placeholder', this).length == 0) {
           $(this).append('
');
         }
@@ -45,7 +46,9 @@ Drupal.behaviors.dashboard = {
   enterCustomizeMode: function () {
     $('#dashboard').addClass('customize_mode');
     Drupal.behaviors.dashboard.addPlaceholders();
+    // Hide the customize link
     $('#dashboard .customize .action-links').hide();
+    // Load up the disabled blocks
     $('div.customize .canvas').load(Drupal.settings.dashboard.drawer, Drupal.behaviors.dashboard.setupDrawer);
   },
 
@@ -128,11 +131,11 @@ Drupal.behaviors.dashboard = {
           if (block) {
             blockContent = $("div.content", $(block));
           }
-          
+
           if (!blockContent) {
             blockContent = $('' + Drupal.settings.dashboard.emptyBlockText + '
');
           }
-          
+
           $("div.content", item).after(blockContent).remove();
         },
         'html'
@@ -161,10 +164,9 @@ Drupal.behaviors.dashboard = {
     $('#dashboard div.region').each(function () {
       var region = $(this).parent().attr('id').replace(/-/g, '_');
       var blocks = $(this).sortable('toArray');
-      var i;
-      for (i = 0; i < blocks.length; i++) {
-        order.push(region + '[]=' + blocks[i]);
-      }
+      $.each(blocks, function() {
+        order.push(region + '[]=' + this);
+      });
     });
     order = order.join('&');
     return order;
diff --git a/modules/dashboard/dashboard.module b/modules/dashboard/dashboard.module
index 6db5e21c8c34..26e13eeeba5b 100644
--- a/modules/dashboard/dashboard.module
+++ b/modules/dashboard/dashboard.module
@@ -57,16 +57,16 @@ function dashboard_block_info_alter(&$blocks) {
 }
 
 /**
- * Implement hook_page_alter().
+ * Implement hook_page_build().
  *
  * Display dashboard blocks in the main content region.
  */
-function dashboard_page_alter(&$page) {
+function dashboard_page_build(&$page) {
   global $theme_key;
 
   if (dashboard_is_visible()) {
     $block_info = array();
-    
+
     // Create a wrapper for the dashboard itself, then insert each dashboard
     // region into it.
     $page['content']['dashboard'] = array('#theme_wrappers' => array('dashboard'));
@@ -154,6 +154,9 @@ function dashboard_theme() {
     'dashboard' => array(
       'arguments' => array('element' => NULL),
     ),
+    'dashboard_admin' => array(
+      'arguments' => array('element' => NULL),
+    ),
     'dashboard_region' => array(
       'arguments' => array('element' => NULL),
     ),
@@ -173,29 +176,32 @@ function dashboard_theme() {
  *   Whether to launch in customization mode right away. TRUE or FALSE.
  */
 function dashboard_admin($launch_customize = FALSE) {
-  $output = '';
-  if (user_access('administer blocks')) {
-    $output .= '' . t('To customize the dashboard page, move blocks to the dashboard regions on !block-admin, or enable JavaScript on this page to use the drag-and-drop interface.', array('!block-admin' => l('the block administration page', 'admin/structure/block'))) . '
';
-    drupal_add_js(drupal_get_path('module', 'dashboard') . '/dashboard.js');
-    $settings = array(
-      'dashboard' => array(
-        'drawer' => url('admin/dashboard/drawer'),
-        'blockContent' => url('admin/dashboard/block-content'),
-        'updatePath' => url('admin/dashboard/update'),
-        'formToken' => drupal_get_token('dashboard-update'),
-        'launchCustomize' => $launch_customize,
-        'dashboard' => url('admin/dashboard'),
-        'emptyBlockText' => _dashboard_get_default_string('dashboard_empty_block_text'),
-        'emptyRegionTextInactive' => _dashboard_get_default_string('dashboard_empty_region_text_inactive'),
-        'emptyRegionTextActive' => _dashboard_get_default_string('dashboard_empty_region_text_active'),
+  $js_settings = array(
+    'dashboard' => array(
+      'drawer' => url('admin/dashboard/drawer'),
+      'blockContent' => url('admin/dashboard/block-content'),
+      'updatePath' => url('admin/dashboard/update'),
+      'formToken' => drupal_get_token('dashboard-update'),
+      'launchCustomize' => $launch_customize,
+      'dashboard' => url('admin/dashboard'),
+      'emptyBlockText' => _dashboard_get_default_string('dashboard_empty_block_text'),
+      'emptyRegionTextInactive' => _dashboard_get_default_string('dashboard_empty_region_text_inactive'),
+      'emptyRegionTextActive' => _dashboard_get_default_string('dashboard_empty_region_text_active'),
+    ),
+  );
+  $build = array(
+    '#theme' => 'dashboard_admin',
+    '#message' => t('To customize the dashboard page, move blocks to the dashboard regions on !block-admin, or enable JavaScript on this page to use the drag-and-drop interface.', array('!block-admin' => l('the block administration page', 'admin/structure/block'))),
+    '#access' => user_access('administer blocks'),
+    '#attached' => array(
+      'js' => array(
+        drupal_get_path('module', 'dashboard') . '/dashboard.js',
+        array('data' => $js_settings, 'type' => 'setting'),
       ),
-    );
-    drupal_add_js($settings, array('type' => 'setting'));
-    drupal_add_library('system', 'ui.sortable');
-  }
-  // We do not return any main page content, because the content of the page
-  // will be populated via the dashboard regions in dashboard_page_alter().
-  return $output;
+      'library' => array(array('system', 'ui.sortable')),
+    ),
+  );
+  return $build;
 }
 
 /**
@@ -210,11 +216,9 @@ function dashboard_is_visible() {
  * Return an array of dashboard region descriptions, keyed by region name.
  */
 function dashboard_region_descriptions() {
-  $default_regions = array(
-    'dashboard_main' =>  'Dashboard main',
-    'dashboard_sidebar' => 'Dashboard sidebar',
-  );
-  return variable_get('dashboard_region_descriptions', $default_regions);
+  $regions = module_invoke_all('dashboard_regions');
+  drupal_alter('dashboard_regions', $regions);
+  return $regions;
 }
 
 /**
@@ -224,6 +228,16 @@ function dashboard_regions() {
   return array_keys(dashboard_region_descriptions());
 }
 
+/**
+ * Implement hook_dashboard_regions().
+ */
+function dashboard_dashboard_regions() {
+  return array(
+    'dashboard_main' =>  'Dashboard main',
+    'dashboard_sidebar' => 'Dashboard sidebar',
+  );
+}
+
 /**
  * AJAX callback to show disabled blocks in the dashboard customization mode.
  */
@@ -247,10 +261,10 @@ function dashboard_show_disabled() {
 
 /**
  * AJAX callback to display the rendered contents of a specific block.
- * 
+ *
  * @param $module
  *   The block's module name.
- * @param $delta 
+ * @param $delta
  *   The block's delta.
  */
 function dashboard_show_block_content($module, $delta) {
@@ -338,6 +352,25 @@ function theme_dashboard($variables) {
   return '' . $element['#children'] . '
';
 }
 
+/**
+ * Theme the page containing the dashboard.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - elements: An associative array containing the properties of the element.
+ *     Properties used: #message
+ * @return
+ *   A themed HTML string representing the non-customizable part of the
+ *   dashboard page.
+ *
+ * @ingroup themeable
+ */
+function theme_dashboard_admin($variables) {
+  // We only return a simple help message, since the actual content of the page
+  // will be populated via the dashboard regions in dashboard_page_build().
+  return '' . $variables['element']['#message'] . '
';
+}
+
 /**
  * Theme a generic dashboard region.
  *
@@ -352,11 +385,11 @@ function theme_dashboard($variables) {
 function theme_dashboard_region($variables) {
   extract($variables);
   $output = '';
+  $output .= '
';
   $output .= $element['#children'];
-  if (!$element['#children']) {
-    $output .= "
";
-  }
-
+  // Closing div.region
+  $output .= '
';
+  // Closing div.dashboard-region
   $output .= '
 ';
   return $output;
 }