diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 0becb4ef68..b11e35bfb8 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1529,7 +1529,10 @@ function template_preprocess_install_page(&$variables) {
*/
function template_preprocess_region(&$variables) {
// Create the $content variable that templates expect.
- $variables['content'] = $variables['elements']['#children'];
+ $variables['content'] = [];
+ foreach (Element::children($variables['elements']) as $key) {
+ $variables['content'][$key] = $variables['elements'][$key];
+ }
$variables['region'] = $variables['elements']['#region'];
}
diff --git a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php
index e8f8b5dfdc..b02849a680 100644
--- a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php
+++ b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php
@@ -270,12 +270,21 @@ protected function prepare(array $main_content, Request $request, RouteMatchInte
$page += $page_display->build();
}
- // $page is now fully built. Find all non-empty page regions, and add a
- // theme wrapper function that allows them to be consistently themed.
+ // $page is now fully built. Find all non-empty page regions, and set a
+ // #theme property that allows them to be consistently themed.
$regions = $this->themeManager->getActiveTheme()->getRegions();
foreach ($regions as $region) {
if (!empty($page[$region])) {
- $page[$region]['#theme_wrappers'][] = 'region';
+ // On most pages, every $page[$region] is an array of block render
+ // arrays, keyed by block ID. However, in some rare cases (e.g.
+ // BatchController:batchPage) a render array with #type="page" is
+ // created manually and $page[$region] may already have a #type or
+ // #theme property. To avoid breaking this render array when we set the
+ // #theme="region" property, wrap it in an element "region_content".
+ if (isset($page[$region]['#type']) || isset($page[$region]['#theme'])) {
+ $page[$region] = ['region_content' => $page[$region]];
+ }
+ $page[$region]['#theme'] = 'region';
$page[$region]['#region'] = $region;
}
}
diff --git a/core/modules/system/templates/region.html.twig b/core/modules/system/templates/region.html.twig
index 219e14b0a4..201e42176c 100644
--- a/core/modules/system/templates/region.html.twig
+++ b/core/modules/system/templates/region.html.twig
@@ -4,7 +4,10 @@
* Default theme implementation to display a region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/modules/system/tests/src/Functional/Render/RegionContentRenderTest.php b/core/modules/system/tests/src/Functional/Render/RegionContentRenderTest.php
new file mode 100644
index 0000000000..aa8b3fafb6
--- /dev/null
+++ b/core/modules/system/tests/src/Functional/Render/RegionContentRenderTest.php
@@ -0,0 +1,66 @@
+ [
+ 'label' => 'I am first',
+ 'weight' => '0',
+ ],
+ 'second' => [
+ 'label' => 'I am second',
+ 'weight' => '1',
+ ],
+ 'special' => [
+ 'label' => 'I am special',
+ 'weight' => '2',
+ ],
+ ];
+
+ // Place the test blocks in the header.
+ foreach ($test_blocks as $id => $test_block) {
+ $this->drupalPlaceBlock('system_powered_by_block', [
+ 'region' => 'header',
+ 'id' => $id,
+ 'label' => $test_block['label'],
+ 'weight' => $test_block['weight'],
+ ]);
+ }
+
+ // Test if the blocks are placed correctly in the region template. See
+ // core/modules/system/tests/themes/test_theme_region_content/templates/region--header.html.twig
+ $this->drupalGet('');
+ $assert = $this->assertSession();
+ $assert->elementExists('css', '#wrapper-special #block-special');
+ $assert->elementExists('css', '#wrapper-the-rest #block-first');
+ $assert->elementExists('css', '#wrapper-the-rest #block-second');
+ $assert->elementNotExists('css', '#wrapper-the-rest #block-special');
+ $assert->elementNotExists('css', '#wrapper-special #block-first');
+ $assert->elementNotExists('css', '#wrapper-special #block-second');
+ }
+
+}
diff --git a/core/modules/system/tests/themes/test_theme_region_content/templates/region--header.html.twig b/core/modules/system/tests/themes/test_theme_region_content/templates/region--header.html.twig
new file mode 100644
index 0000000000..9516b5e992
--- /dev/null
+++ b/core/modules/system/tests/themes/test_theme_region_content/templates/region--header.html.twig
@@ -0,0 +1,8 @@
+{% if content %}
+
+ {{ content.special }}
+
+
+ {{ content|without('special') }}
+
+{% endif %}
diff --git a/core/modules/system/tests/themes/test_theme_region_content/test_theme_region_content.info.yml b/core/modules/system/tests/themes/test_theme_region_content/test_theme_region_content.info.yml
new file mode 100644
index 0000000000..4bb1bf6c7c
--- /dev/null
+++ b/core/modules/system/tests/themes/test_theme_region_content/test_theme_region_content.info.yml
@@ -0,0 +1,5 @@
+name: 'Region content test'
+type: theme
+description: 'Theme to test the rendering of blocks in a region template.'
+version: VERSION
+base theme: stark
diff --git a/core/profiles/demo_umami/themes/umami/templates/classy/layout/region.html.twig b/core/profiles/demo_umami/themes/umami/templates/classy/layout/region.html.twig
index 95e71cec37..20ab315e9f 100644
--- a/core/profiles/demo_umami/themes/umami/templates/classy/layout/region.html.twig
+++ b/core/profiles/demo_umami/themes/umami/templates/classy/layout/region.html.twig
@@ -4,7 +4,10 @@
* Theme override to display a region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/claro/templates/classy/layout/region.html.twig b/core/themes/claro/templates/classy/layout/region.html.twig
index 95e71cec37..20ab315e9f 100644
--- a/core/themes/claro/templates/classy/layout/region.html.twig
+++ b/core/themes/claro/templates/classy/layout/region.html.twig
@@ -4,7 +4,10 @@
* Theme override to display a region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/claro/templates/region--breadcrumb.html.twig b/core/themes/claro/templates/region--breadcrumb.html.twig
index a66f43131d..e35f51cc8b 100644
--- a/core/themes/claro/templates/region--breadcrumb.html.twig
+++ b/core/themes/claro/templates/region--breadcrumb.html.twig
@@ -4,7 +4,10 @@
* Theme override to display a breadcrumb region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--breadcrumb.html.twig b/core/themes/olivero/templates/layout/region--breadcrumb.html.twig
index 5dbd5d45ff..6fb2017416 100644
--- a/core/themes/olivero/templates/layout/region--breadcrumb.html.twig
+++ b/core/themes/olivero/templates/layout/region--breadcrumb.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the breadcrumb region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--content-above.html.twig b/core/themes/olivero/templates/layout/region--content-above.html.twig
index e50082ea39..01812cdc80 100644
--- a/core/themes/olivero/templates/layout/region--content-above.html.twig
+++ b/core/themes/olivero/templates/layout/region--content-above.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the content above region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--content-below.html.twig b/core/themes/olivero/templates/layout/region--content-below.html.twig
index c0f9ed29e5..d8e856c65a 100644
--- a/core/themes/olivero/templates/layout/region--content-below.html.twig
+++ b/core/themes/olivero/templates/layout/region--content-below.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the content below region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--content.html.twig b/core/themes/olivero/templates/layout/region--content.html.twig
index 7f86b58103..21556bcc1b 100644
--- a/core/themes/olivero/templates/layout/region--content.html.twig
+++ b/core/themes/olivero/templates/layout/region--content.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the content region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--footer-bottom.html.twig b/core/themes/olivero/templates/layout/region--footer-bottom.html.twig
index 36ffd885f9..978b8d5c57 100644
--- a/core/themes/olivero/templates/layout/region--footer-bottom.html.twig
+++ b/core/themes/olivero/templates/layout/region--footer-bottom.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the footer bottom region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--footer-top.html.twig b/core/themes/olivero/templates/layout/region--footer-top.html.twig
index 8baaf31405..a09ec7d6a6 100644
--- a/core/themes/olivero/templates/layout/region--footer-top.html.twig
+++ b/core/themes/olivero/templates/layout/region--footer-top.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the footer top region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--header.html.twig b/core/themes/olivero/templates/layout/region--header.html.twig
index 8ecee66336..3d8cee29d1 100644
--- a/core/themes/olivero/templates/layout/region--header.html.twig
+++ b/core/themes/olivero/templates/layout/region--header.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the header region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--highlighted.html.twig b/core/themes/olivero/templates/layout/region--highlighted.html.twig
index 6c42936807..f8b2c90b00 100644
--- a/core/themes/olivero/templates/layout/region--highlighted.html.twig
+++ b/core/themes/olivero/templates/layout/region--highlighted.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the content region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--primary-menu.html.twig b/core/themes/olivero/templates/layout/region--primary-menu.html.twig
index 32ade151fe..e0310cf513 100644
--- a/core/themes/olivero/templates/layout/region--primary-menu.html.twig
+++ b/core/themes/olivero/templates/layout/region--primary-menu.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the header region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--secondary-menu.html.twig b/core/themes/olivero/templates/layout/region--secondary-menu.html.twig
index ce7312194f..2ca6515f5e 100644
--- a/core/themes/olivero/templates/layout/region--secondary-menu.html.twig
+++ b/core/themes/olivero/templates/layout/region--secondary-menu.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the header region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--sidebar.html.twig b/core/themes/olivero/templates/layout/region--sidebar.html.twig
index a3f88864f9..da61a31107 100644
--- a/core/themes/olivero/templates/layout/region--sidebar.html.twig
+++ b/core/themes/olivero/templates/layout/region--sidebar.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the sidebar region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region--social.html.twig b/core/themes/olivero/templates/layout/region--social.html.twig
index 6f3cf69740..f47e948cbb 100644
--- a/core/themes/olivero/templates/layout/region--social.html.twig
+++ b/core/themes/olivero/templates/layout/region--social.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display the social region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/olivero/templates/layout/region.html.twig b/core/themes/olivero/templates/layout/region.html.twig
index 651a0112a5..cf04369f61 100644
--- a/core/themes/olivero/templates/layout/region.html.twig
+++ b/core/themes/olivero/templates/layout/region.html.twig
@@ -4,7 +4,10 @@
* Olivero's theme override to display a region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/stable9/templates/layout/region.html.twig b/core/themes/stable9/templates/layout/region.html.twig
index e5e36d0741..2f78982582 100644
--- a/core/themes/stable9/templates/layout/region.html.twig
+++ b/core/themes/stable9/templates/layout/region.html.twig
@@ -4,7 +4,10 @@
* Theme override to display a region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.
diff --git a/core/themes/starterkit_theme/templates/layout/region.html.twig b/core/themes/starterkit_theme/templates/layout/region.html.twig
index 95e71cec37..20ab315e9f 100644
--- a/core/themes/starterkit_theme/templates/layout/region.html.twig
+++ b/core/themes/starterkit_theme/templates/layout/region.html.twig
@@ -4,7 +4,10 @@
* Theme override to display a region.
*
* Available variables:
- * - content: The content for this region, typically blocks.
+ * - content: The content for this region, typically blocks. Use {{ content }}
+ * to print them all, or print a subset such as {{ content.page_title }}.
+ * Use {{ content|without('page_title') }} to temporarily suppress the
+ * printing of a given child element.
* - attributes: HTML attributes for the region
.
* - region: The name of the region variable as defined in the theme's
* .info.yml file.