From 104bca1e0ea2ea0ff122e50da69cc79bd855d705 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Wed, 15 Jul 2020 15:59:38 +0100
Subject: [PATCH] Issue #2780869 by claudiu.cristea, Lendude, joachim,
 jmadden27: Cannot save a view where a filter value option contains a period

---
 .../optional/views.view.moderated_content.yml |  6 +-
 .../optional/views.view.contextual_recent.yml |  2 +-
 .../config/optional/views.view.archive.yml    |  2 +-
 .../optional/views.view.content_recent.yml    |  2 +-
 .../config/optional/views.view.frontpage.yml  |  2 +-
 .../config/optional/views.view.glossary.yml   |  2 +-
 .../test_views/views.view.test_language.yml   |  8 +--
 ...iew.test_options_list_argument_numeric.yml |  2 +-
 ...view.test_options_list_argument_string.yml |  2 +-
 .../views.view.test_options_list_filter.yml   |  6 +-
 .../Kernel/Views/OptionsListFilterTest.php    | 22 +++++++
 .../src/Kernel/Views/OptionsTestBase.php      |  3 +
 ...view.test_excluded_field_token_display.yml |  2 +-
 .../views.view.test_field_counter_display.yml |  2 +-
 .../optional/views.view.taxonomy_term.yml     |  2 +-
 .../views.view.test_filter_permission.yml     |  2 +-
 .../Kernel/Views/HandlerFilterRolesTest.php   |  4 +-
 .../views/src/Plugin/views/filter/Bundle.php  |  2 +-
 .../src/Plugin/views/filter/InOperator.php    |  9 ++-
 core/modules/views/src/ViewsConfigUpdater.php | 66 ++++++++++++++++++-
 .../views.view.test_argument_default_node.yml |  2 +-
 .../test_views/views.view.test_display.yml    |  2 +-
 ...ews.view.test_duplicate_field_handlers.yml |  2 +-
 .../views.view.test_entity_type_filter.yml    |  6 +-
 .../test_views/views.view.test_glossary.yml   |  2 +-
 .../test_views/views.view.test_tag_cache.yml  |  2 +-
 .../views.view.test_view_sort_translation.yml |  4 +-
 .../Update/InOperatorValuesUpdateTest.php     | 52 +++++++++++++++
 .../Kernel/Entity/FilterEntityBundleTest.php  |  4 +-
 .../Kernel/Handler/FilterInOperatorTest.php   | 54 ++++++++++++++-
 core/modules/views/views.post_update.php      | 12 ++++
 .../install/views.view.articles_aside.yml     |  4 +-
 .../install/views.view.featured_articles.yml  |  2 +-
 .../config/install/views.view.frontpage.yml   |  2 +-
 .../install/views.view.promoted_items.yml     |  8 +--
 .../install/views.view.recipe_collections.yml |  2 +-
 .../config/install/views.view.recipes.yml     |  2 +-
 37 files changed, 254 insertions(+), 56 deletions(-)
 create mode 100644 core/modules/views/tests/src/Functional/Update/InOperatorValuesUpdateTest.php

diff --git a/core/modules/content_moderation/config/optional/views.view.moderated_content.yml b/core/modules/content_moderation/config/optional/views.view.moderated_content.yml
index beedf9d08be1..241dcac94590 100644
--- a/core/modules/content_moderation/config/optional/views.view.moderated_content.yml
+++ b/core/modules/content_moderation/config/optional/views.view.moderated_content.yml
@@ -635,8 +635,8 @@ display:
           admin_label: ''
           operator: in
           value:
-            editorial-draft: editorial-draft
-            editorial-archived: editorial-archived
+            - editorial-draft
+            - editorial-archived
           group: 1
           exposed: true
           expose:
@@ -722,7 +722,7 @@ display:
           admin_label: ''
           operator: 'not in'
           value:
