diff --git a/core/modules/block/block.module b/core/modules/block/block.module index 31ef8db..84f0d83 100644 --- a/core/modules/block/block.module +++ b/core/modules/block/block.module @@ -5,6 +5,8 @@ * Controls the visual building blocks a page is constructed with. */ +use Drupal\Component\Plugin\Exception\PluginException; + /** * Denotes that a block is not enabled in any region and should not be shown. */ @@ -361,7 +363,11 @@ function _block_rehash($theme = NULL) { $block_configs = config_get_storage_names_with_prefix('plugin.core.block.' . $theme); $regions = system_region_list($theme); foreach ($block_configs as $config) { - $blocks[$config] = block_load($config); + // Only list valid block instances. + if (!$block = block_load($config)) { + continue; + } + $blocks[$config] = $block; $config = config($config); $region = $config->get('region'); $status = $config->get('status'); @@ -472,11 +478,25 @@ function block_list($region) { * * @return * A block object. + * + * @todo Add block_load_multiple() and make this function a single-value wrapper. */ function block_load($plugin_id, array $conf = array()) { $manager = drupal_container()->get('plugin.manager.block'); if (!$block = $manager->getInstance(array('config' => $plugin_id))) { - $block = $manager->createInstance($plugin_id, $conf); + // If the block instance does not exist, try to create it. + try { + $block = $manager->createInstance($plugin_id, $conf); + } + catch (PluginException $e) { + $config = config($plugin_id)->get(); + // Ignore blocks belonging to disabled modules, but re-throw valid + // exceptions when the module is enabled and the plugin is misconfigured. + if (empty($config['module']) || module_exists($config['module'])) { + throw $e; + } + return FALSE; + } } return $block; } @@ -486,6 +506,8 @@ function block_load($plugin_id, array $conf = array()) { * * @return * An array of blocks grouped by region. + * + * @todo Remove this function, and replace it with a block_load_multiple(). */ function _block_load_blocks() { global $theme; @@ -493,9 +515,18 @@ function _block_load_blocks() { $instances = config_get_storage_names_with_prefix('plugin.core.block.' . $theme); $manager = drupal_container()->get('plugin.manager.block'); foreach ($instances as $plugin_id) { - $block = $manager->getInstance(array('config' => $plugin_id)); - $config = $block->getConfig(); - $blocks[$config['region']]["$plugin_id"] = $block; + if ($block = $manager->getInstance(array('config' => $plugin_id))) { + $config = $block->getConfig(); + $blocks[$config['region']]["$plugin_id"] = $block; + } + else { + $config = config($plugin_id)->get(); + // Ignore blocks belonging to disabled modules, but re-throw valid + // exceptions when the module is enabled and the plugin is misconfigured. + if (empty($config['module']) || module_exists($config['module'])) { + throw new PluginException(format_string('The plugin @name was not found.', array('@name' => $plugin_id))); + } + } } return $blocks; } diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php index 6a3dd0c..88df26d 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php @@ -379,4 +379,74 @@ function testBlockRehash() { $config = $instance->getConfig(); $this->assertEqual($config['cache'], DRUPAL_NO_CACHE, "Test block's database entry updated to DRUPAL_NO_CACHE."); } + + /** + * Tests blocks belonging to disabled modules. + */ + function testBlockModuleDisable() { + module_enable(array('block_test')); + $this->assertTrue(module_exists('block_test'), 'Test block module enabled.'); + + // Clear the block cache to load the block_test module's block definitions. + $manager = $this->container->get('plugin.manager.block'); + $manager->clearCachedDefinitions(); + + // Add a test block. + $plugin = $manager->getDefinition('test_cache'); + $block = array(); + $block['id'] = 'test_cache'; + $block['machine_name'] = $this->randomName(8); + $block['theme'] = variable_get('theme_default', 'stark'); + $block['region'] = 'header'; + $this->drupalPost('admin/structure/block/manage/' . $block['id'] . '/' . $block['theme'], array('machine_name' => $block['machine_name'], 'region' => $block['region']), t('Save block')); + + // Confirm that the block is displayed on the front page. + $this->drupalGet(''); + $this->assertText('Test block caching'); + + // Disable the block test module and refresh the definitions cache. + module_disable(array('block_test'), FALSE); + $manager->clearCachedDefinitions(); + + // Ensure that the block administration page still functions as expected. + $this->drupalGet('admin/structure/block'); + $this->assertResponse(200); + // A 200 response is possible with a fatal error, so check the title too. + $this->assertTitle(t('Blocks | Drupal')); + + // Ensure that the disabled module's block instance is not listed. + $this->assertNoText(t('Test block caching')); + + // Ensure that the disabled module's block plugin is no longer available. + $this->drupalGet('admin/structure/block/list/block_plugin_ui:' . variable_get('theme_default', 'stark') . '/add'); + $this->assertNoText(t('Test block caching')); + + // Confirm that the block is no longer displayed on the front page. + $this->drupalGet(''); + $this->assertResponse(200); + $this->assertNoText('Test block caching'); + + // Confirm that a different block instance can still be enabled. + $block_id = 'system_powered_by_block'; + $edit = array( + 'title' => $this->randomName(8), + 'machine_name' => $this->randomName(8), + 'region' => 'sidebar_first', + ); + $this->drupalPost('admin/structure/block/manage/' . $block_id . '/stark', $edit, t('Save block')); + $this->assertText(t('The block configuration has been saved.')); + + // Re-enable the module and refresh the definitions cache. + module_enable(array('block_test'), FALSE); + $manager->clearCachedDefinitions(); + + // Reload the admin page and confirm the block can again be configured. + $this->drupalGet('admin/structure/block'); + $this->assertLinkByHref(url('admin/structure/block/manage/plugin.core.block.stark.' . $edit['machine_name'] . '/stark/config')); + + // Confirm that the block is again displayed on the front page. + $this->drupalGet(''); + $this->assertText('Test block caching'); + } + }