diff --git a/block_example/block_example.info.yml b/block_example/block_example.info.yml
new file mode 100644
index 0000000..c25900a
--- /dev/null
+++ b/block_example/block_example.info.yml
@@ -0,0 +1,7 @@
+name: Block Example
+type: module
+description: An example outlining how a module can define blocks.
+package: Example modules
+core: 8.x
+dependencies:
+  - block
diff --git a/block_example/block_example.module b/block_example/block_example.module
new file mode 100644
index 0000000..d512d2f
--- /dev/null
+++ b/block_example/block_example.module
@@ -0,0 +1,73 @@
+<?php
+/**
+ * @file
+ * Module file for block_example.
+ */
+
+/**
+ * @defgroup block_example Example: Block
+ * @ingroup examples
+ * @{
+ * Demonstrates code creation of blocks.
+ *
+ * This is an example outlining how a module can define blocks that can be
+ * displayed on various pages of a site, or how to alter blocks provided by
+ * other modules.
+ */
+
+/**
+ * Implements hook_menu().
+ *
+ * Provides a default page to explain what this module does.
+ */
+function block_example_menu() {
+  $items['examples/block_example'] = array(
+    'page callback' => 'block_example_page',
+    'access callback' => TRUE,
+    'title' => 'Block Example',
+  );
+  return $items;
+}
+
+/**
+ * Simple page function to explain what the block example is about.
+ */
+function block_example_page() {
+  $page = array(
+    '#markup' => t('The Block Example provides two sample blocks which demonstrate the various block APIs. To experiment with the blocks, enable and configure them on <a href="@url">the block admin page</a>.', array('@url' => url('admin/structure/block'))),
+  );
+  return $page;
+}
+
+/**
+ * Implements hook_block_view_alter().
+ *
+ * This hook allows you to modify the output of any block in the system.
+ *
+ * In addition, instead of hook_block_view_alter(), which is called for all
+ * blocks, you can also use hook_block_view_MODULE_DELTA_alter() to alter a
+ * specific block. To change only our block using
+ * hook_block_view_MODULE_DELTA_alter, we would use the function:
+ * block_example_block_view_block_example_example_configurable_text_alter()
+ *
+ * We are going to uppercase the subject (the title of the block as shown to the
+ * user) of any block if the string "uppercase" appears in the block title or
+ * subject. Default block titles are set programmatically in the subject key;
+ * titles created through the UI are saved in the title key. This module creates
+ * an example block to demonstrate this effect (default title set
+ * programmatically as subject).  You can also demonstrate the effect of this
+ * hook by creating a new block whose title has the string 'uppercase' in it
+ * (set as title through the UI).
+ */
+function block_example_block_view_alter(array &$build, \Drupal\block\BlockPluginInterface $block) {
+  // We'll search for the string 'uppercase'.
+  $definition = $block->getDefinition();
+  if ((!empty($build['#configuration']['label']) && stristr($build['#configuration']['label'], 'uppercase')) || (!empty($definition['subject']) && stristr($definition['subject'], 'uppercase'))) {
+    // This will uppercase the block title.
+    $build['#configuration']['label'] = drupal_strtoupper($build['#configuration']['label']);
+  }
+}
+
+/**
+ * @} End of "defgroup block_example".
+ */
diff --git a/block_example/lib/Drupal/block_example/Plugin/Block/ExampleConfigurableTextBlock.php b/block_example/lib/Drupal/block_example/Plugin/Block/ExampleConfigurableTextBlock.php
new file mode 100644
index 0000000..bf9f9a5
--- /dev/null
+++ b/block_example/lib/Drupal/block_example/Plugin/Block/ExampleConfigurableTextBlock.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_example\Plugin\Block\ExampleConfigurableTextBlock.
+ */
+
+namespace Drupal\block_example\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Provides a 'Example: configurable text string' block.
+ *
+ * @Plugin(
+ *   id = "example_configurable_text",
+ *   subject = @Translation("Title of first block (example_configurable_text)"),
+ *   admin_label = @Translation("Title of first block (example_configurable_text)"),
+ *   module = "block_example"
+ * )
+ */
+class ExampleConfigurableTextBlock extends BlockBase {
+
+  /**
+   * Overrides \Drupal\block\BlockBase::settings().
+   */
+  public function settings() {
+    return array(
+      'block_example_string' => t('A default value. This block was created at %time', array('%time' => date('c'))),
+      'cache' => DRUPAL_CACHE_PER_ROLE,
+    );
+  }
+
+  /**
+   * Overrides \Drupal\block\BlockBase::blockForm().
+   */
+  public function blockForm($form, &$form_state) {
+    $form['block_example_string_text'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Block contents'),
+      '#size' => 60,
+      '#description' => t('This text will appear in the example block.'),
+      '#default_value' => $this->configuration['block_example_string'],
+    );
+    return $form;
+  }
+
+  /**
+   * Overrides \Drupal\block\BlockBase::blockSubmit().
+   */
+  public function blockSubmit($form, &$form_state) {
+    $this->configuration['block_example_string'] = $form_state['values']['block_example_string_text'];
+  }
+
+  /**
+   * Implements \Drupal\block\BlockBase::blockBuild().
+   */
+  public function blockBuild() {
+    return array(
+      '#type' => 'markup',
+      '#markup' => $this->configuration['block_example_string'],
+    );
+  }
+
+}
diff --git a/block_example/lib/Drupal/block_example/Plugin/Block/ExampleEmptyBlock.php b/block_example/lib/Drupal/block_example/Plugin/Block/ExampleEmptyBlock.php
new file mode 100644
index 0000000..36fcdd9
--- /dev/null
+++ b/block_example/lib/Drupal/block_example/Plugin/Block/ExampleEmptyBlock.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_example\Plugin\Block\ExampleEmptyBlock.
+ */
+
+namespace Drupal\block_example\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Provides a 'Example: empty block' block.
+ *
+ * @Plugin(
+ *   id = "example_empty",
+ *   subject = @Translation("Example: empty block"),
+ *   admin_label = @Translation("Example: empty block"),
+ *   module = "block_example"
+ * )
+ */
+class ExampleEmptyBlock extends BlockBase {
+
+  /**
+   * Implements \Drupal\block\BlockBase::blockBuild().
+   */
+  public function blockBuild() {
+    return array();
+  }
+
+}
diff --git a/block_example/lib/Drupal/block_example/Plugin/Block/ExampleUppercaseBlock.php b/block_example/lib/Drupal/block_example/Plugin/Block/ExampleUppercaseBlock.php
new file mode 100644
index 0000000..8874c96
--- /dev/null
+++ b/block_example/lib/Drupal/block_example/Plugin/Block/ExampleUppercaseBlock.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_example\Plugin\Block\ExampleUppercaseBlock.
+ */
+
+namespace Drupal\block_example\Plugin\Block;
+
+use Drupal\block\BlockBase;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Provides a 'Example: uppercase this please' block.
+ *
+ * @Plugin(
+ *   id = "example_uppercase",
+ *   subject = @Translation("uppercase this please"),
+ *   admin_label = @Translation("Example: uppercase this please"),
+ *   module = "block_example"
+ * )
+ */
+class ExampleUppercaseBlock extends BlockBase {
+
+  /**
+   * Implements \Drupal\block\BlockBase::blockBuild().
+   */
+  public function blockBuild() {
+    return array(
+      '#type' => 'markup',
+      '#markup' => t("This block's title will be changed to uppercase. Any other block with 'uppercase' in the subject or title will also be altered. If you change this block's title through the UI to omit the word 'uppercase', it will still be altered to uppercase as the subject key has not been changed."),
+    );
+  }
+
+}
diff --git a/block_example/lib/Drupal/block_example/Tests/BlockExampleTest.php b/block_example/lib/Drupal/block_example/Tests/BlockExampleTest.php
new file mode 100644
index 0000000..25d533b
--- /dev/null
+++ b/block_example/lib/Drupal/block_example/Tests/BlockExampleTest.php
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\block_example\Tests\BlockExampleTest.
+ */
+
+namespace Drupal\block_example\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+class BlockExampleTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('block', 'search', 'block_example');
+
+  protected $web_user;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Block example functionality',
+      'description' => 'Test the configuration options and block created by Block Example module.',
+      'group' => 'Examples',
+    );
+  }
+
+  /**
+   * Enable modules and create user with specific permissions.
+   */
+  function setUp() {
+    parent::setUp();
+    // Create user. Search content permission granted for the search block to
+    // be shown.
+    $this->web_user = $this->drupalCreateUser(array('administer blocks', 'search content'));
+  }
+
+  /**
+   * Login user, create an example node, and test block functionality through
+   * the admin and user interfaces.
+   */
+  function testBlockExampleBasic() {
+    // Login the admin user.
+    $this->drupalLogin($this->web_user);
+    $theme_name = config('system.theme')->get('default');
+
+    // Find the blocks in the settings page.
+    $this->drupalGet('admin/structure/block/list/block_plugin_ui:' . $theme_name . '/add');
+    $this->assertRaw(t('Title of first block (example_configurable_text)'), 'Block configurable-string found.');
+    $this->assertRaw(t('Example: empty block'), 'Block empty-block found.');
+
+    // Add blocks
+    // Create a new block and make sure it gets uppercased.
+    $edit = array(
+      'settings[label]' => t('Title of first block (example_configurable_text)'),
+      'machine_name' => 'block_example_example_configurable_text',
+      'region' => 'sidebar_first',
+    );
+    $this->drupalPost('admin/structure/block/add/example_configurable_text/' . $theme_name , $edit, t('Save block'));
+    $this->assertText(t('The block configuration has been saved.'));
+    $this->assertText($edit['settings[label]']);
+
+    $this->drupalGet('admin/structure/block');
+    $this->assertLinkByHref(url('admin/structure/block/manage/' . $theme_name . '.block_example_example_configurable_text/configure'));
+
+    $edit = array(
+      'settings[label]' => t('Configurable block to be uppercased'),
+      'machine_name' => 'uppercased_block',
+      'region' => 'sidebar_first',
+    );
+    $this->drupalPost('admin/structure/block/add/example_uppercase/' . $theme_name, $edit, t('Save block'));
+
+    $edit = array(
+      'settings[label]' => t('Example: empty block'),
+      'machine_name' => 'block_example_example_empty',
+      'region' => 'sidebar_first',
+    );
+    $this->drupalPost('admin/structure/block/add/example_empty/' . $theme_name, $edit, t('Save block'));
+
+    // Verify that blocks are not shown
+    $this->drupalGet('/');
+    $this->assertRaw(t('Title of first block (example_configurable_text)'), 'Block configurable test not found.');
+    $this->assertNoRaw(t('Title of second block (example_empty)'), 'Block empty not found.');
+
+    // Verify that blocks are there. Empty block will not be shown, because it is empty
+    $this->drupalGet('/');
+    $this->assertRaw(t('Title of first block (example_configurable_text)'), 'Block configurable text found.');
+
+    // Change content of configurable text block
+    $edit = array(
+      'settings[block_example_string_text]' => $this->randomName(),
+    );
+    $this->drupalPost('admin/structure/block/manage/' . $theme_name . '.block_example_example_configurable_text/configure', $edit, t('Save block'));
+
+    // Verify that new content is shown
+    $this->drupalGet('/');
+    $this->assertRaw($edit['settings[block_example_string_text]'], 'Content of configurable text block successfully verified.');
+  }
+
+}
