From bc0be2b75955ca83a37f5e5d51b3e18b687de75d Mon Sep 17 00:00:00 2001
From: Charles Tanton <charles@parkroad.co.za>
Date: Mon, 24 Mar 2025 10:58:57 +0200
Subject: [PATCH 1/3] 2264739: Update patch to apply to Drupal 11.x

---
 core/config/schema/core.entity.schema.yml     | 38 ++++++++
 core/includes/theme.inc                       | 86 +++++++++++++++++++
 .../FieldWidget/BooleanCheckboxWidget.php     |  4 +-
 .../Field/FieldWidget/EmailDefaultWidget.php  |  4 +-
 .../EntityReferenceAutocompleteWidget.php     |  4 +-
 .../Plugin/Field/FieldWidget/NumberWidget.php |  4 +-
 .../FieldWidget/StringTextareaWidget.php      |  4 +-
 .../FieldWidget/StringTextfieldWidget.php     |  4 +-
 .../Plugin/Field/FieldWidget/UriWidget.php    |  4 +-
 core/lib/Drupal/Core/Field/WidgetBase.php     | 33 ++++++-
 .../Drupal/Core/Theme/ThemeCommonElements.php |  3 +
 .../comment/config/schema/comment.schema.yml  |  4 +
 .../config/schema/datetime.schema.yml         |  7 ++
 .../FieldWidget/DateTimeDatelistWidget.php    |  2 +-
 .../config/schema/datetime_range.schema.yml   |  7 ++
 .../FieldWidget/DateRangeDatelistWidget.php   |  2 +-
 .../config/schema/field_test.schema.yml       |  9 ++
 .../field/tests/src/Functional/FormTest.php   |  1 +
 .../d6/MigrateFieldWidgetSettingsTest.php     | 22 +++--
 .../file/config/schema/file.schema.yml        |  3 +
 .../Plugin/Field/FieldWidget/FileWidget.php   | 17 +++-
 .../image/config/schema/image.schema.yml      |  3 +
 .../src/Functional/EntityFormDisplayTest.php  |  9 +-
 .../link/config/schema/link.schema.yml        |  3 +
 .../Plugin/Field/FieldWidget/LinkWidget.php   |  2 +-
 .../config/schema/media_library.schema.yml    |  3 +
 .../media_library_test_widget.schema.yml      |  3 +
 .../options/config/schema/options.schema.yml  |  8 ++
 .../path/config/schema/path.schema.yml        |  4 +
 ...ultiple-value-without-order-form.html.twig | 65 ++++++++++++++
 .../config/schema/telephone.schema.yml        |  3 +
 .../FieldWidget/TelephoneDefaultWidget.php    |  4 +-
 .../text/config/schema/text.schema.yml        |  9 ++
 ...tity_form_display.node.article.default.yml | 10 ++-
 ....entity_form_display.node.page.default.yml | 11 ++-
 .../EntityFormDisplayResourceTestBase.php     |  9 +-
 ...ultiple-value-without-order-form.html.twig | 65 ++++++++++++++
 ...ultiple-value-without-order-form.html.twig | 46 ++++++++++
 38 files changed, 486 insertions(+), 33 deletions(-)
 create mode 100644 core/modules/system/templates/field-multiple-value-without-order-form.html.twig
 create mode 100644 core/themes/claro/templates/field-multiple-value-without-order-form.html.twig
 create mode 100644 core/themes/stable9/templates/form/field-multiple-value-without-order-form.html.twig

diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml
index 2934ca7fee0c..2bf4357c6681 100644
--- a/core/config/schema/core.entity.schema.yml
+++ b/core/config/schema/core.entity.schema.yml
@@ -174,11 +174,18 @@ field.formatter.settings.*:
 # Default schema for entity form display field with undefined type.
 field.widget.settings.*:
   type: mapping
+  mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
 
 field.widget.settings.string_textfield:
   type: mapping
   label: 'Text field display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     size:
       type: integer
       label: 'Size of textfield'
@@ -190,6 +197,9 @@ field.widget.settings.string_textarea:
   type: mapping
   label: 'Textarea display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     rows:
       type: integer
       label: 'Rows'
@@ -201,6 +211,9 @@ field.widget.settings.uri:
   type: mapping
   label: 'URI field'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     size:
       type: integer
       label: 'Size of URI field'
@@ -212,6 +225,9 @@ field.widget.settings.email_default:
   type: mapping
   label: 'Email field display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     placeholder:
       type: label
       label: 'Placeholder'
@@ -222,11 +238,18 @@ field.widget.settings.email_default:
 field.widget.settings.datetime_timestamp:
   type: mapping
   label: 'Datetime timestamp display format settings'
+  mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
 
 field.widget.settings.boolean_checkbox:
   type: mapping
   label: 'Boolean checkbox display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     display_label:
       type: boolean
       label: 'Display label'
@@ -239,6 +262,9 @@ field.widget.settings.number:
   type: mapping
   label: 'Number default display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     placeholder:
       type: label
       label: 'Placeholder'
@@ -247,6 +273,9 @@ field.widget.settings.checkbox:
   type: mapping
   label: 'Single on/off checkbox format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     display_label:
       type: boolean
       label: 'Use field label instead of the "On value" as label'
@@ -255,6 +284,9 @@ field.widget.settings.language_select:
   type: mapping
   label: 'Language format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     include_locked:
       type: boolean
       label: 'Include locked languages'
@@ -263,6 +295,9 @@ field.widget.settings.entity_reference_autocomplete_tags:
   type: mapping
   label: 'Entity reference autocomplete (Tags style) display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     match_operator:
       type: string
       label: 'Autocomplete matching'
@@ -280,6 +315,9 @@ field.widget.settings.entity_reference_autocomplete:
   type: mapping
   label: 'Entity reference autocomplete display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     match_operator:
       type: string
       label: 'Autocomplete matching'
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 48bed90cd70a..f3c1d8e0073e 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1541,6 +1541,92 @@ function template_preprocess_field_multiple_value_form(&$variables): void {
   }
 }
 
