In versions of Drupal core prior to 8.0.0-beta13 block plugins that utilized context-aware condition plugins in order to determine their visibility had the context values set by the BlockPageVariant
dispatching a series of BlockEvent
s. These events were subscribed to by services that were able to provide global contexts.
This event was being dispatched for each block, even if not needed and in most cases the context providing event subscribers were calculating a global context multiple times.
In order to improve the performance, and provide a reusable architecture for contrib projects requiring global context, the BlockEvent
s were removed in favour of a LazyContextRepository
.
Now only required contexts are loaded, and only once.
API changes | Changes needed by contrib module authors
\Drupal\block\Event\BlockEvents
, \Drupal\block\Event\BlockContextEvent
and \Drupal\block\EventSubscriber\BlockSubscriberBase
are removed
Context providing services must be tagged as context_provider and implement Drupal\Core\Plugin\Context\ContextProviderInterface
\Drupal\block\BlockRepositoryInterface
changes thus:
- public function getVisibleBlocksPerRegion(array $contexts, array &$cacheable_metadata = []);
+ public function getVisibleBlocksPerRegion(array &$cacheable_metadata = []);
The following context providing services were moved out of block module into their respective modules
Drupal\block\EventSubscriber\CurrentLanguageContext
» Drupal\Core\Language\ContextProvider\CurrentLanguageContext
Drupal\block\EventSubscriber\NodeRouteContext
» Drupal\node\ContextProvider\NodeRouteContext
Drupal\block\EventSubscriber\CurrentUserContext
» Drupal\user\ContextProvider\CurrentUserContext
hook_update_N() for contrib modules
On top of changing the code of block context providers, modules who provide them should also write update functions in order to update existing blocks.
The following steps are needed:
- Write a hook_update_N() function which converts your context IDs to the new one:
function mymodule_update_8001() { $old_context_id = 'mymodule_context'; $new_context_service_id = '@mymodule.context_provider:mymodule_context'; $config_factory = \Drupal::configFactory(); $backup_values = \Drupal::keyValue('update_backup')->get('block_update_8001'); foreach ($backup_values as $block_id => $backup_value) { $missing_context_ids = $backup_value['missing_context_ids']; $status = $backup_value['status']; if (!empty($missing_context_ids[$old_context_id])) { $condition_plugin_ids = $missing_context_ids[$old_context_id]; $block = $config_factory->getEditable('block.block.' . $block_id); $visibility = $block->get('visibility'); foreach ($condition_plugin_ids as $condition_plugin_id) { $visibility[$condition_plugin_id]['context_mapping'][$old_context_id] = $new_context_service_id; } // Cleanup the remaining missing context IDs. $pos = array_search($old_context_id, $missing_context_ids); unset($missing_context_ids[$pos]); if (empty($missing_context_ids)) { // No backup values left, remove the key completely so that block_update_8002() does not disable the block. unset($backup_values[$block_id]); } $block->save(); } } \Drupal::keyValue('update_backup')->set('block_update_8001', $backup_values); }
- Ensure that your hook_update_N() function runs after block_update_8001 and before block_update_8002 using hook_update_dependencies()
hook_update_dependencies() { $dependencies['mymodule'][8001] = [ 'block' => 8001, ]; $dependencies['block'][8002] = [ 'mymodule' => 8001, ]; }
Data model changes
Visibility conditions now store a reference to the service ID as well as the context slot name in their mapping.
Before
visibility:
node_type:
id: node_type
bundles:
article: article
negate: false
context_mapping:
node: node.node
After
visibility:
node_type:
id: node_type
bundles:
article: article
negate: false
context_mapping:
node: @node.node_route_context:node