-            editorial-published: editorial-published
+            - editorial-published
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/contextual/tests/modules/contextual_test/config/optional/views.view.contextual_recent.yml b/core/modules/contextual/tests/modules/contextual_test/config/optional/views.view.contextual_recent.yml
index b3c1ea4c8465..c5d7f33624a6 100644
--- a/core/modules/contextual/tests/modules/contextual_test/config/optional/views.view.contextual_recent.yml
+++ b/core/modules/contextual/tests/modules/contextual_test/config/optional/views.view.contextual_recent.yml
@@ -209,7 +209,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            '***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
+            - '***LANGUAGE_language_content***'
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/node/config/optional/views.view.archive.yml b/core/modules/node/config/optional/views.view.archive.yml
index e76342b2b3fb..ec6d1fa797a5 100644
--- a/core/modules/node/config/optional/views.view.archive.yml
+++ b/core/modules/node/config/optional/views.view.archive.yml
@@ -123,7 +123,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            '***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
+            - '***LANGUAGE_language_content***'
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/node/config/optional/views.view.content_recent.yml b/core/modules/node/config/optional/views.view.content_recent.yml
index 54ef192695ea..b3bb4b262732 100644
--- a/core/modules/node/config/optional/views.view.content_recent.yml
+++ b/core/modules/node/config/optional/views.view.content_recent.yml
@@ -209,7 +209,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            '***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
+            - '***LANGUAGE_language_content***'
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/node/config/optional/views.view.frontpage.yml b/core/modules/node/config/optional/views.view.frontpage.yml
index d9ee305bd356..0b37cc099b0a 100644
--- a/core/modules/node/config/optional/views.view.frontpage.yml
+++ b/core/modules/node/config/optional/views.view.frontpage.yml
@@ -132,7 +132,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            '***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
+            - '***LANGUAGE_language_content***'
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/node/config/optional/views.view.glossary.yml b/core/modules/node/config/optional/views.view.glossary.yml
index 81cd423d886e..f44c743cde65 100644
--- a/core/modules/node/config/optional/views.view.glossary.yml
+++ b/core/modules/node/config/optional/views.view.glossary.yml
@@ -316,7 +316,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            '***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
+            - '***LANGUAGE_language_content***'
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_language.yml b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_language.yml
index b2bbe805ae56..6939123b09f7 100644
--- a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_language.yml
+++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_language.yml
@@ -180,7 +180,7 @@ display:
           table: node_field_data
           field: type
           value:
-            page: page
+            - page
           plugin_id: bundle
           entity_type: node
           entity_field: type
@@ -193,9 +193,9 @@ display:
           admin_label: ''
           operator: in
           value:
-            fr: fr
-            es: es
-            und: und
+            - fr
+            - es
+            - und
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_argument_numeric.yml b/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_argument_numeric.yml
index 3ea7c67bb6bf..20ff503924ea 100644
--- a/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_argument_numeric.yml
+++ b/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_argument_numeric.yml
@@ -105,7 +105,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            article: article
+            - article
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_argument_string.yml b/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_argument_string.yml
index 8ed3633de2c4..5721bd7f764b 100644
--- a/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_argument_string.yml
+++ b/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_argument_string.yml
@@ -105,7 +105,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            article: article
+            - article
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_filter.yml b/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_filter.yml
index 4bc225b8798c..ca7d17341c45 100644
--- a/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_filter.yml
+++ b/core/modules/options/tests/options_test_views/test_views/views.view.test_options_list_filter.yml
@@ -105,8 +105,8 @@ display:
           admin_label: ''
           operator: or
           value:
-            man: man
-            woman: woman
+            - man
+            - woman
           group: 1
           exposed: false
           expose:
@@ -145,7 +145,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            article: article
+            - article
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/options/tests/src/Kernel/Views/OptionsListFilterTest.php b/core/modules/options/tests/src/Kernel/Views/OptionsListFilterTest.php
index 06bedade85a3..8450090bc9bd 100644
--- a/core/modules/options/tests/src/Kernel/Views/OptionsListFilterTest.php
+++ b/core/modules/options/tests/src/Kernel/Views/OptionsListFilterTest.php
@@ -107,6 +107,28 @@ public function testViewsTestOptionsListGroupedFilter() {
 
     $column_map = ['nid' => 'nid'];
     $this->assertIdenticalResultset($view, $resultset, $column_map);
+    $view->destroy();
+
+    $view = Views::getView('test_options_list_filter');
+    $view->setDisplay();
+    // Add a filter with a period in the options.
+    $view->displayHandlers->get('default')->overrideOption('filters', [
+      'field_test_list_string_value' => [
+        'id' => 'field_test_list_string_value',
+        'table' => 'field_data_field_test_list_string',
+        'field' => 'field_test_list_string_value',
+        'relationship' => 'none',
+        'group_type' => 'group',
+        'admin_label' => '',
+        'operator' => 'or',
+        'value' => [$this->fieldValues[2] => $this->fieldValues[2]],
+        'exposed' => FALSE,
+        'plugin_id' => 'list_field',
+      ],
+    ]);
+    $view->save();
+
+    $this->executeView($view);
   }
 
 }
