diff --git a/core/modules/block/block.install b/core/modules/block/block.install new file mode 100644 index 0000000..1a0ac23 --- /dev/null +++ b/core/modules/block/block.install @@ -0,0 +1,137 @@ + 'language.current_language_context', + 'node' => 'node.node_route_context', + 'user' => 'user.current_user_context', + ]; + + // Using the Entity API is fine as long we change the value from one valid + // value to another value. In this update function however, we deal with + // converting the format of the context_mapping, which makes code reacting + // to Entity API hooks tricky, because they would need to be different for + // before/after the update. + // For updating the status flag of the block in the next update function, + // however, we can use Entity API. + // Contributed modules should leverage hook_update_dependencies() in order to + // be executed before block_update_8002(). + $config_factory = \Drupal::configFactory(); + $message = NULL; + $backup_values = []; + + $update_backup = []; + foreach ($config_factory->listAll('block.block.') as $block_config_name) { + $block = $config_factory->getEditable($block_config_name); + if ($visibility = $block->get('visibility')) { + foreach ($visibility as $condition_plugin_id => &$condition) { + foreach ($condition['context_mapping'] as $key => $context) { + if (!isset($context_service_id_map[$key])) { + // Remove the visibility condition for unknown context mapping + // entries, so the update process itself runs through and users can + // fix their block placements manually OR alternatively contrib + // modules can run their own update functions to update mappings + // that they provide. + $backup_values[] = $context; + unset($visibility[$condition_plugin_id]); + continue; + } + // We replace the previous format of "{$context_id}" + // with "@{$service_id}:{$unqualified_context_id}". + $new_context_id = explode('.', $context, 2); + $condition['context_mapping'][$key] = '@' . $context_service_id_map[$key] . ':' . $new_context_id[1]; + } + } + $block->set('visibility', $visibility); + + if ($backup_values) { + // We not only store the missing context mappings but also the + // previous block status so contributed and custom modules could update. + $update_backup[$block->get('id')] = ['missing_context_ids' => $backup_values, 'status' => $block->get('status')]; + } + } + + $block->save(); + } + + if ($update_backup) { + \Drupal::keyValue('update_backup')->set('block_update_8001', $update_backup); + } + + return $message; +} + +/** + * Disables all blocks from the previous update. + */ +function block_update_8002() { + // Note: For this update function it's fine to use the entity API; see the + // explanation in block_update_8001(). + $block_update_8001 = \Drupal::keyValue('update_backup')->get('block_update_8001', []); + + $block_storage = \Drupal::entityManager()->getStorage('block'); + $blocks = $block_storage->loadMultiple(array_keys($block_update_8001)); + /** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $block */ + foreach ($blocks as $block) { + // This block will have an invalid context mapping service and must be + // disabled in order to prevent information disclosure. + $block->setStatus(FALSE); + $block->save(); + } + + // Provides a list of plugin labels, keyed by plugin ID. + $condition_plugin_id_label_map = array_map(function($definition) { + // The label might be a translation wrapper. + return (string) $definition['label']; + }, \Drupal::service('plugin.manager.condition')->getDefinitions()); + + + // Override with the UI labels we are aware of. Sadly they are not machine + // accessible, see + // \Drupal\node\Plugin\Condition\NodeType::buildConfigurationForm(). + $condition_plugin_id_label_map['node_type'] = \Drupal::translation()->translate('Content types'); + $condition_plugin_id_label_map['request_path'] = \Drupal::translation()->translate('Pages'); + $condition_plugin_id_label_map['user_role'] = \Drupal::translation()->translate('Roles'); + + if (count($blocks) > 0) { + $message = \Drupal::translation() + ->translate('Encountered an unknown context mapping key coming probably from a contributed or custom module: One or more mappings could not be updated. Please manually review your visibility settings for the following blocks, which are disabled now:'); + $message .= '