+/**
+ * Prepares variables for individual form element templates.
+ *
+ * Default template: field-multiple-value-without-order-form.html.twig.
+ *
+ * Combines multiple values.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - element: A render element representing the form element.
+ */
+function template_preprocess_field_multiple_value_without_order_form(&$variables) {
+  $element = $variables['element'];
+  $variables['multiple'] = $element['#cardinality_multiple'];
+
+  if ($variables['multiple']) {
+    $items = [];
+    $variables['button'] = [];
+    foreach (Element::children($element) as $key) {
+      if ($key === 'add_more') {
+        $variables['button'] = &$element[$key];
+      }
+      else {
+        $items[$key] = &$element[$key];
+        if (isset($items[$key]['_weight'])) {
+          $items[$key]['_weight']['#access'] = FALSE;
+        }
+      }
+    }
+    usort($items, '_field_multiple_value_form_sort_helper');
+
+    if (isset($element['#file_upload_title'])) {
+      // @see template_preprocess_file_widget_multiple()
+      foreach ($items as $key => &$widget) {
+        // Save the uploading row for last.
+        if (empty($widget['#files'])) {
+          $widget['#title'] = $element['#file_upload_title'];
+          $widget['#title_display'] = 'hidden';
+          $widget['#description'] = \Drupal::service('renderer')->renderPlain($element['#file_upload_description']);
+          continue;
+        }
+
+        // Delay rendering of the "Display" option and the weight selector, so that
+        // each can be rendered later in its own column.
+        if ($element['#display_field']) {
+          hide($widget['display']);
+        }
+
+        // Render everything else together in a column, without the normal wrappers.
+        $widget['#theme_wrappers'] = [];
+        if ($element['#display_field']) {
+          unset($widget['display']['#title']);
+        }
+      }
+    }
+
+    $variables['title'] = [];
+    if (!empty($element['#title'])) {
+      $variables['title'] = [
+        '#type' => 'label',
+        '#title' => $element['#title'],
+        '#required' => !empty($element['#required']) ? $element['#required'] : FALSE,
+        '#title_display' => 'before',
+      ];
+    }
+    $variables['items'] = $items;
+
+    if (!empty($element['#description'])) {
+      $variables['description_display'] = $element['#description_display'];
+      $description_id = $element['#attributes']['aria-describedby'];
+      $description_attributes['id'] = $description_id;
+      $variables['description']['attributes'] = new Attribute($description_attributes);
+      $variables['description']['content'] = $element['#description'];
+
+      // Add the description's id to the items aria attributes.
+      $variables['items']['#attributes']['aria-describedby'] = $element['#attributes']['aria-describedby'];
+    }
+  }
+  else {
+    $variables['elements'] = [];
+    foreach (Element::children($element) as $key) {
+      $variables['elements'][] = $element[$key];
+    }
+  }
+}
+
 /**
  * Prepares variables for breadcrumb templates.
  *
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php
index b0f968124c41..5c7968caf7fd 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php
@@ -32,6 +32,8 @@ public static function defaultSettings() {
    * {@inheritdoc}
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
+    $element = parent::settingsForm($form, $form_state);
+
     $element['display_label'] = [
       '#type' => 'checkbox',
       '#title' => $this->t('Use field label instead of the "On" label as the label.'),
@@ -45,7 +47,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $display_label = $this->getSetting('display_label');
     $summary[] = $this->t('Use field label: @display_label', ['@display_label' => ($display_label ? $this->t('Yes') : $this->t('No'))]);
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
index 75c2b1097d43..1f7bcec4f1f6 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
@@ -33,6 +33,8 @@ public static function defaultSettings() {
    * {@inheritdoc}
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
+    $element = parent::settingsForm($form, $form_state);
+
     $element['size'] = [
       '#type' => 'number',
       '#title' => $this->t('Textfield size'),
@@ -53,7 +55,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $placeholder = $this->getSetting('placeholder');
     if (!empty($placeholder)) {
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php
index f373ac800b82..3c38dde148d7 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php
@@ -37,6 +37,8 @@ public static function defaultSettings() {
    * {@inheritdoc}
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
+    $element = parent::settingsForm($form, $form_state);
+
     $element['match_operator'] = [
       '#type' => 'radios',
       '#title' => $this->t('Autocomplete matching'),
@@ -71,7 +73,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $operators = $this->getMatchOperatorOptions();
     $summary[] = $this->t('Autocomplete matching: @match_operator', ['@match_operator' => $operators[$this->getSetting('match_operator')]]);
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
index e827bfd999e6..82d3ea7c4adc 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
@@ -37,6 +37,8 @@ public static function defaultSettings() {
    * {@inheritdoc}
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
+    $element = parent::settingsForm($form, $form_state);
+
     $element['placeholder'] = [
       '#type' => 'textfield',
       '#title' => $this->t('Placeholder'),
@@ -50,7 +52,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $placeholder = $this->getSetting('placeholder');
     if (!empty($placeholder)) {
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php
index cc550c2f03c7..cb5a13d0d54a 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php
@@ -32,6 +32,8 @@ public static function defaultSettings() {
    * {@inheritdoc}
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
+    $element = parent::settingsForm($form, $form_state);
+
     $element['rows'] = [
       '#type' => 'number',
       '#title' => $this->t('Rows'),
@@ -52,7 +54,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $summary[] = $this->t('Number of rows: @rows', ['@rows' => $this->getSetting('rows')]);
     $placeholder = $this->getSetting('placeholder');
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextfieldWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextfieldWidget.php
index 1523e4f618f7..e86799f4ac33 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextfieldWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextfieldWidget.php
@@ -32,6 +32,8 @@ public static function defaultSettings() {
    * {@inheritdoc}
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
+    $element = parent::settingsForm($form, $form_state);
+
     $element['size'] = [
       '#type' => 'number',
       '#title' => $this->t('Size of textfield'),
@@ -52,7 +54,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $summary[] = $this->t('Textfield size: @size', ['@size' => $this->getSetting('size')]);
     $placeholder = $this->getSetting('placeholder');
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php
index 3052ca3039ac..e5f95b979d9e 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php
@@ -32,6 +32,8 @@ public static function defaultSettings() {
    * {@inheritdoc}
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
+    $element = parent::settingsForm($form, $form_state);
+
     $element['size'] = [
       '#type' => 'number',
       '#title' => $this->t('Size of URI field'),
@@ -52,7 +54,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $summary[] = $this->t('URI field size: @size', ['@size' => $this->getSetting('size')]);
     $placeholder = $this->getSetting('placeholder');
diff --git a/core/lib/Drupal/Core/Field/WidgetBase.php b/core/lib/Drupal/Core/Field/WidgetBase.php
index 6b408991cc02..1bf14aa31c9f 100644
--- a/core/lib/Drupal/Core/Field/WidgetBase.php
+++ b/core/lib/Drupal/Core/Field/WidgetBase.php
@@ -266,7 +266,7 @@ protected function formMultipleElements(FieldItemListInterface $items, array &$f
 
     if ($elements) {
       $elements += [
-        '#theme' => 'field_multiple_value_form',
+        '#theme' => $this->getSetting('orderable') ? 'field_multiple_value_form' : 'field_multiple_value_without_order_form',
         '#field_name' => $field_name,
         '#cardinality' => $cardinality,
         '#cardinality_multiple' => $is_multiple,
@@ -631,18 +631,45 @@ protected static function getWidgetStateParents(array $parents, $field_name) {
     return array_merge(['field_storage', '#parents'], $parents, ['#fields', $field_name]);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function defaultSettings() {
+    return [
+      'orderable' => TRUE,
+    ] + parent::defaultSettings();
+  }
+
   /**
    * {@inheritdoc}
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
-    return [];
+    $element = [];
+    if ($this->fieldDefinition->getFieldStorageDefinition()->getCardinality() != 1) {
+      $element['orderable'] = [
+        '#type' => 'checkbox',
+        '#title' => $this->t('Orderable'),
+        '#default_value' => $this->getSetting('orderable'),
+        '#weight' => -5,
+        '#description' => $this->t('Orderable multiple fields widgets are in a table with drag and drop.'),
+      ];
+    }
+
+    return $element;
   }
 
   /**
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    return [];
+    $summary = [];
+
+    if ($this->fieldDefinition->getFieldStorageDefinition()->getCardinality() != 1) {
+      $orderable = $this->getSetting('orderable');
+      $summary[] = t('Orderable: @orderable', ['@orderable' => ($orderable ? t('Yes') : t('No'))]);
+    }
+
+    return $summary;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Theme/ThemeCommonElements.php b/core/lib/Drupal/Core/Theme/ThemeCommonElements.php
index 05d5e168e1a3..d90d2e9daaee 100644
--- a/core/lib/Drupal/Core/Theme/ThemeCommonElements.php
+++ b/core/lib/Drupal/Core/Theme/ThemeCommonElements.php
@@ -235,6 +235,9 @@ public static function commonElements(): array {
       'field_multiple_value_form' => [
         'render element' => 'element',
       ],
+      'field_multiple_value_without_order_form' => [
+        'render element' => 'element',
+      ],
       'off_canvas_page_wrapper' => [
         'variables' => [
           'children' => NULL,
diff --git a/core/modules/comment/config/schema/comment.schema.yml b/core/modules/comment/config/schema/comment.schema.yml
index 33b3e55ac3ab..25bab191eb3a 100644
--- a/core/modules/comment/config/schema/comment.schema.yml
+++ b/core/modules/comment/config/schema/comment.schema.yml
@@ -23,6 +23,10 @@ field.formatter.settings.comment_default:
 field.widget.settings.comment_default:
   type: mapping
   label: 'Comment display format settings'
+  mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
 
 comment.type.*:
   type: config_entity
diff --git a/core/modules/datetime/config/schema/datetime.schema.yml b/core/modules/datetime/config/schema/datetime.schema.yml
index a6047ee4e1bd..4bd5e1819cd5 100644
--- a/core/modules/datetime/config/schema/datetime.schema.yml
+++ b/core/modules/datetime/config/schema/datetime.schema.yml
@@ -66,6 +66,9 @@ field.widget.settings.datetime_datelist:
   type: mapping
   label: 'Datetime select list display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     increment:
       type: integer
       label: 'Time increments'
@@ -79,3 +82,7 @@ field.widget.settings.datetime_datelist:
 field.widget.settings.datetime_default:
   type: mapping
   label: 'Datetime default display format settings'
+  mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
index e7999309d4fb..79233ae1391f 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
@@ -126,7 +126,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $summary[] = $this->t('Date part order: @order', ['@order' => $this->getSetting('date_order')]);
     if ($this->getFieldSetting('datetime_type') == 'datetime') {
diff --git a/core/modules/datetime_range/config/schema/datetime_range.schema.yml b/core/modules/datetime_range/config/schema/datetime_range.schema.yml
index bb244553edc1..40199bdb227f 100644
--- a/core/modules/datetime_range/config/schema/datetime_range.schema.yml
+++ b/core/modules/datetime_range/config/schema/datetime_range.schema.yml
@@ -79,6 +79,9 @@ field.widget.settings.daterange_datelist:
   type: mapping
   label: 'Date range select list display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     increment:
       type: integer
       label: 'Time increments'
@@ -92,3 +95,7 @@ field.widget.settings.daterange_datelist:
 field.widget.settings.daterange_default:
   type: mapping
   label: 'Date range default display format settings'
+  mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
diff --git a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php
index 0c90959607a9..472d6c3b35b2 100644
--- a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php
+++ b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php
@@ -142,7 +142,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $summary[] = $this->t('Date part order: @order', ['@order' => $this->getSetting('date_order')]);
     if ($this->getFieldSetting('datetime_type') == DateRangeItem::DATETIME_TYPE_DATETIME) {
diff --git a/core/modules/field/tests/modules/field_test/config/schema/field_test.schema.yml b/core/modules/field/tests/modules/field_test/config/schema/field_test.schema.yml
index 5a65b9698686..83ae206f6a5f 100644
--- a/core/modules/field/tests/modules/field_test/config/schema/field_test.schema.yml
+++ b/core/modules/field/tests/modules/field_test/config/schema/field_test.schema.yml
@@ -37,6 +37,9 @@ field.widget.settings.test_field_widget:
   type: mapping
   label: 'Test field widget settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     test_widget_setting:
       type: string
       label: 'Test setting'
@@ -51,6 +54,9 @@ field.widget.settings.test_field_widget_multiple:
   type: mapping
   label: 'Test multiple field widget settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     test_widget_setting_multiple:
       type: string
       label: 'Test setting'
@@ -59,6 +65,9 @@ field.widget.settings.test_field_widget_multiple_single_value:
   type: mapping
   label: 'Test multiple field widget settings: single values'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     test_widget_setting_multiple:
       type: string
       label: 'Test setting'
diff --git a/core/modules/field/tests/src/Functional/FormTest.php b/core/modules/field/tests/src/Functional/FormTest.php
index e5c8838f353d..bda7957c573e 100644
--- a/core/modules/field/tests/src/Functional/FormTest.php
+++ b/core/modules/field/tests/src/Functional/FormTest.php
@@ -94,6 +94,7 @@ protected function setUp(): void {
       'description' => '[site:name]_description',
       'weight' => mt_rand(0, 127),
       'settings' => [
+        'orderable' => TRUE,
         'test_field_setting' => $this->randomMachineName(),
       ],
     ];
diff --git a/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldWidgetSettingsTest.php b/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldWidgetSettingsTest.php
index 6e2bf60c00c4..5cee36185366 100644
--- a/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldWidgetSettingsTest.php
+++ b/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldWidgetSettingsTest.php
@@ -44,6 +44,7 @@ public function testWidgetSettings(): void {
       'weight' => 1,
       'region' => 'content',
       'settings' => [
+        'orderable' => TRUE,
         'size' => 60,
         'placeholder' => '',
       ],
@@ -55,7 +56,7 @@ public function testWidgetSettings(): void {
     $component = $form_display->getComponent('field_test_two');
     $expected['type'] = 'number';
     $expected['weight'] = 1;
-    $expected['settings'] = ['placeholder' => ''];
+    $expected['settings'] = ['orderable' => TRUE, 'placeholder' => ''];
     $this->assertSame($expected, $component);
 
     // Float field.
@@ -67,49 +68,52 @@ public function testWidgetSettings(): void {
     $component = $form_display->getComponent('field_test_email');
     $expected['type'] = 'email_default';
     $expected['weight'] = 6;
-    $expected['settings'] = ['placeholder' => '', 'size' => 60];
+    $expected['settings'] = ['orderable' => TRUE, 'placeholder' => '', 'size' => 60];
     $this->assertSame($expected, $component);
 
     // Link field.
     $component = $form_display->getComponent('field_test_link');
-    $this->assertSame('link_default', $component['type']);
-    $this->assertSame(7, $component['weight']);
-    $this->assertEmpty(array_filter($component['settings']));
+    $expected['type'] = 'link_default';
+    $expected['weight'] = 7;
+    $expected['settings'] = ['orderable' => TRUE, 'placeholder_url' => '', 'placeholder_title' => ''];
+    $this->assertSame($expected, $component);
 
     // File field.
     $component = $form_display->getComponent('field_test_filefield');
     $expected['type'] = 'file_generic';
     $expected['weight'] = 8;
-    $expected['settings'] = ['progress_indicator' => 'bar'];
+    $expected['settings'] = ['orderable' => TRUE, 'progress_indicator' => 'bar'];
     $this->assertSame($expected, $component);
 
     // Image field.
     $component = $form_display->getComponent('field_test_imagefield');
     $expected['type'] = 'image_image';
     $expected['weight'] = 9;
-    $expected['settings'] = ['progress_indicator' => 'bar', 'preview_image_style' => 'thumbnail'];
+    $expected['settings'] = ['orderable' => TRUE, 'progress_indicator' => 'bar', 'preview_image_style' => 'thumbnail'];
     $this->assertSame($expected, $component);
 
     // Phone field.
     $component = $form_display->getComponent('field_test_phone');
     $expected['type'] = 'telephone_default';
     $expected['weight'] = 13;
-    $expected['settings'] = ['placeholder' => ''];
+    $expected['settings'] = ['orderable' => TRUE, 'placeholder' => ''];
     $this->assertSame($expected, $component);
 
     // Date fields.
     $component = $form_display->getComponent('field_test_date');
     $expected['type'] = 'datetime_default';
     $expected['weight'] = 10;
-    $expected['settings'] = [];
+    $expected['settings'] = ['orderable' => TRUE];
     $this->assertSame($expected, $component);
 
     $component = $form_display->getComponent('field_test_datestamp');
     $expected['weight'] = 11;
+    $expected['settings'] = ['orderable' => TRUE];
     $this->assertSame($expected, $component);
 
     $component = $form_display->getComponent('field_test_datetime');
     $expected['weight'] = 12;
+    $expected['settings'] = ['orderable' => TRUE];
     $this->assertSame($expected, $component);
 
     /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
diff --git a/core/modules/file/config/schema/file.schema.yml b/core/modules/file/config/schema/file.schema.yml
index f00ab3d23d71..d76c537e61c0 100644
--- a/core/modules/file/config/schema/file.schema.yml
+++ b/core/modules/file/config/schema/file.schema.yml
@@ -174,6 +174,9 @@ field.widget.settings.file_generic:
   type: mapping
   label: 'File format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     progress_indicator:
       type: string
       label: 'Progress indicator'
diff --git a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
index 62db3ddf1a43..4dd593ecdad7 100644
--- a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
+++ b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
@@ -60,6 +60,8 @@ public static function defaultSettings() {
    * {@inheritdoc}
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
+    $element = parent::settingsForm($form, $form_state);
+
     $element['progress_indicator'] = [
       '#type' => 'radios',
       '#title' => $this->t('Progress indicator'),
@@ -79,7 +81,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
     $summary[] = $this->t('Progress indicator: @progress_indicator', ['@progress_indicator' => $this->getSetting('progress_indicator')]);
     return $summary;
   }
@@ -173,10 +175,17 @@ protected function formMultipleElements(FieldItemListInterface $items, array &$f
       // The group of elements all-together need some extra functionality after
       // building up the full list (like draggable table rows).
       $elements['#file_upload_delta'] = $delta;
-      $elements['#type'] = 'details';
       $elements['#open'] = TRUE;
-      $elements['#theme'] = 'file_widget_multiple';
-      $elements['#theme_wrappers'] = ['details'];
+      if ($this->getSetting('orderable')) {
+        $elements['#type'] = 'details';
+        $elements['#theme'] = 'file_widget_multiple';
+        $elements['#theme_wrappers'] = ['details'];
+      }
+      else {
+        $elements['#theme'] = 'field_multiple_value_without_order_form';
+        $elements['#cardinality_multiple'] = $this->fieldDefinition->getFieldStorageDefinition()->isMultiple();
+      }
+
       $elements['#process'] = [[static::class, 'processMultiple']];
       $elements['#title'] = $title;
 
diff --git a/core/modules/image/config/schema/image.schema.yml b/core/modules/image/config/schema/image.schema.yml
index f805caa378ca..4c3997043b53 100644
--- a/core/modules/image/config/schema/image.schema.yml
+++ b/core/modules/image/config/schema/image.schema.yml
@@ -179,6 +179,9 @@ field.widget.settings.image_image:
   type: mapping
   label: 'Image field display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     progress_indicator:
       type: string
       label: 'Progress indicator'
diff --git a/core/modules/jsonapi/tests/src/Functional/EntityFormDisplayTest.php b/core/modules/jsonapi/tests/src/Functional/EntityFormDisplayTest.php
index 24a34c6fa2dd..ae5eaed0435f 100644
--- a/core/modules/jsonapi/tests/src/Functional/EntityFormDisplayTest.php
+++ b/core/modules/jsonapi/tests/src/Functional/EntityFormDisplayTest.php
@@ -102,13 +102,16 @@ protected function getExpectedDocument(): array {
               'type' => 'datetime_timestamp',
               'weight' => 10,
               'region' => 'content',
-              'settings' => [],
+              'settings' => [
+                'orderable' => TRUE,
+              ],
               'third_party_settings' => [],
             ],
             'promote' => [
               'type' => 'boolean_checkbox',
               'settings' => [
                 'display_label' => TRUE,
+                'orderable' => TRUE,
               ],
               'weight' => 15,
               'region' => 'content',
@@ -120,6 +123,7 @@ protected function getExpectedDocument(): array {
               'region' => 'content',
               'settings' => [
                 'display_label' => TRUE,
+                'orderable' => TRUE,
               ],
               'third_party_settings' => [],
             ],
@@ -127,6 +131,7 @@ protected function getExpectedDocument(): array {
               'type' => 'boolean_checkbox',
               'settings' => [
                 'display_label' => TRUE,
+                'orderable' => TRUE,
               ],
               'weight' => 16,
               'region' => 'content',
@@ -137,6 +142,7 @@ protected function getExpectedDocument(): array {
               'weight' => -5,
               'region' => 'content',
               'settings' => [
+                'orderable' => TRUE,
                 'size' => 60,
                 'placeholder' => '',
               ],
@@ -146,6 +152,7 @@ protected function getExpectedDocument(): array {
               'type' => 'entity_reference_autocomplete',
               'weight' => 5,
               'settings' => [
+                'orderable' => TRUE,
                 'match_operator' => 'CONTAINS',
                 'match_limit' => 10,
                 'size' => 60,
diff --git a/core/modules/link/config/schema/link.schema.yml b/core/modules/link/config/schema/link.schema.yml
index e3a1ffab98e5..493e3fa217e4 100644
--- a/core/modules/link/config/schema/link.schema.yml
+++ b/core/modules/link/config/schema/link.schema.yml
@@ -28,6 +28,9 @@ field.widget.settings.link_default:
   type: mapping
   label: 'Link format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     placeholder_url:
       type: string
       label: 'Placeholder for URL'
diff --git a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
index 3a045b6f641d..8742e83e6962 100644
--- a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
+++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
@@ -403,7 +403,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $placeholder_title = $this->getSetting('placeholder_title');
     $placeholder_url = $this->getSetting('placeholder_url');
diff --git a/core/modules/media_library/config/schema/media_library.schema.yml b/core/modules/media_library/config/schema/media_library.schema.yml
index 312f4ab60718..5d613c4e9695 100644
--- a/core/modules/media_library/config/schema/media_library.schema.yml
+++ b/core/modules/media_library/config/schema/media_library.schema.yml
@@ -2,6 +2,9 @@ field.widget.settings.media_library_widget:
   type: mapping
   label: 'Media library widget settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     media_types:
       type: sequence
       label: 'Allowed media types, in display order'
diff --git a/core/modules/media_library/tests/modules/media_library_test_widget/config/schema/media_library_test_widget.schema.yml b/core/modules/media_library/tests/modules/media_library_test_widget/config/schema/media_library_test_widget.schema.yml
index 81186253e1ae..5957f6b917ef 100644
--- a/core/modules/media_library/tests/modules/media_library_test_widget/config/schema/media_library_test_widget.schema.yml
+++ b/core/modules/media_library/tests/modules/media_library_test_widget/config/schema/media_library_test_widget.schema.yml
@@ -2,6 +2,9 @@ field.widget.settings.media_library_inception_widget:
   type: mapping
   label: 'Media library inception widget settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     media_types:
       type: sequence
       label: 'Allowed media types, in display order'
diff --git a/core/modules/options/config/schema/options.schema.yml b/core/modules/options/config/schema/options.schema.yml
index 87323eb1d456..e89f63bb4209 100644
--- a/core/modules/options/config/schema/options.schema.yml
+++ b/core/modules/options/config/schema/options.schema.yml
@@ -104,10 +104,18 @@ field.formatter.settings.list_key:
 field.widget.settings.options_buttons:
   type: mapping
   label: 'Check boxes/radio buttons format settings'
+  mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
 
 field.widget.settings.options_select:
   type: mapping
   label: 'Select list format settings'
+  mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
 
 views.argument.number_list_field:
   type: views.argument.numeric
diff --git a/core/modules/path/config/schema/path.schema.yml b/core/modules/path/config/schema/path.schema.yml
index 849dbe3c8182..7acad352b969 100644
--- a/core/modules/path/config/schema/path.schema.yml
+++ b/core/modules/path/config/schema/path.schema.yml
@@ -3,3 +3,7 @@
 field.widget.settings.path:
   type: mapping
   label: 'Link format settings'
+  mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
diff --git a/core/modules/system/templates/field-multiple-value-without-order-form.html.twig b/core/modules/system/templates/field-multiple-value-without-order-form.html.twig
new file mode 100644
index 000000000000..236a9fdc3d98
--- /dev/null
+++ b/core/modules/system/templates/field-multiple-value-without-order-form.html.twig
@@ -0,0 +1,65 @@
+{#
+/**
+ * @file
+ * Theme override for an individual form element.
+ *
+ * Available variables for all fields:
+ * - multiple: Whether there are multiple instances of the field.
+ *
+ * Available variables for single cardinality fields:
+ * - elements: Form elements to be rendered.
+ *
+ * Available variables when there are multiple fields.
+ * - table: Table of field items.
+ * - description: The description element containing the following properties:
+ *   - content: The description content of the form element.
+ *   - attributes: HTML attributes to apply to the description container.
+ * - description_display: Description display setting. It can have these values:
+ *   - before: The description is output before the element.
+ *   - after: The description is output after the element. This is the default
+ *     value.
+ *   - invisible: The description is output after the element, hidden visually
+ *     but available to screen readers.
+ * - button: "Add another item" button.
+ *
+ * @see template_preprocess_field_multiple_value_without_order_form()
+ */
+#}
+{%
+  set title_classes = [
+    'label',
+    required ? 'js-form-required',
+    required ? 'form-required',
+  ]
+%}
+{%
+  set description_classes = [
+  'description',
+  description_display == 'invisible' ? 'visually-hidden',
+]
+%}
+{% if multiple %}
+  <div class="js-form-item form-item">
+    {% if title %}
+      {{ title }}
+    {% endif %}
+    {% if description_display == 'before' and description.content %}
+      <div{{ description.attributes.addClass(description_classes) }}>
+        {{ description.content }}
+      </div>
+    {% endif %}
+    {{ items }}
+    {% if description_display in ['after', 'invisible'] and description.content %}
+      <div{{ description.attributes.addClass(description_classes) }}>
+        {{ description.content }}
+      </div>
+    {% endif %}
+    {% if button %}
+      <div class="clearfix">{{ button }}</div>
+    {% endif %}
+  </div>
+{% else %}
+  {% for element in elements %}
+    {{ element }}
+  {% endfor %}
+{% endif %}
diff --git a/core/modules/telephone/config/schema/telephone.schema.yml b/core/modules/telephone/config/schema/telephone.schema.yml
index 516cbc3459dd..2703617b34bf 100644
--- a/core/modules/telephone/config/schema/telephone.schema.yml
+++ b/core/modules/telephone/config/schema/telephone.schema.yml
@@ -12,6 +12,9 @@ field.widget.settings.telephone_default:
   type: mapping
   label: 'Telephone default format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     placeholder:
       type: label
       label: 'Placeholder'