diff --git a/core/modules/options/tests/src/Kernel/Views/OptionsTestBase.php b/core/modules/options/tests/src/Kernel/Views/OptionsTestBase.php
index 8be66d1c25db..ebebeb1c59e5 100644
--- a/core/modules/options/tests/src/Kernel/Views/OptionsTestBase.php
+++ b/core/modules/options/tests/src/Kernel/Views/OptionsTestBase.php
@@ -84,6 +84,7 @@ protected function mockStandardInstall() {
     $this->fieldValues = [
       $this->randomMachineName(),
       $this->randomMachineName(),
+      'option.with.periods',
     ];
 
     $this->fieldNames = ['field_test_list_string', 'field_test_list_integer'];
@@ -98,6 +99,7 @@ protected function mockStandardInstall() {
         'allowed_values' => [
           $this->fieldValues[0] => $this->fieldValues[0],
           $this->fieldValues[1] => $this->fieldValues[1],
+          $this->fieldValues[2] => $this->fieldValues[2],
         ],
       ],
     ])->save();
@@ -110,6 +112,7 @@ protected function mockStandardInstall() {
         'allowed_values' => [
           $this->fieldValues[0],
           $this->fieldValues[1],
+          $this->fieldValues[2],
         ],
       ],
     ])->save();
diff --git a/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_excluded_field_token_display.yml b/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_excluded_field_token_display.yml
index ba3d5457cee1..cfd726ce2017 100644
--- a/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_excluded_field_token_display.yml
+++ b/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_excluded_field_token_display.yml
@@ -205,7 +205,7 @@ display:
           table: node_field_data
           field: type
           value:
-            article: article
+            - article
           entity_type: node
           entity_field: type
           plugin_id: bundle
diff --git a/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_field_counter_display.yml b/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_field_counter_display.yml
index 092e00aa6465..8c4e22d42f48 100644
--- a/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_field_counter_display.yml
+++ b/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_field_counter_display.yml
@@ -147,7 +147,7 @@ display:
           table: node_field_data
           field: type
           value:
-            article: article
+            - article
           entity_type: node
           entity_field: type
           plugin_id: bundle
diff --git a/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml b/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml
index 92da5368f019..3ece15f84d45 100644
--- a/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml
+++ b/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml
@@ -142,7 +142,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            '***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
+            - '***LANGUAGE_language_content***'
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_filter_permission.yml b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_filter_permission.yml
index ca19af958634..b3f0d1cb223f 100644
--- a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_filter_permission.yml
+++ b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_filter_permission.yml
@@ -94,7 +94,7 @@ display:
           admin_label: ''
           operator: or
           value:
