diff --git a/core/modules/action/action.post_update.php b/core/modules/action/action.post_update.php
new file mode 100644
index 0000000000..b88b0dbcac
--- /dev/null
+++ b/core/modules/action/action.post_update.php
@@ -0,0 +1,24 @@
+update($sandbox, 'action', function (ActionConfigEntityInterface $action) use ($resave_ids) {
+ // Save entity to recalculate dependencies.
+ return $action->isConfigurable() && in_array($action->getPlugin()->getPluginId(), $resave_ids, TRUE);
+ });
+}
diff --git a/core/modules/block/block.post_update.php b/core/modules/block/block.post_update.php
new file mode 100644
index 0000000000..e9e332ad08
--- /dev/null
+++ b/core/modules/block/block.post_update.php
@@ -0,0 +1,101 @@
+= 8002 && !\Drupal::state()->get('block_update_8002_placeholder', FALSE)) {
+ return;
+ }
+
+ // Cleanup the state entry as its no longer needed.
+ \Drupal::state()->delete('block_update_8002');
+
+ $block_update_8001 = \Drupal::keyValue('update_backup')->get('block_update_8001', []);
+
+ $block_ids = array_keys($block_update_8001);
+ $block_storage = \Drupal::entityTypeManager()->getStorage('block');
+ $blocks = $block_storage->loadMultiple($block_ids);
+ /** @var $blocks \Drupal\block\BlockInterface[] */
+ foreach ($blocks as $block) {
+ // This block has had conditions removed due to an inability to resolve
+ // contexts in block_update_8001() so disable it.
+
+ // Disable currently enabled blocks.
+ if ($block_update_8001[$block->id()]['status']) {
+ $block->setStatus(FALSE);
+ $block->save();
+ }
+ }
+
+ // Provides a list of plugin labels, keyed by plugin ID.
+ $condition_plugin_id_label_map = array_column(\Drupal::service('plugin.manager.condition')->getDefinitions(), 'label', 'id');
+
+ // 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'] = t('Content types');
+ $condition_plugin_id_label_map['request_path'] = t('Pages');
+ $condition_plugin_id_label_map['user_role'] = t('Roles');
+
+ if (count($block_ids) > 0) {
+ $message = t('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 .= '
';
+ foreach ($blocks as $disabled_block_id => $disabled_block) {
+ $message .= '- ' . t('@label (Visibility: @plugin_ids)', [
+ '@label' => $disabled_block->get('settings')['label'],
+ '@plugin_ids' => implode(', ', array_intersect_key($condition_plugin_id_label_map, array_flip(array_keys($block_update_8001[$disabled_block_id]['missing_context_ids'])))),
+ ]) . '
';
+ }
+ $message .= '
';
+
+ return $message;
+ }
+}
+
+/**
+ * Disable blocks that are placed into the "disabled" region.
+ */
+function block_post_update_disabled_region_update() {
+ // An empty update will flush caches, forcing block_rebuild() to run.
+}
+
+/**
+ * Fix invalid 'negate' values in block visibility conditions.
+ */
+function block_post_update_fix_negate_in_conditions() {
+ $block_storage = \Drupal::entityTypeManager()->getStorage('block');
+ /** @var \Drupal\block\BlockInterface[] $blocks */
+ $blocks = $block_storage->loadMultiple();
+ foreach ($blocks as $block) {
+ $block_needs_saving = FALSE;
+ // Check each visibility condition for an invalid negate value, and fix it.
+ foreach ($block->getVisibilityConditions() as $condition_id => $condition) {
+ $configuration = $condition->getConfiguration();
+ if (array_key_exists('negate', $configuration) && !is_bool($configuration['negate'])) {
+ $configuration['negate'] = (bool) $configuration['negate'];
+ $condition->setConfiguration($configuration);
+ $block_needs_saving = TRUE;
+ }
+ }
+ if ($block_needs_saving) {
+ $block->save();
+ }
+ }
+}
diff --git a/core/modules/block_content/block_content.post_update.php b/core/modules/block_content/block_content.post_update.php
new file mode 100644
index 0000000000..db7f50460c
--- /dev/null
+++ b/core/modules/block_content/block_content.post_update.php
@@ -0,0 +1,95 @@
+moduleExists('views')) {
+ return;
+ }
+
+ $entity_type = \Drupal::entityTypeManager()->getDefinition('block_content');
+ $storage = \Drupal::entityTypeManager()->getStorage('block_content');
+
+ // If the storage class is an instance SqlContentEntityStorage we can use it
+ // to determine the table to use, otherwise we have to get the table from the
+ // entity type.
+ if ($storage instanceof SqlContentEntityStorage) {
+ $table = $entity_type->isTranslatable() ? $storage->getDataTable() : $storage->getBaseTable();
+ }
+ else {
+ $table = $entity_type->isTranslatable() ? $entity_type->getDataTable() : $entity_type->getBaseTable();
+ }
+ // If we were not able to get a table name we can not update the views.
+ if (empty($table)) {
+ return;
+ }
+
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($table) {
+ /** @var \Drupal\views\ViewEntityInterface $view */
+ if ($view->get('base_table') !== $table) {
+ return FALSE;
+ }
+ $save_view = FALSE;
+ $displays = $view->get('display');
+ foreach ($displays as $display_name => &$display) {
+ // Update the default display and displays that have overridden filters.
+ if (!isset($display['display_options']['filters']['reusable']) &&
+ ($display_name === 'default' || isset($display['display_options']['filters']))) {
+ $display['display_options']['filters']['reusable'] = [
+ 'id' => 'reusable',
+ 'table' => $table,
+ 'field' => 'reusable',
+ 'relationship' => 'none',
+ 'group_type' => 'group',
+ 'admin_label' => '',
+ 'operator' => '=',
+ 'value' => '1',
+ 'group' => 1,
+ 'exposed' => FALSE,
+ 'expose' => [
+ 'operator_id' => '',
+ 'label' => '',
+ 'description' => '',
+ 'use_operator' => FALSE,
+ 'operator' => '',
+ 'identifier' => '',
+ 'required' => FALSE,
+ 'remember' => FALSE,
+ 'multiple' => FALSE,
+ ],
+ 'is_grouped' => FALSE,
+ 'group_info' => [
+ 'label' => '',
+ 'description' => '',
+ 'identifier' => '',
+ 'optional' => TRUE,
+ 'widget' => 'select',
+ 'multiple' => FALSE,
+ 'remember' => FALSE,
+ 'default_group' => 'All',
+ 'default_group_multiple' => [],
+ 'group_items' => [],
+ ],
+ 'entity_type' => 'block_content',
+ 'entity_field' => 'reusable',
+ 'plugin_id' => 'boolean',
+ ];
+ $save_view = TRUE;
+ }
+ }
+ if ($save_view) {
+ $view->set('display', $displays);
+ }
+ return $save_view;
+ });
+}
diff --git a/core/modules/comment/comment.post_update.php b/core/modules/comment/comment.post_update.php
new file mode 100644
index 0000000000..64587ae154
--- /dev/null
+++ b/core/modules/comment/comment.post_update.php
@@ -0,0 +1,48 @@
+getModule('comment')->getPath() . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY;
+ $storage = new FileStorage($config_install_path);
+ $entity_type_manager
+ ->getStorage('action')
+ ->create($storage->read('system.action.comment_delete_action'))
+ ->save();
+
+ // Only create if the views module is enabled.
+ if (!$module_handler->moduleExists('views')) {
+ return;
+ }
+
+ // Save the comment admin view to config.
+ $optional_install_path = $module_handler->getModule('comment')->getPath() . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY;
+ $storage = new FileStorage($optional_install_path);
+ $entity_type_manager
+ ->getStorage('view')
+ ->create($storage->read('views.view.comment'))
+ ->save();
+}
+
+/**
+ * Add comment settings.
+ */
+function comment_post_update_add_ip_address_setting() {
+ $config_factory = \Drupal::configFactory();
+ $settings = $config_factory->getEditable('comment.settings');
+ $settings->set('log_ip_addresses', TRUE)
+ ->save(TRUE);
+}
diff --git a/core/modules/contact/contact.post_update.php b/core/modules/contact/contact.post_update.php
new file mode 100644
index 0000000000..1cd4555ab4
--- /dev/null
+++ b/core/modules/contact/contact.post_update.php
@@ -0,0 +1,21 @@
+setMessage('Your message has been sent.')
+ ->setRedirectPath('')
+ ->save();
+ }
+}
diff --git a/core/modules/content_moderation/content_moderation.post_update.php b/core/modules/content_moderation/content_moderation.post_update.php
new file mode 100644
index 0000000000..918238ea15
--- /dev/null
+++ b/core/modules/content_moderation/content_moderation.post_update.php
@@ -0,0 +1,201 @@
+getTypePlugin();
+ foreach ($plugin->getEntityTypes() as $entity_type_id) {
+ $sandbox['entity_type_ids'][$entity_type_id] = $entity_type_id;
+ foreach ($plugin->getBundlesForEntityType($entity_type_id) as $bundle) {
+ $sandbox['bundles'][$entity_type_id][$bundle] = $bundle;
+ }
+ }
+ }
+ $sandbox['offset'] = 0;
+ $sandbox['limit'] = Settings::get('entity_update_batch_size', 50);
+ $sandbox['total'] = count($sandbox['entity_type_ids']);
+ $entity_type_id = array_shift($sandbox['entity_type_ids']);
+ }
+
+ // If there are no moderated bundles or we processed all of them, we are done.
+ $entity_type_manager = \Drupal::entityTypeManager();
+ /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $content_moderation_state_storage */
+ $content_moderation_state_storage = $entity_type_manager->getStorage('content_moderation_state');
+ if (!$entity_type_id) {
+ $content_moderation_state_storage->resetCache();
+ $sandbox['#finished'] = 1;
+ return;
+ }
+
+ // Retrieve a batch of moderated entities to be processed.
+ $storage = $entity_type_manager->getStorage($entity_type_id);
+ $entity_type = $entity_type_manager->getDefinition($entity_type_id);
+ $query = $storage->getQuery()
+ ->accessCheck(FALSE)
+ ->sort($entity_type->getKey('id'))
+ ->range($sandbox['offset'], $sandbox['limit']);
+ $bundle_key = $entity_type->getKey('bundle');
+ if ($bundle_key && !empty($sandbox['bundles'][$entity_type_id])) {
+ $bundles = array_keys($sandbox['bundles'][$entity_type_id]);
+ $query->condition($bundle_key, $bundles, 'IN');
+ }
+ $entity_ids = $query->execute();
+
+ // Compute progress status and skip to the next entity type, if needed.
+ $sandbox['#finished'] = ($sandbox['total'] - count($sandbox['entity_type_ids']) - 1) / $sandbox['total'];
+ if (!$entity_ids) {
+ $sandbox['offset'] = 0;
+ $entity_type_id = array_shift($sandbox['entity_type_ids']) ?: FALSE;
+ return;
+ }
+
+ // Load the "content_moderation_state" revisions corresponding to the
+ // moderated entity default revisions.
+ $result = $content_moderation_state_storage->getQuery()
+ ->allRevisions()
+ ->condition('content_entity_type_id', $entity_type_id)
+ ->condition('content_entity_revision_id', array_keys($entity_ids), 'IN')
+ ->execute();
+ /** @var \Drupal\Core\Entity\ContentEntityInterface[] $revisions */
+ $revisions = $content_moderation_state_storage->loadMultipleRevisions(array_keys($result));
+
+ // Update "content_moderation_state" data.
+ foreach ($revisions as $revision) {
+ if (!$revision->isDefaultRevision()) {
+ $revision->setNewRevision(FALSE);
+ $revision->isDefaultRevision(TRUE);
+ $content_moderation_state_storage->save($revision);
+ }
+ }
+
+ // Clear static cache to avoid memory issues.
+ $storage->resetCache($entity_ids);
+
+ $sandbox['offset'] += $sandbox['limit'];
+}
+
+/**
+ * Set the default moderation state for new content to 'draft'.
+ */
+function content_moderation_post_update_set_default_moderation_state(&$sandbox) {
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'workflow', function (Workflow $workflow) {
+ if ($workflow->get('type') === 'content_moderation') {
+ $configuration = $workflow->getTypePlugin()->getConfiguration();
+ $configuration['default_moderation_state'] = 'draft';
+ $workflow->getTypePlugin()->setConfiguration($configuration);
+ return TRUE;
+ }
+ return FALSE;
+ });
+}
+
+/**
+ * Set the filter on the moderation view to be the latest translation affected.
+ */
+function content_moderation_post_update_set_views_filter_latest_translation_affected_revision(&$sandbox) {
+ $original_plugin_name = 'latest_revision';
+ $new_plugin_name = 'latest_translation_affected_revision';
+
+ // Check that views is installed and the moderated content view exists.
+ if (\Drupal::moduleHandler()->moduleExists('views') && $view = View::load('moderated_content')) {
+ $display = &$view->getDisplay('default');
+ if (!isset($display['display_options']['filters'][$original_plugin_name])) {
+ return;
+ }
+
+ $translation_affected_filter = [
+ 'id' => $new_plugin_name,
+ 'field' => $new_plugin_name,
+ 'plugin_id' => $new_plugin_name,
+ ] + $display['display_options']['filters'][$original_plugin_name];
+
+ $display['display_options']['filters'] = [$new_plugin_name => $translation_affected_filter] + $display['display_options']['filters'];
+ unset($display['display_options']['filters'][$original_plugin_name]);
+
+ $view->save();
+ }
+}
+
+/**
+ * Update the dependencies of entity displays to include associated workflow.
+ */
+function content_moderation_post_update_entity_display_dependencies(&$sandbox) {
+ /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
+ $moderation_info = \Drupal::service('content_moderation.moderation_information');
+ /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
+ $entity_type_manager = \Drupal::service('entity_type.manager');
+
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'entity_form_display', function (EntityFormDisplay $entity_form_display) use ($moderation_info, $entity_type_manager) {
+ $associated_entity_type = $entity_type_manager->getDefinition($entity_form_display->getTargetEntityTypeId());
+
+ if ($moderation_info->isModeratedEntityType($associated_entity_type)) {
+ $entity_form_display->calculateDependencies();
+ return TRUE;
+ }
+ elseif ($moderation_state_component = $entity_form_display->getComponent('moderation_state')) {
+ // Remove the component from the entity form display, then manually delete
+ // it from the hidden components list, completely purging it.
+ $entity_form_display->removeComponent('moderation_state');
+ $hidden_components = $entity_form_display->get('hidden');
+ unset($hidden_components['moderation_state']);
+ $entity_form_display->set('hidden', $hidden_components);
+ $entity_form_display->calculateDependencies();
+ return TRUE;
+ }
+
+ return FALSE;
+ });
+}
+
+/**
+ * Update the moderation state views field plugin ID.
+ */
+function content_moderation_post_update_views_field_plugin_id(&$sandbox) {
+ // If Views is not installed, there is nothing to do.
+ if (!\Drupal::moduleHandler()->moduleExists('views')) {
+ return;
+ }
+
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) {
+ /** @var \Drupal\views\ViewEntityInterface $view */
+ $updated = FALSE;
+ $displays = $view->get('display');
+ foreach ($displays as &$display) {
+ if (empty($display['display_options']['fields'])) {
+ continue;
+ }
+ foreach ($display['display_options']['fields'] as &$display_field) {
+ if ($display_field['id'] === 'moderation_state' && $display_field['plugin_id'] === 'field') {
+ $display_field['plugin_id'] = 'moderation_state_field';
+ $updated = TRUE;
+ }
+ }
+ }
+ $view->set('display', $displays);
+ return $updated;
+ });
+}
diff --git a/core/modules/contextual/contextual.post_update.php b/core/modules/contextual/contextual.post_update.php
new file mode 100644
index 0000000000..8decad05f0
--- /dev/null
+++ b/core/modules/contextual/contextual.post_update.php
@@ -0,0 +1,14 @@
+getStorage('view')->loadMultiple();
+ $config_factory = \Drupal::configFactory();
+ $message = NULL;
+ $ids = [];
+
+ foreach ($views as $view) {
+ $displays = $view->get('display');
+ $needs_bc_layer_update = FALSE;
+
+ foreach ($displays as $display_name => $display) {
+
+ // Check if datetime_range filters need updates.
+ if (!$needs_bc_layer_update && isset($display['display_options']['filters'])) {
+ foreach ($display['display_options']['filters'] as $field_name => $filter) {
+ if ($filter['plugin_id'] == 'string') {
+
+ // Get field config.
+ $filter_views_data = Views::viewsData()->get($filter['table'])[$filter['field']]['filter'];
+ if (!isset($filter_views_data['entity_type']) || !isset($filter_views_data['field_name'])) {
+ continue;
+ }
+ $field_storage_name = 'field.storage.' . $filter_views_data['entity_type'] . '.' . $filter_views_data['field_name'];
+ $field_configuration = $config_factory->get($field_storage_name);
+
+ if ($field_configuration->get('type') == 'daterange') {
+ // Trigger the BC layer control.
+ $needs_bc_layer_update = TRUE;
+ continue 2;
+ }
+ }
+ }
+ }
+
+ // Check if datetime_range sort handlers need updates.
+ if (!$needs_bc_layer_update && isset($display['display_options']['sorts'])) {
+ foreach ($display['display_options']['sorts'] as $field_name => $sort) {
+ if ($sort['plugin_id'] == 'standard') {
+
+ // Get field config.
+ $sort_views_data = Views::viewsData()->get($sort['table'])[$sort['field']]['sort'];
+ if (!isset($sort_views_data['entity_type']) || !isset($sort_views_data['field_name'])) {
+ continue;
+ }
+ $field_storage_name = 'field.storage.' . $sort_views_data['entity_type'] . '.' . $sort_views_data['field_name'];
+ $field_configuration = $config_factory->get($field_storage_name);
+
+ if ($field_configuration->get('type') == 'daterange') {
+ // Trigger the BC layer control.
+ $needs_bc_layer_update = TRUE;
+ continue 2;
+ }
+ }
+ }
+ }
+ }
+
+ // If current view needs BC layer updates save it and the hook view_presave
+ // will do the rest.
+ if ($needs_bc_layer_update) {
+ $view->save();
+ $ids[] = $view->id();
+ }
+ }
+
+ if (!empty($ids)) {
+ $message = \Drupal::translation()->translate('Updated datetime_range filter/sort plugins for views: @ids', ['@ids' => implode(', ', array_unique($ids))]);
+ }
+
+ return $message;
+}
diff --git a/core/modules/dblog/dblog.post_update.php b/core/modules/dblog/dblog.post_update.php
new file mode 100644
index 0000000000..6021ec6b52
--- /dev/null
+++ b/core/modules/dblog/dblog.post_update.php
@@ -0,0 +1,35 @@
+moduleExists('views')) {
+ if (!View::load('watchdog')) {
+ // Save the watchdog view to config.
+ $module_handler = \Drupal::moduleHandler();
+ $optional_install_path = $module_handler->getModule('dblog')->getPath() . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY;
+ $storage = new FileStorage($optional_install_path);
+
+ \Drupal::entityTypeManager()
+ ->getStorage('view')
+ ->create($storage->read('views.view.watchdog'))
+ ->save();
+
+ return t('The watchdog view has been created.');
+ }
+
+ return t("The watchdog view already exists and was not replaced. To replace the 'Recent log messages' with a view, rename the watchdog view and uninstall and install the 'Database Log' module");
+ }
+}
diff --git a/core/modules/editor/editor.post_update.php b/core/modules/editor/editor.post_update.php
new file mode 100644
index 0000000000..8483900488
--- /dev/null
+++ b/core/modules/editor/editor.post_update.php
@@ -0,0 +1,12 @@
+save();
+ }
+
+ return t('All field storage configuration objects re-saved.');
+}
+
+/**
+ * Fixes the 'handler' setting for entity reference fields.
+ */
+function field_post_update_entity_reference_handler_setting() {
+ foreach (FieldConfig::loadMultiple() as $field_config) {
+ $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
+ $item_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
+ $class = $field_type_manager->getPluginClass($field_config->getType());
+ if ($class === $item_class || is_subclass_of($class, $item_class)) {
+ // field_field_config_presave() will fix the 'handler' setting on save.
+ $field_config->save();
+ }
+ }
+
+ return t('Selection handler for entity reference fields have been adjusted.');
+}
+
+/**
+ * Adds the 'size' setting for email widgets.
+ */
+function field_post_update_email_widget_size_setting() {
+ foreach (EntityFormDisplay::loadMultiple() as $entity_form_display) {
+ $changed = FALSE;
+ foreach ($entity_form_display->getComponents() as $name => $options) {
+ if (isset($options['type']) && $options['type'] === 'email_default') {
+ $options['settings']['size'] = '60';
+ $entity_form_display->setComponent($name, $options);
+ $changed = TRUE;
+ }
+ }
+
+ if ($changed) {
+ $entity_form_display->save();
+ }
+ }
+
+ return t('The new size setting for email widgets has been added.');
+}
+
+/**
+ * Remove the stale 'handler_submit' setting for entity_reference fields.
+ */
+function field_post_update_remove_handler_submit_setting() {
+ $config = \Drupal::configFactory();
+ /** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */
+ $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
+
+ // Iterate on all field configs.
+ foreach ($config->listAll('field.field.') as $field_id) {
+ $field = $config->getEditable($field_id);
+ $class = $field_type_manager->getPluginClass($field->get('field_type'));
+
+ // Deal only with entity reference fields and descendants.
+ if ($class === EntityReferenceItem::class || is_subclass_of($class, EntityReferenceItem::class)) {
+ if ($field->get('settings.handler_submit')) {
+ // Remove 'handler_settings' from settings.
+ $field->clear('settings.handler_submit')->save();
+ }
+ }
+ }
+}
diff --git a/core/modules/image/image.post_update.php b/core/modules/image/image.post_update.php
new file mode 100644
index 0000000000..cde93fc2e9
--- /dev/null
+++ b/core/modules/image/image.post_update.php
@@ -0,0 +1,39 @@
+save();
+ }
+}
+
+/**
+ * Add 'anchor' setting to 'Scale and crop' effects.
+ */
+function image_post_update_scale_and_crop_effect_add_anchor(&$sandbox = NULL) {
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'image_style', function ($image_style) {
+ /** @var \Drupal\image\ImageStyleInterface $image_style */
+ $effects = $image_style->getEffects();
+ foreach ($effects as $effect) {
+ if ($effect->getPluginId() === 'image_scale_and_crop') {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ });
+}
diff --git a/core/modules/language/language.post_update.php b/core/modules/language/language.post_update.php
new file mode 100644
index 0000000000..f7f9c29726
--- /dev/null
+++ b/core/modules/language/language.post_update.php
@@ -0,0 +1,28 @@
+get('content');
+ $changed = FALSE;
+ foreach (array_keys($content) as $element) {
+ if (isset($content[$element]['type']) && $content[$element]['type'] == 'language_select') {
+ $content[$element]['settings']['include_locked'] = TRUE;
+ $changed = TRUE;
+ }
+ }
+ if ($changed) {
+ $display_form->set('content', $content);
+ $display_form->save();
+ }
+ }
+}
diff --git a/core/modules/layout_builder/layout_builder.post_update.php b/core/modules/layout_builder/layout_builder.post_update.php
new file mode 100644
index 0000000000..1b4a2acb03
--- /dev/null
+++ b/core/modules/layout_builder/layout_builder.post_update.php
@@ -0,0 +1,301 @@
+getStorage('entity_view_display');
+ if (!isset($sandbox['ids'])) {
+ $sandbox['ids'] = $storage->getQuery()->accessCheck(FALSE)->execute();
+ $sandbox['count'] = count($sandbox['ids']);
+ }
+
+ for ($i = 0; $i < 10 && count($sandbox['ids']); $i++) {
+ $id = array_shift($sandbox['ids']);
+ if ($display = $storage->load($id)) {
+ $display->save();
+ }
+ }
+
+ $sandbox['#finished'] = empty($sandbox['ids']) ? 1 : ($sandbox['count'] - count($sandbox['ids'])) / $sandbox['count'];
+}
+
+/**
+ * Ensure all extra fields are properly stored on entity view displays.
+ *
+ * Previously
+ * \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::setComponent()
+ * was not correctly setting the configuration for extra fields. This function
+ * calls setComponent() for all extra field components to ensure the updated
+ * logic is invoked on all extra fields to correct the settings.
+ */
+function layout_builder_post_update_add_extra_fields(&$sandbox = NULL) {
+ $entity_field_manager = \Drupal::service('entity_field.manager');
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'entity_view_display', function (LayoutEntityDisplayInterface $display) use ($entity_field_manager) {
+ if (!$display->isLayoutBuilderEnabled()) {
+ return FALSE;
+ }
+
+ $extra_fields = $entity_field_manager->getExtraFields($display->getTargetEntityTypeId(), $display->getTargetBundle());
+ $components = $display->getComponents();
+ // Sort the components to avoid them being reordered by setComponent().
+ uasort($components, 'Drupal\Component\Utility\SortArray::sortByWeightElement');
+ $result = FALSE;
+ foreach ($components as $name => $component) {
+ if (isset($extra_fields['display'][$name])) {
+ $display->setComponent($name, $component);
+ $result = TRUE;
+ }
+ }
+ return $result;
+ });
+}
+
+/**
+ * Clear caches due to changes to section storage annotation changes.
+ */
+function layout_builder_post_update_section_storage_context_definitions() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear caches due to changes to annotation changes to the Overrides plugin.
+ */
+function layout_builder_post_update_overrides_view_mode_annotation() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear caches due to routing changes for the new discard changes form.
+ */
+function layout_builder_post_update_cancel_link_to_discard_changes_form() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear caches due to the removal of the layout_is_rebuilding query string.
+ */
+function layout_builder_post_update_remove_layout_is_rebuilding() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear caches due to routing changes to move the Layout Builder UI to forms.
+ */
+function layout_builder_post_update_routing_entity_form() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear caches to discover new blank layout plugin.
+ */
+function layout_builder_post_update_discover_blank_layout_plugin() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear caches due to routing changes to changing the URLs for defaults.
+ */
+function layout_builder_post_update_routing_defaults() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear caches due to new link added to Layout Builder's contextual links.
+ */
+function layout_builder_post_update_discover_new_contextual_links() {
+ // Empty post-update hook.
+}
+
+/**
+ * Fix Layout Builder tempstore keys of existing entries.
+ */
+function layout_builder_post_update_fix_tempstore_keys() {
+ /** @var \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface $section_storage_manager */
+ $section_storage_manager = \Drupal::service('plugin.manager.layout_builder.section_storage');
+ /** @var \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $key_value_factory */
+ $key_value_factory = \Drupal::service('keyvalue.expirable');
+
+ // Loop through each section storage type.
+ foreach (array_keys($section_storage_manager->getDefinitions()) as $section_storage_type) {
+ $key_value = $key_value_factory->get("tempstore.shared.layout_builder.section_storage.$section_storage_type");
+ foreach ($key_value->getAll() as $key => $value) {
+ $contexts = $section_storage_manager->loadEmpty($section_storage_type)->deriveContextsFromRoute($key, [], '', []);
+ if ($section_storage = $section_storage_manager->load($section_storage_type, $contexts)) {
+
+ // Some overrides were stored with an incorrect view mode value. Update
+ // the view mode on the temporary section storage, if necessary.
+ if ($section_storage_type === 'overrides') {
+ $view_mode = $value->data['section_storage']->getContextValue('view_mode');
+ $new_view_mode = $section_storage->getContextValue('view_mode');
+ if ($view_mode !== $new_view_mode) {
+ $value->data['section_storage']->setContextValue('view_mode', $new_view_mode);
+ $key_value->set($key, $value);
+ }
+ }
+
+ // The previous tempstore key names were exact matches with the section
+ // storage ID. Attempt to load the corresponding section storage and
+ // rename the tempstore entry if the section storage provides a more
+ // granular tempstore key.
+ if ($section_storage instanceof TempStoreIdentifierInterface) {
+ $new_key = $section_storage->getTempstoreKey();
+ if ($key !== $new_key) {
+ if ($key_value->has($new_key)) {
+ $key_value->delete($new_key);
+ }
+ $key_value->rename($key, $new_key);
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Clear caches due to config schema additions.
+ */
+function layout_builder_post_update_section_third_party_settings_schema() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear caches due to dependency changes in the layout_builder render element.
+ */
+function layout_builder_post_update_layout_builder_dependency_change() {
+ // Empty post-update hook.
+}
+
+/**
+ * Add new custom block permission to all roles with 'configure any layout'.
+ */
+function layout_builder_post_update_update_permissions() {
+ foreach (Role::loadMultiple() as $role) {
+ if ($role->hasPermission('configure any layout')) {
+ $role->grantPermission('create and edit custom blocks')->save();
+ }
+ }
+}
+
+/**
+ * Set the layout builder field as non-translatable where possible.
+ */
+function layout_builder_post_update_make_layout_untranslatable() {
+ /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
+ $field_manager = \Drupal::service('entity_field.manager');
+ $field_map = $field_manager->getFieldMap();
+ foreach ($field_map as $entity_type_id => $field_infos) {
+ if (isset($field_infos[OverridesSectionStorage::FIELD_NAME]['bundles'])) {
+ $non_translatable_bundle_count = 0;
+ foreach ($field_infos[OverridesSectionStorage::FIELD_NAME]['bundles'] as $bundle) {
+ // The field map can contain stale information. If the field does not
+ // exist, ignore it. The field map will be rebuilt when the cache is
+ // cleared at the end of the update process.
+ if (!$field_config = FieldConfig::loadByName($entity_type_id, $bundle, OverridesSectionStorage::FIELD_NAME)) {
+ continue;
+ }
+ if (!$field_config->isTranslatable()) {
+ $non_translatable_bundle_count++;
+ // The layout field is already configured to be non-translatable so it
+ // does not need to be updated.
+ continue;
+ }
+ if (_layout_builder_bundle_has_no_translations($entity_type_id, $bundle) || _layout_builder_bundle_has_no_layouts($entity_type_id, $bundle)) {
+ // Either none of the entities have layouts or none of them have
+ // translations. In either case it is safe to set the field to be
+ // non-translatable.
+ $field_config->setTranslatable(FALSE);
+ $field_config->save();
+ $non_translatable_bundle_count++;
+ }
+ }
+ // Set the field storage to untranslatable if the field config for each
+ // bundle is now untranslatable. This removes layout fields for the
+ // entity type from the Content Translation configuration form.
+ if (count($field_infos[OverridesSectionStorage::FIELD_NAME]['bundles']) === $non_translatable_bundle_count) {
+ $field_storage = FieldStorageConfig::loadByName($entity_type_id, OverridesSectionStorage::FIELD_NAME);
+ $field_storage->setTranslatable(FALSE);
+ $field_storage->save();
+ }
+ }
+ }
+}
+
+/**
+ * Determines if there are zero layout overrides for the bundle.
+ *
+ * @param string $entity_type_id
+ * The entity type ID.
+ * @param string $bundle
+ * The bundle name.
+ *
+ * @return bool
+ * TRUE if there are zero layout overrides for the bundle, otherwise FALSE.
+ */
+function _layout_builder_bundle_has_no_layouts($entity_type_id, $bundle) {
+ $entity_update_manager = \Drupal::entityDefinitionUpdateManager();
+ $entity_type = $entity_update_manager->getEntityType($entity_type_id);
+ $bundle_key = $entity_type->getKey('bundle');
+ $query = \Drupal::entityTypeManager()->getStorage($entity_type_id)->getQuery();
+ if ($bundle_key) {
+ $query->condition($bundle_key, $bundle);
+ }
+ if ($entity_type->isRevisionable()) {
+ $query->allRevisions();
+ }
+ $query->exists(OverridesSectionStorage::FIELD_NAME)
+ ->accessCheck(FALSE)
+ ->range(0, 1);
+ $results = $query->execute();
+ return empty($results);
+}
+
+/**
+ * Determines if there are zero translations for the bundle.
+ *
+ * @param string $entity_type_id
+ * The entity type ID.
+ * @param string $bundle
+ * The bundle name.
+ *
+ * @return bool
+ * TRUE if there are zero translations for the bundle, otherwise FALSE.
+ */
+function _layout_builder_bundle_has_no_translations($entity_type_id, $bundle) {
+ $entity_update_manager = \Drupal::entityDefinitionUpdateManager();
+ $entity_type = $entity_update_manager->getEntityType($entity_type_id);
+ if (!$entity_type->isTranslatable()) {
+ return TRUE;
+ }
+ $query = \Drupal::entityTypeManager()->getStorage($entity_type_id)->getQuery();
+ $bundle_key = $entity_type->getKey('bundle');
+ if ($entity_type->hasKey('default_langcode')) {
+ if ($bundle_key) {
+ $query->condition($bundle_key, $bundle);
+ }
+ if ($entity_type->isRevisionable()) {
+ $query->allRevisions();
+ }
+ $query->condition($entity_type->getKey('default_langcode'), 0)
+ ->accessCheck(FALSE)
+ ->range(0, 1);
+ $results = $query->execute();
+ return empty($results);
+ }
+ // A translatable entity type should always have a default_langcode key. If it
+ // doesn't we have no way to determine if there are translations.
+ return FALSE;
+}
diff --git a/core/modules/layout_discovery/layout_discovery.post_update.php b/core/modules/layout_discovery/layout_discovery.post_update.php
new file mode 100644
index 0000000000..9f342b7562
--- /dev/null
+++ b/core/modules/layout_discovery/layout_discovery.post_update.php
@@ -0,0 +1,22 @@
+update($sandbox, 'entity_form_display');
+}
+
+/**
+ * Recalculate dependencies for the entity_view_display entity.
+ */
+function layout_discovery_post_update_recalculate_entity_view_display_dependencies(&$sandbox = NULL) {
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'entity_view_display');
+}
diff --git a/core/modules/locale/locale.post_update.php b/core/modules/locale/locale.post_update.php
new file mode 100644
index 0000000000..f4f5eca22a
--- /dev/null
+++ b/core/modules/locale/locale.post_update.php
@@ -0,0 +1,13 @@
+getEditable('media.settings');
+ if ($config->get('standalone_url') === NULL) {
+ $config->set('standalone_url', TRUE)->save(TRUE);
+ }
+}
+
+/**
+ * Add a status extra filter to the media view default display.
+ */
+function media_post_update_add_status_extra_filter() {
+ $view = Views::getView('media');
+
+ if (!$view) {
+ return;
+ }
+
+ // Fetch the filters from the default display and add the new 'status_extra'
+ // filter if it does not yet exist.
+ $default_display = $view->getDisplay();
+ $filters = $default_display->getOption('filters');
+
+ if (!isset($filters['status_extra'])) {
+ $filters['status_extra'] = [
+ 'group_info' => [
+ 'widget' => 'select',
+ 'group_items' => [],
+ 'multiple' => FALSE,
+ 'description' => '',
+ 'default_group_multiple' => [],
+ 'default_group' => 'All',
+ 'label' => '',
+ 'identifier' => '',
+ 'optional' => TRUE,
+ 'remember' => FALSE,
+ ],
+ 'group' => 1,
+ 'relationship' => 'none',
+ 'exposed' => FALSE,
+ 'expose' => [
+ 'use_operator' => FALSE,
+ 'remember' => FALSE,
+ 'operator_id' => '',
+ 'multiple' => FALSE,
+ 'description' => '',
+ 'required' => FALSE,
+ 'label' => '',
+ 'operator_limit_selection' => FALSE,
+ 'operator' => '',
+ 'identifier' => '',
+ 'operator_list' => [],
+ 'remember_roles' => [RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID],
+ ],
+ 'entity_type' => 'media',
+ 'value' => '',
+ 'field' => 'status_extra',
+ 'is_grouped' => FALSE,
+ 'admin_label' => '',
+ 'operator' => '=',
+ 'table' => 'media_field_data',
+ 'plugin_id' => 'media_status',
+ 'id' => 'status_extra',
+ 'group_type' => 'group',
+ ];
+ $default_display->setOption('filters', $filters);
+ $view->save();
+
+ return t("The 'Published status or admin user' filter was added to the %label view.", [
+ '%label' => $view->storage->label(),
+ ]);
+ }
+}
diff --git a/core/modules/media_library/media_library.post_update.php b/core/modules/media_library/media_library.post_update.php
new file mode 100644
index 0000000000..876fde8298
--- /dev/null
+++ b/core/modules/media_library/media_library.post_update.php
@@ -0,0 +1,776 @@
+ 'media.media_library',
+ 'targetEntityType' => 'media',
+ 'label' => t('Media library'),
+ 'dependencies' => [
+ 'enforced' => [
+ 'module' => [
+ 'media_library',
+ ],
+ ],
+ 'module' => [
+ 'media',
+ ],
+ ],
+ ];
+ if (!EntityViewMode::load('media.media_library')) {
+ EntityViewMode::create($values)->save();
+ }
+ if (!EntityFormMode::load('media.media_library')) {
+ EntityFormMode::create($values)->save();
+ }
+
+ // The Media Library needs a special form display and view display to make
+ // sure the Media Library is displayed properly. These were not automatically
+ // created for custom media types, so let's make sure this is fixed.
+ $types = [];
+ foreach (MediaType::loadMultiple() as $type) {
+ $form_display_created = _media_library_configure_form_display($type);
+ $view_display_created = _media_library_configure_view_display($type);
+ if ($form_display_created || $view_display_created) {
+ $types[] = $type->label();
+ }
+ }
+ if ($types) {
+ return t('Media Library form and view displays have been created for the following media types: @types.', [
+ '@types' => implode(', ', $types),
+ ]);
+ }
+}
+
+/**
+ * Add a table display to the media library view and link grid/table displays.
+ */
+function media_library_post_update_table_display() {
+ $view = Views::getView('media_library');
+
+ if (!$view) {
+ return t('The media_library view could not be updated because it has been deleted. The Media Library module needs this view in order to work properly. Uninstall and reinstall the module so the view will be re-created.');
+ }
+
+ // Override CSS classes to allow targeting grid displays.
+ $view->setDisplay('default');
+ $default_display = $view->getDisplay('default');
+ $style = $default_display->getOption('style');
+ $style['options']['row_class'] = 'media-library-item media-library-item--grid js-media-library-item js-click-to-select';
+ $default_display->setOption('style', $style);
+
+ // Override CSS classes to allow targeting widget displays.
+ $view->setDisplay('widget');
+ $grid_display = $view->getDisplay('widget');
+ $grid_display->overrideOption('css_class', 'media-library-view js-media-library-view media-library-view--widget');
+
+ // Create the new table display.
+ $table_display = $view->newDisplay('page', 'Widget (table)', 'widget_table');
+ $table_display->setOption('path', 'admin/content/media-widget-table');
+
+ // Override CSS classes to allow targeting widget displays.
+ $table_display->overrideOption('css_class', 'media-library-view js-media-library-view media-library-view--widget');
+
+ // Set table as the display style.
+ $table_display->overrideOption('style', [
+ 'type' => 'table',
+ 'options' => [
+ 'row_class' => 'media-library-item media-library-item--table js-media-library-item js-click-to-select',
+ 'default_row_class' => TRUE,
+ ],
+ ]);
+
+ // Set fields for table display.
+ $table_display->overrideOption('row', [
+ 'type' => 'fields',
+ ]);
+ $table_display->overrideOption('fields', [
+ 'media_library_select_form' => [
+ 'id' => 'media_library_select_form',
+ 'label' => '',
+ 'table' => 'media',
+ 'field' => 'media_library_select_form',
+ 'relationship' => 'none',
+ 'entity_type' => 'media',
+ 'plugin_id' => 'media_library_select_form',
+ 'element_wrapper_class' => 'js-click-to-select-checkbox',
+ 'element_class' => '',
+ ],
+ 'thumbnail__target_id' => [
+ 'id' => 'thumbnail__target_id',
+ 'label' => 'Thumbnail',
+ 'table' => 'media_field_data',
+ 'field' => 'thumbnail__target_id',
+ 'relationship' => 'none',
+ 'type' => 'image',
+ 'entity_type' => 'media',
+ 'entity_field' => 'thumbnail',
+ 'plugin_id' => 'field',
+ 'settings' => [
+ 'image_style' => 'media_library',
+ 'image_link' => '',
+ ],
+ ],
+ 'name' => [
+ 'id' => 'name',
+ 'label' => 'Name',
+ 'table' => 'media_field_data',
+ 'field' => 'name',
+ 'relationship' => 'none',
+ 'type' => 'string',
+ 'entity_type' => 'media',
+ 'entity_field' => 'name',
+ 'plugin_id' => 'field',
+ 'settings' => [
+ 'link_to_entity' => FALSE,
+ ],
+ ],
+ 'uid' => [
+ 'id' => 'uid',
+ 'label' => 'Author',
+ 'table' => 'media_field_revision',
+ 'field' => 'uid',
+ 'relationship' => 'none',
+ 'type' => 'entity_reference_label',
+ 'entity_type' => 'media',
+ 'entity_field' => 'uid',
+ 'plugin_id' => 'field',
+ 'settings' => [
+ 'link' => TRUE,
+ ],
+ ],
+ 'changed' => [
+ 'id' => 'changed',
+ 'label' => 'Updated',
+ 'table' => 'media_field_data',
+ 'field' => 'changed',
+ 'relationship' => 'none',
+ 'type' => 'timestamp',
+ 'entity_type' => 'media',
+ 'entity_field' => 'changed',
+ 'plugin_id' => 'field',
+ 'settings' => [
+ 'date_format' => 'short',
+ 'custom_date_format' => '',
+ 'timezone' => '',
+ ],
+ ],
+ ]);
+
+ // Override the table display options in the same way as the grid display.
+ $table_display->overrideOption('access', $grid_display->getOption('access'));
+ $table_display->overrideOption('filters', $grid_display->getOption('filters'));
+ $table_display->overrideOption('arguments', $grid_display->getOption('arguments'));
+ $table_display->overrideOption('rendering_language', $grid_display->getOption('rendering_language'));
+
+ // Also override the sorts and pager if the grid display has overrides.
+ $defaults = $grid_display->getOption('defaults');
+ if (isset($defaults['sorts']) && !$defaults['sorts']) {
+ $table_display->overrideOption('sorts', $grid_display->getOption('sorts'));
+ }
+ if (isset($defaults['pager']) && !$defaults['pager']) {
+ $table_display->overrideOption('pager', $grid_display->getOption('pager'));
+ }
+
+ // Add display links to both widget and widget table displays.
+ $display_links = [
+ 'display_link_grid' => [
+ 'id' => 'display_link_grid',
+ 'table' => 'views',
+ 'field' => 'display_link',
+ 'display_id' => 'widget',
+ 'label' => 'Grid',
+ 'plugin_id' => 'display_link',
+ 'empty' => TRUE,
+ ],
+ 'display_link_table' => [
+ 'id' => 'display_link_table',
+ 'table' => 'views',
+ 'field' => 'display_link',
+ 'display_id' => 'widget_table',
+ 'label' => 'Table',
+ 'plugin_id' => 'display_link',
+ 'empty' => TRUE,
+ ],
+ ];
+ $grid_display->overrideOption('header', $display_links);
+ $table_display->overrideOption('header', $display_links);
+
+ $view->save();
+}
+
+/**
+ * Create the 'media_library' image style if necessary.
+ */
+function media_library_post_update_add_media_library_image_style() {
+ // Bail out early if the image style was already created by
+ // media_library_update_8701(), or manually by the site owner.
+ if (ImageStyle::load('media_library')) {
+ return;
+ }
+
+ $image_style = ImageStyle::create([
+ 'name' => 'media_library',
+ 'label' => 'Media Library (220x220)',
+ ]);
+ // Add a scale effect.
+ $image_style->addImageEffect([
+ 'id' => 'image_scale',
+ 'weight' => 0,
+ 'data' => [
+ 'width' => 220,
+ 'height' => 220,
+ 'upscale' => FALSE,
+ ],
+ ]);
+ $image_style->save();
+
+ return t('The %label image style has been created successfully.', ['%label' => 'Media Library (220x220)']);
+}
+
+/**
+ * Add a status extra filter to the media library view default display.
+ */
+function media_library_post_update_add_status_extra_filter() {
+ $view = Views::getView('media_library');
+
+ if (!$view) {
+ return t('The media_library view could not be updated because it has been deleted. The Media Library module needs this view in order to work properly. Uninstall and reinstall the module so the view will be re-created.');
+ }
+
+ // Fetch the filters from the default display and add the new 'status_extra'
+ // filter if it does not yet exist.
+ $default_display = $view->getDisplay();
+ $filters = $default_display->getOption('filters');
+
+ if (!isset($filters['status_extra'])) {
+ $filters['status_extra'] = [
+ 'group_info' => [
+ 'widget' => 'select',
+ 'group_items' => [],
+ 'multiple' => FALSE,
+ 'description' => '',
+ 'default_group_multiple' => [],
+ 'default_group' => 'All',
+ 'label' => '',
+ 'identifier' => '',
+ 'optional' => TRUE,
+ 'remember' => FALSE,
+ ],
+ 'group' => 1,
+ 'relationship' => 'none',
+ 'exposed' => FALSE,
+ 'expose' => [
+ 'use_operator' => FALSE,
+ 'remember' => FALSE,
+ 'operator_id' => '',
+ 'multiple' => FALSE,
+ 'description' => '',
+ 'required' => FALSE,
+ 'label' => '',
+ 'operator_limit_selection' => FALSE,
+ 'operator' => '',
+ 'identifier' => '',
+ 'operator_list' => [],
+ 'remember_roles' => [RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID],
+ ],
+ 'entity_type' => 'media',
+ 'value' => '',
+ 'field' => 'status_extra',
+ 'is_grouped' => FALSE,
+ 'admin_label' => '',
+ 'operator' => '=',
+ 'table' => 'media_field_data',
+ 'plugin_id' => 'media_status',
+ 'id' => 'status_extra',
+ 'group_type' => 'group',
+ ];
+ $default_display->setOption('filters', $filters);
+ $view->save();
+
+ return t("The 'Published status or admin user' filter was added to the %label view.", [
+ '%label' => $view->storage->label(),
+ ]);
+ }
+}
+
+/**
+ * Add edit and delete button to media library view page display.
+ */
+function media_library_post_update_add_buttons_to_page_view() {
+ $view = Views::getView('media_library');
+ if (!$view) {
+ return;
+ }
+
+ $display = &$view->storage->getDisplay('page');
+ if ($display) {
+ // Fetch the fields from the page display, if the fields are not yet
+ // overridden, get the fields from the default display.
+ if (empty($display['display_options']['fields'])) {
+ $defaults = $view->storage->getDisplay('default');
+ $display['display_options']['fields'] = $defaults['display_options']['fields'];
+ // Override the fields for the page display.
+ $display['display_options']['defaults']['fields'] = FALSE;
+ }
+
+ $fields = $display['display_options']['fields'];
+
+ // Check if the name field already exists and add if it doesn't.
+ if (!isset($fields['name'])) {
+ $fields['name'] = [
+ 'id' => 'name',
+ 'table' => 'media_field_data',
+ 'field' => 'name',
+ 'relationship' => 'none',
+ 'group_type' => 'group',
+ 'admin_label' => '',
+ 'label' => '',
+ 'exclude' => TRUE,
+ 'alter' => [
+ 'alter_text' => FALSE,
+ 'text' => '',
+ 'make_link' => FALSE,
+ 'path' => '',
+ 'absolute' => FALSE,
+ 'external' => FALSE,
+ 'replace_spaces' => FALSE,
+ 'path_case' => 'none',
+ 'trim_whitespace' => FALSE,
+ 'alt' => '',
+ 'rel' => '',
+ 'link_class' => '',
+ 'prefix' => '',
+ 'suffix' => '',
+ 'target' => '',
+ 'nl2br' => FALSE,
+ 'max_length' => 0,
+ 'word_boundary' => TRUE,
+ 'ellipsis' => TRUE,
+ 'more_link' => FALSE,
+ 'more_link_text' => '',
+ 'more_link_path' => '',
+ 'strip_tags' => FALSE,
+ 'trim' => FALSE,
+ 'preserve_tags' => '',
+ 'html' => FALSE,
+ ],
+ 'element_type' => '',
+ 'element_class' => '',
+ 'element_label_type' => '',
+ 'element_label_class' => '',
+ 'element_label_colon' => FALSE,
+ 'element_wrapper_type' => '',
+ 'element_wrapper_class' => '',
+ 'element_default_classes' => TRUE,
+ 'empty' => '',
+ 'hide_empty' => FALSE,
+ 'empty_zero' => FALSE,
+ 'hide_alter_empty' => TRUE,
+ 'click_sort_column' => 'value',
+ 'type' => 'string',
+ 'settings' => [
+ 'link_to_entity' => FALSE,
+ ],
+ 'group_column' => 'value',
+ 'group_columns' => [],
+ 'group_rows' => TRUE,
+ 'delta_limit' => 0,
+ 'delta_offset' => 0,
+ 'delta_reversed' => FALSE,
+ 'delta_first_last' => FALSE,
+ 'multi_type' => 'separator',
+ 'separator' => ', ',
+ 'field_api_classes' => FALSE,
+ 'entity_type' => 'media',
+ 'entity_field' => 'name',
+ 'plugin_id' => 'field',
+ ];
+ }
+
+ // Check if the edit link field already exists and add if it doesn't.
+ if (!isset($fields['edit_media'])) {
+ $fields['edit_media'] = [
+ 'id' => 'edit_media',
+ 'table' => 'media',
+ 'field' => 'edit_media',
+ 'relationship' => 'none',
+ 'group_type' => 'group',
+ 'admin_label' => '',
+ 'label' => '',
+ 'exclude' => FALSE,
+ 'alter' => [
+ 'alter_text' => TRUE,
+ 'text' => 'Edit {{ name }}',
+ 'make_link' => TRUE,
+ 'path' => '',
+ 'absolute' => FALSE,
+ 'external' => FALSE,
+ 'replace_spaces' => FALSE,
+ 'path_case' => 'none',
+ 'trim_whitespace' => FALSE,
+ 'alt' => 'Edit {{ name }}',
+ 'rel' => '',
+ 'link_class' => 'media-library-item__edit',
+ 'prefix' => '',
+ 'suffix' => '',
+ 'target' => '',
+ 'nl2br' => FALSE,
+ 'max_length' => 0,
+ 'word_boundary' => TRUE,
+ 'ellipsis' => TRUE,
+ 'more_link' => FALSE,
+ 'more_link_text' => '',
+ 'more_link_path' => '',
+ 'strip_tags' => FALSE,
+ 'trim' => FALSE,
+ 'preserve_tags' => '',
+ 'html' => FALSE,
+ ],
+ 'element_type' => '',
+ 'element_class' => '',
+ 'element_label_type' => '',
+ 'element_label_class' => '',
+ 'element_label_colon' => FALSE,
+ 'element_wrapper_type' => '0',
+ 'element_wrapper_class' => '',
+ 'element_default_classes' => FALSE,
+ 'empty' => '',
+ 'hide_empty' => FALSE,
+ 'empty_zero' => FALSE,
+ 'hide_alter_empty' => TRUE,
+ 'text' => 'Edit',
+ 'output_url_as_text' => FALSE,
+ 'absolute' => FALSE,
+ 'entity_type' => 'media',
+ 'plugin_id' => 'entity_link_edit',
+ ];
+ }
+
+ // Check if the delete link field already exists and add if it doesn't.
+ if (!isset($fields['delete_media'])) {
+ $fields['delete_media'] = [
+ 'id' => 'delete_media',
+ 'table' => 'media',
+ 'field' => 'delete_media',
+ 'relationship' => 'none',
+ 'group_type' => 'group',
+ 'admin_label' => '',
+ 'label' => '',
+ 'exclude' => FALSE,
+ 'alter' => [
+ 'alter_text' => TRUE,
+ 'text' => 'Delete {{ name }}',
+ 'make_link' => TRUE,
+ 'path' => '',
+ 'absolute' => FALSE,
+ 'external' => FALSE,
+ 'replace_spaces' => FALSE,
+ 'path_case' => 'none',
+ 'trim_whitespace' => FALSE,
+ 'alt' => 'Delete {{ name }}',
+ 'rel' => '',
+ 'link_class' => 'media-library-item__remove',
+ 'prefix' => '',
+ 'suffix' => '',
+ 'target' => '',
+ 'nl2br' => FALSE,
+ 'max_length' => 0,
+ 'word_boundary' => TRUE,
+ 'ellipsis' => TRUE,
+ 'more_link' => FALSE,
+ 'more_link_text' => '',
+ 'more_link_path' => '',
+ 'strip_tags' => FALSE,
+ 'trim' => FALSE,
+ 'preserve_tags' => '',
+ 'html' => FALSE,
+ ],
+ 'element_type' => '',
+ 'element_class' => '',
+ 'element_label_type' => '',
+ 'element_label_class' => '',
+ 'element_label_colon' => FALSE,
+ 'element_wrapper_type' => '0',
+ 'element_wrapper_class' => '',
+ 'element_default_classes' => FALSE,
+ 'empty' => '',
+ 'hide_empty' => FALSE,
+ 'empty_zero' => FALSE,
+ 'hide_alter_empty' => TRUE,
+ 'text' => 'Delete',
+ 'output_url_as_text' => FALSE,
+ 'absolute' => FALSE,
+ 'entity_type' => 'media',
+ 'plugin_id' => 'entity_link_delete',
+ ];
+ }
+
+ // Move the rendered entity field to the last position for accessibility.
+ $rendered_entity = $fields['rendered_entity'];
+ unset($fields['rendered_entity']);
+ $fields['rendered_entity'] = $rendered_entity;
+
+ $display['display_options']['fields'] = $fields;
+ $view->storage->save(TRUE);
+ }
+}
+
+/**
+ * Add non js prefixed classes to checkboxes if not present.
+ *
+ * Note the inclusion of "update_8001" in the function name. This ensures the
+ * function is executed after media_library_post_update_table_display(), as
+ * hook_post_update_NAME() implementations within the same file are executed in
+ * alphanumeric order.
+ */
+function media_library_post_update_update_8001_checkbox_classes() {
+ $view = Views::getView('media_library');
+ if (!$view) {
+ return;
+ }
+ $display_items = [
+ [
+ 'display_id' => 'default',
+ 'option' => 'element_class',
+ 'field' => 'media_bulk_form',
+ ],
+ [
+ 'display_id' => 'page',
+ 'option' => 'element_class',
+ 'field' => 'media_bulk_form',
+ ],
+ [
+ 'display_id' => 'widget',
+ 'option' => 'element_wrapper_class',
+ 'field' => 'media_library_select_form',
+ ],
+ [
+ 'display_id' => 'widget_table',
+ 'option' => 'element_wrapper_class',
+ 'field' => 'media_library_select_form',
+ ],
+ ];
+ foreach ($display_items as $item) {
+ $display_id = $item['display_id'];
+ $option = $item['option'];
+ $field = $item['field'];
+ $display = &$view->storage->getDisplay($display_id);
+
+ // Only proceed if the display, field and option exist.
+ if (!$display || !isset($display['display_options']['fields'][$field][$option])) {
+ continue;
+ }
+ $classes = $display['display_options']['fields'][$field][$option];
+ $classes_array = preg_split('/\s+/', $classes);
+ if (!in_array('media-library-item__click-to-select-checkbox', $classes_array, TRUE)) {
+ $display['display_options']['fields'][$field][$option] = "$classes media-library-item__click-to-select-checkbox";
+ $view->save();
+ }
+ }
+}
+
+/**
+ * Sets /admin/content/media to the table display of the 'media' view.
+ */
+function media_library_post_update_default_administrative_list_to_table_display() {
+ $view = Views::getView('media');
+ if ($view) {
+ $display = &$view->storage->getDisplay('media_page_list');
+
+ if ($display && $display['display_options']['path'] === 'admin/content/media-table') {
+ $display['display_options']['path'] = 'admin/content/media';
+ $view->storage->save();
+ }
+ }
+
+ $view = Views::getView('media_library');
+ if (!$view) {
+ return;
+ }
+ $display = &$view->storage->getDisplay('page');
+ if ($display && $display['display_options']['path'] === 'admin/content/media') {
+ $display['display_options']['path'] .= '-grid';
+
+ // Only delete the menu settings if they have not been changed.
+ if (isset($display['display_options']['menu']) && $display['display_options']['menu']['type'] === 'tab' && $display['display_options']['menu']['title'] === 'Media') {
+ unset($display['display_options']['menu']);
+ }
+ $view->storage->save();
+ }
+}
+
+/**
+ * Add langcode filters to media library view displays.
+ */
+function media_library_post_update_add_langcode_filters() {
+ $view = Views::getView('media_library');
+
+ if (!$view) {
+ return;
+ }
+
+ // Fetch the filters from the default display and add the new 'langcode'
+ // filter if it does not yet exist.
+ $default_display = $view->getDisplay();
+ $filters = $default_display->getOption('filters');
+
+ $added_langcode = FALSE;
+ if (!isset($filters['langcode'])) {
+ $filters['langcode'] = [
+ 'id' => 'langcode',
+ 'table' => 'media_field_data',
+ 'field' => 'langcode',
+ 'relationship' => 'none',
+ 'group_type' => 'group',
+ 'admin_label' => '',
+ 'operator' => 'in',
+ 'value' => [],
+ 'group' => 1,
+ 'exposed' => TRUE,
+ 'expose' => [
+ 'use_operator' => FALSE,
+ 'remember' => FALSE,
+ 'operator_id' => 'langcode_op',
+ 'multiple' => FALSE,
+ 'description' => '',
+ 'required' => FALSE,
+ 'reduce' => FALSE,
+ 'label' => 'Language',
+ 'operator_limit_selection' => FALSE,
+ 'operator' => 'langcode_op',
+ 'identifier' => 'langcode',
+ 'operator_list' => [],
+ 'remember_roles' => [
+ 'administrator' => '0',
+ 'authenticated' => 'authenticated',
+ 'anonymous' => '0',
+ ],
+ ],
+ 'is_grouped' => FALSE,
+ 'group_info' => [
+ 'widget' => 'select',
+ 'group_items' => [],
+ 'multiple' => FALSE,
+ 'description' => '',
+ 'default_group_multiple' => [],
+ 'default_group' => 'All',
+ 'label' => '',
+ 'identifier' => '',
+ 'optional' => TRUE,
+ 'remember' => FALSE,
+ ],
+ 'entity_type' => 'media',
+ 'entity_field' => 'langcode',
+ 'plugin_id' => 'language',
+ ];
+ $default_display->setOption('filters', $filters);
+ $added_langcode = TRUE;
+ }
+
+ $added_default_langcode_displays = [];
+ foreach (['widget', 'widget_table'] as $display_id) {
+ // Check if the display still exists, or else skip it.
+ if (!$view->displayHandlers->has($display_id)) {
+ continue;
+ }
+
+ $view->setDisplay($display_id);
+ $display = $view->getDisplay();
+
+ // Fetch the filters from the display and add the 'default_langcode' filter
+ // if it does not yet exist.
+ $filters = $display->getOption('filters');
+ if (!isset($filters['default_langcode'])) {
+ $filters['default_langcode'] = [
+ 'id' => 'default_langcode',
+ 'table' => 'media_field_data',
+ 'field' => 'default_langcode',
+ 'relationship' => 'none',
+ 'group_type' => 'group',
+ 'admin_label' => '',
+ 'operator' => '=',
+ 'value' => '1',
+ 'group' => 1,
+ 'exposed' => FALSE,
+ 'expose' => [
+ 'use_operator' => FALSE,
+ 'remember' => FALSE,
+ 'operator_id' => '',
+ 'multiple' => FALSE,
+ 'description' => '',
+ 'required' => FALSE,
+ 'label' => '',
+ 'operator_limit_selection' => FALSE,
+ 'operator' => '',
+ 'identifier' => '',
+ 'operator_list' => [],
+ 'remember_roles' => [
+ RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID,
+ ],
+ ],
+ 'is_grouped' => FALSE,
+ 'group_info' => [
+ 'widget' => 'select',
+ 'group_items' => [],
+ 'multiple' => FALSE,
+ 'description' => '',
+ 'default_group_multiple' => [],
+ 'default_group' => 'All',
+ 'label' => '',
+ 'identifier' => '',
+ 'optional' => TRUE,
+ 'remember' => FALSE,
+ ],
+ 'entity_type' => 'media',
+ 'entity_field' => 'default_langcode',
+ 'plugin_id' => 'boolean',
+ ];
+ $display->setOption('filters', $filters);
+
+ // Change the rendering language of the rows to the interface language.
+ $display->setOption('rendering_language', '***LANGUAGE_language_interface***');
+
+ $added_default_langcode_displays[] = $view->storage->get('display')[$display_id]['display_title'];
+ }
+ }
+
+ if ($added_langcode && $added_default_langcode_displays) {
+ $view->save();
+ return t("The 'Language' filter was added to the default display of the %label view and the 'Default translation' filter was added to the following displays: %displays", [
+ '%label' => $view->storage->label(),
+ '%displays' => implode(', ', $added_default_langcode_displays),
+ ]);
+ }
+
+ if ($added_langcode) {
+ $view->save();
+ return t("The 'Language' filter was added to the default display of the %label view.", [
+ '%label' => $view->storage->label(),
+ '%displays' => implode(', ', $added_default_langcode_displays),
+ ]);
+ }
+
+ if ($added_default_langcode_displays) {
+ $view->save();
+ return t("The 'Default translation' filter was added to the following %label view displays: %displays", [
+ '%label' => $view->storage->label(),
+ '%displays' => implode(', ', $added_default_langcode_displays),
+ ]);
+ }
+}
diff --git a/core/modules/menu_link_content/menu_link_content.post_update.php b/core/modules/menu_link_content/menu_link_content.post_update.php
new file mode 100644
index 0000000000..0c0a64388e
--- /dev/null
+++ b/core/modules/menu_link_content/menu_link_content.post_update.php
@@ -0,0 +1,103 @@
+getEntityType('menu_link_content');
+ $field_storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions('menu_link_content');
+
+ // Update the entity type definition.
+ $entity_keys = $entity_type->getKeys();
+ $entity_keys['revision'] = 'revision_id';
+ $entity_keys['revision_translation_affected'] = 'revision_translation_affected';
+ $entity_type->set('entity_keys', $entity_keys);
+ $entity_type->set('revision_table', 'menu_link_content_revision');
+ $entity_type->set('revision_data_table', 'menu_link_content_field_revision');
+ $revision_metadata_keys = [
+ 'revision_default' => 'revision_default',
+ 'revision_user' => 'revision_user',
+ 'revision_created' => 'revision_created',
+ 'revision_log_message' => 'revision_log_message',
+ ];
+ $entity_type->set('revision_metadata_keys', $revision_metadata_keys);
+
+ // Update the field storage definitions and add the new ones required by a
+ // revisionable entity type.
+ $field_storage_definitions['langcode']->setRevisionable(TRUE);
+ $field_storage_definitions['title']->setRevisionable(TRUE);
+ $field_storage_definitions['description']->setRevisionable(TRUE);
+ $field_storage_definitions['link']->setRevisionable(TRUE);
+ $field_storage_definitions['external']->setRevisionable(TRUE);
+ $field_storage_definitions['enabled']->setRevisionable(TRUE);
+ $field_storage_definitions['changed']->setRevisionable(TRUE);
+
+ $field_storage_definitions['revision_id'] = BaseFieldDefinition::create('integer')
+ ->setName('revision_id')
+ ->setTargetEntityTypeId('menu_link_content')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Revision ID'))
+ ->setReadOnly(TRUE)
+ ->setSetting('unsigned', TRUE);
+
+ $field_storage_definitions['revision_default'] = BaseFieldDefinition::create('boolean')
+ ->setName('revision_default')
+ ->setTargetEntityTypeId('menu_link_content')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Default revision'))
+ ->setDescription(new TranslatableMarkup('A flag indicating whether this was a default revision when it was saved.'))
+ ->setStorageRequired(TRUE)
+ ->setInternal(TRUE)
+ ->setTranslatable(FALSE)
+ ->setRevisionable(TRUE);
+
+ $field_storage_definitions['revision_translation_affected'] = BaseFieldDefinition::create('boolean')
+ ->setName('revision_translation_affected')
+ ->setTargetEntityTypeId('menu_link_content')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Revision translation affected'))
+ ->setDescription(new TranslatableMarkup('Indicates if the last edit of a translation belongs to current revision.'))
+ ->setReadOnly(TRUE)
+ ->setRevisionable(TRUE)
+ ->setTranslatable(TRUE);
+
+ $field_storage_definitions['revision_created'] = BaseFieldDefinition::create('created')
+ ->setName('revision_created')
+ ->setTargetEntityTypeId('menu_link_content')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Revision create time'))
+ ->setDescription(new TranslatableMarkup('The time that the current revision was created.'))
+ ->setRevisionable(TRUE);
+ $field_storage_definitions['revision_user'] = BaseFieldDefinition::create('entity_reference')
+ ->setName('revision_user')
+ ->setTargetEntityTypeId('menu_link_content')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Revision user'))
+ ->setDescription(new TranslatableMarkup('The user ID of the author of the current revision.'))
+ ->setSetting('target_type', 'user')
+ ->setRevisionable(TRUE);
+ $field_storage_definitions['revision_log_message'] = BaseFieldDefinition::create('string_long')
+ ->setName('revision_log_message')
+ ->setTargetEntityTypeId('menu_link_content')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Revision log message'))
+ ->setDescription(new TranslatableMarkup('Briefly describe the changes you have made.'))
+ ->setRevisionable(TRUE)
+ ->setDefaultValue('');
+
+ $definition_update_manager->updateFieldableEntityType($entity_type, $field_storage_definitions, $sandbox);
+
+ return t('Custom menu links have been converted to be revisionable.');
+}
diff --git a/core/modules/migrate_drupal/migrate_drupal.post_update.php b/core/modules/migrate_drupal/migrate_drupal.post_update.php
new file mode 100644
index 0000000000..b02d957a81
--- /dev/null
+++ b/core/modules/migrate_drupal/migrate_drupal.post_update.php
@@ -0,0 +1,15 @@
+condition('targetEntityType', 'node');
+ $ids = $query->execute();
+ $form_displays = EntityFormDisplay::loadMultiple($ids);
+
+ // Assign status settings for each 'node' target entity types with 'default'
+ // form mode.
+ foreach ($form_displays as $id => $form_display) {
+ /** @var \Drupal\Core\Entity\Display\EntityDisplayInterface $form_display */
+ $form_display->setComponent('status', [
+ 'type' => 'boolean_checkbox',
+ 'settings' => [
+ 'display_label' => TRUE,
+ ],
+ ])->save();
+ }
+}
+
+/**
+ * Clear caches due to updated views data.
+ */
+function node_post_update_node_revision_views_data() {
+ // Empty post-update hook.
+}
diff --git a/core/modules/path/path.post_update.php b/core/modules/path/path.post_update.php
new file mode 100644
index 0000000000..b11ec8f935
--- /dev/null
+++ b/core/modules/path/path.post_update.php
@@ -0,0 +1,23 @@
+getEntityType('language_content_settings')) {
+ ContentLanguageSettings::loadByEntityTypeBundle('path_alias', 'path_alias')
+ ->setDefaultLangcode(LanguageInterface::LANGCODE_NOT_SPECIFIED)
+ ->setLanguageAlterable(TRUE)
+ ->trustData()
+ ->save();
+ }
+}
diff --git a/core/modules/responsive_image/responsive_image.post_update.php b/core/modules/responsive_image/responsive_image.post_update.php
new file mode 100644
index 0000000000..de9424f026
--- /dev/null
+++ b/core/modules/responsive_image/responsive_image.post_update.php
@@ -0,0 +1,23 @@
+getDependencies();
+ $new_dependencies = $entity_view_display->calculateDependencies()->getDependencies();
+ if ($old_dependencies !== $new_dependencies) {
+ $entity_view_display->save();
+ }
+ });
+}
diff --git a/core/modules/rest/rest.post_update.php b/core/modules/rest/rest.post_update.php
new file mode 100644
index 0000000000..e1e1d20301
--- /dev/null
+++ b/core/modules/rest/rest.post_update.php
@@ -0,0 +1,70 @@
+get('rest_update_8201_resources', []);
+ foreach ($resources as $key => $resource) {
+ $resource = RestResourceConfig::create([
+ 'id' => str_replace(':', '.', $key),
+ 'granularity' => RestResourceConfigInterface::METHOD_GRANULARITY,
+ 'configuration' => $resource,
+ ]);
+ $resource->save();
+ }
+}
+
+/**
+ * Simplify method-granularity REST resource config to resource-granularity.
+ *
+ * @see https://www.drupal.org/node/2721595
+ */
+function rest_post_update_resource_granularity() {
+ /** @var \Drupal\rest\RestResourceConfigInterface[] $resource_config_entities */
+ $resource_config_entities = RestResourceConfig::loadMultiple();
+
+ foreach ($resource_config_entities as $resource_config_entity) {
+ if ($resource_config_entity->get('granularity') === RestResourceConfigInterface::METHOD_GRANULARITY) {
+ $configuration = $resource_config_entity->get('configuration');
+
+ $format_and_auth_configuration = [];
+ foreach (array_keys($configuration) as $method) {
+ $format_and_auth_configuration['format'][$method] = implode(',', $configuration[$method]['supported_formats']);
+ $format_and_auth_configuration['auth'][$method] = implode(',', $configuration[$method]['supported_auth']);
+ }
+
+ // If each method has the same formats and the same authentication
+ // providers configured, convert it to 'granularity: resource', which has
+ // a simpler/less verbose configuration.
+ if (count(array_unique($format_and_auth_configuration['format'])) === 1 && count(array_unique($format_and_auth_configuration['auth'])) === 1) {
+ $first_method = array_keys($configuration)[0];
+ $resource_config_entity->set('configuration', [
+ 'methods' => array_keys($configuration),
+ 'formats' => $configuration[$first_method]['supported_formats'],
+ 'authentication' => $configuration[$first_method]['supported_auth'],
+ ]);
+ $resource_config_entity->set('granularity', RestResourceConfigInterface::RESOURCE_GRANULARITY);
+ $resource_config_entity->save();
+ }
+ }
+ }
+}
+
+/**
+ * Clear caches due to changes in route definitions.
+ */
+function rest_post_update_161923() {
+ // Empty post-update hook.
+}
diff --git a/core/modules/search/search.post_update.php b/core/modules/search/search.post_update.php
new file mode 100644
index 0000000000..a6b1fd968b
--- /dev/null
+++ b/core/modules/search/search.post_update.php
@@ -0,0 +1,24 @@
+moduleExists('block')) {
+ // Early exit when block module disabled.
+ return;
+ }
+ \Drupal::classResolver(ConfigEntityUpdater::class)
+ ->update($sandbox, 'block', function (BlockInterface $block) {
+ // Save search block to set default search page from plugin.
+ return $block->getPluginId() === 'search_form_block';
+ });
+}
diff --git a/core/modules/system/system.post_update.php b/core/modules/system/system.post_update.php
new file mode 100644
index 0000000000..114d289120
--- /dev/null
+++ b/core/modules/system/system.post_update.php
@@ -0,0 +1,242 @@
+listAll();
+ $sandbox['count'] = count($sandbox['config_names']);
+ }
+ /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
+ $config_manager = \Drupal::service('config.manager');
+
+ $count = 0;
+ foreach ($sandbox['config_names'] as $key => $config_name) {
+ if ($entity = $config_manager->loadConfigEntityByName($config_name)) {
+ $entity->save();
+ }
+ unset($sandbox['config_names'][$key]);
+ $count++;
+ // Do 50 at a time.
+ if ($count == 50) {
+ break;
+ }
+ }
+
+ $sandbox['#finished'] = empty($sandbox['config_names']) ? 1 : ($sandbox['count'] - count($sandbox['config_names'])) / $sandbox['count'];
+ return t('Configuration dependencies recalculated');
+}
+
+/**
+ * Update entity displays to contain the region for each field.
+ */
+function system_post_update_add_region_to_entity_displays() {
+ $entity_save = function (EntityDisplayInterface $entity) {
+ // preSave() will fill in the correct region based on the 'type'.
+ $entity->save();
+ };
+ array_map($entity_save, EntityViewDisplay::loadMultiple());
+ array_map($entity_save, EntityFormDisplay::loadMultiple());
+}
+
+/**
+ * Force caches using hashes to be cleared (Twig, render cache, etc.).
+ */
+function system_post_update_hashes_clear_cache() {
+ // Empty post-update hook.
+}
+
+/**
+ * Force plugin definitions to be cleared.
+ *
+ * @see https://www.drupal.org/node/2802663
+ */
+function system_post_update_timestamp_plugins() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear caches to ensure Classy's message library is always added.
+ */
+function system_post_update_classy_message_library() {
+ // Empty post-update hook.
+}
+
+/**
+ * Force field type plugin definitions to be cleared.
+ *
+ * @see https://www.drupal.org/node/2403703
+ */
+function system_post_update_field_type_plugins() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear caches due to schema changes in core.entity.schema.yml.
+ */
+function system_post_update_field_formatter_entity_schema() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear the library cache and ensure aggregate files are regenerated.
+ */
+function system_post_update_fix_jquery_extend() {
+ // Empty post-update hook.
+}
+
+/**
+ * Change plugin IDs of actions.
+ */
+function system_post_update_change_action_plugins() {
+ $old_new_action_id_map = [
+ 'comment_publish_action' => 'entity:publish_action:comment',
+ 'comment_unpublish_action' => 'entity:unpublish_action:comment',
+ 'comment_save_action' => 'entity:save_action:comment',
+ 'node_publish_action' => 'entity:publish_action:node',
+ 'node_unpublish_action' => 'entity:unpublish_action:node',
+ 'node_save_action' => 'entity:save_action:node',
+ ];
+
+ /** @var \Drupal\system\Entity\Action[] $actions */
+ $actions = \Drupal::entityTypeManager()->getStorage('action')->loadMultiple();
+ foreach ($actions as $action) {
+ if (isset($old_new_action_id_map[$action->getPlugin()->getPluginId()])) {
+ $action->setPlugin($old_new_action_id_map[$action->getPlugin()->getPluginId()]);
+ $action->save();
+ }
+ }
+}
+
+/**
+ * Change plugin IDs of delete actions.
+ */
+function system_post_update_change_delete_action_plugins() {
+ $old_new_action_id_map = [
+ 'comment_delete_action' => 'entity:delete_action:comment',
+ 'node_delete_action' => 'entity:delete_action:node',
+ ];
+
+ /** @var \Drupal\system\Entity\Action[] $actions */
+ $actions = \Drupal::entityTypeManager()->getStorage('action')->loadMultiple();
+ foreach ($actions as $action) {
+ if (isset($old_new_action_id_map[$action->getPlugin()->getPluginId()])) {
+ $action->setPlugin($old_new_action_id_map[$action->getPlugin()->getPluginId()]);
+ $action->save();
+ }
+ }
+}
+
+/**
+ * Force cache clear for language item callback.
+ *
+ * @see https://www.drupal.org/node/2851736
+ */
+function system_post_update_language_item_callback() {
+ // Empty post-update hook.
+}
+
+/**
+ * Update all entity displays that contain extra fields.
+ */
+function system_post_update_extra_fields(&$sandbox = NULL) {
+ $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
+ $entity_field_manager = \Drupal::service('entity_field.manager');
+
+ $callback = function (EntityDisplayInterface $display) use ($entity_field_manager) {
+ $display_context = $display instanceof EntityViewDisplayInterface ? 'display' : 'form';
+ $extra_fields = $entity_field_manager->getExtraFields($display->getTargetEntityTypeId(), $display->getTargetBundle());
+
+ // If any extra fields are used as a component, resave the display with the
+ // updated component information.
+ $needs_save = FALSE;
+ if (!empty($extra_fields[$display_context])) {
+ foreach ($extra_fields[$display_context] as $name => $extra_field) {
+ if ($component = $display->getComponent($name)) {
+ $display->setComponent($name, $component);
+ $needs_save = TRUE;
+ }
+ }
+ }
+ return $needs_save;
+ };
+
+ $config_entity_updater->update($sandbox, 'entity_form_display', $callback);
+ $config_entity_updater->update($sandbox, 'entity_view_display', $callback);
+}
+
+/**
+ * Force cache clear to ensure aggregated JavaScript files are regenerated.
+ *
+ * @see https://www.drupal.org/project/drupal/issues/2995570
+ */
+function system_post_update_states_clear_cache() {
+ // Empty post-update hook.
+}
+
+/**
+ * Initialize 'expand_all_items' values to system_menu_block.
+ */
+function system_post_update_add_expand_all_items_key_in_system_menu_block(&$sandbox = NULL) {
+ if (!\Drupal::moduleHandler()->moduleExists('block')) {
+ return;
+ }
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'block', function ($block) {
+ return strpos($block->getPluginId(), 'system_menu_block:') === 0;
+ });
+}
+
+/**
+ * Clear the menu cache.
+ *
+ * @see https://www.drupal.org/project/drupal/issues/3044364
+ */
+function system_post_update_clear_menu_cache() {
+ // Empty post-update hook.
+}
+
+/**
+ * Clear the schema cache.
+ */
+function system_post_update_layout_plugin_schema_change() {
+ // Empty post-update hook.
+}
+
+/**
+ * Populate the new 'match_limit' setting for the ER autocomplete widget.
+ */
+function system_post_update_entity_reference_autocomplete_match_limit(&$sandbox = NULL) {
+ $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
+ /** @var \Drupal\Core\Field\WidgetPluginManager $field_widget_manager */
+ $field_widget_manager = \Drupal::service('plugin.manager.field.widget');
+
+ $callback = function (EntityDisplayInterface $display) use ($field_widget_manager) {
+ foreach ($display->getComponents() as $field_name => $component) {
+ if (empty($component['type'])) {
+ continue;
+ }
+
+ $plugin_definition = $field_widget_manager->getDefinition($component['type'], FALSE);
+ if (is_a($plugin_definition['class'], EntityReferenceAutocompleteWidget::class, TRUE)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ };
+
+ $config_entity_updater->update($sandbox, 'entity_form_display', $callback);
+}
diff --git a/core/modules/taxonomy/taxonomy.post_update.php b/core/modules/taxonomy/taxonomy.post_update.php
new file mode 100644
index 0000000000..6b1c6bde08
--- /dev/null
+++ b/core/modules/taxonomy/taxonomy.post_update.php
@@ -0,0 +1,255 @@
+moduleExists('views')) {
+ return;
+ }
+
+ $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+ $entity_type = $definition_update_manager->getEntityType('taxonomy_term');
+ $published_key = $entity_type->getKey('published');
+
+ $status_filter = [
+ 'id' => 'status',
+ 'table' => 'taxonomy_term_field_data',
+ 'field' => $published_key,
+ 'relationship' => 'none',
+ 'group_type' => 'group',
+ 'admin_label' => '',
+ 'operator' => '=',
+ 'value' => '1',
+ 'group' => 1,
+ 'exposed' => FALSE,
+ 'expose' => [
+ 'operator_id' => '',
+ 'label' => '',
+ 'description' => '',
+ 'use_operator' => FALSE,
+ 'operator' => '',
+ 'identifier' => '',
+ 'required' => FALSE,
+ 'remember' => FALSE,
+ 'multiple' => FALSE,
+ 'remember_roles' => [
+ 'authenticated' => 'authenticated',
+ 'anonymous' => '0',
+ 'administrator' => '0',
+ ],
+ ],
+ 'is_grouped' => FALSE,
+ 'group_info' => [
+ 'label' => '',
+ 'description' => '',
+ 'identifier' => '',
+ 'optional' => TRUE,
+ 'widget' => 'select',
+ 'multiple' => FALSE,
+ 'remember' => FALSE,
+ 'default_group' => 'All',
+ 'default_group_multiple' => [],
+ 'group_items' => [],
+ ],
+ 'entity_type' => 'taxonomy_term',
+ 'entity_field' => $published_key,
+ 'plugin_id' => 'boolean',
+ ];
+
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($published_key, $status_filter) {
+ /** @var \Drupal\views\ViewEntityInterface $view */
+ // Only alter taxonomy term views.
+ if ($view->get('base_table') !== 'taxonomy_term_field_data') {
+ return FALSE;
+ }
+
+ $displays = $view->get('display');
+ foreach ($displays as $display_name => &$display) {
+ // Update any existing 'content_translation_status fields.
+ $fields = isset($display['display_options']['fields']) ? $display['display_options']['fields'] : [];
+ foreach ($fields as $id => $field) {
+ if (isset($field['field']) && $field['field'] == 'content_translation_status') {
+ $fields[$id]['field'] = $published_key;
+ }
+ }
+ $display['display_options']['fields'] = $fields;
+
+ // Update any existing 'content_translation_status sorts.
+ $sorts = isset($display['display_options']['sorts']) ? $display['display_options']['sorts'] : [];
+ foreach ($sorts as $id => $sort) {
+ if (isset($sort['field']) && $sort['field'] == 'content_translation_status') {
+ $sorts[$id]['field'] = $published_key;
+ }
+ }
+ $display['display_options']['sorts'] = $sorts;
+
+ // Update any existing 'content_translation_status' filters or add a new
+ // one if necessary.
+ $filters = isset($display['display_options']['filters']) ? $display['display_options']['filters'] : [];
+ $has_status_filter = FALSE;
+ foreach ($filters as $id => $filter) {
+ if (isset($filter['field']) && $filter['field'] == 'content_translation_status') {
+ $filters[$id]['field'] = $published_key;
+ $has_status_filter = TRUE;
+ }
+ }
+
+ if (!$has_status_filter) {
+ $status_filter['id'] = ViewExecutable::generateHandlerId($published_key, $filters);
+ $filters[$status_filter['id']] = $status_filter;
+ }
+ $display['display_options']['filters'] = $filters;
+ }
+ $view->set('display', $displays);
+
+ return TRUE;
+ });
+}
+
+/**
+ * Remove the 'hierarchy' property from vocabularies.
+ */
+function taxonomy_post_update_remove_hierarchy_from_vocabularies(&$sandbox = NULL) {
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'taxonomy_vocabulary', function () {
+ return TRUE;
+ });
+}
+
+/**
+ * Update taxonomy terms to be revisionable.
+ */
+function taxonomy_post_update_make_taxonomy_term_revisionable(&$sandbox) {
+ $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+ /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $last_installed_schema_repository */
+ $last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository');
+
+ $entity_type = $definition_update_manager->getEntityType('taxonomy_term');
+ $field_storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions('taxonomy_term');
+
+ // Update the entity type definition.
+ $entity_keys = $entity_type->getKeys();
+ $entity_keys['revision'] = 'revision_id';
+ $entity_keys['revision_translation_affected'] = 'revision_translation_affected';
+ $entity_type->set('entity_keys', $entity_keys);
+ $entity_type->set('revision_table', 'taxonomy_term_revision');
+ $entity_type->set('revision_data_table', 'taxonomy_term_field_revision');
+ $revision_metadata_keys = [
+ 'revision_default' => 'revision_default',
+ 'revision_user' => 'revision_user',
+ 'revision_created' => 'revision_created',
+ 'revision_log_message' => 'revision_log_message',
+ ];
+ $entity_type->set('revision_metadata_keys', $revision_metadata_keys);
+
+ // Update the field storage definitions and add the new ones required by a
+ // revisionable entity type.
+ $field_storage_definitions['langcode']->setRevisionable(TRUE);
+ $field_storage_definitions['name']->setRevisionable(TRUE);
+ $field_storage_definitions['description']->setRevisionable(TRUE);
+ $field_storage_definitions['changed']->setRevisionable(TRUE);
+
+ $field_storage_definitions['revision_id'] = BaseFieldDefinition::create('integer')
+ ->setName('revision_id')
+ ->setTargetEntityTypeId('taxonomy_term')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Revision ID'))
+ ->setReadOnly(TRUE)
+ ->setSetting('unsigned', TRUE);
+
+ $field_storage_definitions['revision_default'] = BaseFieldDefinition::create('boolean')
+ ->setName('revision_default')
+ ->setTargetEntityTypeId('taxonomy_term')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Default revision'))
+ ->setDescription(new TranslatableMarkup('A flag indicating whether this was a default revision when it was saved.'))
+ ->setStorageRequired(TRUE)
+ ->setInternal(TRUE)
+ ->setTranslatable(FALSE)
+ ->setRevisionable(TRUE);
+
+ $field_storage_definitions['revision_translation_affected'] = BaseFieldDefinition::create('boolean')
+ ->setName('revision_translation_affected')
+ ->setTargetEntityTypeId('taxonomy_term')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Revision translation affected'))
+ ->setDescription(new TranslatableMarkup('Indicates if the last edit of a translation belongs to current revision.'))
+ ->setReadOnly(TRUE)
+ ->setRevisionable(TRUE)
+ ->setTranslatable(TRUE);
+
+ $field_storage_definitions['revision_created'] = BaseFieldDefinition::create('created')
+ ->setName('revision_created')
+ ->setTargetEntityTypeId('taxonomy_term')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Revision create time'))
+ ->setDescription(new TranslatableMarkup('The time that the current revision was created.'))
+ ->setRevisionable(TRUE);
+ $field_storage_definitions['revision_user'] = BaseFieldDefinition::create('entity_reference')
+ ->setName('revision_user')
+ ->setTargetEntityTypeId('taxonomy_term')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Revision user'))
+ ->setDescription(new TranslatableMarkup('The user ID of the author of the current revision.'))
+ ->setSetting('target_type', 'user')
+ ->setRevisionable(TRUE);
+ $field_storage_definitions['revision_log_message'] = BaseFieldDefinition::create('string_long')
+ ->setName('revision_log_message')
+ ->setTargetEntityTypeId('taxonomy_term')
+ ->setTargetBundle(NULL)
+ ->setLabel(new TranslatableMarkup('Revision log message'))
+ ->setDescription(new TranslatableMarkup('Briefly describe the changes you have made.'))
+ ->setRevisionable(TRUE)
+ ->setDefaultValue('');
+
+ $definition_update_manager->updateFieldableEntityType($entity_type, $field_storage_definitions, $sandbox);
+
+ return t('Taxonomy terms have been converted to be revisionable.');
+}
+
+/**
+ * Add status with settings to all form displays for taxonomy entities.
+ */
+function taxonomy_post_update_configure_status_field_widget(&$sandbox = NULL) {
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'entity_form_display', function (EntityDisplayInterface $entity_form_display) {
+ // Only update taxonomy term entity form displays with no existing options
+ // for the status field.
+ if ($entity_form_display->getTargetEntityTypeId() == 'taxonomy_term' && empty($entity_form_display->getComponent('status'))) {
+ $entity_form_display->setComponent('status', [
+ 'type' => 'boolean_checkbox',
+ 'settings' => [
+ 'display_label' => TRUE,
+ ],
+ ]);
+ return TRUE;
+ };
+ return FALSE;
+ });
+}
diff --git a/core/modules/text/text.post_update.php b/core/modules/text/text.post_update.php
new file mode 100644
index 0000000000..5c98e26b00
--- /dev/null
+++ b/core/modules/text/text.post_update.php
@@ -0,0 +1,49 @@
+getComponents() as $field_name => $component) {
+ if (empty($component['type'])) {
+ continue;
+ }
+
+ $plugin_definition = $field_widget_manager->getDefinition($component['type'], FALSE);
+ if (is_a($plugin_definition['class'], TextareaWithSummaryWidget::class, TRUE)) {
+ $component['settings']['show_summary'] = FALSE;
+ $display->setComponent($field_name, $component);
+ $needs_save = TRUE;
+ }
+ }
+
+ return $needs_save;
+ };
+
+ $field_callback = function (FieldConfigInterface $field) {
+ if ($field->getType() !== 'text_with_summary') {
+ return FALSE;
+ }
+ $field->setSetting('required_summary', FALSE);
+ return TRUE;
+ };
+
+ $config_entity_updater->update($sandbox, 'entity_form_display', $widget_callback);
+ $config_entity_updater->update($sandbox, 'field_config', $field_callback);
+}
diff --git a/core/modules/user/user.post_update.php b/core/modules/user/user.post_update.php
new file mode 100644
index 0000000000..3f19b0c16f
--- /dev/null
+++ b/core/modules/user/user.post_update.php
@@ -0,0 +1,22 @@
+getPermissions();
+ sort($permissions);
+ if ($permissions !== $role->getPermissions()) {
+ $role->save();
+ }
+ };
+ array_map($entity_save, Role::loadMultiple());
+}
diff --git a/core/modules/views/views.post_update.php b/core/modules/views/views.post_update.php
new file mode 100644
index 0000000000..c949f81885
--- /dev/null
+++ b/core/modules/views/views.post_update.php
@@ -0,0 +1,438 @@
+getStorage('view')->loadMultiple();
+
+ /* @var \Drupal\views\Entity\View[] $views */
+ foreach ($views as $view) {
+ $displays = $view->get('display');
+ foreach (array_keys($displays) as $display_id) {
+ $display =& $view->getDisplay($display_id);
+ // Unset the cache_metadata key, so all cacheability metadata for the
+ // display is recalculated.
+ unset($display['cache_metadata']);
+ }
+ $view->save();
+ }
+
+}
+
+/**
+ * Update some views fields that were previously duplicated.
+ */
+function views_post_update_cleanup_duplicate_views_data() {
+ $config_factory = \Drupal::configFactory();
+ $ids = [];
+ $message = NULL;
+ $data_tables = [];
+ $base_tables = [];
+ $revision_tables = [];
+ $entities_by_table = [];
+ $duplicate_fields = [];
+ $handler_types = Views::getHandlerTypes();
+
+ /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
+ $entity_type_manager = \Drupal::service('entity_type.manager');
+ // This will allow us to create an index of all entity types of the site.
+ foreach ($entity_type_manager->getDefinitions() as $entity_type_id => $entity_type) {
+ // Store the entity keyed by base table. If it has a data table, use that as
+ // well.
+ if ($data_table = $entity_type->getDataTable()) {
+ $entities_by_table[$data_table] = $entity_type;
+ }
+ if ($base_table = $entity_type->getBaseTable()) {
+ $entities_by_table[$base_table] = $entity_type;
+ }
+
+ // The following code basically contains the same kind of logic as
+ // \Drupal\Core\Entity\Sql\SqlContentEntityStorage::initTableLayout() to
+ // prefetch all tables (base, data, revision, and revision data).
+ $base_tables[$entity_type_id] = $entity_type->getBaseTable() ?: $entity_type->id();
+ $revisionable = $entity_type->isRevisionable();
+
+ $revision_table = '';
+ if ($revisionable) {
+ $revision_table = $entity_type->getRevisionTable() ?: $entity_type->id() . '_revision';
+ }
+ $revision_tables[$entity_type_id] = $revision_table;
+
+ $translatable = $entity_type->isTranslatable();
+ $data_table = '';
+ // For example the data table just exists, when the entity type is
+ // translatable.
+ if ($translatable) {
+ $data_table = $entity_type->getDataTable() ?: $entity_type->id() . '_field_data';
+ }
+ $data_tables[$entity_type_id] = $data_table;
+
+ $duplicate_fields[$entity_type_id] = array_intersect_key($entity_type->getKeys(), array_flip(['id', 'revision', 'bundle']));
+ }
+
+ foreach ($config_factory->listAll('views.view.') as $view_config_name) {
+ $changed = FALSE;
+ $view = $config_factory->getEditable($view_config_name);
+
+ $displays = $view->get('display');
+ if (isset($entities_by_table[$view->get('base_table')])) {
+ $entity_type = $entities_by_table[$view->get('base_table')];
+ $entity_type_id = $entity_type->id();
+ $data_table = $data_tables[$entity_type_id];
+ $base_table = $base_tables[$entity_type_id];
+ $revision_table = $revision_tables[$entity_type_id];
+
+ if ($data_table) {
+ foreach ($displays as $display_name => &$display) {
+ foreach ($handler_types as $handler_type) {
+ if (!empty($display['display_options'][$handler_type['plural']])) {
+ foreach ($display['display_options'][$handler_type['plural']] as $field_name => &$field) {
+ $table = $field['table'];
+ if (($table === $base_table || $table === $revision_table) && in_array($field_name, $duplicate_fields[$entity_type_id])) {
+ $field['table'] = $data_table;
+ $changed = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ($changed) {
+ $view->set('display', $displays);
+ $view->save();
+ $ids[] = $view->get('id');
+ }
+ }
+ if (!empty($ids)) {
+ $message = new TranslatableMarkup('Updated tables for field handlers for views: @ids', ['@ids' => implode(', ', array_unique($ids))]);
+ }
+
+ return $message;
+}
+
+/**
+ * Include field formatter dependencies in a view when the formatter is used.
+ */
+function views_post_update_field_formatter_dependencies() {
+ $views = View::loadMultiple();
+ array_walk($views, function (View $view) {
+ $view->save();
+ });
+}
+
+/**
+ * Fix views with dependencies on taxonomy terms that don't exist.
+ */
+function views_post_update_taxonomy_index_tid() {
+ $views = View::loadMultiple();
+ array_walk($views, function (View $view) {
+ $old_dependencies = $view->getDependencies();
+ $new_dependencies = $view->calculateDependencies()->getDependencies();
+ if ($old_dependencies !== $new_dependencies) {
+ $view->save();
+ }
+ });
+}
+
+/**
+ * Fix views with serializer dependencies.
+ */
+function views_post_update_serializer_dependencies() {
+ $views = View::loadMultiple();
+ array_walk($views, function (View $view) {
+ $old_dependencies = $view->getDependencies();
+ $new_dependencies = $view->calculateDependencies()->getDependencies();
+ if ($old_dependencies !== $new_dependencies) {
+ $view->save();
+ }
+ });
+}
+
+/**
+ * Set all boolean filter values to strings.
+ */
+function views_post_update_boolean_filter_values() {
+ $config_factory = \Drupal::configFactory();
+ foreach ($config_factory->listAll('views.view.') as $view_config_name) {
+ $view = $config_factory->getEditable($view_config_name);
+ $save = FALSE;
+ foreach ($view->get('display') as $display_name => $display) {
+ if (isset($display['display_options']['filters'])) {
+ foreach ($display['display_options']['filters'] as $filter_name => $filter) {
+ if (isset($filter['plugin_id']) && $filter['plugin_id'] === 'boolean') {
+ $new_value = FALSE;
+ // Update all boolean and integer values to strings.
+ if ($filter['value'] === TRUE || $filter['value'] === 1) {
+ $new_value = '1';
+ }
+ elseif ($filter['value'] === FALSE || $filter['value'] === 0) {
+ $new_value = '0';
+ }
+ if ($new_value !== FALSE) {
+ $view->set("display.$display_name.display_options.filters.$filter_name.value", $new_value);
+ $save = TRUE;
+ }
+ }
+ }
+ }
+ }
+ if ($save) {
+ $view->save();
+ }
+ }
+}
+
+/**
+ * Rebuild caches to ensure schema changes are read in.
+ */
+function views_post_update_grouped_filters() {
+ // Empty update to cause a cache rebuild so that the schema changes are read.
+}
+
+/**
+ * Fix table names for revision metadata fields.
+ *
+ * @see https://www.drupal.org/node/2831499
+ */
+function views_post_update_revision_metadata_fields() {
+ // The table names are fixed automatically in
+ // \Drupal\views\Entity\View::preSave(), so we just need to re-save all views.
+ $views = View::loadMultiple();
+ array_walk($views, function (View $view) {
+ $view->save();
+ });
+}
+
+/**
+ * Add additional settings to the entity link field and convert node_path usage
+ * to entity_link.
+ */
+function views_post_update_entity_link_url() {
+ // Load all views.
+ $views = \Drupal::entityTypeManager()->getStorage('view')->loadMultiple();
+
+ /* @var \Drupal\views\Entity\View[] $views */
+ foreach ($views as $view) {
+ $displays = $view->get('display');
+ $changed = FALSE;
+ foreach ($displays as $display_name => &$display) {
+ if (isset($display['display_options']['fields'])) {
+ foreach ($display['display_options']['fields'] as $field_name => &$field) {
+ if (isset($field['plugin_id']) && $field['plugin_id'] === 'entity_link') {
+ // Add any missing settings for entity_link.
+ if (!isset($field['output_url_as_text'])) {
+ $field['output_url_as_text'] = FALSE;
+ $changed = TRUE;
+ }
+ if (!isset($field['absolute'])) {
+ $field['absolute'] = FALSE;
+ $changed = TRUE;
+ }
+ }
+ elseif (isset($field['plugin_id']) && $field['plugin_id'] === 'node_path') {
+ // Convert the use of node_path to entity_link.
+ $field['plugin_id'] = 'entity_link';
+ $field['field'] = 'view_node';
+ $field['output_url_as_text'] = TRUE;
+ $changed = TRUE;
+ }
+ }
+ }
+ }
+ if ($changed) {
+ $view->set('display', $displays);
+ $view->save();
+ }
+ }
+}
+
+/**
+ * Update dependencies for moved bulk field plugin.
+ */
+function views_post_update_bulk_field_moved() {
+ $views = View::loadMultiple();
+ array_walk($views, function (View $view) {
+ $old_dependencies = $view->getDependencies();
+ $new_dependencies = $view->calculateDependencies()->getDependencies();
+ if ($old_dependencies !== $new_dependencies) {
+ $view->save();
+ }
+ });
+}
+
+/**
+ * Add placeholder settings to string or numeric filters.
+ */
+function views_post_update_filter_placeholder_text() {
+ // Load all views.
+ $views = \Drupal::entityTypeManager()->getStorage('view')->loadMultiple();
+ /** @var \Drupal\views\Plugin\ViewsHandlerManager $filter_manager */
+ $filter_manager = \Drupal::service('plugin.manager.views.filter');
+
+ /* @var \Drupal\views\Entity\View[] $views */
+ foreach ($views as $view) {
+ $displays = $view->get('display');
+ $save = FALSE;
+ foreach ($displays as $display_name => &$display) {
+ if (isset($display['display_options']['filters'])) {
+ foreach ($display['display_options']['filters'] as $filter_name => &$filter) {
+ // Any of the children of the modified classes will also be inheriting
+ // the new settings.
+ $filter_instance = $filter_manager->getHandler($filter);
+ if ($filter_instance instanceof StringFilter) {
+ if (!isset($filter['expose']['placeholder'])) {
+ $filter['expose']['placeholder'] = '';
+ $save = TRUE;
+ }
+ }
+ elseif ($filter_instance instanceof NumericFilter) {
+ if (!isset($filter['expose']['placeholder'])) {
+ $filter['expose']['placeholder'] = '';
+ $save = TRUE;
+ }
+ if (!isset($filter['expose']['min_placeholder'])) {
+ $filter['expose']['min_placeholder'] = '';
+ $save = TRUE;
+ }
+ if (!isset($filter['expose']['max_placeholder'])) {
+ $filter['expose']['max_placeholder'] = '';
+ $save = TRUE;
+ }
+ }
+ }
+ }
+ }
+ if ($save) {
+ $view->set('display', $displays);
+ $view->save();
+ }
+ }
+}
+
+/**
+ * Include views data table provider in views dependencies.
+ */
+function views_post_update_views_data_table_dependencies(&$sandbox = NULL) {
+ $storage = \Drupal::entityTypeManager()->getStorage('view');
+ if (!isset($sandbox['views'])) {
+ $sandbox['views'] = $storage->getQuery()->accessCheck(FALSE)->execute();
+ $sandbox['count'] = count($sandbox['views']);
+ }
+
+ // Process 10 views at a time.
+ $views = $storage->loadMultiple(array_splice($sandbox['views'], 0, 10));
+ foreach ($views as $view) {
+ $original_dependencies = $view->getDependencies();
+ // Only re-save if dependencies have changed.
+ if ($view->calculateDependencies()->getDependencies() !== $original_dependencies) {
+ // We can trust the data because we've already recalculated the
+ // dependencies.
+ $view->trustData();
+ $view->save();
+ }
+ }
+
+ $sandbox['#finished'] = empty($sandbox['views']) ? 1 : ($sandbox['count'] - count($sandbox['views'])) / $sandbox['count'];
+}
+
+/**
+ * Fix cache max age for table displays.
+ */
+function views_post_update_table_display_cache_max_age(&$sandbox = NULL) {
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) {
+ /** @var \Drupal\views\ViewEntityInterface $view */
+ $displays = $view->get('display');
+ foreach ($displays as $display_name => &$display) {
+ if (isset($display['display_options']['style']['type']) && $display['display_options']['style']['type'] === 'table') {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ });
+}
+
+/**
+ * Update exposed filter blocks label display to be disabled.
+ */
+function views_post_update_exposed_filter_blocks_label_display(&$sandbox = NULL) {
+ // If Block is not installed, there's nothing to do.
+ if (!\Drupal::moduleHandler()->moduleExists('block')) {
+ return;
+ }
+
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'block', function ($block) {
+ /** @var \Drupal\block\BlockInterface $block */
+ if (strpos($block->getPluginId(), 'views_exposed_filter_block:') === 0) {
+ $block->getPlugin()->setConfigurationValue('label_display', '0');
+ return TRUE;
+ }
+
+ return FALSE;
+ });
+}
+
+/**
+ * Rebuild cache to allow placeholder texts to be translatable.
+ */
+function views_post_update_make_placeholders_translatable() {
+ // Empty update to cause a cache rebuild to allow placeholder texts to be
+ // translatable.
+}
+
+/**
+ * Define default values for limit operators settings in all filters.
+ */
+function views_post_update_limit_operator_defaults(&$sandbox = NULL) {
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) {
+ /** @var \Drupal\views\ViewEntityInterface $view */
+ $displays = $view->get('display');
+
+ $update = FALSE;
+ foreach ($displays as $display_name => &$display) {
+ if (!isset($display['display_options']['filters'])) {
+ continue;
+ }
+
+ foreach ($display['display_options']['filters'] as $filter_name => $filter) {
+ if (!isset($filter['expose']['operator_limit_selection'])) {
+ $filter['expose']['operator_limit_selection'] = FALSE;
+ $update = TRUE;
+ }
+ if (!isset($filter['expose']['operator_list'])) {
+ $filter['expose']['operator_list'] = [];
+ $update = TRUE;
+ }
+ if ($update) {
+ $view->set("display.$display_name.display_options.filters.$filter_name", $filter);
+ }
+ }
+ }
+ return $update;
+ });
+}
+
+/**
+ * Remove core key from views configuration.
+ */
+function views_post_update_remove_core_key(&$sandbox = NULL) {
+ \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function () {
+ // Re-save all views.
+ return TRUE;
+ });
+}
diff --git a/core/modules/workspaces/workspaces.post_update.php b/core/modules/workspaces/workspaces.post_update.php
new file mode 100644
index 0000000000..2c5d162ebd
--- /dev/null
+++ b/core/modules/workspaces/workspaces.post_update.php
@@ -0,0 +1,155 @@
+getStorage('workspace')->load('live')) {
+ $workspace->delete();
+ }
+}
+
+/**
+ * Move the workspace association data to an entity field and a custom table.
+ */
+function workspaces_post_update_move_association_data(&$sandbox) {
+ $database = \Drupal::database();
+ $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+ $entity_type_manager = \Drupal::entityTypeManager();
+ $entity_type = $entity_definition_update_manager->getEntityType('workspace_association');
+
+ // We can't migrate the workspace association data if the entity type is not
+ // using its default storage.
+ if ($entity_type->getHandlerClasses()['storage'] !== 'Drupal\workspaces\WorkspaceAssociationStorage') {
+ return;
+ }
+
+ // Since the custom storage class doesn't exist anymore, we have to use core's
+ // default storage.
+ $entity_type->setStorageClass(SqlContentEntityStorage::class);
+
+ // If 'progress' is not set, this will be the first run of the batch.
+ if (!isset($sandbox['progress'])) {
+ $sandbox['progress'] = 0;
+ $sandbox['current_id'] = -1;
+
+ // Create a temporary table for the new workspace_association index.
+ $schema = [
+ 'description' => 'Stores the association between entity revisions and their workspace.',
+ 'fields' => [
+ 'workspace' => [
+ 'type' => 'varchar_ascii',
+ 'length' => 128,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'The workspace ID.',
+ ],
+ 'target_entity_type_id' => [
+ 'type' => 'varchar_ascii',
+ 'length' => EntityTypeInterface::ID_MAX_LENGTH,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'The ID of the associated entity type.',
+ ],
+ 'target_entity_id' => [
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'description' => 'The ID of the associated entity.',
+ ],
+ 'target_entity_revision_id' => [
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'description' => 'The revision ID of the associated entity.',
+ ],
+ ],
+ 'indexes' => [
+ 'target_entity_revision_id' => ['target_entity_revision_id'],
+ ],
+ 'primary key' => ['workspace', 'target_entity_type_id', 'target_entity_id'],
+ ];
+ if ($database->schema()->tableExists('tmp_workspace_association')) {
+ $database->schema()->dropTable('tmp_workspace_association');
+ }
+ $database->schema()->createTable('tmp_workspace_association', $schema);
+
+ // Copy all the data from the base table of the 'workspace_association'
+ // entity type to the temporary association table.
+ $select = $database->select($entity_type->getBaseTable())
+ ->fields($entity_type->getBaseTable(), ['workspace', 'target_entity_type_id', 'target_entity_id', 'target_entity_revision_id']);
+ $database->insert('tmp_workspace_association')->from($select)->execute();
+ }
+
+ $table_name = $entity_type->getRevisionTable();
+ $revision_field_name = 'revision_id';
+
+ // Get the next entity association revision records to migrate.
+ $step_size = Settings::get('entity_update_batch_size', 50);
+ $workspace_association_records = $database->select($table_name, 't')
+ ->condition("t.$revision_field_name", $sandbox['current_id'], '>')
+ ->fields('t')
+ ->orderBy($revision_field_name, 'ASC')
+ ->range(0, $step_size)
+ ->execute()
+ ->fetchAll();
+
+ foreach ($workspace_association_records as $record) {
+ // Set the workspace reference on the tracked entity revision.
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
+ $revision = $entity_type_manager->getStorage($record->target_entity_type_id)->loadRevision($record->target_entity_revision_id);
+ $revision->set('workspace', $record->workspace);
+ $revision->setSyncing(TRUE);
+ $revision->save();
+
+ $sandbox['progress']++;
+ $sandbox['current_id'] = $record->{$revision_field_name};
+ }
+
+ // Get an updated count of workspace_association revisions that still need to
+ // be migrated to the new storage.
+ $missing = $database->select($table_name, 't')
+ ->condition("t.$revision_field_name", $sandbox['current_id'], '>')
+ ->orderBy($revision_field_name, 'ASC')
+ ->countQuery()
+ ->execute()
+ ->fetchField();
+ $sandbox['#finished'] = $missing ? $sandbox['progress'] / ($sandbox['progress'] + (int) $missing) : 1;
+
+ // Uninstall the 'workspace_association' entity type and rename the temporary
+ // table.
+ if ($sandbox['#finished'] == 1) {
+ $entity_type->setStorageClass(ContentEntityNullStorage::class);
+ $entity_definition_update_manager->uninstallEntityType($entity_type);
+ $database->schema()->dropTable('workspace_association');
+ $database->schema()->dropTable('workspace_association_revision');
+
+ $database->schema()->renameTable('tmp_workspace_association', 'workspace_association');
+ }
+}
+
+/**
+ * Add the workspace 'parent' field to the 'deploy' form display.
+ */
+function workspaces_post_update_update_deploy_form_display() {
+ if ($form_display = EntityFormDisplay::load('workspace.workspace.deploy')) {
+ $form_display->removeComponent('parent')->save();
+ }
+}