diff --git a/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php b/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
index a8dcdec775bd..8e9b3275366d 100644
--- a/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
+++ b/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
@@ -32,6 +32,8 @@ public static function defaultSettings() {
    * {@inheritdoc}
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
+    $element = parent::settingsForm($form, $form_state);
+
     $element['placeholder'] = [
       '#type' => 'textfield',
       '#title' => $this->t('Placeholder'),
@@ -45,7 +47,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $placeholder = $this->getSetting('placeholder');
     if (!empty($placeholder)) {
diff --git a/core/modules/text/config/schema/text.schema.yml b/core/modules/text/config/schema/text.schema.yml
index 8b08b109d466..b35b8e01e81a 100644
--- a/core/modules/text/config/schema/text.schema.yml
+++ b/core/modules/text/config/schema/text.schema.yml
@@ -124,6 +124,9 @@ field.widget.settings.text_textarea:
   type: mapping
   label: 'Text area (multiple rows) display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     rows:
       type: integer
       label: 'Rows'
@@ -135,6 +138,9 @@ field.widget.settings.text_textarea_with_summary:
   type: mapping
   label: 'Text area with a summary display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     rows:
       type: integer
       label: 'Rows'
@@ -152,6 +158,9 @@ field.widget.settings.text_textfield:
   type: mapping
   label: 'Text field display format settings'
   mapping:
+    orderable:
+      type: boolean
+      label: 'Orderable'
     size:
       type: integer
       label: 'Size of textfield'
diff --git a/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml b/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml
index 15cc3308b7af..60a5d83f8db3 100644
--- a/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml
+++ b/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml
@@ -23,6 +23,7 @@ content:
     weight: 2
     region: content
     settings:
+      orderable: true
       rows: 9
       summary_rows: 3
       placeholder: ''
@@ -38,7 +39,8 @@ content:
     type: datetime_timestamp
     weight: 10
     region: content
-    settings: {  }
+    settings:
+      orderable: true
     third_party_settings: {  }
   field_image:
     type: image_image
@@ -62,13 +64,15 @@ content:
     type: path
     weight: 30
     region: content
-    settings: {  }
+    settings:
+      orderable: true
     third_party_settings: {  }
   promote:
     type: boolean_checkbox
     weight: 15
     region: content
     settings:
+      orderable: true
       display_label: true
     third_party_settings: {  }
   status:
@@ -83,6 +87,7 @@ content:
     weight: 16
     region: content
     settings:
+      orderable: true
       display_label: true
     third_party_settings: {  }
   title:
@@ -98,6 +103,7 @@ content:
     weight: 5
     region: content
     settings:
+      orderable: true
       match_operator: CONTAINS
       match_limit: 10
       size: 60
diff --git a/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml b/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml
index edb853ed3de0..75e0f7d7969a 100644
--- a/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml
+++ b/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml
@@ -17,6 +17,7 @@ content:
     weight: 31
     region: content
     settings:
+      orderable: true
       rows: 9
       summary_rows: 3
       placeholder: ''
@@ -26,19 +27,22 @@ content:
     type: datetime_timestamp
     weight: 10
     region: content
-    settings: {  }
+    settings:
+      orderable: true
     third_party_settings: {  }
   path:
     type: path
     weight: 30
     region: content
-    settings: {  }
+    settings:
+      orderable: true
     third_party_settings: {  }
   promote:
     type: boolean_checkbox
     weight: 15
     region: content
     settings:
+      orderable: true
       display_label: true
     third_party_settings: {  }
   status:
@@ -53,6 +57,7 @@ content:
     weight: 16
     region: content
     settings:
+      orderable: true
       display_label: true
     third_party_settings: {  }
   title:
@@ -60,6 +65,7 @@ content:
     weight: -5
     region: content
     settings:
+      orderable: true
       size: 60
       placeholder: ''
     third_party_settings: {  }
@@ -68,6 +74,7 @@ content:
     weight: 5
     region: content
     settings:
+      orderable: true
       match_operator: CONTAINS
       match_limit: 10
       size: 60
diff --git a/core/tests/Drupal/FunctionalTests/Rest/EntityFormDisplayResourceTestBase.php b/core/tests/Drupal/FunctionalTests/Rest/EntityFormDisplayResourceTestBase.php
index 00afb056689f..33c796a33251 100644
--- a/core/tests/Drupal/FunctionalTests/Rest/EntityFormDisplayResourceTestBase.php
+++ b/core/tests/Drupal/FunctionalTests/Rest/EntityFormDisplayResourceTestBase.php
@@ -69,13 +69,16 @@ protected function getExpectedNormalizedEntity() {
           'type' => 'datetime_timestamp',
           'weight' => 10,
           'region' => 'content',
-          'settings' => [],
+          'settings' => [
+            'orderable' => TRUE,
+          ],
           'third_party_settings' => [],
         ],
         'promote' => [
           'type' => 'boolean_checkbox',
           'settings' => [
             'display_label' => TRUE,
+            'orderable' => TRUE,
           ],
           'weight' => 15,
           'region' => 'content',
@@ -87,6 +90,7 @@ protected function getExpectedNormalizedEntity() {
           'region' => 'content',
           'settings' => [
             'display_label' => TRUE,
+            'orderable' => TRUE,
           ],
           'third_party_settings' => [],
         ],
@@ -94,6 +98,7 @@ protected function getExpectedNormalizedEntity() {
           'type' => 'boolean_checkbox',
           'settings' => [
             'display_label' => TRUE,
+            'orderable' => TRUE,
           ],
           'weight' => 16,
           'region' => 'content',
@@ -104,6 +109,7 @@ protected function getExpectedNormalizedEntity() {
           'weight' => -5,
           'region' => 'content',
           'settings' => [
+            'orderable' => TRUE,
             'size' => 60,
             'placeholder' => '',
           ],
@@ -115,6 +121,7 @@ protected function getExpectedNormalizedEntity() {
           'settings' => [
             'match_operator' => 'CONTAINS',
             'match_limit' => 10,
+            'orderable' => TRUE,
             'size' => 60,
             'placeholder' => '',
           ],
diff --git a/core/themes/claro/templates/field-multiple-value-without-order-form.html.twig b/core/themes/claro/templates/field-multiple-value-without-order-form.html.twig
new file mode 100644
index 000000000000..f4aa75faf281
--- /dev/null
+++ b/core/themes/claro/templates/field-multiple-value-without-order-form.html.twig
@@ -0,0 +1,65 @@
+{#
+/**
+ * @file
+ * Theme override for an individual form element.
+ *
+ * Available variables for all fields:
+ * - multiple: Whether there are multiple instances of the field.
+ *
+ * Available variables for single cardinality fields:
+ * - elements: Form elements to be rendered.
+ *
+ * Available variables when there are multiple fields.
+ * - table: Table of field items.
+ * - description: The description element containing the following properties:
+ *   - content: The description content of the form element.
+ *   - attributes: HTML attributes to apply to the description container.
+ * - description_display: Description display setting. It can have these values:
+ *   - before: The description is output before the element.
+ *   - after: The description is output after the element. This is the default
+ *     value.
+ *   - invisible: The description is output after the element, hidden visually
+ *     but available to screen readers.
+ * - button: "Add another item" button.
+ *
+ * @see template_preprocess_field_multiple_value_without_order_form()
+ */
+#}
+{%
+  set title_classes = [
+    'label',
+    required ? 'js-form-required',
+    required ? 'form-required',
+  ]
+%}
+{%
+  set description_classes = [
+  'form-item__description',
+  description_display == 'invisible' ? 'visually-hidden',
+]
+%}
+{% if multiple %}
+  <div class="js-form-item form-item">
+    {% if title %}
+      {{ title }}
+    {% endif %}
+    {% if description_display == 'before' and description.content %}
+      <div{{ description.attributes.addClass(description_classes) }}>
+        {{ description.content }}
+      </div>
+    {% endif %}
+    {{ items }}
+    {% if description_display in ['after', 'invisible'] and description.content %}
+      <div{{ description.attributes.addClass(description_classes) }}>
+        {{ description.content }}
+      </div>
+    {% endif %}
+    {% if button %}
+      <div class="clearfix">{{ button }}</div>
+    {% endif %}
+  </div>
+{% else %}
+  {% for element in elements %}
+    {{ element }}
+  {% endfor %}
+{% endif %}
diff --git a/core/themes/stable9/templates/form/field-multiple-value-without-order-form.html.twig b/core/themes/stable9/templates/form/field-multiple-value-without-order-form.html.twig
new file mode 100644
index 000000000000..c86c13b796fb
--- /dev/null
+++ b/core/themes/stable9/templates/form/field-multiple-value-without-order-form.html.twig
@@ -0,0 +1,46 @@
+{#
+/**
+ * @file
+ * Theme override for an individual form element.
+ *
+ * Available variables for all fields:
+ * - multiple: Whether there are multiple instances of the field.
+ *
+ * Available variables for single cardinality fields:
+ * - elements: Form elements to be rendered.
+ *
+ * Available variables when there are multiple fields.
+ * - table: Table of field items.
+ * - description: The description element containing the following properties:
+ *   - content: The description content of the form element.
+ *   - attributes: HTML attributes to apply to the description container.
+ * - button: "Add another item" button.
+ *
+ * @see template_preprocess_field_multiple_value_without_order_form()
+ */
+#}
+{%
+  set title_classes = [
+    'label',
+    required ? 'js-form-required',
+    required ? 'form-required',
+  ]
+%}
+{% if multiple %}
+  {% if title %}
+    <h4{{ title_attributes.addClass(title_classes) }}>{{ title }}</h4>
+  {% endif %}
+  <div class="js-form-item form-item">
+    {{ items }}
+    {% if description.content %}
+      <div{{ description.attributes.addClass('description') }} >{{ description.content }}</div>
+    {% endif %}
+    {% if button %}
+      <div class="clearfix">{{ button }}</div>
+    {% endif %}
+  </div>
+{% else %}
+  {% for element in elements %}
+    {{ element }}
+  {% endfor %}
+{% endif %}{# empty Twig template #}
-- 
GitLab


From 81c9e9353f295b9af02d25702046454936e3ca10 Mon Sep 17 00:00:00 2001
From: Charles Tanton <charles@parkroad.co.za>
Date: Mon, 24 Mar 2025 11:47:20 +0200
Subject: [PATCH 2/3] 2264739: Fix PHPCS issues

---
 core/includes/theme.inc                   | 7 ++++---
 core/lib/Drupal/Core/Field/WidgetBase.php | 2 +-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index f3c1d8e0073e..c59f20eb1175 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1583,13 +1583,14 @@ function template_preprocess_field_multiple_value_without_order_form(&$variables
           continue;
         }
 
-        // Delay rendering of the "Display" option and the weight selector, so that
-        // each can be rendered later in its own column.
+        // Delay rendering of the "Display" option and the weight selector, so
+        // that each can be rendered later in its own column.
         if ($element['#display_field']) {
           hide($widget['display']);
         }
 
-        // Render everything else together in a column, without the normal wrappers.
+        // Render everything else together in a column, without the normal
+        // wrappers.
         $widget['#theme_wrappers'] = [];
         if ($element['#display_field']) {
           unset($widget['display']['#title']);
diff --git a/core/lib/Drupal/Core/Field/WidgetBase.php b/core/lib/Drupal/Core/Field/WidgetBase.php
index 1bf14aa31c9f..e4b6b228b61f 100644
--- a/core/lib/Drupal/Core/Field/WidgetBase.php
+++ b/core/lib/Drupal/Core/Field/WidgetBase.php
@@ -666,7 +666,7 @@ public function settingsSummary() {
 
     if ($this->fieldDefinition->getFieldStorageDefinition()->getCardinality() != 1) {
       $orderable = $this->getSetting('orderable');
-      $summary[] = t('Orderable: @orderable', ['@orderable' => ($orderable ? t('Yes') : t('No'))]);
+      $summary[] = $this->t('Orderable: @orderable', ['@orderable' => ($orderable ? $this->t('Yes') : $this->t('No'))]);
     }
 
     return $summary;
-- 
GitLab


From 7fc41791562cab31219f402f18be53532142d755 Mon Sep 17 00:00:00 2001
From: Charles Tanton <charles@parkroad.co.za>
Date: Mon, 24 Mar 2025 11:56:55 +0200
Subject: [PATCH 3/3] 2264739: Fix PHPStan issues

---
 core/includes/theme.inc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index c59f20eb1175..f1f089cfa6e8 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1552,7 +1552,7 @@ function template_preprocess_field_multiple_value_form(&$variables): void {
  *   An associative array containing:
  *   - element: A render element representing the form element.
  */
-function template_preprocess_field_multiple_value_without_order_form(&$variables) {
+function template_preprocess_field_multiple_value_without_order_form(&$variables): void {
   $element = $variables['element'];
   $variables['multiple'] = $element['#cardinality_multiple'];
 
@@ -1579,7 +1579,7 @@ function template_preprocess_field_multiple_value_without_order_form(&$variables
         if (empty($widget['#files'])) {
           $widget['#title'] = $element['#file_upload_title'];
           $widget['#title_display'] = 'hidden';
-          $widget['#description'] = \Drupal::service('renderer')->renderPlain($element['#file_upload_description']);
+          $widget['#description'] = \Drupal::service('renderer')->renderInIsolation($element['#file_upload_description']);
           continue;
         }
 
-- 
GitLab