-            'access user profiles': 'access user profiles'
+            - access user profiles
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/user/tests/src/Kernel/Views/HandlerFilterRolesTest.php b/core/modules/user/tests/src/Kernel/Views/HandlerFilterRolesTest.php
index 878300b79d51..043ad850469b 100644
--- a/core/modules/user/tests/src/Kernel/Views/HandlerFilterRolesTest.php
+++ b/core/modules/user/tests/src/Kernel/Views/HandlerFilterRolesTest.php
@@ -54,7 +54,7 @@ public function testDependencies() {
       'table' => 'user__roles',
       'field' => 'roles_target_id',
       'value' => [
-        'test_user_role' => 'test_user_role',
+        'test_user_role',
       ],
       'operator' => 'empty',
       'plugin_id' => 'user_roles',
@@ -70,7 +70,7 @@ public function testDependencies() {
       'table' => 'user__roles',
       'field' => 'roles_target_id',
       'value' => [
-        'test_user_role' => 'test_user_role',
+        'test_user_role',
       ],
       'operator' => 'not empty',
       'plugin_id' => 'user_roles',
diff --git a/core/modules/views/src/Plugin/views/filter/Bundle.php b/core/modules/views/src/Plugin/views/filter/Bundle.php
index 703173d79fdb..aec1401b7267 100644
--- a/core/modules/views/src/Plugin/views/filter/Bundle.php
+++ b/core/modules/views/src/Plugin/views/filter/Bundle.php
@@ -128,7 +128,7 @@ public function calculateDependencies() {
     $bundle_entity_type = $this->entityType->getBundleEntityType();
     $bundle_entity_storage = $this->entityTypeManager->getStorage($bundle_entity_type);
 
-    foreach (array_keys($this->value) as $bundle) {
+    foreach ($this->value as $bundle) {
       if ($bundle_entity = $bundle_entity_storage->load($bundle)) {
         $dependencies[$bundle_entity->getConfigDependencyKey()][] = $bundle_entity->getConfigDependencyName();
       }
diff --git a/core/modules/views/src/Plugin/views/filter/InOperator.php b/core/modules/views/src/Plugin/views/filter/InOperator.php
index 8a884898f596..5fcb23ab14e3 100644
--- a/core/modules/views/src/Plugin/views/filter/InOperator.php
+++ b/core/modules/views/src/Plugin/views/filter/InOperator.php
@@ -208,7 +208,7 @@ protected function valueForm(&$form, FormStateInterface $form_state) {
       }
 
       if (empty($this->options['expose']['multiple'])) {
-        if (empty($this->options['expose']['required']) && (empty($default_value) || !empty($this->options['expose']['reduce'])) || isset($this->options['value']['all'])) {
+        if (empty($this->options['expose']['required']) && (empty($default_value) || !empty($this->options['expose']['reduce'])) || in_array('all', $this->options['value'], TRUE)) {
           $default_value = 'All';
         }
         elseif (empty($default_value)) {
@@ -275,11 +275,11 @@ public function reduceValueOptions($input = NULL) {
       elseif (is_object($option) && !$option instanceof MarkupInterface) {
         $keys = array_keys($option->option);
         $key = array_shift($keys);
-        if (isset($this->options['value'][$key])) {
+        if (in_array($key, $this->options['value'], TRUE)) {
           $options[$id] = $option;
         }
       }
-      elseif (isset($this->options['value'][$id])) {
+      elseif (in_array($id, $this->options['value'], TRUE)) {
         $options[$id] = $option;
       }
     }
@@ -316,8 +316,7 @@ protected function valueSubmit($form, FormStateInterface $form_state) {
     // Luckily, the '#value' on the checkboxes form actually contains
     // *only* a list of checkboxes that were set, and we can use that
     // instead.
-
-    $form_state->setValue(['options', 'value'], $form['value']['#value']);
+    $form_state->setValue(['options', 'value'], array_values($form['value']['#value']));
   }
 
   public function adminSummary() {
diff --git a/core/modules/views/src/ViewsConfigUpdater.php b/core/modules/views/src/ViewsConfigUpdater.php
index 88442d46ddc1..f1dc4b124fc7 100644
--- a/core/modules/views/src/ViewsConfigUpdater.php
+++ b/core/modules/views/src/ViewsConfigUpdater.php
@@ -10,6 +10,8 @@
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Entity\Sql\DefaultTableMapping;
+use Drupal\views\Plugin\views\filter\InOperator;
+use Drupal\views\Plugin\ViewsHandlerManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -57,6 +59,13 @@ class ViewsConfigUpdater implements ContainerInjectionInterface {
    */
   protected $multivalueBaseFieldsUpdateTableInfo;
 
+  /**
+   * The Views filter plugin manager service.
+   *
+   * @var \Drupal\views\Plugin\ViewsHandlerManager
+   */
+  protected $filterPluginManager;
+
   /**
    * Flag determining whether deprecations should be triggered.
    *
@@ -82,17 +91,21 @@ class ViewsConfigUpdater implements ContainerInjectionInterface {
    *   The typed config manager.
    * @param \Drupal\views\ViewsData $views_data
    *   The views data service.
+   * @param \Drupal\views\Plugin\ViewsHandlerManager $filter_plugin_manager
+   *   The Views filter plugin manager service.
    */
   public function __construct(
     EntityTypeManagerInterface $entity_type_manager,
     EntityFieldManagerInterface $entity_field_manager,
     TypedConfigManagerInterface $typed_config_manager,
-    ViewsData $views_data
+    ViewsData $views_data,
+    ViewsHandlerManager $filter_plugin_manager
   ) {
     $this->entityTypeManager = $entity_type_manager;
     $this->entityFieldManager = $entity_field_manager;
     $this->typedConfigManager = $typed_config_manager;
     $this->viewsData = $views_data;
+    $this->filterPluginManager = $filter_plugin_manager;
   }
 
   /**
@@ -103,7 +116,8 @@ public static function create(ContainerInterface $container) {
       $container->get('entity_type.manager'),
       $container->get('entity_field.manager'),
       $container->get('config.typed'),
-      $container->get('views.views_data')
+      $container->get('views.views_data'),
+      $container->get('plugin.manager.views.filter')
     );
   }
 
@@ -138,6 +152,9 @@ public function updateAll(ViewEntityInterface $view) {
       if ($this->processMultivalueBaseFieldHandler($handler, $handler_type, $key, $display_id, $view)) {
         $changed = TRUE;
       }
+      if ($this->processInOperatorFilterValues($handler, $handler_type)) {
+        $changed = TRUE;
+      }
       return $changed;
     });
   }
@@ -477,4 +494,49 @@ protected function mapOperatorFromSingleToMultiple($single_operator) {
     }
   }
 
+  /**
+   * Update values for of in_operators filters.
+   *
+   * @param \Drupal\views\ViewEntityInterface $view
+   *   The View to update.
+   *
+   * @return bool
+   *   Whether the view was updated.
+   */
+  public function needsInOperatorFilterValuesUpdate(ViewEntityInterface $view): bool {
+    return $this->processDisplayHandlers($view, TRUE, function (array &$handler, string $handler_type): bool {
+      return $this->processInOperatorFilterValues($handler, $handler_type);
+    });
+  }
+
+  /**
+   * Processes the in_operator filter values.
+   *
+   * @param array $handler
+   *   A display handler.
+   * @param string $handler_type
+   *   The handler type.
+   *
+   * @return bool
+   *   Whether the handler was updated.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   *   If the filter plugin instance cannot be created.
+   */
+  protected function processInOperatorFilterValues(array &$handler, string $handler_type): bool {
+    if ($handler_type === 'filter' && !empty($handler['value']) && is_array($handler['value'])) {
+      $values = array_values($handler['value']);
+      // Only process if the keys are the same as the values.
+      if ($values === array_keys($handler['value'])) {
+        $class = $this->filterPluginManager->getDefinition($handler['plugin_id'])['class'];
+        // Process for 'in_operator' plugin but also for its descendants.
+        if ($class === InOperator::class || is_subclass_of($class, InOperator::class)) {
+          $handler['value'] = $values;
+          return TRUE;
+        }
+      }
+    }
+    return FALSE;
+  }
+
 }
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_argument_default_node.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_argument_default_node.yml
index 02d3db1beec3..e000db0c3c28 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_argument_default_node.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_argument_default_node.yml
@@ -135,7 +135,7 @@ display:
           table: node_field_data
           field: type
           value:
-            page: page
+            - page
           entity_type: node
           entity_field: type
           plugin_id: bundle
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display.yml
index 3a426e426250..4f80881ee259 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display.yml
@@ -47,7 +47,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            '***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
+            - '***LANGUAGE_language_content***'
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_duplicate_field_handlers.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_duplicate_field_handlers.yml
index bca6747c2c1b..84fb91b920db 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_duplicate_field_handlers.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_duplicate_field_handlers.yml
@@ -131,7 +131,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            article: article
+            - article
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_type_filter.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_type_filter.yml
index 0c6d0be80b17..cae09605ae4c 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_type_filter.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_type_filter.yml
@@ -101,9 +101,9 @@ display:
           field: type
           relationship: none
           value:
-            180575: '180575'
-            test_bundle: test_bundle
-            test_bundle_2: test_bundle_2
+            - '180575'
+            - test_bundle
+            - test_bundle_2
           plugin_id: bundle
           entity_type: node
           entity_field: type
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_glossary.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_glossary.yml
index a6d3a3641afd..2f40c5901a50 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_glossary.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_glossary.yml
@@ -314,7 +314,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            '***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
+            - '***LANGUAGE_language_content***'
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_tag_cache.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_tag_cache.yml
index 78e7ca30ba62..fe4dff1424c5 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_tag_cache.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_tag_cache.yml
@@ -68,7 +68,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            page: page
+            - page
           group: 1
           exposed: false
           expose:
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_sort_translation.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_sort_translation.yml
index d161b0b27325..701847bf8b37 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_sort_translation.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_sort_translation.yml
@@ -42,7 +42,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            'en': 'en'
+            - en
           group: 1
           exposed: false
           entity_type: node
@@ -77,7 +77,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            'de': 'de'
+            - de
           group: 1
           exposed: false
           entity_type: node
diff --git a/core/modules/views/tests/src/Functional/Update/InOperatorValuesUpdateTest.php b/core/modules/views/tests/src/Functional/Update/InOperatorValuesUpdateTest.php
new file mode 100644
index 000000000000..a64eb3371918
--- /dev/null
+++ b/core/modules/views/tests/src/Functional/Update/InOperatorValuesUpdateTest.php
@@ -0,0 +1,52 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\views\Functional\Update;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
+
+/**
+ * Tests the upgrade path for in_operation filter values.
+ *
+ * @group views
+ * @group legacy
+ *
+ * @coversDefaultClass \Drupal\views\ViewsConfigUpdater
+ *
+ * @see views_post_update_in_operator_values()
+ */
+class InOperatorValuesUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles(): void {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.8.0.bare.standard.php.gz',
+    ];
+  }
+
+  /**
+   * Tests the upgrade path for in_operation filter values.
+   *
+   * @covers ::needsInOperatorFilterValuesUpdate
+   * @covers ::processInOperatorFilterValues
+   */
+  public function testInOperatorValuesUpdate(): void {
+    $config_factory = \Drupal::configFactory();
+    $view = $config_factory->get('views.view.frontpage');
+    $path = 'display.default.display_options.filters.langcode.value';
+    $value = $view->get($path);
+    $this->assertSame([
+      '***LANGUAGE_language_content***' => '***LANGUAGE_language_content***',
+    ], $value);
+
+    $this->runUpdates();
+
+    $view = $config_factory->get('views.view.frontpage');
+    $value = $view->get($path);
+    $this->assertSame(['***LANGUAGE_language_content***'], $value);
+  }
+
+}
diff --git a/core/modules/views/tests/src/Kernel/Entity/FilterEntityBundleTest.php b/core/modules/views/tests/src/Kernel/Entity/FilterEntityBundleTest.php
index 19c9e5bde314..ee1e7e8d0bf7 100644
--- a/core/modules/views/tests/src/Kernel/Entity/FilterEntityBundleTest.php
+++ b/core/modules/views/tests/src/Kernel/Entity/FilterEntityBundleTest.php
@@ -84,7 +84,7 @@ public function testFilterEntity() {
       // Test each bundle type.
       $view->initDisplay();
       $filters = $view->display_handler->getOption('filters');
-      $filters['type']['value'] = [$key => $key];
+      $filters['type']['value'] = [$key];
       $view->display_handler->setOption('filters', $filters);
       $this->executeView($view);
 
@@ -96,7 +96,7 @@ public function testFilterEntity() {
     // Test an invalid bundle type to make sure we have no results.
     $view->initDisplay();
     $filters = $view->display_handler->getOption('filters');
-    $filters['type']['value'] = ['type_3' => 'type_3'];
+    $filters['type']['value'] = ['type_3'];
     $view->display_handler->setOption('filters', $filters);
     $this->executeView($view);
 
diff --git a/core/modules/views/tests/src/Kernel/Handler/FilterInOperatorTest.php b/core/modules/views/tests/src/Kernel/Handler/FilterInOperatorTest.php
index eaada3ef04f0..d20fdb9ce137 100644
--- a/core/modules/views/tests/src/Kernel/Handler/FilterInOperatorTest.php
+++ b/core/modules/views/tests/src/Kernel/Handler/FilterInOperatorTest.php
@@ -15,6 +15,7 @@
  * @group views
  */
 class FilterInOperatorTest extends ViewsKernelTestBase {
+
   use StringTranslationTrait;
 
   protected static $modules = ['system'];
@@ -39,6 +40,22 @@ class FilterInOperatorTest extends ViewsKernelTestBase {
   public function viewsData() {
     $data = parent::viewsData();
     $data['views_test_data']['age']['filter']['id'] = 'in_operator';
+    $data['views_test_data']['job']['filter']['id'] = 'in_operator';
+    return $data;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function dataSet() {
+    $data = parent::dataSet();
+    $data[] = [
+      'name' => 'Dries',
+      'age' => 8,
+      'job' => 'B.D.F.L.',
+      'created' => gmmktime(6, 30, 30, 1, 1, 2000),
+      'status' => 1,
+    ];
     return $data;
   }
 
@@ -82,7 +99,7 @@ public function testFilterInOperatorSimple() {
         'id' => 'age',
         'field' => 'age',
         'table' => 'views_test_data',
-        'value' => [26, 30],
+        'value' => [26, 30, 8],
         'operator' => 'not in',
       ],
     ]);
@@ -224,7 +241,7 @@ protected function getGroupedExposedFilters() {
             2 => [
               'title' => 'Age is not one of 26, 30',
               'operator' => 'not in',
-              'value' => [26, 30],
+              'value' => [26, 30, 8],
             ],
           ],
         ],
@@ -246,7 +263,7 @@ public function testFilterOptionAsMarkup() {
     $manager = $this->container->get('plugin.manager.views.filter');
     /** @var \Drupal\views\Plugin\views\filter\InOperator $operator */
     $operator = $manager->createInstance('in_operator');
-    $options = ['value' => ['foo' => [], 'baz' => []]];
+    $options = ['value' => ['foo', 'baz']];
     $operator->init($view->reveal(), $display->reveal(), $options);
 
     $input_options = [
@@ -260,7 +277,38 @@ public function testFilterOptionAsMarkup() {
     $this->assertInstanceOf(TranslatableMarkup::class, $reduced_values['baz']);
     $this->assertSame('qux', (string) $reduced_values['baz']);
     $this->assertSame('bar', $reduced_values['foo']);
+  }
+
+  /**
+   * Tests that the InOperator filter can handle options containing dots.
+   */
+  public function testFilterInOperatorSimpleString(): void {
+    $view = Views::getView('test_view');
+    $view->setDisplay();
+
+    // Add an in_operator on job.
+    $view->displayHandlers->get('default')->overrideOption('filters', [
+      'job' => [
+        'id' => 'job',
+        'field' => 'job',
+        'table' => 'views_test_data',
+        'value' => ['B.D.F.L.' => 'B.D.F.L.'],
+        'plugin_id' => 'in_operator',
+      ],
+    ]);
+    $view->save();
+
+    $this->executeView($view);
 
+    $expected_result = [
+      [
+        'name' => 'Dries',
+        'age' => 8,
+      ],
+    ];
+
+    $this->assertCount(1, $view->result);
+    $this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
   }
 
 }
diff --git a/core/modules/views/views.post_update.php b/core/modules/views/views.post_update.php
index 23aedc1c0323..d04db0ddf0c1 100644
--- a/core/modules/views/views.post_update.php
+++ b/core/modules/views/views.post_update.php
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Config\Entity\ConfigEntityUpdater;
+use Drupal\views\ViewEntityInterface;
 use Drupal\views\ViewsConfigUpdater;
 
 /**
@@ -51,3 +52,14 @@ function views_post_update_field_names_for_multivalue_fields(&$sandbox = NULL) {
 function views_post_update_configuration_entity_relationships() {
   // Empty update to clear Views data.
 }
+
+/**
+ * Update the in_operator filter plugins values.
+ */
+function views_post_update_in_operator_values(?array &$sandbox = NULL): void {
+  /** @var \Drupal\views\ViewsConfigUpdater $view_config_updater */
+  $view_config_updater = \Drupal::classResolver(ViewsConfigUpdater::class);
+  \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function (ViewEntityInterface $view) use ($view_config_updater): bool {
+    return $view_config_updater->needsInOperatorFilterValuesUpdate($view);
+  });
+}
diff --git a/core/profiles/demo_umami/config/install/views.view.articles_aside.yml b/core/profiles/demo_umami/config/install/views.view.articles_aside.yml
index 70989b335c19..1748ff6529ed 100644
--- a/core/profiles/demo_umami/config/install/views.view.articles_aside.yml
+++ b/core/profiles/demo_umami/config/install/views.view.articles_aside.yml
@@ -125,7 +125,7 @@ display:
           table: node_field_data
           field: type
           value:
-            article: article
+            - article
           entity_type: node
           entity_field: type
           plugin_id: bundle
@@ -141,7 +141,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            '***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
+            - '***LANGUAGE_language_content***'
           group: 1
           exposed: false
           expose:
diff --git a/core/profiles/demo_umami/config/install/views.view.featured_articles.yml b/core/profiles/demo_umami/config/install/views.view.featured_articles.yml
index 88d5550615d9..40ff01461454 100644
--- a/core/profiles/demo_umami/config/install/views.view.featured_articles.yml
+++ b/core/profiles/demo_umami/config/install/views.view.featured_articles.yml
@@ -139,7 +139,7 @@ display:
           table: node_field_data
           field: type
           value:
-            article: article
+            - article
           entity_type: node
           entity_field: type
           plugin_id: bundle
diff --git a/core/profiles/demo_umami/config/install/views.view.frontpage.yml b/core/profiles/demo_umami/config/install/views.view.frontpage.yml
index 86397d039a5b..a614aa2c8d9d 100644
--- a/core/profiles/demo_umami/config/install/views.view.frontpage.yml
+++ b/core/profiles/demo_umami/config/install/views.view.frontpage.yml
@@ -133,7 +133,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            recipe: recipe
+            - recipe
           group: 1
           exposed: false
           expose:
diff --git a/core/profiles/demo_umami/config/install/views.view.promoted_items.yml b/core/profiles/demo_umami/config/install/views.view.promoted_items.yml
index ee99489eb8a7..6427d0a15d0b 100644
--- a/core/profiles/demo_umami/config/install/views.view.promoted_items.yml
+++ b/core/profiles/demo_umami/config/install/views.view.promoted_items.yml
@@ -171,8 +171,8 @@ display:
           admin_label: ''
           operator: in
           value:
-            article: article
-            recipe: recipe
+            - article
+            - recipe
           group: 1
           exposed: false
           expose:
@@ -330,7 +330,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            recipe: recipe
+            - recipe
           group: 1
           exposed: false
           expose:
@@ -491,7 +491,7 @@ display:
           admin_label: ''
           operator: in
           value:
-            article: article
+            - article
           group: 1
           exposed: false
           expose:
diff --git a/core/profiles/demo_umami/config/install/views.view.recipe_collections.yml b/core/profiles/demo_umami/config/install/views.view.recipe_collections.yml
index 1257ba1b1d18..6c2509344401 100644
--- a/core/profiles/demo_umami/config/install/views.view.recipe_collections.yml
+++ b/core/profiles/demo_umami/config/install/views.view.recipe_collections.yml
@@ -118,7 +118,7 @@ display:
           table: taxonomy_term_field_data
           field: vid
           value:
-            tags: tags
+            - tags
           entity_type: taxonomy_term
           entity_field: vid
           plugin_id: bundle
diff --git a/core/profiles/demo_umami/config/install/views.view.recipes.yml b/core/profiles/demo_umami/config/install/views.view.recipes.yml
index 7a5bc31f38e9..8c1475355855 100644
--- a/core/profiles/demo_umami/config/install/views.view.recipes.yml
+++ b/core/profiles/demo_umami/config/install/views.view.recipes.yml
@@ -139,7 +139,7 @@ display:
           table: node_field_data
           field: type
           value:
-            recipe: recipe
+            - recipe
           entity_type: node
           entity_field: type
           plugin_id: bundle
-- 
GitLab