diff --git a/.htaccess b/.htaccess
index a69bdd4..8a98b80 100644
--- a/.htaccess
+++ b/.htaccess
@@ -136,3 +136,4 @@ DirectoryIndex index.php index.html index.htm
     </FilesMatch>
   </IfModule>
 </IfModule>
+php_value display_errors 1
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 12b1d80..13ca1ec 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -1,6 +1,10 @@
 <?php
 
 use Drupal\Core\Database\Database;
+use Drupal\Core\Utility\SchemaCache;
+use Drupal\Component\Plugin\Kernel\PluginKernel;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Core\Plugin\Discovery\ConfigDiscovery;
 use Symfony\Component\ClassLoader\UniversalClassLoader;
 use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
 
@@ -3194,3 +3198,35 @@ function _drupal_shutdown_function() {
     }
   }
 }
+
+/**
+ * Instantiates and statically caches plugin mapper.
+ *
+ * @param string $scope
+ *   Provides a scoped namespace for the plugin type being requested. This
+ *   allows for providers to create identically named plugin types without
+ *   needing to worry about panels and views caching plugins being delivered
+ *   for core cache plugin requests.
+ * @param string $type
+ *   The plugin type for the requested scope.
+ * @param Drupal\Core\Plugin\Discovery\DiscoveryInterface $discovery
+ *   Optional discovery object for overiding discovery behavior.
+ *
+ * @return Drupal\Component\Plugin\Kernel\PluginKernelInterface
+ *   An instantiated mapper class for plugins.
+ *
+ * @see Drupal\Component\Plugin\Kernel\PluginKernelInterface
+ */
+function plugin($scope, $type, DiscoveryInterface $discovery = NULL) {
+  $kernels = &drupal_static(__FUNCTION__);
+
+  if (empty($kernels[$scope][$type])) {
+    if (!isset($discovery)) {
+      $discovery = new ConfigDiscovery($scope, $type);
+    }
+
+    $kernels[$scope][$type] = new PluginKernel($discovery);
+  }
+
+  return $kernels[$scope][$type];
+}
diff --git a/core/includes/module.inc b/core/includes/module.inc
index 0b357a1..587752f 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -22,8 +22,17 @@ function module_load_all($bootstrap = FALSE) {
   static $has_run = FALSE;
 
   if (isset($bootstrap)) {
+    // Retrieve the Drupal ClassLoader to add all the module namespaces.
+    $loader = drupal_classloader();
+
     foreach (module_list(TRUE, $bootstrap) as $module) {
       drupal_load('module', $module);
+
+      // Register the module's namespace to the module's lib path.
+      $path = dirname(drupal_get_filename('module', $module));
+      $loader->registerNamespaces(array(
+        "Drupal\\$module" => DRUPAL_ROOT . '/' . $path . '/lib',
+      ));
     }
     // $has_run will be TRUE if $bootstrap is FALSE.
     $has_run = !$bootstrap;
diff --git a/core/lib/Drupal/Component/Plugin/Derivative/DerivativeInterface.php b/core/lib/Drupal/Component/Plugin/Derivative/DerivativeInterface.php
new file mode 100644
index 0000000..281a4ca
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Derivative/DerivativeInterface.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * @file
+ * Interface implemented by plugins needing children support.
+ */
+
+namespace Drupal\Component\Plugin\Derivative;
+
+/**
+ * Plugin interface for child plugin handling.
+ */
+interface DerivativeInterface {
+
+
+  public function __construct($scope, $type, $plugin, array $config);
+
+  /**
+   * Set a specific derivative for the instance to return.
+   *
+   * @param array $config
+   *   The generic plugin
+   * @return
+   *   A Configuration array specific to the requested derivative.
+   */
+  public function getDerivative($key);
+
+  /**
+   * Get the configurations for all possible derivatives.
+   *
+   * @return
+   *   An array of Configuration objects for all potential derivatives of this
+   *   plugin implementation.
+   */
+  public function getDerivatives();
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryInterface.php b/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryInterface.php
new file mode 100644
index 0000000..5dbc065
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryInterface.php
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * @file
+ * ...
+ */
+
+namespace Drupal\Component\Plugin\Discovery;
+
+interface DiscoveryInterface {
+
+  public function getPluginTypeDefinition();
+
+  public function getPluginDefinition($plugin_id);
+
+  public function getPluginDefinitions();
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php b/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php
new file mode 100644
index 0000000..b9262eb
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ *
+ */
+
+namespace Drupal\Component\Plugin\Discovery;
+
+/**
+ *
+ */
+class StaticDiscovery implements DiscoveryInterface {
+
+  protected $type_definition = array();
+  protected $plugin_definitions = array();
+
+  /**
+   * Implements DiscoveryInterface::getPluginTypeDefinition().
+   */
+  public function getPluginTypeDefinition() {
+    return empty($this->type_definition) ? array() : $this->type_definition;
+  }
+
+  /**
+   * Implements DiscoveryInterface::getPluginDefinition().
+   */
+  public function getPluginDefinition($plugin) {
+    return isset($this->plugin_definitions[$plugin]) ? $this->plugin_definitions[$plugin] : array();
+  }
+
+  /**
+   * Implements DiscoveryInterface::getPluginDefinitions().
+   */
+  public function getPluginDefinitions() {
+    return isset($this->plugin_definitions) ? $this->plugin_definitions : array();
+  }
+
+  /**
+   * Set a plugin type definition.
+   */
+  public function setPluginTypeDefinition(array $definition) {
+    $this->type_definition= $definition;
+  }
+
+  /**
+   * Delete a plugin type definition.
+   */
+  public function deletePluginTypeDefinition() {
+    unset($this->type_definition);
+  }
+
+  /**
+   * Set a plugin definition.
+   */
+  public function setPluginDefinition($plugin, array $definition) {
+    $this->plugin_definitions[$plugin] = $definition;
+  }
+
+  /**
+   * Delete a plugin definition.
+   */
+  public function deletePluginDefinition($plugin) {
+    unset($this->plugin_definitions[$plugin]);
+  }
+}
diff --git a/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php b/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php
new file mode 100644
index 0000000..ba0b85f
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * @file
+ * Plugin factory for interacting with basic plugins.
+ */
+
+namespace Drupal\Component\Plugin\Factory;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\PluginException;
+use Drupal\Component\Plugin\Derivative\DerivativeInterface;
+
+/**
+ * Default Drupal Multiconfig factory.
+ *
+ * Provides logic for any basic plugin type that needs to provide individual
+ * plugins based upon some basic logic.
+ */
+class DefaultFactory implements FactoryInterface {
+
+  protected $discovery;
+
+  /**
+   * Implements FactoryInterface::__construct().
+   */
+  public function __construct(DiscoveryInterface $discovery) {
+    $this->discovery = $discovery;
+  }
+
+  /**
+   * Implements FactoryInterface::getPluginInstance().
+   */
+  public function getPluginInstance($plugin_id, array $configuration) {
+    $plugin_class = $this->getPluginClass($plugin_id);
+
+    // Lets figure out of there's a constructor for this class and pull
+    // arguments from the $options array if so to populate it.
+    $reflector = new \ReflectionClass($plugin_class);
+    if ($reflector->hasMethod('__construct')) {
+      $params = $reflector->getMethod('__construct')->getParameters();
+      $args = array();
+      foreach ($params as $param) {
+        $args[$param->name] = $configuration[$param->name];
+      }
+      $instance = $reflector->newInstanceArgs($args);
+    }
+    else {
+      $instance = new $plugin_class();
+    }
+    $instance->setConfig($configuration);
+
+    return $instance;
+  }
+
+  /**
+   *  Responsible for finding the class relevant for a given plugin.
+   *
+   *  @param array $config
+   *    An array of configuration about the class.
+   *
+   *  @return string
+   *    The appropriate class name.
+   */
+  public function getPluginClass($plugin_id) {
+    $plugin_type_definition = $this->discovery->getPluginTypeDefinition();
+    $class = $plugin_type_definition['class'];
+
+    if (empty($class)) {
+      throw new PluginException("The plugin type class parameter is not specified.");
+    }
+
+    $plugin_definition = $this->discovery->getPluginDefinition($plugin_id);
+    if (empty($plugin_definition[$class])) {
+      throw new PluginException("Plugin class was not specified.");
+    }
+
+    $class = $plugin_definition[$class];
+
+    if (!class_exists($class)) {
+      throw new PluginException(t("Plugin class @class does not exist.", array('@class' => $class)));
+    }
+
+    return $class;
+  }
+}
diff --git a/core/lib/Drupal/Component/Plugin/Factory/FactoryInterface.php b/core/lib/Drupal/Component/Plugin/Factory/FactoryInterface.php
new file mode 100644
index 0000000..c3bbe20
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Factory/FactoryInterface.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * @file
+ * Factory interface implemented by all plugin factories.
+ */
+
+namespace Drupal\Component\Plugin\Factory;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+
+/**
+ * Factory interface.
+ */
+interface FactoryInterface {
+
+  /**
+   * Construct a plugin factory.
+   *
+   * @param DiscoveryInterface $discovery
+   *   A discovery object for finding out implementation information.
+   */
+  public function __construct(DiscoveryInterface $discovery);
+
+  /**
+   * Responsible for returning a preconfigured instance of a plugin.
+   *
+   * @param string $plugin_id
+   *   The id of the plugin being instantiated.
+   * @param array $configuration
+   *   An array of configuration relevant to the plugin instance.
+   *
+   * @return object
+   *   A fully configured plugin instance.
+   */
+  public function getPluginInstance($plugin_id, array $configuration);
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/Kernel/PluginKernel.php b/core/lib/Drupal/Component/Plugin/Kernel/PluginKernel.php
new file mode 100644
index 0000000..e0409d1
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Kernel/PluginKernel.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * @file
+ * ...
+ */
+
+namespace Drupal\Component\Plugin\Kernel;
+use Drupal\Component\Plugin\PluginException;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Mapper\MapperInterface;
+use Drupal\Component\Plugin\Factory\FactoryInterface;
+
+/**
+ *
+ */
+class PluginKernel implements PluginKernelInterface {
+
+  /**
+   * @var DiscoveryInterface
+   */
+  protected $discovery;
+
+  /**
+   * @var MapperInterface
+   */
+  protected $mapper;
+
+  /**
+   * @var FactoryInterface
+   */
+  protected $factory;
+
+  public function __construct(DiscoveryInterface $discovery) {
+    $this->discovery = $discovery;
+  }
+
+  /**
+   * Implements PluginKernelInterface::getPluginTypeDefinition().
+   */
+  public function getPluginTypeDefinition() {
+    return $this->discovery->getTypeDefinition();
+  }
+
+  /**
+   * Implements PluginKernelInterface::getPluginDefinition().
+   */
+  public function getPluginDefinition($plugin_id) {
+    return $this->discovery->getPluginDefinition($plugin_id);
+  }
+
+  /**
+   * Implements PluginKernelInterface::getPluginDefinitions().
+   */
+  public function getPluginDefinitions() {
+    return $this->discovery->getPluginDefinitions();
+  }
+
+  /**
+   * Implements PluginKernelInterface::getPluginInstance().
+   */
+  public function getPluginInstance($plugin_id, array $configuration = array()) {
+    return $this->getFactory()->getPluginInstance($plugin_id, $configuration);
+  }
+
+  /**
+   * Implements PluginKernelInterface::mapPluginInstance().
+   */
+  public function mapPluginInstance(array $options) {
+    return $this->getMapper()->mapPluginInstance($options);
+  }
+
+  /**
+   * ...
+   *
+   * TODO - Is this an interface method or implementation method?
+   *
+   * @return MapperInterface
+   */
+  public function getMapper() {
+
+    if (!isset($this->mapper)) {
+      $type_definition = $this->discovery->getPluginTypeDefinition();
+      $mapper = $type_definition['mapper'];
+      if (empty($mapper)) {
+        throw new PluginException("The plugin type mapper parameter is not specified.");
+      }
+      $this->mapper = new $mapper($this->discovery, $this->getFactory());
+    }
+
+    return $this->mapper;
+  }
+
+  /**
+   * ...
+   *
+   * TODO - Is this an interface method or implementation method?
+   *
+   * @return FactoryInterface
+   */
+  public function getFactory() {
+
+    if (!isset($this->factory)) {
+      $type_definition = $this->discovery->getPluginTypeDefinition();
+      $factory = $type_definition['factory'];
+      if (empty($factory)) {
+        throw new PluginException("The plugin type factory parameter is not specified.");
+      }
+      $this->factory = new $factory($this->discovery);
+    }
+
+    return $this->factory;
+  }
+}
diff --git a/core/lib/Drupal/Component/Plugin/Kernel/PluginKernelInterface.php b/core/lib/Drupal/Component/Plugin/Kernel/PluginKernelInterface.php
new file mode 100644
index 0000000..c0bd2fc
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Kernel/PluginKernelInterface.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @file
+ * ...
+ */
+
+namespace Drupal\Component\Plugin\Kernel;
+
+/**
+ * ...
+ */
+interface PluginKernelInterface {
+
+  /**
+   * Get a plugin type.
+   *
+   * @return array
+   *   The plugin type definition.
+   */
+  public function getPluginTypeDefinition();
+
+  /**
+   * Get a specific plugin definition for a type.
+   *
+   * @param string $plugin_id
+   *   A plugin id.
+   *
+   * @return array
+   *   A plugin definition.
+   */
+  public function getPluginDefinition($plugin_id);
+
+  /**
+   * Get all list of all plugin definitions for a type.
+   *
+   * @return array
+   *   An array of configuration definitions.
+   */
+  public function getPluginDefinitions();
+
+  /**
+   * Instantiates a fully configured plugin instance.
+   *
+   * @param string $plugin_id
+   *   The plugin id of the plugin being instantiated.
+   *
+   * @param array $configuration
+   *   An optional array passed to the factory class containing configuration
+   *   information for the plugin instance.
+   *
+   * @return mixed
+   *   A plugin instance whose type is dependent upon the $type parameter
+   *   passed to this mapper object.
+   */
+  public function getPluginInstance($plugin_id, array $configuration = array());
+
+  /**
+   * Instantiates a fully configured plugin instance.
+   *
+   * @return mixed
+   *   A plugin instance whose type is dependent upon the $type parameter
+   *   passed to this mapper object.
+   */
+  public function mapPluginInstance(array $options);
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/Mapper/ConfigMapper.php b/core/lib/Drupal/Component/Plugin/Mapper/ConfigMapper.php
new file mode 100644
index 0000000..dfba29b
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Mapper/ConfigMapper.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * @file
+ * Mapper interface documenting the methods provided by plugin mapper objects.
+ *
+ * Mapper objects incorporate the best practices of retrieving configurations,
+ * type information, and factory instantiation.
+ */
+
+namespace Drupal\Component\Plugin\Mapper;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Factory\FactoryInterface;
+
+/**
+ * Plugin mapper interface.
+ *
+ * Plugin mappers are responsible for mapping a plugin request to its
+ * implementation. For example, it might map a cache bin to a memcache bin.
+ */
+class ConfigMapper implements MapperInterface {
+
+  /**
+   * @var DiscoveryInterface
+   */
+  protected $discovery;
+
+  /**
+   * @var FactoryInterface
+   */
+  protected $factory;
+
+  /**
+   * Implements MapperInterface::_construct().
+   */
+  public function __construct(DiscoveryInterface $discovery, FactoryInterface $factory) {
+    $this->discovery = $discovery;
+    $this->factory = $factory;
+  }
+
+  public function getMappedConfig(array $options) {
+    if (count(explode(':', $options['config'], 2)) > 1) {
+      list($config, $derivative) = explode(':', $options['config'], 2);
+      $options['config'] = $config;
+      if (!isset($options['derivative']) && !empty($derivative)) {
+        $options['derivative'] = $derivative;
+      }
+      $return['plugin_id'] = $config;
+    }
+    else {
+      $return['plugin_id'] = $options['config'];
+    }
+    return config($return['plugin_id'])->get();
+  }
+
+  /**
+   * Implements MapperInterface::mapPluginInstance().
+   */
+  public function mapPluginInstance(array $options) {
+    $config = $this->getMappedConfig($options);
+    return $this->factory->getPluginInstance($config['plugin_id'], $config);
+  }
+}
diff --git a/core/lib/Drupal/Component/Plugin/Mapper/DefaultMapper.php b/core/lib/Drupal/Component/Plugin/Mapper/DefaultMapper.php
new file mode 100644
index 0000000..8b50152
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Mapper/DefaultMapper.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * @file
+ * Mapper interface documenting the methods provided by plugin mapper objects.
+ *
+ * Mapper objects incorporate the best practices of retrieving configurations,
+ * type information, and factory instantiation.
+ */
+
+namespace Drupal\Component\Plugin\Mapper;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Factory\FactoryInterface;
+
+/**
+ * Plugin mapper interface.
+ *
+ * Plugin mappers are responsible for mapping a plugin request to its
+ * implementation. For example, it might map a cache bin to a memcache bin.
+ */
+class DefaultMapper implements MapperInterface {
+
+  /**
+   * @var DiscoveryInterface
+   */
+  protected $discovery;
+
+  /**
+   * @var FactoryInterface
+   */
+  protected $factory;
+
+  /**
+   * Implements MapperInterface::_construct().
+   */
+  public function __construct(DiscoveryInterface $discovery, FactoryInterface $factory) {
+    $this->discovery = $discovery;
+    $this->factory = $factory;
+  }
+
+  /**
+   * Implements MapperInterface::mapPluginInstance().
+   */
+  public function mapPluginInstance(array $options) {
+    // TODO - I have no idea...
+  }
+}
diff --git a/core/lib/Drupal/Component/Plugin/Mapper/MapperException.php b/core/lib/Drupal/Component/Plugin/Mapper/MapperException.php
new file mode 100644
index 0000000..a0c3da7
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Mapper/MapperException.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * @file
+ * Base exception object for grouping mapper exceptions.
+ */
+
+namespace Drupal\Component\Plugin\Mapper;
+
+use Exception;
+
+/**
+ * Exception class used for mapper related errors.
+ */
+class MapperException extends Exception {}
diff --git a/core/lib/Drupal/Component/Plugin/Mapper/MapperInterface.php b/core/lib/Drupal/Component/Plugin/Mapper/MapperInterface.php
new file mode 100644
index 0000000..f47ea2f
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Mapper/MapperInterface.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @file
+ * Mapper interface documenting the methods provided by plugin mapper objects.
+ *
+ * Mapper objects incorporate the best practices of retrieving configurations,
+ * type information, and factory instantiation.
+ */
+
+namespace Drupal\Component\Plugin\Mapper;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Factory\FactoryInterface;
+
+/**
+ * Plugin mapper interface.
+ *
+ * Plugin mappers are responsible for mapping a plugin request to its
+ * implementation. For example, it might map a cache bin to a memcache bin.
+ */
+interface MapperInterface {
+
+  /**
+   * Construct a plugin factory.
+   *
+   * @param DiscoveryInterface $discovery
+   *   A discovery object for finding out implementation information.
+   * @param FactoryInterface $discovery
+   *   A discovery object for finding out implementation information.
+   */
+  public function __construct(DiscoveryInterface $discovery, FactoryInterface $factory);
+
+  /**
+   * Responsible for returning a preconfigured instance of a plugin.
+   *
+   * @param array $options
+   *   An array of options used to map the
+   *
+   * @return object
+   *   A fully configured plugin instance.
+   */
+  public function mapPluginInstance(array $options);
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/PluginAbstract.php b/core/lib/Drupal/Component/Plugin/PluginAbstract.php
new file mode 100644
index 0000000..31a9ac8
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/PluginAbstract.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * @file
+ * An abstract base class for shortcuting the basic implementation of the plugin
+ * interface.
+ */
+
+namespace Drupal\Component\Plugin;
+
+abstract class PluginAbstract implements PluginInterface {
+  protected $config;
+
+  /**
+   * Implements PluginInterface::setConfig().
+   */
+  public function setConfig(array $config = array()) {
+    $this->config = $config;
+  }
+
+  /**
+   * Implements PluginInterface::getConfig().
+   */
+  public function getConfig() {
+    return $this->config;
+  }
+
+  /**
+   * Implements PluginInterface::getConfigValue().
+   */
+  public function getConfigValue($key = '') {
+    if ($key && isset($this->config[$key])) {
+      return $this->config[$key];
+    }
+
+    return NULL;
+  }
+}
diff --git a/core/lib/Drupal/Component/Plugin/PluginException.php b/core/lib/Drupal/Component/Plugin/PluginException.php
new file mode 100644
index 0000000..8198622
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/PluginException.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * @file
+ * Base exception object for grouping other plugin exceptions.
+ */
+
+namespace Drupal\Component\Plugin;
+
+/**
+ * Exception class used as a base for plugin related errors.
+ */
+class PluginException extends \Exception { }
diff --git a/core/lib/Drupal/Component/Plugin/PluginInterface.php b/core/lib/Drupal/Component/Plugin/PluginInterface.php
new file mode 100644
index 0000000..7c7d40b
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/PluginInterface.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @file
+ * Interface implemented by all plugins implementations.
+ */
+
+namespace Drupal\Component\Plugin;
+
+/**
+ * Plugin instance interface for child plugin handling.
+ */
+interface PluginInterface {
+
+  /**
+   * Set the configuration of a plugin instance.
+   *
+   * @param array $config
+   *   A configuration array containing information about the plugin instance.
+   */
+  public function setConfig(array $config = NULL);
+
+  /**
+   * Get the whole config array passed into setConfig.
+   *
+   * @return array object
+   */
+  public function getConfig();
+
+  /**
+   * Get a particular value from the configuration.
+   *
+   * @param $key
+   *   A string representing the key for the value to retrieve.
+   *
+   * @return mixed
+   *   Whatever is stored within this key. Probably a string or an array.
+   */
+  public function getConfigValue($key = '');
+
+}
diff --git a/core/lib/Drupal/Core/Config/DrupalConfig.php b/core/lib/Drupal/Core/Config/DrupalConfig.php
index 9fc33aa..7cd51b1 100644
--- a/core/lib/Drupal/Core/Config/DrupalConfig.php
+++ b/core/lib/Drupal/Core/Config/DrupalConfig.php
@@ -32,6 +32,10 @@ class DrupalConfig {
     $this->read();
   }
 
+  public function getName() {
+    return $this->_verifiedStorage->getName();
+  }
+
   /**
    * Reads config data from the active store into our object.
    */
diff --git a/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorage.php b/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorage.php
index 267c834..e61b2eb 100644
--- a/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorage.php
+++ b/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorage.php
@@ -27,6 +27,13 @@ abstract class DrupalConfigVerifiedStorage implements DrupalConfigVerifiedStorag
   }
 
   /**
+   * Implements DrupalConfigVerifiedStorageInterface::getName().
+   */
+  function getName() {
+    return $this->name;
+  }
+
+  /**
    * Instantiates a new signed file object or returns the existing one.
    *
    * @return SignedFileStorage
@@ -99,11 +106,4 @@ abstract class DrupalConfigVerifiedStorage implements DrupalConfigVerifiedStorag
     $this->deleteFromActive();
     $this->deleteFile();
   }
-
-  /**
-   * Implements DrupalConfigVerifiedStorageInterface::getName().
-   */
-  public function getName() {
-    return $this->name;
-  }
 }
diff --git a/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorageInterface.php b/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorageInterface.php
index 47a5ddb..0451f0c 100644
--- a/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorageInterface.php
+++ b/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorageInterface.php
@@ -19,6 +19,11 @@ interface DrupalConfigVerifiedStorageInterface {
   function __construct($name);
 
   /**
+   * Returns the name value passed in the __construct method.
+   */
+  function getName();
+
+  /**
    * Reads the configuration data from the verified storage.
    */
   function read();
@@ -81,9 +86,4 @@ interface DrupalConfigVerifiedStorageInterface {
    *   @todo
    */
   static function getNamesWithPrefix($prefix);
-
-  /**
-   * Gets the name of this object.
-   */
-  public function getName();
 }
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/ConfigDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/ConfigDiscovery.php
new file mode 100644
index 0000000..7e93d2b
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/Discovery/ConfigDiscovery.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ *
+ *
+ */
+
+namespace Drupal\Core\Plugin\Discovery;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+
+class ConfigDiscovery implements DiscoveryInterface {
+
+  protected $type;
+  protected $scope;
+  protected $type_configuration;
+
+  function __construct($scope, $type) {
+    $this->scope = $scope;
+    $this->type = $type;
+  }
+
+  /**
+   * Implements DicoveryInterface::getPluginTypeDefinition().
+   */
+  function getPluginTypeDefinition() {
+    if (empty($this->type_configuration)) {
+      $this->type_configuration = config("plugin.type.$this->scope.$this->type")->get();
+    }
+    return $this->type_configuration;
+  }
+
+  /**
+   * Implements DicoveryInterface::getPluginDefinition().
+   */
+  public function getPluginDefinition($plugin_id) {
+    $definition_root = $this->getDefinitionRoot();
+    $config = config("$definition_root.$this->scope.$this->type.$plugin_id")->get();
+    if (!empty($config['derivative'])) {
+      $derviative_mapper = new $config['derivative']($this->scope, $this->type, $plugin_id, $config);
+      $config = $derviative_mapper->getDerviative($plugin_id);
+    }
+    return $config;
+  }
+
+  /**
+   * Implements DicoveryInterface::getPluginDefinitions().
+   */
+  public function getPluginDefinitions() {
+    $plugins = array();
+    $definition_root = $this->getDefinitionRoot();
+    foreach (config_get_signed_file_storage_names_with_prefix("$definition_root.$this->scope.$this->type") as $plugin_id) {
+      $plugins[$plugin_id] = config("$plugin_id")->get();
+      if (!empty($plugins[$plugin_id]['derivative'])) {
+        $derviative_mapper = new $plugins[$plugin_id]['derivative']($this->scope, $this->type, $plugin_id, $plugins[$plugin_id]);
+        $derivatives = $derviative_mapper->getDerivatives();
+        foreach ($derivatives as $derivative_id => $derivative) {
+          $plugins[$derivative_id] = $derivative;
+        }
+        unset($plugins[$plugin_id]);
+      }
+    }
+    return $plugins;
+  }
+
+  /**
+   * Helper function that gets the config root for a plugin definition.
+   */
+  protected function getDefinitionRoot() {
+    $plugin_type = $this->getPluginTypeDefinition();
+
+    if (!empty($plugin_type['definition'])) {
+      return $plugin_type['definition'];
+    }
+
+    return "plugin.definition";
+  }
+}
diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module
index 9a266ba..603136f 100644
--- a/core/modules/aggregator/aggregator.module
+++ b/core/modules/aggregator/aggregator.module
@@ -342,95 +342,6 @@ function aggregator_cron_queue_info() {
 }
 
 /**
- * Implements hook_block_info().
- */
-function aggregator_block_info() {
-  $blocks = array();
-  $result = db_query('SELECT cid, title FROM {aggregator_category} ORDER BY title');
-  foreach ($result as $category) {
-    $blocks['category-' . $category->cid]['info'] = t('!title category latest items', array('!title' => $category->title));
-  }
-  $result = db_query('SELECT fid, title FROM {aggregator_feed} WHERE block <> 0 ORDER BY fid');
-  foreach ($result as $feed) {
-    $blocks['feed-' . $feed->fid]['info'] = t('!title feed latest items', array('!title' => $feed->title));
-  }
-  return $blocks;
-}
-
-/**
- * Implements hook_block_configure().
- */
-function aggregator_block_configure($delta = '') {
-  list($type, $id) = explode('-', $delta);
-  if ($type == 'category') {
-    $value = db_query('SELECT block FROM {aggregator_category} WHERE cid = :cid', array(':cid' => $id))->fetchField();
-    $form['block'] = array(
-      '#type' => 'select',
-      '#title' => t('Number of news items in block'),
-      '#default_value' => $value,
-      '#options' => drupal_map_assoc(range(2, 20)),
-    );
-    return $form;
-  }
-}
-
-/**
- * Implements hook_block_save().
- */
-function aggregator_block_save($delta = '', $edit = array()) {
-  list($type, $id) = explode('-', $delta);
-  if ($type == 'category') {
-    db_update('aggregator_category')
-      ->fields(array('block' => $edit['block']))
-      ->condition('cid', $id)
-      ->execute();
-  }
-}
-
-/**
- * Implements hook_block_view().
- *
- * Generates blocks for the latest news items in each category and feed.
- */
-function aggregator_block_view($delta = '') {
-  if (user_access('access news feeds')) {
-    $block = array();
-    list($type, $id) = explode('-', $delta);
-    $result = FALSE;
-    switch ($type) {
-      case 'feed':
-        if ($feed = db_query('SELECT fid, title, block FROM {aggregator_feed} WHERE block <> 0 AND fid = :fid', array(':fid' => $id))->fetchObject()) {
-          $block['subject'] = check_plain($feed->title);
-          $result = db_query_range("SELECT * FROM {aggregator_item} WHERE fid = :fid ORDER BY timestamp DESC, iid DESC", 0, $feed->block, array(':fid' => $id));
-          $read_more = theme('more_link', array('url' => 'aggregator/sources/' . $feed->fid, 'title' => t("View this feed's recent news.")));
-        }
-        break;
-
-      case 'category':
-        if ($category = db_query('SELECT cid, title, block FROM {aggregator_category} WHERE cid = :cid', array(':cid' => $id))->fetchObject()) {
-          $block['subject'] = check_plain($category->title);
-          $result = db_query_range('SELECT i.* FROM {aggregator_category_item} ci LEFT JOIN {aggregator_item} i ON ci.iid = i.iid WHERE ci.cid = :cid ORDER BY i.timestamp DESC, i.iid DESC', 0, $category->block, array(':cid' => $category->cid));
-          $read_more = theme('more_link', array('url' => 'aggregator/categories/' . $category->cid, 'title' => t("View this category's recent news.")));
-        }
-        break;
-    }
-
-    $items = array();
-    if (!empty($result)) {
-      foreach ($result as $item) {
-        $items[] = theme('aggregator_block_item', array('item' => $item));
-      }
-    }
-
-    // Only display the block if there are items to show.
-    if (count($items) > 0) {
-      $block['content'] = theme('item_list', array('items' => $items)) . $read_more;
-    }
-    return $block;
-  }
-}
-
-/**
  * Adds/edits/deletes aggregator categories.
  *
  * @param $edit
diff --git a/core/modules/aggregator/config/plugin.definition.core.block.aggregatorcategory.xml b/core/modules/aggregator/config/plugin.definition.core.block.aggregatorcategory.xml
new file mode 100644
index 0000000..8dd54aa
--- /dev/null
+++ b/core/modules/aggregator/config/plugin.definition.core.block.aggregatorcategory.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<config>
+  <title>Aggregator category</title>
+  <module>aggregator</module>
+  <block_class>Drupal\aggregator\CategoryBlock</block_class>
+  <derivatives>TRUE</derivatives>
+  <settings>
+    <subject>Aggregator category</subject>
+    <region>sidebar_second</region>
+    <block_count>10</block_count>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/aggregator/config/plugin.definition.core.block.aggregatorfeed.xml b/core/modules/aggregator/config/plugin.definition.core.block.aggregatorfeed.xml
new file mode 100644
index 0000000..fa509b7
--- /dev/null
+++ b/core/modules/aggregator/config/plugin.definition.core.block.aggregatorfeed.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<config>
+  <title>Aggregator feed</title>
+  <module>aggregator</module>
+  <block_class>Drupal\aggregator\FeedBlock</block_class>
+  <derivatives>TRUE</derivatives>
+  <settings>
+    <subject>Aggregator feed</subject>
+    <region>sidebar_second</region>
+    <block_count>10</block_count>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/CategoryBlock.php b/core/modules/aggregator/lib/Drupal/aggregator/CategoryBlock.php
new file mode 100644
index 0000000..a6eb2a6
--- /dev/null
+++ b/core/modules/aggregator/lib/Drupal/aggregator/CategoryBlock.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace Drupal\aggregator;
+
+use Drupal\Core\Plugin\PluginDerivativeInterface;
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   Aggregator category blocks.
+ */
+class CategoryBlock extends AbstractBlock implements PluginDerivativeInterface {
+  protected $derivatives;
+  protected $derivative;
+
+  public function __construct() {
+    $this->derivatives = array();
+  }
+
+  /**
+   * Implements AccessInterface::access().
+   */
+  public function access() {
+    return user_access('access news feeds');
+  }
+
+  /**
+   * Implements BlockInterface::configure().
+   */
+  public function configure($form, &$form_state) {
+    $form = parent::configure($form, $form_state);
+    $form['block_count'] = array(
+      '#type' => 'select',
+      '#title' => t('Number of news items in block'),
+      '#default_value' => $this->config['settings']['block_count'],
+      '#options' => drupal_map_assoc(range(2, 20)),
+    );
+    return $form;
+  }
+
+  /**
+   * Implements BlockInterface::configureSubmit().
+   */
+  public function configureSubmit($form, &$form_state) {
+    parent::configureSubmit($form, $form_state);
+    $this->config['settings']['block_count'] = $form_state['values']['block_count'];
+  }
+
+  /**
+   * Implements PluginChildrenInterface::getChild().
+   */
+  public function getDerivative($derivative) {
+    $this->derivative = $derivative;
+    if (!isset($this->derivatives[$derivative])) {
+      $this->getDerivatives();
+    }
+    if(isset($this->derivatives[$derivative])) {
+      $this->config = $this->derivatives[$derivative];
+      return $this->derivatives[$derivative];
+    }
+    return array();
+  }
+
+  /**
+   * Implements PluginChildrenInterface::getChildren().
+   */
+  public function getDerivatives() {
+    $result = db_query('SELECT cid, title FROM {aggregator_category} ORDER BY title');
+    foreach ($result as $category) {
+      $this->derivatives[$category->cid] = $this->config;
+      $this->derivatives[$category->cid]['delta'] = $category->cid;
+      $this->derivatives[$category->cid]['subject'] = $category->title;
+    }
+    return $this->derivatives;
+  }
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    $derivative = $this->getConfigValue('derivative');
+    return array(
+      'info' => t('@title category latest items', array('@title' => $derivative['subject'])),
+    );
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    $id = $this->derivative;
+    if ($category = db_query('SELECT cid, title, block FROM {aggregator_category} WHERE cid = :cid', array(':cid' => $id))->fetchObject()) {
+      $result = db_query_range('SELECT i.* FROM {aggregator_category_item} ci LEFT JOIN {aggregator_item} i ON ci.iid = i.iid WHERE ci.cid = :cid ORDER BY i.timestamp DESC, i.iid DESC', 0, $this->config['settings']['block_count'], array(':cid' => $category->cid));
+      $read_more = theme('more_link', array('url' => 'aggregator/categories/' . $category->cid, 'title' => t("View this category's recent news.")));
+
+      $items = array();
+      foreach ($result as $item) {
+        $items[] = theme('aggregator_block_item', array('item' => $item));
+      }
+
+      // Only display the block if there are items to show.
+      if (count($items) > 0) {
+        return array(
+          '#block' => $this->derivatives[$this->derivative],
+          '#children' => theme('item_list', array('items' => $items)) . $read_more,
+        );
+      }
+      return array();
+    }
+  }
+}
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/FeedBlock.php b/core/modules/aggregator/lib/Drupal/aggregator/FeedBlock.php
new file mode 100644
index 0000000..fe977b2
--- /dev/null
+++ b/core/modules/aggregator/lib/Drupal/aggregator/FeedBlock.php
@@ -0,0 +1,109 @@
+<?php
+
+namespace Drupal\aggregator;
+
+use Drupal\Core\Plugin\PluginDerivativeInterface;
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   Aggregator feed blocks.
+ */
+class FeedBlock extends AbstractBlock implements PluginDerivativeInterface {
+  protected $derivatives;
+  protected $derivative;
+
+  public function __construct() {
+    $this->derivatives = array();
+  }
+
+  /**
+   * Implements AccessInterface::access().
+   */
+  public function access() {
+    return user_access('access news feeds');
+  }
+
+  /**
+   * Implements BlockInterface::configure().
+   */
+  public function configure($form, &$form_state) {
+    $form = parent::configure($form, $form_state);
+    $form['block_count'] = array(
+      '#type' => 'select',
+      '#title' => t('Number of news items in block'),
+      '#default_value' => $this->config['block_count'],
+      '#options' => drupal_map_assoc(range(2, 20)),
+    );
+    return $form;
+  }
+
+  /**
+   * Implements BlockInterface::configureSubmit().
+   */
+  public function configureSubmit($form, &$form_state) {
+    parent::configureSubmit($form, $form_state);
+    $this->config['block_count'] = $form_state['values']['block_count'];
+  }
+
+  /**
+   * Implements PluginDerivativeInterface::getDerivative().
+   */
+  public function getDerivative($derivative) {
+    $this->derivative = $derivative;
+    if (!isset($this->derivatives[$derivative])) {
+      $this->getDerivatives();
+    }
+    if (isset($this->derivatives[$derivative])) {
+      $this->config = $this->derivatives[$derivative];
+      return $this->derivatives[$derivative];
+    }
+  }
+
+  /**
+   * Implements PluginDerivativeInterface::getDerivatives().
+   */
+  public function getDerivatives() {
+    $result = db_query('SELECT fid, title FROM {aggregator_feed} WHERE block <> 0 ORDER BY fid');
+    foreach ($result as $feed) {
+      $this->derivatives[$feed->fid] = $this->config;
+      $this->derivatives[$feed->fid]['delta'] = $feed->fid;
+      $this->derivatives[$feed->fid]['subject'] = $feed->title;
+    }
+    return $this->derivatives;
+  }
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    $derivative = $this->getConfigValue('derivative');
+    return array(
+      'info' => t('@title feed latest items', array('@title' => $derivative['subject'])),
+    );
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    $id = $this->derivative;
+    if ($feed = db_query('SELECT fid, title, block FROM {aggregator_feed} WHERE block <> 0 AND fid = :fid', array(':fid' => $id))->fetchObject()) {
+      $result = db_query_range("SELECT * FROM {aggregator_item} WHERE fid = :fid ORDER BY timestamp DESC, iid DESC", 0, $this->config['block_count'], array(':fid' => $id));
+      $read_more = theme('more_link', array('url' => 'aggregator/sources/' . $feed->fid, 'title' => t("View this feed's recent news.")));
+
+      $items = array();
+      foreach ($result as $item) {
+        $items[] = theme('aggregator_block_item', array('item' => $item));
+      }
+
+      // Only display the block if there are items to show.
+      if (count($items) > 0) {
+        return array(
+          '#block' => $this->config,
+          '#children' => theme('item_list', array('items' => $items)) . $read_more,
+        );
+      }
+    }
+  }
+}
diff --git a/core/modules/block/block.admin.inc b/core/modules/block/block.admin.inc
index 8a5553d..6c024b8 100644
--- a/core/modules/block/block.admin.inc
+++ b/core/modules/block/block.admin.inc
@@ -114,18 +114,15 @@ function block_admin_display_form($form, &$form_state, $blocks, $theme, $block_r
   $form['blocks'] = array();
   $form['#tree'] = TRUE;
 
-  foreach ($blocks as $i => $block) {
-    $key = $block['module'] . '_' . $block['delta'];
-    $form['blocks'][$key]['module'] = array(
+  foreach ($blocks as $key => $instance) {
+    $block = $instance->getConfig();
+    $form['blocks'][$key]['config_id'] = array(
       '#type' => 'value',
-      '#value' => $block['module'],
-    );
-    $form['blocks'][$key]['delta'] = array(
-      '#type' => 'value',
-      '#value' => $block['delta'],
+      '#value' => $block['config_id'],
     );
+    $info = $instance->info();
     $form['blocks'][$key]['info'] = array(
-      '#markup' => check_plain($block['info']),
+      '#markup' => check_plain($info['info']),
     );
     $form['blocks'][$key]['theme'] = array(
       '#type' => 'hidden',
@@ -136,28 +133,26 @@ function block_admin_display_form($form, &$form_state, $blocks, $theme, $block_r
       '#default_value' => $block['weight'],
       '#delta' => $weight_delta,
       '#title_display' => 'invisible',
-      '#title' => t('Weight for @block block', array('@block' => $block['info'])),
+      '#title' => t('Weight for @block block', array('@block' => $info['info'])),
     );
     $form['blocks'][$key]['region'] = array(
       '#type' => 'select',
       '#default_value' => $block['region'] != BLOCK_REGION_NONE ? $block['region'] : NULL,
       '#empty_value' => BLOCK_REGION_NONE,
       '#title_display' => 'invisible',
-      '#title' => t('Region for @block block', array('@block' => $block['info'])),
+      '#title' => t('Region for @block block', array('@block' => $info['info'])),
       '#options' => $block_regions,
     );
     $form['blocks'][$key]['configure'] = array(
       '#type' => 'link',
       '#title' => t('configure'),
-      '#href' => 'admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure',
+      '#href' => 'admin/structure/block/manage/' . $block['config_id'] . '/configure',
     );
-    if ($block['module'] == 'block') {
-      $form['blocks'][$key]['delete'] = array(
-        '#type' => 'link',
-        '#title' => t('delete'),
-        '#href' => 'admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/delete',
-     );
-    }
+    $form['blocks'][$key]['delete'] = array(
+      '#type' => 'link',
+      '#title' => t('delete'),
+      '#href' => 'admin/structure/block/manage/' . $block['config_id'] . '/delete',
+   );
   }
   // Do not allow disabling the main system content block when it is present.
   if (isset($form['blocks']['system_main']['region'])) {
@@ -182,30 +177,13 @@ function block_admin_display_form($form, &$form_state, $blocks, $theme, $block_r
  * @see block_admin_display_form()
  */
 function block_admin_display_form_submit($form, &$form_state) {
-  $transaction = db_transaction();
-  try {
-    foreach ($form_state['values']['blocks'] 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();
-    }
-  }
-  catch (Exception $e) {
-    $transaction->rollback();
-    watchdog_exception('block', $e);
-    throw $e;
+  foreach ($form_state['values']['blocks'] as $block) {
+    $config = config($block['config_id']);
+    $config->set('weight', $block['weight']);
+    $config->set('region', $block['region']);
+    $config->save();
   }
   drupal_set_message(t('The block settings have been updated.'));
-  cache_clear_all();
 }
 
 /**
@@ -213,8 +191,10 @@ function block_admin_display_form_submit($form, &$form_state) {
  *
  * Callback for usort() in block_admin_display_prepare_blocks().
  */
-function _block_compare($a, $b) {
+function _block_compare($ainstance, $binstance) {
   global $theme_key;
+  $a = $ainstance->getConfig();
+  $b = $binstance->getConfig();
 
   // Theme should be set before calling this function, or the current theme
   // is being used.
@@ -247,7 +227,9 @@ function _block_compare($a, $b) {
     }
   }
   // Sort by title.
-  return strcmp($a['info'], $b['info']);
+  $ainfo = $ainstance->info();
+  $binfo = $binstance->info();
+  return strcmp($ainfo['info'], $binfo['info']);
 }
 
 /**
@@ -265,190 +247,13 @@ function _block_compare($a, $b) {
  * @see block_admin_configure_submit()
  * @ingroup forms
  */
-function block_admin_configure($form, &$form_state, $module, $delta) {
-  $block = block_load($module, $delta);
-  $form['module'] = array(
-    '#type' => 'value',
-    '#value' => $block->module,
-  );
-  $form['delta'] = array(
+function block_admin_configure($form, &$form_state, $plugin_id) {
+  $instance = block_load($plugin_id);
+  $form['instance'] = array(
     '#type' => 'value',
-    '#value' => $block->delta,
-  );
-
-  // Get the block subject for the page title.
-  $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);
-  }
-
-  $form['settings']['title'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Block title'),
-    '#maxlength' => 64,
-    '#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>!placeholder</em> to display no title, or leave blank to use the default block title.', array('!placeholder' => '&lt;none&gt;')),
-    '#default_value' => isset($block->title) ? $block->title : '',
-    '#weight' => -19,
-  );
-
-  // Module-specific block configuration.
-  if ($settings = module_invoke($block->module, 'block_configure', $block->delta)) {
-    foreach ($settings as $k => $v) {
-      $form['settings'][$k] = $v;
-    }
-  }
-
-  // Region settings.
-  $form['regions'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Region settings'),
-    '#collapsible' => FALSE,
-    '#description' => t('Specify in which themes and regions this block is displayed.'),
-    '#tree' => TRUE,
+    '#value' => $instance,
   );
-
-  $theme_default = variable_get('theme_default', 'stark');
-  $admin_theme = variable_get('admin_theme');
-  foreach (list_themes() as $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' => $block->module,
-        ':delta' => $block->delta,
-        ':theme' => $key,
-      ))->fetchField();
-
-      // Use a meaningful title for the main site theme and administrative
-      // theme.
-      $theme_title = $theme->info['name'];
-      if ($key == $theme_default) {
-        $theme_title = t('!theme (default theme)', array('!theme' => $theme_title));
-      }
-      elseif ($admin_theme && $key == $admin_theme) {
-        $theme_title = t('!theme (administration theme)', array('!theme' => $theme_title));
-      }
-      $form['regions'][$key] = array(
-        '#type' => 'select',
-        '#title' => $theme_title,
-        '#default_value' => !empty($region) && $region != -1 ? $region : NULL,
-        '#empty_value' => BLOCK_REGION_NONE,
-        '#options' => system_region_list($key, REGIONS_VISIBLE),
-        '#weight' => ($key == $theme_default ? 9 : 10),
-      );
-    }
-  }
-
-  // Visibility settings.
-  $form['visibility_title'] = array(
-    '#type' => 'item',
-    '#title' => t('Visibility settings'),
-  );
-  $form['visibility'] = array(
-    '#type' => 'vertical_tabs',
-    '#attached' => array(
-      'js' => array(drupal_get_path('module', 'block') . '/block.js'),
-    ),
-  );
-
-  // Per-path visibility.
-  $form['visibility']['path'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Pages'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-    '#group' => 'visibility',
-    '#weight' => 0,
-  );
-
-  $access = user_access('use PHP for settings');
-  if (isset($block->visibility) && $block->visibility == BLOCK_VISIBILITY_PHP && !$access) {
-    $form['visibility']['path']['visibility'] = array(
-      '#type' => 'value',
-      '#value' => BLOCK_VISIBILITY_PHP,
-    );
-    $form['visibility']['path']['pages'] = array(
-      '#type' => 'value',
-      '#value' => isset($block->pages) ? $block->pages : '',
-    );
-  }
-  else {
-    $options = array(
-      BLOCK_VISIBILITY_NOTLISTED => t('All pages except those listed'),
-      BLOCK_VISIBILITY_LISTED => t('Only the listed pages'),
-    );
-    $description = t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %user for the current user's page and %user-wildcard for every user page. %front is the front page.", array('%user' => 'user', '%user-wildcard' => 'user/*', '%front' => '<front>'));
-
-    if (module_exists('php') && $access) {
-      $options += array(BLOCK_VISIBILITY_PHP => t('Pages on which this PHP code returns <code>TRUE</code> (experts only)'));
-      $title = t('Pages or PHP code');
-      $description .= ' ' . t('If the PHP option is chosen, enter PHP code between %php. Note that executing incorrect PHP code can break your Drupal site.', array('%php' => '<?php ?>'));
-    }
-    else {
-      $title = t('Pages');
-    }
-    $form['visibility']['path']['visibility'] = array(
-      '#type' => 'radios',
-      '#title' => t('Show block on specific pages'),
-      '#options' => $options,
-      '#default_value' => isset($block->visibility) ? $block->visibility : BLOCK_VISIBILITY_NOTLISTED,
-    );
-    $form['visibility']['path']['pages'] = array(
-      '#type' => 'textarea',
-      '#title' => '<span class="element-invisible">' . $title . '</span>',
-      '#default_value' => isset($block->pages) ? $block->pages : '',
-      '#description' => $description,
-    );
-  }
-
-  // Per-role visibility.
-  $default_role_options = db_query("SELECT rid FROM {block_role} WHERE module = :module AND delta = :delta", array(
-    ':module' => $block->module,
-    ':delta' => $block->delta,
-  ))->fetchCol();
-  $role_options = array_map('check_plain', user_roles());
-  $form['visibility']['role'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Roles'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-    '#group' => 'visibility',
-    '#weight' => 10,
-  );
-  $form['visibility']['role']['roles'] = array(
-    '#type' => 'checkboxes',
-    '#title' => t('Show block for specific roles'),
-    '#default_value' => $default_role_options,
-    '#options' => $role_options,
-    '#description' => t('Show this block only for the selected role(s). If you select no roles, the block will be visible to all users.'),
-  );
-
-  // Per-user visibility.
-  $form['visibility']['user'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Users'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-    '#group' => 'visibility',
-    '#weight' => 20,
-  );
-  $form['visibility']['user']['custom'] = array(
-    '#type' => 'radios',
-    '#title' => t('Customizable per user'),
-    '#options' => array(
-      BLOCK_CUSTOM_FIXED => t('Not customizable'),
-      BLOCK_CUSTOM_ENABLED => t('Customizable, visible by default'),
-      BLOCK_CUSTOM_DISABLED => t('Customizable, hidden by default'),
-    ),
-    '#description' => t('Allow individual users to customize the visibility of this block in their account settings.'),
-    '#default_value' => isset($block->custom) ? $block->custom : BLOCK_CUSTOM_FIXED,
-  );
-
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save block'),
-  );
-
+  $form += $instance->configure($form, $form_state);
   return $form;
 }
 
@@ -459,15 +264,7 @@ function block_admin_configure($form, &$form_state, $module, $delta) {
  * @see block_admin_configure_submit()
  */
 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'],
-      ':info' => $form_state['values']['info'],
-    ))->fetchField();
-    if (empty($form_state['values']['info']) || $custom_block_exists) {
-      form_set_error('info', t('Ensure that each block description is unique.'));
-    }
-  }
+  $form_state['values']['instance']->configureValidate($form, $form_state);
 }
 
 /**
@@ -477,57 +274,15 @@ function block_admin_configure_validate($form, &$form_state) {
  * @see block_admin_configure_validate()
  */
 function block_admin_configure_submit($form, &$form_state) {
-  if (!form_get_errors()) {
-    $transaction = db_transaction();
-    try {
-      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();
-
-      db_delete('block_role')
-        ->condition('module', $form_state['values']['module'])
-        ->condition('delta', $form_state['values']['delta'])
-        ->execute();
-      $query = db_insert('block_role')->fields(array('rid', 'module', 'delta'));
-      foreach (array_filter($form_state['values']['roles']) as $rid) {
-        $query->values(array(
-          'rid' => $rid,
-          'module' => $form_state['values']['module'],
-          'delta' => $form_state['values']['delta'],
-        ));
-      }
-      $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 == BLOCK_REGION_NONE ? '' : $region),
-            'pages' => trim($form_state['values']['pages']),
-            'status' => (int) ($region != BLOCK_REGION_NONE),
-          ))
-          ->execute();
-      }
-
-      module_invoke($form_state['values']['module'], 'block_save', $form_state['values']['delta'], $form_state['values']);
-    }
-    catch (Exception $e) {
-      $transaction->rollback();
-      watchdog_exception('block', $e);
-      throw $e;
-    }
-    drupal_set_message(t('The block configuration has been saved.'));
-    cache_clear_all();
-    $form_state['redirect'] = 'admin/structure/block';
+  $form_state['values']['instance']->configureSubmit($form, $form_state);
+  $config_values = $form_state['values']['instance']->getConfig();
+  $config_id = $config_values['config_id'];
+  unset($config_values['config_id']);
+  $config = config($config_id);
+  foreach ($config_values as $key => $value) {
+    $config->set($key, $value);
   }
+  $config->save();
 }
 
 /**
@@ -539,7 +294,22 @@ function block_admin_configure_submit($form, &$form_state) {
  * @ingroup forms
  */
 function block_add_block_form($form, &$form_state) {
-  return block_admin_configure($form, $form_state, 'block', NULL);
+  $definitions = plugin('core', 'block')->getPluginDefinitions();
+  $options = array();
+  foreach ($definitions as $plugin_id => $config) {
+    $plugin_components = explode('.', $plugin_id);
+    $options[array_pop($plugin_components)] = $config['title'];
+  }
+  $form['block'] = array(
+    '#title' => t('Select a new block instance.'),
+    '#type' => 'select',
+    '#options' => $options,
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Next'),
+  );
+  return $form;
 }
 
 /**
@@ -548,13 +318,7 @@ function block_add_block_form($form, &$form_state) {
  * @see block_add_block_form()
  * @see block_add_block_form_submit()
  */
-function block_add_block_form_validate($form, &$form_state) {
-  $custom_block_exists = (bool) db_query_range('SELECT 1 FROM {block_custom} WHERE info = :info', 0, 1, array(':info' => $form_state['values']['info']))->fetchField();
-
-  if (empty($form_state['values']['info']) || $custom_block_exists) {
-    form_set_error('info', t('Ensure that each block description is unique.'));
-  }
-}
+function block_add_block_form_validate($form, &$form_state) {}
 
 /**
  * Form submission handler for block_add_block_form().
@@ -565,60 +329,25 @@ function block_add_block_form_validate($form, &$form_state) {
  * @see block_add_block_form_validate()
  */
 function block_add_block_form_submit($form, &$form_state) {
-  $delta = db_insert('block_custom')
-    ->fields(array(
-      'body' => $form_state['values']['body']['value'],
-      'info' => $form_state['values']['info'],
-      'format' => $form_state['values']['body']['format'],
-    ))
-    ->execute();
-  // Store block delta to allow other modules to work with new block.
-  $form_state['values']['delta'] = $delta;
-
-  $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'));
-  foreach (array_filter($form_state['values']['roles']) as $rid) {
-    $query->values(array(
-      'rid' => $rid,
-      'module' => $form_state['values']['module'],
-      'delta' => $delta,
-    ));
+  $plugin_id = $form_state['values']['block'];
+  $definition = plugin('core', 'block')->getPluginDefinition($plugin_id);
+  $uuid = new Drupal\Component\Uuid\Uuid();
+  $config_name = 'plugin.core.block.' . $uuid->generate();
+  $settings = isset($definition['settings']) ? $definition['settings'] : array();
+  $config = array(
+    'plugin_id' => $plugin_id,
+    'config_id' => $config_name,
+  );
+  foreach ($settings as $key => $value) {
+    $config[$key] = $value;
   }
-  $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 == BLOCK_REGION_NONE ? '' : $region),
-        'pages' => trim($form_state['values']['pages']),
-        'status' => (int) ($region != BLOCK_REGION_NONE),
-      ))
-      ->execute();
+  $config['weight'] = 0;
+  if (isset($options['derivative'])) {
+    $config['derivative'] = $options['derivative'];
   }
-
-  drupal_set_message(t('The block has been created.'));
-  cache_clear_all();
-  $form_state['redirect'] = 'admin/structure/block';
+  $verified_storage = new Drupal\Core\Config\DrupalVerifiedStorageSQL($config_name);
+  $verified_storage->write(config_encode($config));
+  $form_state['redirect'] = 'admin/structure/block/manage/' . $config_name;
 }
 
 /**
@@ -633,13 +362,15 @@ function block_add_block_form_submit($form, &$form_state) {
  * @see block_menu()
  * @see block_custom_block_delete_submit()
  */
