diff -u b/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php --- b/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -577,12 +577,12 @@ // Gather prefixes. This will be used to limit the found functions to the // expected naming conventions. $prefixes = array_keys((array) $this->moduleHandler->getModuleList()); + foreach (array_reverse($theme->getBaseThemes()) as $base) { + $prefixes[] = $base->getName(); + } if ($theme->getEngine()) { $prefixes[] = $theme->getEngine() . '_engine'; } - foreach ($theme->getBaseThemes() as $base) { - $prefixes[] = $base->getName(); - } $prefixes[] = $theme->getName(); // Collect all known hooks. Discovered functions must be based on a known hook. @@ -635,6 +635,8 @@ if (isset($cache[$hook]['preprocess functions']) && empty($cache[$hook]['preprocess functions'])) { unset($cache[$hook]['preprocess functions']); } + // Ensure uniqueness. + $cache[$hook]['preprocess functions'] = array_unique($cache[$hook]['preprocess functions']); } } reverted: --- b/core/modules/system/src/Tests/Theme/RegistryTest.php +++ a/core/modules/system/src/Tests/Theme/RegistryTest.php @@ -66,6 +66,42 @@ } /** + * Tests the theme registry with multiple subthemes. + */ + public function testMultipleSubThemes() { + $theme_handler = \Drupal::service('theme_handler'); + $theme_handler->install(['test_basetheme', 'test_subtheme', 'test_subsubtheme']); + + $registry_subsub_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_subsubtheme'); + $registry_subsub_theme->setThemeManager(\Drupal::theme()); + $registry_sub_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_subtheme'); + $registry_sub_theme->setThemeManager(\Drupal::theme()); + $registry_base_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_basetheme'); + $registry_base_theme->setThemeManager(\Drupal::theme()); + + $preprocess_functions = $registry_subsub_theme->get()['theme_test_template_test']['preprocess functions']; + $this->assertIdentical([ + 'template_preprocess', + 'test_basetheme_preprocess_theme_test_template_test', + 'test_subtheme_preprocess_theme_test_template_test', + 'test_subsubtheme_preprocess_theme_test_template_test', + ], $preprocess_functions); + + $preprocess_functions = $registry_sub_theme->get()['theme_test_template_test']['preprocess functions']; + $this->assertIdentical([ + 'template_preprocess', + 'test_basetheme_preprocess_theme_test_template_test', + 'test_subtheme_preprocess_theme_test_template_test', + ], $preprocess_functions); + + $preprocess_functions = $registry_base_theme->get()['theme_test_template_test']['preprocess functions']; + $this->assertIdentical([ + 'template_preprocess', + 'test_basetheme_preprocess_theme_test_template_test', + ], $preprocess_functions); + } + + /** * Tests that the theme registry can be altered by themes. */ public function testThemeRegistryAlterByTheme() { reverted: --- b/core/modules/system/src/Tests/Theme/RegistryTest.php.orig +++ /dev/null @@ -1,119 +0,0 @@ -setMethod('GET'); - $cid = 'test_theme_registry'; - - // Directly instantiate the theme registry, this will cause a base cache - // entry to be written in __construct(). - $cache = \Drupal::cache(); - $lock_backend = \Drupal::lock(); - $registry = new ThemeRegistry($cid, $cache, $lock_backend, array('theme_registry'), $this->container->get('module_handler')->isLoaded()); - - $this->assertTrue(\Drupal::cache()->get($cid), 'Cache entry was created.'); - - // Trigger a cache miss for an offset. - $this->assertTrue($registry->get('theme_test_template_test'), 'Offset was returned correctly from the theme registry.'); - // This will cause the ThemeRegistry class to write an updated version of - // the cache entry when it is destroyed, usually at the end of the request. - // Before that happens, manually delete the cache entry we created earlier - // so that the new entry is written from scratch. - \Drupal::cache()->delete($cid); - - // Destroy the class so that it triggers a cache write for the offset. - $registry->destruct(); - - $this->assertTrue(\Drupal::cache()->get($cid), 'Cache entry was created.'); - - // Create a new instance of the class. Confirm that both the offset - // requested previously, and one that has not yet been requested are both - // available. - $registry = new ThemeRegistry($cid, $cache, $lock_backend, array('theme_registry'), $this->container->get('module_handler')->isLoaded()); - $this->assertTrue($registry->get('theme_test_template_test'), 'Offset was returned correctly from the theme registry'); - $this->assertTrue($registry->get('theme_test_template_test_2'), 'Offset was returned correctly from the theme registry'); - } - - /** - * Tests the theme registry with multiple subthemes. - */ - public function testMultipleSubThemes() { - $theme_handler = \Drupal::service('theme_handler'); - $theme_handler->install(['test_basetheme', 'test_subtheme', 'test_subsubtheme']); - - $registry_subsub_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_subsubtheme'); - $registry_subsub_theme->setThemeManager(\Drupal::theme()); - $registry_sub_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_subtheme'); - $registry_sub_theme->setThemeManager(\Drupal::theme()); - $registry_base_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_basetheme'); - $registry_base_theme->setThemeManager(\Drupal::theme()); - - $preprocess_functions = $registry_subsub_theme->get()['theme_test_template_test']['preprocess functions']; - $this->assertIdentical([ - 'template_preprocess', - 'test_basetheme_preprocess_theme_test_template_test', - 'test_subtheme_preprocess_theme_test_template_test', - 'test_subsubtheme_preprocess_theme_test_template_test', - ], $preprocess_functions); - - $preprocess_functions = $registry_sub_theme->get()['theme_test_template_test']['preprocess functions']; - $this->assertIdentical([ - 'template_preprocess', - 'test_basetheme_preprocess_theme_test_template_test', - 'test_subtheme_preprocess_theme_test_template_test', - ], $preprocess_functions); - - $preprocess_functions = $registry_base_theme->get()['theme_test_template_test']['preprocess functions']; - $this->assertIdentical([ - 'template_preprocess', - 'test_basetheme_preprocess_theme_test_template_test', - ], $preprocess_functions); - } - - /** - * Tests that the theme registry can be altered by themes. - */ - public function testThemeRegistryAlterByTheme() { - - /** @var \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler */ - $theme_handler = \Drupal::service('theme_handler'); - $theme_handler->install(['test_theme']); - $theme_handler->setDefault('test_theme'); - - $registry = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_theme'); - $registry->setThemeManager(\Drupal::theme()); - $this->assertEqual('value', $registry->get()['theme_test_template_test']['variables']['additional']); - } - -} reverted: --- b/core/modules/system/tests/themes/test_theme/test_theme.theme.orig +++ /dev/null @@ -1,107 +0,0 @@ -alter('theme_test_alter'). - */ -function test_theme_theme_test_alter_alter(&$data) { - $data = 'test_theme_theme_test_alter_alter was invoked'; -} - -/** - * Implements hook_theme_suggestions_alter(). - */ -function test_theme_theme_suggestions_alter(array &$suggestions, array $variables, $hook) { - drupal_set_message(__FUNCTION__ . '() executed.'); - // Theme alter hooks run after module alter hooks, so add this theme - // suggestion to the beginning of the array so that the suggestion added by - // the theme_suggestions_test module can be picked up when that module is - // enabled. - if ($hook == 'theme_test_general_suggestions') { - array_unshift($suggestions, 'theme_test_general_suggestions__' . 'theme_override'); - } -} - -/** - * Implements hook_theme_suggestions_HOOK_alter(). - */ -function test_theme_theme_suggestions_theme_test_suggestions_alter(array &$suggestions, array $variables) { - drupal_set_message(__FUNCTION__ . '() executed.'); - // Theme alter hooks run after module alter hooks, so add this theme - // suggestion to the beginning of the array so that the suggestion added by - // the theme_suggestions_test module can be picked up when that module is - // enabled. - array_unshift($suggestions, 'theme_test_suggestions__' . 'theme_override'); -} - -/** - * Implements hook_theme_suggestions_HOOK_alter(). - */ -function test_theme_theme_suggestions_theme_test_function_suggestions_alter(array &$suggestions, array $variables) { - // Theme alter hooks run after module alter hooks, so add this theme - // suggestion to the beginning of the array so that the suggestion added by - // the theme_suggestions_test module can be picked up when that module is - // enabled. - array_unshift($suggestions, 'theme_test_function_suggestions__' . 'theme_override'); -} - -/** - * Returns HTML for a theme function suggestion test. - * - * Implements the theme_test_function_suggestions__theme_override suggestion. - */ -function test_theme_theme_test_function_suggestions__theme_override($variables) { - return 'Theme function overridden based on new theme suggestion provided by the test_theme theme.'; -} - -/** - * Returns HTML for a theme function suggestion test. - * - * Implements the theme_test_function_suggestions__module_override suggestion. - */ -function test_theme_theme_test_function_suggestions__module_override($variables) { - return 'Theme function overridden based on new theme suggestion provided by a module.'; -} - -/** - * Implements hook_theme_registry_alter(). - */ -function test_theme_theme_registry_alter(&$registry) { - $registry['theme_test_template_test']['variables']['additional'] = 'value'; -}