diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php index a0af702..7cf4b3c 100644 --- a/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Theme; +use Drupal\Component\Utility\NestedArray; use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\DestructableInterface; @@ -565,10 +566,18 @@ protected function processExtension(array &$cache, $name, $type, $theme, $path) $info['preprocess functions'] = array_merge($cache[$hook]['preprocess functions'], $info['preprocess functions']); } $result[$hook]['preprocess functions'] = $info['preprocess functions']; + + // If a theme implementation definition provides both 'template' and + // 'function', the 'function' will be used. In this case, if the new + // result provides a 'template' value, any existing 'function' value + // must be removed for the override to be called. + if (isset($result[$hook]['template'])) { + unset($cache[$hook]['function']); + } } // Merge the newly created theme hooks into the existing cache. - $cache = $result + $cache; + $cache = NestedArray::mergeDeep($cache, $result); } // Let themes have variable preprocessors even if they didn't register a diff --git a/core/modules/layout_discovery/tests/src/Kernel/LayoutTest.php b/core/modules/layout_discovery/tests/src/Kernel/LayoutTest.php index 9d4c446..c3785df 100644 --- a/core/modules/layout_discovery/tests/src/Kernel/LayoutTest.php +++ b/core/modules/layout_discovery/tests/src/Kernel/LayoutTest.php @@ -34,6 +34,17 @@ protected function setUp() { } /** + * Tests that a layout provided by a theme has the preprocess function set. + */ + public function testThemeProvidedLayout() { + $this->container->get('theme_installer')->install(['test_layout_theme']); + $this->config('system.theme')->set('default', 'test_layout_theme')->save(); + + $theme_definitions = $this->container->get('theme.registry')->get(); + $this->assertTrue(in_array('template_preprocess_layout', $theme_definitions['test_layout_theme']['preprocess functions'])); + } + + /** * Test rendering a layout. * * @dataProvider renderLayoutData diff --git a/core/modules/layout_discovery/tests/themes/test_layout_theme/templates/test-layout-theme.html.twig b/core/modules/layout_discovery/tests/themes/test_layout_theme/templates/test-layout-theme.html.twig new file mode 100644 index 0000000..67675f6 --- /dev/null +++ b/core/modules/layout_discovery/tests/themes/test_layout_theme/templates/test-layout-theme.html.twig @@ -0,0 +1 @@ +{{ content.content }} diff --git a/core/modules/layout_discovery/tests/themes/test_layout_theme/test_layout_theme.info.yml b/core/modules/layout_discovery/tests/themes/test_layout_theme/test_layout_theme.info.yml new file mode 100644 index 0000000..021d43f --- /dev/null +++ b/core/modules/layout_discovery/tests/themes/test_layout_theme/test_layout_theme.info.yml @@ -0,0 +1,6 @@ +name: 'Test layout theme' +type: theme +description: 'Theme for testing a theme-provided layout' +version: VERSION +base theme: classy +core: 8.x diff --git a/core/modules/layout_discovery/tests/themes/test_layout_theme/test_layout_theme.layouts.yml b/core/modules/layout_discovery/tests/themes/test_layout_theme/test_layout_theme.layouts.yml new file mode 100644 index 0000000..9da19dd --- /dev/null +++ b/core/modules/layout_discovery/tests/themes/test_layout_theme/test_layout_theme.layouts.yml @@ -0,0 +1,7 @@ +test_layout_theme: + label: 'Test Layout - Theme' + category: 'Test Layout Theme' + template: templates/test-layout-theme + regions: + content: + label: Content diff --git a/core/modules/system/tests/modules/theme_test/theme_test.module b/core/modules/system/tests/modules/theme_test/theme_test.module index 2e6f164..41aa222 100644 --- a/core/modules/system/tests/modules/theme_test/theme_test.module +++ b/core/modules/system/tests/modules/theme_test/theme_test.module @@ -66,6 +66,10 @@ function theme_test_theme($existing, $type, $theme, $path) { 'bar' => '', ], ]; + $items['theme_test_registered_by_module'] = [ + 'render element' => 'content', + 'base hook' => 'container', + ]; return $items; } diff --git a/core/modules/system/tests/themes/test_theme/templates/theme-test-registered-by-module.html.twig b/core/modules/system/tests/themes/test_theme/templates/theme-test-registered-by-module.html.twig new file mode 100644 index 0000000..3432e01 --- /dev/null +++ b/core/modules/system/tests/themes/test_theme/templates/theme-test-registered-by-module.html.twig @@ -0,0 +1,2 @@ +{# Output for Theme API test #} +Template provided by theme is registered by module. diff --git a/core/tests/Drupal/KernelTests/Core/Theme/RegistryTest.php b/core/tests/Drupal/KernelTests/Core/Theme/RegistryTest.php index a962fec..f3bf4ba 100644 --- a/core/tests/Drupal/KernelTests/Core/Theme/RegistryTest.php +++ b/core/tests/Drupal/KernelTests/Core/Theme/RegistryTest.php @@ -192,4 +192,22 @@ public function testThemeSuggestions() { ], $suggestions, 'Found expected page node suggestions.'); } + /** + * Tests theme-provided templates that are registered by modules. + */ + public function testThemeTemplatesRegisteredByModules() { + $theme_handler = \Drupal::service('theme_handler'); + $theme_handler->install(['test_theme']); + + $registry_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_theme'); + $registry_theme->setThemeManager(\Drupal::theme()); + + $expected = [ + 'template_preprocess', + 'template_preprocess_container', + ]; + $registry = $registry_theme->get(); + $this->assertEquals($expected, $registry['theme_test_registered_by_module']['preprocess functions']); + } + }