-function block_custom_block_delete($form, &$form_state, $module, $delta) {
-  $block = block_load($module, $delta);
-  $custom_block = block_custom_block_get($block->delta);
-  $form['info'] = array('#type' => 'hidden', '#value' => $custom_block['info'] ? $custom_block['info'] : $custom_block['title']);
-  $form['bid'] = array('#type' => 'hidden', '#value' => $block->delta);
-
-  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'));
+function block_custom_block_delete($form, &$form_state, $plugin_id) {
+  $block = block_load($plugin_id);
+  $form['plugin_id'] = array('#type' => 'value', '#value' => $plugin_id);
+  $info = $block->info();
+  $subject = $block->getConfigValue('subject');
+  $subject = empty($subject) ? $info['info'] : $subject;
+  $form['subject'] = array('#type' => 'value', '#value' => $subject);
+
+  return confirm_form($form, t('Are you sure you want to delete the block %name?', array('%name' => $subject)), 'admin/structure/block', '', t('Delete'), t('Cancel'));
 }
 
 /**
@@ -648,19 +379,9 @@ function block_custom_block_delete($form, &$form_state, $module, $delta) {
  * @see block_custom_block_delete()
  */
 function block_custom_block_delete_submit($form, &$form_state) {
-  db_delete('block_custom')
-    ->condition('bid', $form_state['values']['bid'])
-    ->execute();
-  db_delete('block')
-    ->condition('module', 'block')
-    ->condition('delta', $form_state['values']['bid'])
-    ->execute();
-  db_delete('block_role')
-    ->condition('module', 'block')
-    ->condition('delta', $form_state['values']['bid'])
-    ->execute();
-  drupal_set_message(t('The block %name has been removed.', array('%name' => $form_state['values']['info'])));
-  cache_clear_all();
+  $config = config($form_state['values']['plugin_id']);
+  $config->delete();
+  drupal_set_message(t('The block %name has been removed.', array('%name' => $form_state['values']['subject'])));
   $form_state['redirect'] = 'admin/structure/block';
   return;
 }
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 25bd3b1..4e3e517 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -112,22 +112,22 @@ function block_menu() {
     'access arguments' => array('administer blocks'),
     'file' => 'block.admin.inc',
   );
-  $items['admin/structure/block/manage/%/%'] = array(
+  $items['admin/structure/block/manage/%'] = array(
     'title' => 'Configure block',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('block_admin_configure', 4, 5),
+    'page arguments' => array('block_admin_configure', 4),
     'access arguments' => array('administer blocks'),
     'file' => 'block.admin.inc',
   );
-  $items['admin/structure/block/manage/%/%/configure'] = array(
+  $items['admin/structure/block/manage/%/configure'] = array(
     'title' => 'Configure block',
     'type' => MENU_DEFAULT_LOCAL_TASK,
     'context' => MENU_CONTEXT_INLINE,
   );
-  $items['admin/structure/block/manage/%/%/delete'] = array(
+  $items['admin/structure/block/manage/%/delete'] = array(
     'title' => 'Delete block',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('block_custom_block_delete', 4, 5),
+    'page arguments' => array('block_custom_block_delete', 4),
     'access arguments' => array('administer blocks'),
     'type' => MENU_LOCAL_TASK,
     'context' => MENU_CONTEXT_NONE,
@@ -343,7 +343,6 @@ function block_get_blocks_by_region($region) {
  *   A renderable array.
  */
 function _block_get_renderable_region($list = array()) {
-  $weight = 0;
   $build = array();
   // Block caching is not compatible with node_access modules. We also
   // preserve the submission of forms in blocks, by fetching from cache
@@ -356,13 +355,16 @@ function _block_get_renderable_region($list = array()) {
     !in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD'));
 
   foreach ($list as $key => $block) {
+    $config = $block->getConfig();
+    $info = $block->info();
+    $config['cache'] = isset($info['cache']) ? $info['cache'] : DRUPAL_NO_CACHE;
     $build[$key] = array(
       '#block' => $block,
-      '#weight' => ++$weight,
+      '#weight' => (int) $config['weight'],
       '#theme_wrappers' => array('block'),
     );
 
-    if ($not_cacheable || in_array($block->cache, array(DRUPAL_NO_CACHE, DRUPAL_CACHE_CUSTOM))) {
+    if ($not_cacheable || in_array($config['cache'], array(DRUPAL_NO_CACHE, DRUPAL_CACHE_CUSTOM))) {
       // Non-cached blocks get built immediately. Provides more content
       // that can be easily manipulated during hook_page_alter().
       $build[$key] = _block_get_renderable_block($build[$key]);
@@ -371,8 +373,8 @@ function _block_get_renderable_region($list = array()) {
       $build[$key] += array(
         '#pre_render' => array('_block_get_renderable_block'),
         '#cache' => array(
-          'keys' => array($block->module, $block->delta),
-          'granularity' => $block->cache,
+          'keys' => array($config['module'], $config['delta']),
+          'granularity' => $config['cache'],
           'bin' => 'block',
           'expire' => CACHE_TEMPORARY,
         ),
@@ -384,11 +386,10 @@ function _block_get_renderable_region($list = array()) {
     // skip the help block, since we assume that most users do not need or want
     // to perform contextual actions on the help block, and the links needlessly
     // draw attention on it.
-    if ($key != 'system_main' && $key != 'system_help') {
-      $build[$key]['#contextual_links']['block'] = array('admin/structure/block/manage', array($block->module, $block->delta));
+    if ($config['plugin_id'] != 'systemhelp' && $config['plugin_id'] != 'systemmain') {
+      $build[$key]['#contextual_links']['block'] = array('admin/structure/block/manage', array($key));
     }
   }
-  $build['#sorted'] = TRUE;
   return $build;
 }
 
@@ -403,107 +404,11 @@ function _block_get_renderable_region($list = array()) {
  *   Blocks currently exported by modules.
  */
 function _block_rehash($theme = NULL) {
-  global $theme_key;
-
-  drupal_theme_initialize();
-  if (!isset($theme)) {
-    // If theme is not specifically set, rehash for the current theme.
-    $theme = $theme_key;
-  }
-  $regions = system_region_list($theme);
-
-  // These are the blocks the function will return.
   $blocks = array();
-  // 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;
-    }
-  }
-  // Save the blocks defined in code for alter context.
-  $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']  = '';
-      }
-      // Make sure weight is set.
-      if (!isset($block['weight'])) {
-        $block['weight'] = 0;
-      }
-      if (!empty($block['region']) && $block['region'] != BLOCK_REGION_NONE && !isset($regions[$block['region']])) {
-        drupal_set_message(t('The block %info was assigned to the invalid region %region and has been disabled.', array('%info' => $block['info'], '%region' => $block['region'])), 'warning');
-        // Disabled modules are moved into the BLOCK_REGION_NONE later so no
-        // need to move the bock 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;
-      }
-      // There is no point saving disabled blocks. Still, we need to save them
-      // because the 'title' attribute is saved to the {blocks} table.
-      if (isset($block['bid'])) {
-        // If the block has a bid property, it comes from the database and
-        // the record needs to be updated, so set the primary key to 'bid'
-        // before passing to drupal_write_record().
-        $primary_keys = array('bid');
-        // Remove a block from the list of blocks to keep if it became disabled.
-        unset($bids[$block['bid']]);
-      }
-      else {
-        $primary_keys = array();
-      }
-      drupal_write_record('block', $block, $primary_keys);
-      // Add to the list of blocks we return.
-      $blocks[] = $block;
-    }
-  }
-  if ($bids) {
-    // Remove disabled that are no longer defined by the code from the
-    // database.
-    db_delete('block')
-      ->condition('bid', $bids, 'NOT IN')
-      ->condition('theme', $theme)
-      ->execute();
+  $instances = array();
+  $block_configs = config_get_signed_file_storage_names_with_prefix('plugin.core.block');
+  foreach ($block_configs as $config) {
+    $blocks[$config] = block_load($config);
   }
   return $blocks;
 }
@@ -711,28 +616,24 @@ function block_list($region) {
 /**
  * Loads a block object from the database.
  *
- * @param $module
- *   Name of the module that implements the block to load.
- * @param $delta
- *   Unique ID of the block within the context of $module. Pass NULL to return
- *   an empty block object for $module.
+ * @param $plugin_id
+ *   The plugin_id to load.
+ * @param $conf
+ *   An optional configuration array for creating a block instance from php
+ *   instead of relying on configuration xml.
  *
  * @return
  *   A block object.
  */
-function block_load($module, $delta) {
-  if (isset($delta)) {
-    $block = db_query('SELECT * FROM {block} WHERE module = :module AND delta = :delta', array(':module' => $module, ':delta' => $delta))->fetchObject();
+function block_load($plugin_id, $conf = array()) {
+  try {
+    $block = plugin('core', 'block')->mapPluginInstance(array('config' => $plugin_id));
   }
-
-  // If the block does not exist in the database yet return a stub block
-  // object.
-  if (empty($block)) {
-    $block = new stdClass();
-    $block->module = $module;
-    $block->delta = $delta;
+  catch (Drupal\Core\Plugin\MapperException $e) {
+    // @TODO: Write a custom verified storage class that can have the conf
+    // array passed to it so that we can generate one off blocks from pure php
+    // array as configuration.
   }
-
   return $block;
 }
 
@@ -743,28 +644,13 @@ function block_load($module, $delta) {
  *   An array of blocks grouped by region.
  */
 function _block_load_blocks() {
-  global $theme_key;
-
-  $query = db_select('block', 'b');
-  $query->addField('b', 'title', 'subject');
-  $result = $query
-    ->fields('b')
-    ->condition('b.theme', $theme_key)
-    ->condition('b.status', 1)
-    ->orderBy('b.region')
-    ->orderBy('b.weight')
-    ->orderBy('b.module')
-    ->addTag('block_load')
-    ->addTag('translatable')
-    ->execute();
-
-  $block_info = $result->fetchAllAssoc('bid');
-  // Allow modules to modify the block list.
-  drupal_alter('block_list', $block_info);
-
   $blocks = array();
-  foreach ($block_info as $block) {
-    $blocks[$block->region]["{$block->module}_{$block->delta}"] = $block;
+  $block_plugins = config_get_signed_file_storage_names_with_prefix('plugin.core.block');
+  foreach ($block_plugins as $plugin_id) {
+    $plugin = config($plugin_id)->get();
+    $block = plugin('core', 'block')->getPluginInstance($plugin['plugin_id'], $plugin);
+    $config = $block->getConfig();
+    $blocks[$config['region']]["$plugin_id"] = $block;
   }
   return $blocks;
 }
@@ -871,45 +757,9 @@ function block_block_list_alter(&$blocks) {
  */
 function _block_get_renderable_block($element) {
   $block = $element['#block'];
-
-  // Render the block content if it has not been created already.
-  if (!isset($block->content)) {
-    $array = module_invoke($block->module, 'block_view', $block->delta);
-
-    // Allow modules to modify the block before it is viewed, via either
-    // hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter().
-    drupal_alter(array('block_view', "block_view_{$block->module}_{$block->delta}"), $array, $block);
-
-    if (empty($array['content'])) {
-      // Blocks without content should emit no markup at all.
-      $element += array(
-        '#access' => FALSE,
-        '#printed' => TRUE,
-      );
-    }
-    elseif (isset($array) && is_array($array)) {
-      foreach ($array as $k => $v) {
-        $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);
-    }
-    // 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
-      // markup.
-      $block->subject = $block->title == '<none>' ? '' : check_plain($block->title);
-    }
-
-    // Add the content renderable array to the main element.
-    $element['content'] = $block->content;
-    unset($block->content);
-    $element['#block'] = $block;
+  // Don't bother to build blocks that aren't accessible.
+  if ($element['#access'] = $block->access()) {
+    $element += $block->build();
   }
   return $element;
 }
@@ -948,7 +798,7 @@ function block_flush_caches() {
  */
 function template_preprocess_block(&$variables) {
   $block_counter = &drupal_static(__FUNCTION__, array());
-  $variables['block'] = $variables['elements']['#block'];
+  $variables['block'] = (object) $variables['elements']['#block']->getConfig();
   // All blocks get an independent counter for each region.
   if (!isset($block_counter[$variables['block']->region])) {
     $block_counter[$variables['block']->region] = 1;
@@ -960,13 +810,16 @@ function template_preprocess_block(&$variables) {
   // Create the $content variable that templates expect.
   $variables['content'] = $variables['elements']['#children'];
 
-  $variables['classes_array'][] = drupal_html_class('block-' . $variables['block']->module);
+  $variables['classes_array'][] = drupal_html_class('block-' . $variables['block']->plugin_id);
+  if (!empty($variables['block']->css_class)) {
+    $variables['block_html_id'] = drupal_html_class($variables['block']->css_class);;
+  }
 
   // Add default class for block content.
   $variables['content_attributes_array']['class'][] = 'content';
 
   $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->region;
-  $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->module;
+  $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->plugin_id;
   // Hyphens (-) and underscores (_) play a special role in theme suggestions.
   // Theme suggestions should only contain underscores, because within
   // drupal_find_theme_templates(), underscores are converted to hyphens to
@@ -975,10 +828,12 @@ function template_preprocess_block(&$variables) {
   // contains a hyphen, it will end up as an underscore after this conversion,
   // and your function names won't be recognized. So, we need to convert
   // hyphens to underscores in block deltas for the theme suggestions.
-  $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->module . '__' . strtr($variables['block']->delta, '-', '_');
+  $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->plugin_id . '__' . strtr($variables['block']->config_id, '-', '_');
 
   // Create a valid HTML ID and make sure it is unique.
-  $variables['block_html_id'] = drupal_html_id('block-' . $variables['block']->module . '-' . $variables['block']->delta);
+  if (!empty($variables['block']->css_id)) {
+    $variables['block_html_id'] = drupal_html_id($variables['block']->css_id);
+  }
 }
 
 /**
diff --git a/core/modules/block/block.tpl.php b/core/modules/block/block.tpl.php
index 78387a8..a52d506 100644
--- a/core/modules/block/block.tpl.php
+++ b/core/modules/block/block.tpl.php
@@ -44,7 +44,7 @@
  * @ingroup themeable
  */
 ?>
-<div id="<?php print $block_html_id; ?>" class="<?php print $classes; ?>"<?php print $attributes; ?>>
+<div <?php !empty($block_html_id) ? print 'id="' . $block_html_id . '"': ''; ?> class="<?php print $classes; ?>"<?php print $attributes; ?>>
 
   <?php print render($title_prefix); ?>
 <?php if ($block->subject): ?>
diff --git a/core/modules/block/config/plugin.type.core.block.xml b/core/modules/block/config/plugin.type.core.block.xml
new file mode 100644
index 0000000..1f568bb
--- /dev/null
+++ b/core/modules/block/config/plugin.type.core.block.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<config>
+  <factory>Drupal\Component\Plugin\Factory\DefaultFactory</factory>
+  <mapper>Drupal\Component\Plugin\Mapper\ConfigMapper</mapper>
+  <title>Block</title>
+  <description>Block plugin mechanism.</description>
+  <class>block_class</class>
+</config>
diff --git a/core/modules/block/lib/Drupal/block/AbstractBlock.php b/core/modules/block/lib/Drupal/block/AbstractBlock.php
new file mode 100644
index 0000000..007ca05
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/AbstractBlock.php
@@ -0,0 +1,228 @@
+<?php
+
+namespace Drupal\block;
+
+use Drupal\Component\Plugin\PluginAbstract;
+use Symfony\Component\Routing\RequestContext;
+
+/**
+ * @file
+ *   An abstract block implementation to be inherited from to take care of many
+ *   common block setup tasks.
+ */
+abstract class AbstractBlock extends PluginAbstract implements BlockInterface {
+  protected $context;
+
+  /**
+   * Implements BlockInterface::access().
+   */
+  public function access() {
+    return TRUE;
+  }
+
+  /**
+   * Implements BlockInterface::configure().
+   */
+  public function configure($form, &$form_state) {
+    $form['module'] = array(
+      '#type' => 'value',
+      '#value' => $this->getConfigValue('module'),
+    );
+    $form['delta'] = array(
+      '#type' => 'value',
+      '#value' => $this->getConfigValue('delta'),
+    );
+
+    // Get the block subject for the page title.
+    $subject = $this->getConfigValue('subject');
+    if ($subject) {
+      drupal_set_title(t("'%subject' block", array('%subject' => $subject)), PASS_THROUGH);
+    }
+
+    $form['settings']['title'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Block title'),
+      '#maxlength' => 64,
+      '#description' => $this->getConfigValue('module') == 'block' ? t('The title of the block as shown to the user.') : t('Override the default title for the block. Use <em>!placeholder</em> to display no title, or leave blank to use the default block title.', array('!placeholder' => '&lt;none&gt;')),
+      '#default_value' => isset($subject) ? $subject : '',
+      '#weight' => -19,
+    );
+
+    // Region settings.
+    $form['regions'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Region settings'),
+      '#collapsible' => FALSE,
+      '#description' => t('Specify in which themes and regions this block is displayed.'),
+      '#tree' => TRUE,
+    );
+
+    // Visibility settings.
+    $form['visibility_title'] = array(
+      '#type' => 'item',
+      '#title' => t('Visibility settings'),
+    );
+    $form['visibility'] = array(
+      '#type' => 'vertical_tabs',
+      '#attached' => array(
+        'js' => array(drupal_get_path('module', 'block') . '/block.js'),
+      ),
+    );
+
+    // Per-path visibility.
+    $form['visibility']['path'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Pages'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#group' => 'visibility',
+      '#weight' => 0,
+    );
+
+    //@TODO remove this access check and inject it in some other way.
+    // In fact this entire visibility settings section probably needs a
+    // separate user interface in the near future.
+    $access = user_access('use PHP for settings');
+    if (isset($block->visibility) && $block->visibility == BLOCK_VISIBILITY_PHP && !$access) {
+      $form['visibility']['path']['visibility'] = array(
+        '#type' => 'value',
+        '#value' => BLOCK_VISIBILITY_PHP,
+      );
+      $form['visibility']['path']['pages'] = array(
+        '#type' => 'value',
+        '#value' => isset($block->pages) ? $block->pages : '',
+      );
+    }
+    else {
+      $options = array(
+        BLOCK_VISIBILITY_NOTLISTED => t('All pages except those listed'),
+        BLOCK_VISIBILITY_LISTED => t('Only the listed pages'),
+      );
+      $description = t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %user for the current user's page and %user-wildcard for every user page. %front is the front page.", array('%user' => 'user', '%user-wildcard' => 'user/*', '%front' => '<front>'));
+
+      if (module_exists('php') && $access) {
+        $options += array(BLOCK_VISIBILITY_PHP => t('Pages on which this PHP code returns <code>TRUE</code> (experts only)'));
+        $title = t('Pages or PHP code');
+        $description .= ' ' . t('If the PHP option is chosen, enter PHP code between %php. Note that executing incorrect PHP code can break your Drupal site.', array('%php' => '<?php ?>'));
+      }
+      else {
+        $title = t('Pages');
+      }
+      $form['visibility']['path']['visibility'] = array(
+        '#type' => 'radios',
+        '#title' => t('Show block on specific pages'),
+        '#options' => $options,
+        '#default_value' => isset($block->visibility) ? $block->visibility : BLOCK_VISIBILITY_NOTLISTED,
+      );
+      $form['visibility']['path']['pages'] = array(
+        '#type' => 'textarea',
+        '#title' => '<span class="element-invisible">' . $title . '</span>',
+        '#default_value' => isset($block->pages) ? $block->pages : '',
+        '#description' => $description,
+      );
+    }
+
+    // Per-role visibility.
+    $default_role_options = db_query("SELECT rid FROM {block_role} WHERE module = :module", array(
+      ':module' => $this->getConfigValue('module'),
+    ))->fetchCol();
+    $role_options = array_map('check_plain', user_roles());
+    $form['visibility']['role'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Roles'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#group' => 'visibility',
+      '#weight' => 10,
+    );
+    $form['visibility']['role']['roles'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Show block for specific roles'),
+      '#default_value' => $default_role_options,
+      '#options' => $role_options,
+      '#description' => t('Show this block only for the selected role(s). If you select no roles, the block will be visible to all users.'),
+    );
+
+    // Per-user visibility.
+    $form['visibility']['user'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Users'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#group' => 'visibility',
+      '#weight' => 20,
+    );
+    $form['visibility']['user']['custom'] = array(
+      '#type' => 'radios',
+      '#title' => t('Customizable per user'),
+      '#options' => array(
+        BLOCK_CUSTOM_FIXED => t('Not customizable'),
+        BLOCK_CUSTOM_ENABLED => t('Customizable, visible by default'),
+        BLOCK_CUSTOM_DISABLED => t('Customizable, hidden by default'),
+      ),
+      '#description' => t('Allow individual users to customize the visibility of this block in their account settings.'),
+      '#default_value' => isset($block->custom) ? $block->custom : BLOCK_CUSTOM_FIXED,
+    );
+
+    $form['actions'] = array('#type' => 'actions');
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save block'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * Implements BlockInterface::configureValidate().
+   */
+  public function configureValidate($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'],
+        ':info' => $form_state['values']['info'],
+      ))->fetchField();
+      if (empty($form_state['values']['info']) || $custom_block_exists) {
+        form_set_error('info', t('Ensure that each block description is unique.'));
+      }
+    }
+  }
+
+  /**
+   * Implements BlockInterface::configureSubmit().
+   */
+  public function configureSubmit($form, &$form_state) {
+    if (!form_get_errors()) {
+      $transaction = db_transaction();
+      try {
+        $keys = array(
+          'visibility' => 'visibility',
+          'pages' => 'pages',
+          'custom' => 'custom',
+          'title' => 'subject',
+          'module',
+          'delta',
+        );
+        $instance = $form_state['values']['instance'];
+        foreach ($keys as $key => $new_key) {
+          if (isset($form_state['values'][$key])) {
+            $this->config[$new_key] = $form_state['values'][$key];
+          }
+        }
+      }
+      catch (Exception $e) {
+        $transaction->rollback();
+        watchdog_exception('block', $e);
+        throw $e;
+      }
+      drupal_set_message(t('The block configuration has been saved.'));
+      cache_clear_all();
+      $form_state['redirect'] = 'admin/structure/block';
+    }
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {}
+}
diff --git a/core/modules/block/lib/Drupal/block/BlockInterface.php b/core/modules/block/lib/Drupal/block/BlockInterface.php
new file mode 100644
index 0000000..c2fb19b
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/BlockInterface.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Drupal\block;
+
+/**
+ * Interface definition for Block plugins.
+ */
+interface BlockInterface {
+
+  /**
+   * Retrieves information for the blocks admin pages.
+   *
+   * @return array().
+   */
+  public function info();
+
+  /**
+   * A simple access method. This should be replaced with access plugins before
+   * Drupal 8 is released.
+   *
+   * @return bool.
+   */
+  public function access();
+
+  /**
+   * The configuration form for the block.
+   *
+   * @return form array().
+   */
+  public function configure($form, &$form_state);
+
+  /**
+   * The validation for the configuration form.
+   */
+  public function configureValidate($form, &$form_state);
+
+  /**
+   * The submission for the configuration form.
+   */
+  public function configureSubmit($form, &$form_state);
+
+  /**
+   * A function for building renderable block arrays. A block theme wrapper
+   * will be wrapped around this by the caller.
+   *
+   * @return renderable array().
+   */
+  public function build();
+}
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index a714419..c79e410 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -205,7 +205,7 @@ function comment_field_extra_fields() {
 function comment_theme() {
   return array(
     'comment_block' => array(
-      'variables' => array(),
+      'variables' => array('number' => NULL),
     ),
     'comment_preview' => array(
       'variables' => array('comment' => NULL),
@@ -431,51 +431,6 @@ function comment_permission() {
 }
 
 /**
- * Implements hook_block_info().
- */
-function comment_block_info() {
-  $blocks['recent']['info'] = t('Recent comments');
-  $blocks['recent']['properties']['administrative'] = TRUE;
-
-  return $blocks;
-}
-
-/**
- * Implements hook_block_configure().
- */
-function comment_block_configure($delta = '') {
-  $form['comment_block_count'] = array(
-    '#type' => 'select',
-    '#title' => t('Number of recent comments'),
-    '#default_value' => variable_get('comment_block_count', 10),
-    '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 30)),
-  );
-
-  return $form;
-}
-
-/**
- * Implements hook_block_save().
- */
-function comment_block_save($delta = '', $edit = array()) {
-  variable_set('comment_block_count', (int) $edit['comment_block_count']);
-}
-
-/**
- * Implements hook_block_view().
- *
- * Generates a block with the most recent comments.
- */
-function comment_block_view($delta = '') {
-  if (user_access('access comments')) {
-    $block['subject'] = t('Recent comments');
-    $block['content'] = theme('comment_block');
-
-    return $block;
-  }
-}
-
-/**
  * Redirects comment links to the correct page depending on comment settings.
  *
  * Since comments are paged there is no way to guarantee which page a comment
@@ -611,9 +566,9 @@ function comment_new_page_count($num_comments, $new_replies, $node) {
  *
  * @ingroup themeable
  */
-function theme_comment_block() {
+function theme_comment_block($variables) {
   $items = array();
-  $number = variable_get('comment_block_count', 10);
+  $number = $variables['number'];
   foreach (comment_get_recent($number) as $comment) {
     $items[] = l($comment->subject, 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)) . '&nbsp;<span>' . t('@time ago', array('@time' => format_interval(REQUEST_TIME - $comment->changed))) . '</span>';
   }
@@ -2108,7 +2063,7 @@ function comment_form_submit($form, &$form_state) {
  * Implements hook_preprocess_block().
  */
 function comment_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'comment') {
+  if ($variables['block']->plugin_id == 'commentrecent') {
     $variables['attributes_array']['role'] = 'navigation';
   }
 }
diff --git a/core/modules/comment/config/plugin.definition.core.block.commentrecent.xml b/core/modules/comment/config/plugin.definition.core.block.commentrecent.xml
new file mode 100644
index 0000000..408de3d
--- /dev/null
+++ b/core/modules/comment/config/plugin.definition.core.block.commentrecent.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<config>
+  <title>Recent Comments</title>
+  <module>comment</module>
+  <delta>recent</delta>
+  <block_class>Drupal\comment\RecentBlock</block_class>
+  <settings>
+    <subject>Recent comments</subject>
+    <region>sidebar_first</region>
+    <block_count>10</block_count>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/comment/lib/Drupal/comment/RecentBlock.php b/core/modules/comment/lib/Drupal/comment/RecentBlock.php
new file mode 100644
index 0000000..0231129
--- /dev/null
+++ b/core/modules/comment/lib/Drupal/comment/RecentBlock.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\comment;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   Comment module recent comments block.
+ */
+class RecentBlock extends AbstractBlock {
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('Recent comments'),
+    );
+  }
+
+  /**
+   * Implements AccessInterface::access().
+   */
+  public function access() {
+    return user_access('access comments');
+  }
+
+  /**
+   * Implements BlockInterface::configure().
+   */
+  public function configure($form, &$form_state) {
+    $form = parent::configure($form, $form_state);
+    $form['block_count'] = array(
+      '#type' => 'select',
+      '#title' => t('Number of recent comments'),
+      '#default_value' => $this->config['block_count'],
+      '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 30)),
+    );
+    return $form;
+  }
+
+  /**
+   * Implements BlockInterface::configureSubmit().
+   */
+  public function configureSubmit($form, &$form_state) {
+    parent::configureSubmit($form, $form_state);
+    $this->config['block_count'] = $form_state['values']['block_count'];
+  }
+
+  /**
+   * Implements BlockInterface::build();
+   */
+  public function build() {
+    return array(
+      '#block' => $this->config,
+      '#theme' => 'comment_block',
+      '#number' => $this->config['block_count'],
+    );
+  }
+}
diff --git a/core/modules/dashboard/dashboard.module b/core/modules/dashboard/dashboard.module
index 889af83..837df15 100644
--- a/core/modules/dashboard/dashboard.module
+++ b/core/modules/dashboard/dashboard.module
@@ -411,13 +411,6 @@ function dashboard_form_block_admin_configure_alter(&$form, &$form_state) {
 }
 
 /**
- * Implements hook_form_FORM_ID_alter().
- */
-function dashboard_form_block_add_block_form_alter(&$form, &$form_state) {
-  dashboard_form_block_admin_configure_alter($form, $form_state);
-}
-
-/**
  * Preprocesses variables for block-admin-display-form.tpl.php.
  */
 function template_preprocess_dashboard_admin_display_form(&$variables) {
diff --git a/core/modules/forum/config/plugin.definition.core.block.forumactive.xml b/core/modules/forum/config/plugin.definition.core.block.forumactive.xml
new file mode 100644
index 0000000..067854c
--- /dev/null
+++ b/core/modules/forum/config/plugin.definition.core.block.forumactive.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<config>
+  <title>Active forum topics</title>
+  <module>forum</module>
+  <delta>active</delta>
+  <block_class>Drupal\forum\ActiveBlock</block_class>
+  <settings>
+    <subject>Active forum topics</subject>
+    <block_count>5</block_count>
+    <region>sidebar_second</region>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/forum/config/plugin.definition.core.block.forumnew.xml b/core/modules/forum/config/plugin.definition.core.block.forumnew.xml
new file mode 100644
index 0000000..5912611
--- /dev/null
+++ b/core/modules/forum/config/plugin.definition.core.block.forumnew.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<config>
+  <title>New forum topics</title>
+  <module>forum</module>
+  <delta>new</delta>
+  <block_class>Drupal\forum\NewBlock</block_class>
+  <settings>
+    <subject>New forum topics</subject>
+    <region>sidebar_second</region>
+    <block_count>5</block_count>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 180f1c9..128e1a1 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -624,71 +624,6 @@ function forum_form_node_form_alter(&$form, &$form_state, $form_id) {
 }
 
 /**
- * Implements hook_block_info().
- */
-function forum_block_info() {
-  $blocks['active'] = array(
-    'info' => t('Active forum topics'),
-    'cache' => DRUPAL_CACHE_CUSTOM,
-    'properties' => array('administrative' => TRUE),
-  );
-  $blocks['new'] = array(
-    'info' => t('New forum topics'),
-    'cache' => DRUPAL_CACHE_CUSTOM,
-    'properties' => array('administrative' => TRUE),
-  );
-  return $blocks;
-}
-
-/**
- * Implements hook_block_configure().
- */
-function forum_block_configure($delta = '') {
-  $form['forum_block_num_' . $delta] = array('#type' => 'select', '#title' => t('Number of topics'), '#default_value' => variable_get('forum_block_num_' . $delta, '5'), '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)));
-  return $form;
-}
-
-/**
- * Implements hook_block_save().
- */
-function forum_block_save($delta = '', $edit = array()) {
-  variable_set('forum_block_num_' . $delta, $edit['forum_block_num_' . $delta]);
-}
-
-/**
- * Implements hook_block_view().
- *
- * Generates a block containing the currently active forum topics and the
- * most recently added forum topics.
- */
-function forum_block_view($delta = '') {
-  $query = db_select('forum_index', 'f')
-    ->fields('f')
-    ->addTag('node_access');
-  switch ($delta) {
-    case 'active':
-      $title = t('Active forum topics');
-      $query
-        ->orderBy('f.last_comment_timestamp', 'DESC')
-        ->range(0, variable_get('forum_block_num_active', '5'));
-      break;
-
-    case 'new':
-      $title = t('New forum topics');
-      $query
-        ->orderBy('f.created', 'DESC')
-        ->range(0, variable_get('forum_block_num_new', '5'));
-      break;
-  }
-
-  $block['subject'] = $title;
-  // Cache based on the altered query. Enables us to cache with node access enabled.
-  $block['content'] = drupal_render_cache_by_query($query, 'forum_block_view');
-  $block['content']['#access'] = user_access('access content');
-  return $block;
-}
-
-/**
 * A #pre_render callback. Lists nodes based on the element's #query property.
 *
 * @see forum_block_view()
diff --git a/core/modules/forum/lib/Drupal/forum/ActiveBlock.php b/core/modules/forum/lib/Drupal/forum/ActiveBlock.php
new file mode 100644
index 0000000..711a60b
--- /dev/null
+++ b/core/modules/forum/lib/Drupal/forum/ActiveBlock.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Drupal\forum;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   Forum module active forums block.
+ */
+class ActiveBlock extends AbstractBlock {
+
+  /**
+   * Implements BlockInterface::access().
+   */
+  public function access() {
+    return user_access('access content');
+  }
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('Active forum topics'),
+      'cache' => DRUPAL_CACHE_CUSTOM,
+      'properties' => array(
+        'administrative' => TRUE,
+      ),
+    );
+  }
+
+  /**
+   * Implements BlockInterface::configure().
+   */
+  public function configure($form, &$form_state) {
+    $form = parent::configure($form, $form_state);
+    $form['block_count'] = array(
+      '#type' => 'select',
+      '#title' => t('Number of topics'),
+      '#default_value' => $this->config['block_count'],
+      '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)));
+    return $form;
+  }
+
+  /**
+   * Implements BlockInterface::configureSubmit().
+   */
+  public function configureSubmit($form, &$form_state) {
+    parent::configureSubmit($form, $form_state);
+    $this->config['block_count'] = $form_state['values']['block_count'];
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    $query = db_select('forum_index', 'f')
+      ->fields('f')
+      ->addTag('node_access')
+      ->orderBy('f.last_comment_timestamp', 'DESC')
+      ->range(0, $this->config['block_count']);
+
+    return array(
+      '#block' => $this->config,
+      drupal_render_cache_by_query($query, 'forum_block_view'),
+    );
+  }
+}
diff --git a/core/modules/forum/lib/Drupal/forum/NewBlock.php b/core/modules/forum/lib/Drupal/forum/NewBlock.php
new file mode 100644
index 0000000..9fa1479
--- /dev/null
+++ b/core/modules/forum/lib/Drupal/forum/NewBlock.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Drupal\forum;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   Forum module active forums block.
+ */
+class NewBlock extends AbstractBlock {
+
+  /**
+   * Implements BlockInterface::access().
+   */
+  public function access() {
+    return user_access('access content');
+  }
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('New forum topics'),
+      'cache' => DRUPAL_CACHE_CUSTOM,
+      'properties' => array(
+        'administrative' => TRUE,
+      ),
+    );
+  }
+
+  /**
+   * Implements BlockInterface::configure().
+   */
+  public function configure($form, &$form_state) {
+    $form = parent::configure($form, $form_state);
+    $form['block_count'] = array(
+      '#type' => 'select',
+      '#title' => t('Number of topics'),
+      '#default_value' => $this->config['block_count'],
+      '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)));
+    return $form;
+  }
+
+  /**
+   * Implements BlockInterface::configureSubmit().
+   */
+  public function configureSubmit($form, &$form_state) {
+    parent::configureSubmit($form, $form_state);
+    $this->config['block_count'] = $form_state['values']['block_count'];
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    $query = db_select('forum_index', 'f')
+      ->fields('f')
+      ->addTag('node_access')
+      ->orderBy('f.created', 'DESC')
+      ->range(0, $this->config['block_count']);
+
+    return array(
+      '#block' => $this->config,
+      drupal_render_cache_by_query($query, 'forum_block_view'),
+    );
+  }
+}
diff --git a/core/modules/help/help.module b/core/modules/help/help.module
index 9e74751..3b84df4 100644
--- a/core/modules/help/help.module
+++ b/core/modules/help/help.module
@@ -64,12 +64,3 @@ function help_help($path, $arg) {
       return $output;
   }
 }
-
-/**
- * Implements hook_preprocess_block().
- */
-function help_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'help') {
-    $variables['attributes_array']['role'] = 'complementary';
-  }
-}
diff --git a/core/modules/menu/config/plugin.definition.core.block.menu.xml b/core/modules/menu/config/plugin.definition.core.block.menu.xml
new file mode 100644
index 0000000..a412552
--- /dev/null
+++ b/core/modules/menu/config/plugin.definition.core.block.menu.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<config>
+  <title>Menu</title>
+  <module>menu</module>
+  <block_class>Drupal\menu\MenuBlock</block_class>
+  <derivatives>TRUE</derivatives>
+  <settings>
+    <subject>Menu</subject>
+    <region>sidebar_second</region>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/menu/lib/Drupal/menu/MenuBlock.php b/core/modules/menu/lib/Drupal/menu/MenuBlock.php
new file mode 100644
index 0000000..620e800
--- /dev/null
+++ b/core/modules/menu/lib/Drupal/menu/MenuBlock.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Drupal\menu;
+
+use Drupal\system\SystemMenuBlock;
+
+/**
+ * @file
+ *   Menu module block for rendering custom menus from the menu_get_menus()
+ *   function.
+ */
+class MenuBlock extends SystemMenuBlock {
+
+  public function __construct() {
+    $this->menus = menu_get_menus(FALSE);
+    $this->derivatives = array();
+  }
+}
diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module
index 1f8bd3a..a3e3403 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -463,36 +463,6 @@ function menu_reset_item($link) {
 }
 
 /**
- * Implements hook_block_info().
- */
-function menu_block_info() {
-  $menus = menu_get_menus(FALSE);
-
-  $blocks = array();
-  foreach ($menus as $name => $title) {
-    $blocks[$name]['info'] = check_plain($title);
-    // Menu blocks can't be cached because each menu item can have
-    // a custom access callback. menu.inc manages its own caching.
-    $blocks[$name]['cache'] = DRUPAL_NO_CACHE;
-  }
-  return $blocks;
-}
-
-/**
- * Implements hook_block_view().
- */
-function menu_block_view($delta = '') {
-  $menus = menu_get_menus(FALSE);
-  $data['subject'] = check_plain($menus[$delta]);
-  $data['content'] = menu_tree($delta);
-  // Add contextual links for this block.
-  if (!empty($data['content'])) {
-    $data['content']['#contextual_links']['menu'] = array('admin/structure/menu/manage', array($delta));
-  }
-  return $data;
-}
-
-/**
  * Implements hook_block_view_alter().
  */
 function menu_block_view_alter(&$data, $block) {
@@ -797,7 +767,7 @@ function menu_get_menus($all = TRUE) {
  * Implements hook_preprocess_block().
  */
 function menu_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'menu') {
+  if ($variables['block']->plugin_id == 'menu') {
     $variables['attributes_array']['role'] = 'navigation';
   }
 }
diff --git a/core/modules/node/config/plugin.definition.core.block.noderecent.xml b/core/modules/node/config/plugin.definition.core.block.noderecent.xml
new file mode 100644
index 0000000..e46c85e
--- /dev/null
+++ b/core/modules/node/config/plugin.definition.core.block.noderecent.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<config>
+  <title>Recent Content</title>
+  <module>node</module>
+  <delta>recent</delta>
+  <block_class>Drupal\node\RecentBlock</block_class>
+  <settings>
+    <subject>Recent content</subject>
+    <region>sidebar_first</region>
+    <block_count>10</block_count>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/node/config/plugin.definition.core.block.nodesyndicate.xml b/core/modules/node/config/plugin.definition.core.block.nodesyndicate.xml
new file mode 100644
index 0000000..ca148a6
--- /dev/null
+++ b/core/modules/node/config/plugin.definition.core.block.nodesyndicate.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<config>
+  <title>Syndicate</title>
+  <module>node</module>
+  <delta>syndicate</delta>
+  <block_class>Drupal\node\SyndicateBlock</block_class>
+  <settings>
+    <subject>Syndicate</subject>
+    <region>footer</region>
+    <status>FALSE</status>
+  </settings>
+</config>
diff --git a/core/modules/node/lib/Drupal/node/RecentBlock.php b/core/modules/node/lib/Drupal/node/RecentBlock.php
new file mode 100644
index 0000000..7027b86
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/RecentBlock.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Drupal\node;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   Node module recent content block.
+ */
+class RecentBlock extends AbstractBlock {
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('Recent content'),
+    );
+  }
+
+  /**
+   * Implements AccessInterface::access().
+   */
+  public function access() {
+    return user_access('access content');
+  }
+
+  /**
+   * Implements BlockInterface::configure().
+   */
+  public function configure($form, &$form_state) {
+    $form = parent::configure($form, $form_state);
+    $form['block_count'] = array(
+      '#type' => 'select',
+      '#title' => t('Number of recent content items to display'),
+      '#default_value' => $this->config['settings']['block_count'],
+      '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 30)),
+    );
+    return $form;
+  }
+
+  /**
+   * Implements BlockInterface::configureSubmit().
+   */
+  public function configureSubmit($form, &$form_state) {
+    parent::configureSubmit($form, $form_state);
+    $this->config['settings']['block_count'] = $form_state['values']['block_count'];
+  }
+
+  /**
+   * Implements BlockInterface::build();
+   */
+  public function build() {
+    if ($nodes = node_get_recent($this->config['settings']['block_count'])) {
+      return array(
+        '#block' => $this->config,
+        '#theme' => 'node_recent_block',
+        '#nodes' => $nodes,
+      );
+    }
+    else {
+      return array(
+        '#block' => $this->config,
+        '#children' => t('No content available.'),
+      );
+    }
+  }
+}
diff --git a/core/modules/node/lib/Drupal/node/SyndicateBlock.php b/core/modules/node/lib/Drupal/node/SyndicateBlock.php
new file mode 100644
index 0000000..b982424
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/SyndicateBlock.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\node;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   Node module Syndicate block.
+ */
+class SyndicateBlock extends AbstractBlock {
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('Syndicate'),
+      'cache' => DRUPAL_NO_CACHE,
+    );
+  }
+
+  /**
+   * Implements AccessInterface::access().
+   */
+  public function access() {
+    return user_access('access content');
+  }
+
+  /**
+   * Implements BlockInterface::build();
+   */
+  public function build() {
+    return array(
+      '#block' => $this->config,
+      '#theme' => 'feed_icon',
+      '#url' => 'rss.xml',
+    );
+  }
+}
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index a59a5c7..3bc85d5 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -1494,15 +1494,13 @@ function node_is_page($node) {
  * Implements hook_preprocess_block().
  */
 function node_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'node') {
-    switch ($variables['block']->delta) {
-      case 'syndicate':
-        $variables['attributes_array']['role'] = 'complementary';
-        break;
-      case 'recent':
-        $variables['attributes_array']['role'] = 'navigation';
-        break;
-    }
+  switch ($variables['block']->plugin_id) {
+    case 'nodesyndicate':
+      $variables['attributes_array']['role'] = 'complementary';
+      break;
+    case 'noderecent':
+      $variables['attributes_array']['role'] = 'navigation';
+      break;
   }
 }
 
@@ -2245,78 +2243,6 @@ function node_revision_list($node) {
 }
 
 /**
- * Implements hook_block_info().
- */
-function node_block_info() {
-  $blocks['syndicate']['info'] = t('Syndicate');
-  // Not worth caching.
-  $blocks['syndicate']['cache'] = DRUPAL_NO_CACHE;
-
-  $blocks['recent']['info'] = t('Recent content');
-  $blocks['recent']['properties']['administrative'] = TRUE;
-
-  return $blocks;
-}
-
-/**
- * Implements hook_block_view().
- */
-function node_block_view($delta = '') {
-  $block = array();
-
-  switch ($delta) {
-    case 'syndicate':
-      $block['subject'] = t('Syndicate');
-      $block['content'] = array(
-        '#theme' => 'feed_icon',
-        '#url' => 'rss.xml',
-        '#title' => t('Syndicate'),
-      );
-      break;
-
-    case 'recent':
-      if (user_access('access content')) {
-        $block['subject'] = t('Recent content');
-        if ($nodes = node_get_recent(variable_get('node_recent_block_count', 10))) {
-          $block['content'] = array(
-            '#theme' => 'node_recent_block',
-            '#nodes' => $nodes,
-          );
-        } else {
-          $block['content'] = t('No content available.');
-        }
-      }
-      break;
-  }
-  return $block;
-}
-
-/**
- * Implements hook_block_configure().
- */
-function node_block_configure($delta = '') {
-  $form = array();
-  if ($delta == 'recent') {
-    $form['node_recent_block_count'] = array(
-      '#type' => 'select',
-      '#title' => t('Number of recent content items to display'),
-      '#default_value' => variable_get('node_recent_block_count', 10),
-      '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 30)),
-    );
-  }
-  return $form;
-}
-
-/**
- * Implements hook_block_save().
- */
-function node_block_save($delta = '', $edit = array()) {
-  if ($delta == 'recent') {
-    variable_set('node_recent_block_count', $edit['node_recent_block_count']);
-  }
-}
-
-/**
  * Finds the most recently changed nodes that are available to the current user.
  *
  * @param $number
@@ -2426,7 +2352,7 @@ function theme_node_recent_content($variables) {
  * Adds node-type specific visibility options to add block form.
  */
 function node_form_block_add_block_form_alter(&$form, &$form_state) {
-  node_form_block_admin_configure_alter($form, $form_state);
+  //node_form_block_admin_configure_alter($form, $form_state);
 }
 
 /**
@@ -2437,9 +2363,8 @@ function node_form_block_add_block_form_alter(&$form, &$form_state) {
  * @see node_form_block_admin_configure_submit()
  */
 function node_form_block_admin_configure_alter(&$form, &$form_state) {
-  $default_type_options = db_query("SELECT type FROM {block_node_type} WHERE module = :module AND delta = :delta", array(
+  $default_type_options = db_query("SELECT type FROM {block_node_type} WHERE module = :module", array(
     ':module' => $form['module']['#value'],
-    ':delta' => $form['delta']['#value'],
   ))->fetchCol();
   $form['visibility']['node_type'] = array(
     '#type' => 'fieldset',
@@ -2465,41 +2390,18 @@ function node_form_block_admin_configure_alter(&$form, &$form_state) {
 function node_form_block_admin_configure_submit($form, &$form_state) {
   db_delete('block_node_type')
     ->condition('module', $form_state['values']['module'])
-    ->condition('delta', $form_state['values']['delta'])
     ->execute();
-  $query = db_insert('block_node_type')->fields(array('type', 'module', 'delta'));
+  $query = db_insert('block_node_type')->fields(array('type', 'module'));
   foreach (array_filter($form_state['values']['types']) as $type) {
     $query->values(array(
       'type' => $type,
       'module' => $form_state['values']['module'],
-      'delta' => $form_state['values']['delta'],
     ));
   }
   $query->execute();
 }
 
 /**
- * Implements hook_form_FORM_ID_alter() for block_custom_block_delete().
- *
- * Adds node specific submit handler to delete custom block form.
- *
- * @see node_form_block_custom_block_delete_submit()
- */
-function node_form_block_custom_block_delete_alter(&$form, &$form_state) {
-  $form['#submit'][] = 'node_form_block_custom_block_delete_submit';
-}
-
-/**
- * Form submission handler for node_form_block_custom_block_delete_alter().
- */
-function node_form_block_custom_block_delete_submit($form, &$form_state) {
-  db_delete('block_node_type')
-    ->condition('module', 'block')
-    ->condition('delta', $form_state['values']['bid'])
-    ->execute();
-}
-
-/**
  * Implements hook_modules_uninstalled().
  *
  * Cleans up the {block_node_type} table from modules' blocks.
diff --git a/core/modules/search/config/plugin.definition.core.block.search.xml b/core/modules/search/config/plugin.definition.core.block.search.xml
new file mode 100644
index 0000000..365e6c6
--- /dev/null
+++ b/core/modules/search/config/plugin.definition.core.block.search.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<config>
+  <title>Search</title>
+  <module>search</module>
+  <delta>form</delta>
+  <block_class>Drupal\search\SearchBlock</block_class>
+  <settings>
+    <subject>Search</subject>
+    <region>sidebar_first</region>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/search/lib/Drupal/search/SearchBlock.php b/core/modules/search/lib/Drupal/search/SearchBlock.php
new file mode 100644
index 0000000..f704c05
--- /dev/null
+++ b/core/modules/search/lib/Drupal/search/SearchBlock.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\search;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   Search module's search form block.
+ */
+class SearchBlock extends AbstractBlock {
+
+  /**
+   * Implements AccessInterface::access().
+   */
+  public function access() {
+    return user_access('search content');
+  }
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('Search form'),
+      'cache' => DRUPAL_NO_CACHE,
+    );
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    return array(
+      '#block' => $this->config,
+      drupal_get_form('search_block_form'),
+    );
+  }
+}
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index 587ef43..39619a6 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -132,32 +132,10 @@ function search_permission() {
 }
 
 /**
- * Implements hook_block_info().
- */
-function search_block_info() {
-  $blocks['form']['info'] = t('Search form');
-  // Not worth caching.
-  $blocks['form']['cache'] = DRUPAL_NO_CACHE;
-  $blocks['form']['properties']['administrative'] = TRUE;
-  return $blocks;
-}
-
-/**
- * Implements hook_block_view().
- */
-function search_block_view($delta = '') {
-  if (user_access('search content')) {
-    $block['subject'] = t('Search');
-    $block['content'] = drupal_get_form('search_block_form');
-    return $block;
-  }
-}
-
-/**
  * Implements hook_preprocess_block().
  */
 function search_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'search' && $variables['block']->delta == 'form') {
+  if ($variables['block']->plugin_id == 'search') {
     $variables['attributes_array']['role'] = 'search';
     $variables['content_attributes_array']['class'][] = 'container-inline';
   }
diff --git a/core/modules/shortcut/config/plugin.definition.core.block.shortcutmenu.xml b/core/modules/shortcut/config/plugin.definition.core.block.shortcutmenu.xml
new file mode 100644
index 0000000..86db408
--- /dev/null
+++ b/core/modules/shortcut/config/plugin.definition.core.block.shortcutmenu.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<config>
+  <title>Shortcuts</title>
+  <module>shortcut</module>
+  <delta>shortcuts</delta>
+  <block_class>Drupal\shortcut\ShortcutsBlock</block_class>
+  <settings>
+    <subject>Shortcuts</subject>
+    <region>footer</region>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutsBlock.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutsBlock.php
new file mode 100644
index 0000000..dacb9d1
--- /dev/null
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutsBlock.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\shortcut;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   Shortcuts block.
+ */
+class ShortcutsBlock extends AbstractBlock {
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('Shortcuts'),
+      'cache' => DRUPAL_NO_CACHE,
+    );
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    $shortcut_set = shortcut_current_displayed_set();
+    return array(
+      '#block' => $this->config,
+      shortcut_renderable_links($shortcut_set),
+    );
+  }
+}
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index aa43503..1737baa 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -184,29 +184,6 @@ function shortcut_theme() {
 }
 
 /**
- * Implements hook_block_info().
- */
-function shortcut_block_info() {
-  $blocks['shortcuts']['info'] = t('Shortcuts');
-  // Shortcut blocks can't be cached because each menu item can have a custom
-  // access callback. menu.inc manages its own caching.
-  $blocks['shortcuts']['cache'] = DRUPAL_NO_CACHE;
-  return $blocks;
-}
-
-/**
- * Implements hook_block_view().
- */
-function shortcut_block_view($delta = '') {
-  if ($delta == 'shortcuts') {
-    $shortcut_set = shortcut_current_displayed_set();
-    $data['subject'] = t('@shortcut_set shortcuts', array('@shortcut_set' => $shortcut_set->title));
-    $data['content'] = shortcut_renderable_links($shortcut_set);
-    return $data;
-  }
-}
-
-/**
  * Access callback for editing a shortcut set.
  *
  * @param object $shortcut_set
@@ -643,7 +620,7 @@ function shortcut_renderable_links($shortcut_set = NULL) {
  * Implements hook_preprocess_block().
  */
 function shortcut_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'shortcut') {
+  if ($variables['block']->plugin_id == 'shortcutmenu') {
     $variables['attributes_array']['role'] = 'navigation';
   }
 }
diff --git a/core/modules/simpletest/tests/plugins.test b/core/modules/simpletest/tests/plugins.test
new file mode 100644
index 0000000..3f01dc0
--- /dev/null
+++ b/core/modules/simpletest/tests/plugins.test
@@ -0,0 +1,53 @@
+<?php
+
+use Drupal\Component\Plugin\Discovery\StaticDiscovery;
+use Drupal\Component\Plugin\PluginAbstract;
+
+class PluginBaseTestCase extends DrupalUnitTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Plugin wrapper',
+      'description' => 'Test that the plugin wrapper does the things is says it will.',
+      'group' => 'Plugin API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+    // We're a unit test using classes... don't let the db registry blow up.
+    spl_autoload_unregister('drupal_autoload_class');
+    spl_autoload_unregister('drupal_autoload_interface');
+
+    // Setup a plugin type to test.
+    $discovery = new StaticDiscovery();
+    // Initialize the plugin singleton with a discovery class for our test type.
+    plugin('simpletest', 'plugin', $discovery);
+
+    $discovery->setPluginTypeDefinition(array(
+      'class' => 'class',
+      'factory' => 'Drupal\\Component\\Plugin\\Factory\\DefaultFactory'
+    ));
+    $discovery->setPluginDefinition('coolaid', array(
+      'string' => 'oh yeah',
+      'class' => 'PluginBaseTestPluginClass',
+    ));
+  }
+
+  function testDefaultPluginMapper() {
+    $test_kernel = plugin('core', 'cache');
+    $this->assertEqual(get_class($test_kernel), 'Drupal\\Component\\Plugin\\Kernel\\PluginKernel', 'Correct kernel type returned in default case.');
+  }
+
+  function testPluginDefintionFetching() {
+    $plugin_definition = plugin('simpletest', 'plugin')->getPluginDefinition('coolaid');
+    $this->assertEqual($plugin_definition['string'], 'oh yeah', 'Plugin definition retrievable by the plugin kernel getPluginDefinition().');
+  }
+
+  function testPluginInstanceFetching() {
+    $plugin = plugin('simpletest', 'plugin')->getPluginInstance('coolaid');
+    $this->assertEqual(get_class($plugin), 'PluginBaseTestPluginClass', 'Correct plugin implementation returned by the plugin kernel getPluginInstance().');
+  }
+}
+
+class PluginBaseTestPluginClass extends PluginAbstract {
+}
diff --git a/core/modules/system/config/plugin.definition.core.block.systemhelp.xml b/core/modules/system/config/plugin.definition.core.block.systemhelp.xml
new file mode 100644
index 0000000..cbcdf5c
--- /dev/null
+++ b/core/modules/system/config/plugin.definition.core.block.systemhelp.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<config>
+  <title>Help</title>
+  <module>system</module>
+  <delta>help</delta>
+  <block_class>Drupal\system\SystemHelpBlock</block_class>
+  <settings>
+    <subject></subject>
+    <region>help</region>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/system/config/plugin.definition.core.block.systemmain.xml b/core/modules/system/config/plugin.definition.core.block.systemmain.xml
new file mode 100644
index 0000000..108019b
--- /dev/null
+++ b/core/modules/system/config/plugin.definition.core.block.systemmain.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<config>
+  <title>Main Content</title>
+  <module>system</module>
+  <delta>main</delta>
+  <block_class>Drupal\system\SystemMainBlock</block_class>
+  <settings>
+    <subject></subject>
+    <region>content</region>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/system/config/plugin.definition.core.block.systemmenu.xml b/core/modules/system/config/plugin.definition.core.block.systemmenu.xml
new file mode 100644
index 0000000..1af224b
--- /dev/null
+++ b/core/modules/system/config/plugin.definition.core.block.systemmenu.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<config>
+  <title>System Menu</title>
+  <module>system</module>
+  <block_class>Drupal\system\SystemMenuBlock</block_class>
+  <derivatives>TRUE</derivatives>
+  <settings>
+    <subject>System Menu</subject>
+    <region>sidebar_second</region>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/system/config/plugin.definition.core.block.systempoweredby.xml b/core/modules/system/config/plugin.definition.core.block.systempoweredby.xml
new file mode 100644
index 0000000..2d9eba7
--- /dev/null
+++ b/core/modules/system/config/plugin.definition.core.block.systempoweredby.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<config>
+  <title>Powered by Drupal</title>
+  <module>system</module>
+  <delta>poweredby</delta>
+  <block_class>Drupal\system\SystemPoweredByBlock</block_class>
+  <settings>
+    <subject></subject>
+    <region>footer</region>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/system/lib/Drupal/system/SystemHelpBlock.php b/core/modules/system/lib/Drupal/system/SystemHelpBlock.php
new file mode 100644
index 0000000..80a5264
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/SystemHelpBlock.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Drupal\system;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   System module block for rendering the help for a page.
+ */
+class SystemHelpBlock extends AbstractBlock {
+  private $help;
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('System help'),
+      'cache' => DRUPAL_NO_CACHE,
+    );
+  }
+
+  /**
+   * Implements AccessInterface::access().
+   */
+  public function access() {
+    $this->help = menu_get_active_help();
+    return $this->help ? TRUE : FALSE;
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    return array(
+      '#block' => $this->config,
+      '#children' => $this->help,
+    );
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/SystemMainBlock.php b/core/modules/system/lib/Drupal/system/SystemMainBlock.php
new file mode 100644
index 0000000..e0ef1d3
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/SystemMainBlock.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\system;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   System module block for rendering the main content for a page.
+ */
+class SystemMainBlock extends AbstractBlock {
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('Main page content'),
+      // Cached elsewhere.
+      'cache' => DRUPAL_NO_CACHE,
+    );
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    return array(
+      '#block' => $this->config,
+      drupal_set_page_content(),
+    );
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/SystemMenuBlock.php b/core/modules/system/lib/Drupal/system/SystemMenuBlock.php
new file mode 100644
index 0000000..edf4613
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/SystemMenuBlock.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Drupal\system;
+
+use Drupal\Component\Plugin\Derivative\DerivativeInterface;
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   System module block for rendering system menus from the
+ *   menu_list_system_menus() funtion.
+ */
+class SystemMenuBlock extends AbstractBlock implements DerivativeInterface {
+  protected $derivatives;
+  protected $derivative;
+  protected $menus;
+
+  public function __construct() {
+    $this->menus = menu_list_system_menus();
+    $this->derivatives = array();
+  }
+
+  /**
+   * Implements AccessInterface::access().
+   */
+  public function access() {
+    global $user;
+    if (!$user->uid) {
+      return FALSE;
+    }
+    return parent::access();
+  }
+
+  /**
+   * Implements PluginChildrenInterface::getChild().
+   */
+  public function getDerivative($derivative) {
+    $this->derivative = $derivative;
+    if (!isset($this->derivative[$derivative])) {
+      $this->getDerivatives();
+    }
+    if(isset($this->derivatives[$derivative])) {
+      $this->config = $this->derivatives[$derivative];
+      return $this->derivatives[$derivative];
+    }
+    return array();
+  }
+
+  /**
+   * Implements PluginChildrenInterface::getChildren().
+   */
+  public function getDerivatives() {
+    foreach ($this->menus as $menu => $name) {
+      $this->derivatives[$menu] = $this->config;
+      $this->derivatives[$menu]['delta'] = $menu;
+      $this->derivatives[$menu]['subject'] = $name;
+    }
+    return $this->derivatives;
+  }
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('System Menu: @menu', array('@menu' => $this->menus[$this->getConfigValue('derivative')])),
+      'cache' => DRUPAL_NO_CACHE,
+    );
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    return array(
+      '#block' => $this->config,
+      menu_tree($this->derivative),
+    );
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/SystemPoweredByBlock.php b/core/modules/system/lib/Drupal/system/SystemPoweredByBlock.php
new file mode 100644
index 0000000..e4b0b7d
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/SystemPoweredByBlock.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\system;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   System module block for rendering a powered-by Drupal link.
+ */
+class SystemPoweredByBlock extends AbstractBlock {
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('Powered by Drupal'),
+      'cache' => DRUPAL_NO_CACHE,
+    );
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    return array(
+      '#block' => $this->config,
+      '#children' => theme('system_powered_by'),
+    );
+  }
+}
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index a3594b9..c2d8f9e 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2128,23 +2128,17 @@ function system_block_view($delta = '') {
  * Implements hook_preprocess_block().
  */
 function system_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'system') {
-
-    switch ($variables['block']->delta) {
-      case 'powered-by':
-        $variables['attributes_array']['role'] = 'complementary';
-        break;
-      case 'help':
-        $variables['attributes_array']['role'] = 'complementary';
-        break;
-
-      // System menu blocks should get the same class as menu module blocks.
-      default:
-        if (in_array($variables['block']->delta, array_keys(menu_list_system_menus()))) {
-          $variables['attributes_array']['role'] = 'navigation';
-          $variables['classes_array'][] = 'block-menu';
-        }
-    }
+  switch ($variables['block']->plugin_id) {
+    case 'systempoweredby':
+      $variables['attributes_array']['role'] = 'complementary';
+      break;
+    case 'systemhelp':
+      $variables['attributes_array']['role'] = 'complementary';
+      break;
+    case 'systemmenu':
+      $variables['attributes_array']['role'] = 'navigation';
+      $variables['classes_array'][] = 'block-menu';
+      break;
   }
 }
 
diff --git a/core/modules/user/config/plugin.definition.core.block.userlogin.xml b/core/modules/user/config/plugin.definition.core.block.userlogin.xml
new file mode 100644
index 0000000..1f0c881
--- /dev/null
+++ b/core/modules/user/config/plugin.definition.core.block.userlogin.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<config>
+  <title>User login</title>
+  <module>user</module>
+  <delta>login</delta>
+  <block_class>Drupal\user\UserLoginBlock</block_class>
+  <settings>
+    <subject>User login</subject>
+    <region>sidebar_first</region>
+    <status>TRUE</status>
+  </settings>
+</config>
diff --git a/core/modules/user/config/plugin.definition.core.block.usernew.xml b/core/modules/user/config/plugin.definition.core.block.usernew.xml
new file mode 100644
index 0000000..cdac006
--- /dev/null
+++ b/core/modules/user/config/plugin.definition.core.block.usernew.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<config>
+  <title>Who's new</title>
+  <module>user</module>
+  <delta>new</delta>
+  <block_class>Drupal\user\UserNewBlock</block_class>
+  <settings>
+    <subject>Who's new</subject>
+    <region>sidebar_second</region>
+    <status>TRUE</status>
+    <whois_new_count>5</whois_new_count>
+  </settings>
+</config>
diff --git a/core/modules/user/config/plugin.definition.core.block.useronline.xml b/core/modules/user/config/plugin.definition.core.block.useronline.xml
new file mode 100644
index 0000000..df3f675
--- /dev/null
+++ b/core/modules/user/config/plugin.definition.core.block.useronline.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<config>
+  <title>Who's Online</title>
+  <module>user</module>
+  <delta>online</delta>
+  <block_class>Drupal\user\UserOnlineBlock</block_class>
+  <settings>
+    <subject>Who's Online</subject>
+    <region>sidebar_second</region>
+    <status>TRUE</status>
+    <seconds_online>900</seconds_online>
+    <max_list_count>5</max_list_count>
+  </settings>
+</config>
diff --git a/core/modules/user/lib/Drupal/user/UserLoginBlock.php b/core/modules/user/lib/Drupal/user/UserLoginBlock.php
new file mode 100644
index 0000000..e73d806
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserLoginBlock.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Drupal\user;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   System module block for rendering the help for a page.
+ */
+class UserLoginBlock extends AbstractBlock {
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('User login'),
+      'cache' => DRUPAL_NO_CACHE,
+    );
+  }
+
+  /**
+   * Implements AccessInterface::access().
+   */
+  public function access() {
+    global $user;
+    return (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1))));
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    return array(
+      '#block' => $this->config,
+      drupal_get_form('user_login_block'),
+    );
+  }
+}
diff --git a/core/modules/user/lib/Drupal/user/UserNewBlock.php b/core/modules/user/lib/Drupal/user/UserNewBlock.php
new file mode 100644
index 0000000..91c3c9a
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserNewBlock.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Drupal\user;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   System module block for rendering the help for a page.
+ */
+class UserNewBlock extends AbstractBlock {
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('Who\'s new'),
+      'properties' => array(
+        'administrative' => TRUE,
+      ),
+    );
+  }
+
+  /**
+   * Implements AccessInterface::access().
+   */
+  public function access() {
+    return user_access('access content');
+  }
+
+  /**
+   * Implements BlockInterface::configure().
+   */
+  public function configure($form, &$form_state) {
+    $form = parent::configure($form, $form_state);
+    $form['user_block_whois_new_count'] = array(
+      '#type' => 'select',
+      '#title' => t('Number of users to display'),
+      '#default_value' => $this->config['whois_new_count'],
+      '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
+    );
+    return $form;
+  }
+
+  /**
+   * Implements BlockInterface::configureSubmit().
+   */
+  public function configureSubmit($form, &$form_state) {
+    parent::configureSubmit($form, $form_state);
+    $this->config['whois_new_count'] = $form_state['values']['user_block_whois_new_count'];
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    // Retrieve a list of new users who have subsequently accessed the site successfully.
+    $items = db_query_range('SELECT uid, name FROM {users} WHERE status <> 0 AND access <> 0 ORDER BY created DESC', 0, $this->config['whois_new_count'])->fetchAll();
+    return array(
+      '#block' => $this->config,
+      '#children' => theme('user_list', array('users' => $items)),
+    );
+  }
+}
diff --git a/core/modules/user/lib/Drupal/user/UserOnlineBlock.php b/core/modules/user/lib/Drupal/user/UserOnlineBlock.php
new file mode 100644
index 0000000..051862a
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserOnlineBlock.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Drupal\user;
+
+use Drupal\block\AbstractBlock;
+
+/**
+ * @file
+ *   System module block for rendering the help for a page.
+ */
+class UserOnlineBlock extends AbstractBlock {
+
+  /**
+   * Implements BlockInterface::info().
+   */
+  public function info() {
+    return array(
+      'info' => t('Who\'s online'),
+      'cache' => DRUPAL_NO_CACHE,
+      'properties' => array(
+        'administrative' => TRUE,
+      ),
+    );
+  }
+
+  /**
+   * Implements BlockInterface::access().
+   */
+  public function access() {
+    return user_access('access content');
+  }
+
+  /**
+   * Implements BlockInterface::configure().
+   */
+  public function configure($form, &$form_state) {
+    $form = parent::configure($form, $form_state);
+    $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval');
+    $form['user_block_seconds_online'] = array(
+      '#type' => 'select',
+      '#title' => t('User activity'),
+      '#default_value' => $this->config['seconds_online'],
+      '#options' => $period,
+      '#description' => t('A user is considered online for this long after they have last viewed a page.')
+    );
+    $form['user_block_max_list_count'] = array(
+      '#type' => 'select',
+      '#title' => t('User list length'),
+      '#default_value' => $this->config['max_list_count'],
+      '#options' => drupal_map_assoc(array(0, 5, 10, 15, 20, 25, 30, 40, 50, 75, 100)),
+      '#description' => t('Maximum number of currently online users to display.')
+    );
+    return $form;
+  }
+
+  /**
+   * Implements BlockInterface::configureSubmit().
+   */
+  public function configureSubmit($form, &$form_state) {
+    parent::configureSubmit($form, &$form_state);
+    $this->config['seconds_online'] = $form_state['values']['user_block_seconds_online'];
+    $this->config['max_list_count'] = $form_state['values']['user_block_max_list_count'];
+  }
+
+  /**
+   * Implements BlockInterface::build().
+   */
+  public function build() {
+    // Count users active within the defined period.
+    $interval = REQUEST_TIME - $this->config['max_list_count'];
+
+    // Perform database queries to gather online user lists. We use s.timestamp
+    // rather than u.access because it is much faster.
+    $authenticated_count = db_query("SELECT COUNT(DISTINCT s.uid) FROM {sessions} s WHERE s.timestamp >= :timestamp AND s.uid > 0", array(':timestamp' => $interval))->fetchField();
+
+    $output = '<p>' . format_plural($authenticated_count, 'There is currently 1 user online.', 'There are currently @count users online.') . '</p>';
+
+    // Display a list of currently online users.
+    $max_users = $this->config['max_list_count'];
+    if ($authenticated_count && $max_users) {
+      $items = db_query_range('SELECT u.uid, u.name, MAX(s.timestamp) AS max_timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= :interval AND s.uid > 0 GROUP BY u.uid, u.name ORDER BY max_timestamp DESC', 0, $max_users, array(':interval' => $interval))->fetchAll();
+      $output .= theme('user_list', array('users' => $items));
+    }
+
+    return array(
+      '#block' => $this->config,
+      '#children' => $output,
+    );
+  }
+}
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 3b1d9cb..f08cc3e 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1216,138 +1216,19 @@ function user_login_block($form) {
 }
 
 /**
- * Implements hook_block_info().
- */
-function user_block_info() {
-  global $user;
-
-  $blocks['login']['info'] = t('User login');
-  // Not worth caching.
-  $blocks['login']['cache'] = DRUPAL_NO_CACHE;
-
-  $blocks['new']['info'] = t('Who\'s new');
-  $blocks['new']['properties']['administrative'] = TRUE;
-
-  // Too dynamic to cache.
-  $blocks['online']['info'] = t('Who\'s online');
-  $blocks['online']['cache'] = DRUPAL_NO_CACHE;
-  $blocks['online']['properties']['administrative'] = TRUE;
-
-  return $blocks;
-}
-
-/**
- * Implements hook_block_configure().
- */
-function user_block_configure($delta = '') {
-  global $user;
-
-  switch ($delta) {
-    case 'new':
-      $form['user_block_whois_new_count'] = array(
-        '#type' => 'select',
-        '#title' => t('Number of users to display'),
-        '#default_value' => variable_get('user_block_whois_new_count', 5),
-        '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
-      );
-      return $form;
-
-    case 'online':
-      $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval');
-      $form['user_block_seconds_online'] = array('#type' => 'select', '#title' => t('User activity'), '#default_value' => variable_get('user_block_seconds_online', 900), '#options' => $period, '#description' => t('A user is considered online for this long after they have last viewed a page.'));
-      $form['user_block_max_list_count'] = array('#type' => 'select', '#title' => t('User list length'), '#default_value' => variable_get('user_block_max_list_count', 10), '#options' => drupal_map_assoc(array(0, 5, 10, 15, 20, 25, 30, 40, 50, 75, 100)), '#description' => t('Maximum number of currently online users to display.'));
-      return $form;
-  }
-}
-
-/**
- * Implements hook_block_save().
- */
-function user_block_save($delta = '', $edit = array()) {
-  global $user;
-
-  switch ($delta) {
-    case 'new':
-      variable_set('user_block_whois_new_count', $edit['user_block_whois_new_count']);
-      break;
-
-    case 'online':
-      variable_set('user_block_seconds_online', $edit['user_block_seconds_online']);
-      variable_set('user_block_max_list_count', $edit['user_block_max_list_count']);
-      break;
-  }
-}
-
-/**
- * Implements hook_block_view().
- */
-function user_block_view($delta = '') {
-  global $user;
-
-  $block = array();
-
-  switch ($delta) {
-    case 'login':
-      // For usability's sake, avoid showing two login forms on one page.
-      if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) {
-
-        $block['subject'] = t('User login');
-        $block['content'] = drupal_get_form('user_login_block');
-      }
-      return $block;
-
-    case 'new':
-      if (user_access('access content')) {
-        // Retrieve a list of new users who have subsequently accessed the site successfully.
-        $items = db_query_range('SELECT uid, name FROM {users} WHERE status <> 0 AND access <> 0 ORDER BY created DESC', 0, variable_get('user_block_whois_new_count', 5))->fetchAll();
-        $output = theme('user_list', array('users' => $items));
-
-        $block['subject'] = t('Who\'s new');
-        $block['content'] = $output;
-      }
-      return $block;
-
-    case 'online':
-      if (user_access('access content')) {
-        // Count users active within the defined period.
-        $interval = REQUEST_TIME - variable_get('user_block_seconds_online', 900);
-
-        // Perform database queries to gather online user lists. We use s.timestamp
-        // rather than u.access because it is much faster.
-        $authenticated_count = db_query("SELECT COUNT(DISTINCT s.uid) FROM {sessions} s WHERE s.timestamp >= :timestamp AND s.uid > 0", array(':timestamp' => $interval))->fetchField();
-
-        $output = '<p>' . format_plural($authenticated_count, 'There is currently 1 user online.', 'There are currently @count users online.') . '</p>';
-
-        // Display a list of currently online users.
-        $max_users = variable_get('user_block_max_list_count', 10);
-        if ($authenticated_count && $max_users) {
-          $items = db_query_range('SELECT u.uid, u.name, MAX(s.timestamp) AS max_timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= :interval AND s.uid > 0 GROUP BY u.uid, u.name ORDER BY max_timestamp DESC', 0, $max_users, array(':interval' => $interval))->fetchAll();
-          $output .= theme('user_list', array('users' => $items));
-        }
-
-        $block['subject'] = t('Who\'s online');
-        $block['content'] = $output;
-      }
-      return $block;
-  }
-}
-
-/**
  * Implements hook_preprocess_block().
  */
 function user_preprocess_block(&$variables) {
-  if ($variables['block']->module == 'user') {
-    switch ($variables['block']->delta) {
-      case 'login':
-        $variables['attributes_array']['role'] = 'form';
-        break;
-      case 'new':
-        $variables['attributes_array']['role'] = 'complementary';
-        break;
-      case 'online':
-        $variables['attributes_array']['role'] = 'complementary';
-        break;
-    }
+  switch ($variables['block']->plugin_id) {
+    case 'userlogin':
+      $variables['attributes_array']['role'] = 'form';
+      break;
+    case 'usernew':
+      $variables['attributes_array']['role'] = 'complementary';
+      break;
+    case 'useronline':
+      $variables['attributes_array']['role'] = 'complementary';
+      break;
   }
 }
 
diff --git a/index.php b/index.php
index b91fb1e..6b15630 100644
--- a/index.php
+++ b/index.php
@@ -18,4 +18,7 @@ define('DRUPAL_ROOT', getcwd());
 
 require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+//foreach (module_list() as $module) {
+//config_install_default_config($module);
+//}
 menu_execute_active_handler();
