diff --git a/core/lib/Drupal/Core/Theme/ThemeManager.php b/core/lib/Drupal/Core/Theme/ThemeManager.php index c58d176..183b453 100644 --- a/core/lib/Drupal/Core/Theme/ThemeManager.php +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php @@ -155,14 +155,19 @@ public function render($hook, array $variables) { // preprocess callbacks. $original_hook = $hook; + // Set derived suggestions for directly called suggestions like + // '#theme' => 'comment__node__article'. + $derived_suggestions[] = $derived_suggestion = $original_hook; + while ($pos = strrpos($derived_suggestion, '__')) { + $derived_suggestion = substr($derived_suggestion, 0, $pos); + $derived_suggestions[] = $derived_suggestion; + } + // If there's no implementation, check for more generic fallbacks. // If there's still no implementation, log an error and return an empty // string. if (!$theme_registry->has($hook)) { - // Iteratively strip everything after the last '__' delimiter, until an - // implementation is found. - while ($pos = strrpos($hook, '__')) { - $hook = substr($hook, 0, $pos); + foreach (array_slice($derived_suggestions, 1) as $hook) { if ($theme_registry->has($hook)) { break; } @@ -228,12 +233,14 @@ public function render($hook, array $variables) { // Invoke hook_theme_suggestions_HOOK(). $suggestions = $this->moduleHandler->invokeAll('theme_suggestions_' . $base_theme_hook, [$variables]); + // If the theme implementation was invoked with a direct theme suggestion // like '#theme' => 'node__article', add it to the suggestions array before // invoking suggestion alter hooks. - if (isset($info['base hook'])) { + if (isset($info['base hook']) && !in_array($hook, array_slice($derived_suggestions, 0, -1))) { $suggestions[] = $hook; } + $suggestions = array_merge($suggestions, array_reverse(array_slice($derived_suggestions, 0, -1))); // Invoke hook_theme_suggestions_alter() and // hook_theme_suggestions_HOOK_alter(). @@ -244,6 +251,11 @@ public function render($hook, array $variables) { $this->moduleHandler->alter($hooks, $suggestions, $variables, $base_theme_hook); $this->alter($hooks, $suggestions, $variables, $base_theme_hook); + // Add the base suggestion, should always have the lowest priority + if (!in_array(array_slice($derived_suggestions, -1), $suggestions)) { + $suggestions = array_merge(array_slice($derived_suggestions, -1), $suggestions); + } + // Check if each suggestion exists in the theme registry, and if so, // use it instead of the base hook. For example, a function may use // '#theme' => 'node', but a module can add 'node__article' as a suggestion @@ -381,6 +393,8 @@ public function render($hook, array $variables) { if (isset($theme_hook_suggestion)) { $variables['theme_hook_suggestion'] = $theme_hook_suggestion; } + // Make sure we pass the file name suggestions that were actually used + $variables['file_name_suggestions'] = $suggestions; $output = $render_function($template_file, $variables); } diff --git a/core/themes/engines/twig/twig.engine b/core/themes/engines/twig/twig.engine index 791f908..fa4cf79 100644 --- a/core/themes/engines/twig/twig.engine +++ b/core/themes/engines/twig/twig.engine @@ -78,32 +78,11 @@ function twig_render_template($template_file, array $variables) { $output['debug_prefix'] .= "\n"; // If there are theme suggestions, reverse the array so more specific // suggestions are shown first. - if (!empty($variables['theme_hook_suggestions'])) { - $variables['theme_hook_suggestions'] = array_reverse($variables['theme_hook_suggestions']); - } - // Add debug output for directly called suggestions like - // '#theme' => 'comment__node__article'. - if (strpos($variables['theme_hook_original'], '__') !== FALSE) { - $derived_suggestions[] = $hook = $variables['theme_hook_original']; - while ($pos = strrpos($hook, '__')) { - $hook = substr($hook, 0, $pos); - $derived_suggestions[] = $hook; - } - // Get the value of the base hook (last derived suggestion) and append it - // to the end of all theme suggestions. - $base_hook = array_pop($derived_suggestions); - $variables['theme_hook_suggestions'] = array_merge($derived_suggestions, $variables['theme_hook_suggestions']); - $variables['theme_hook_suggestions'][] = $base_hook; - } - if (!empty($variables['theme_hook_suggestions'])) { + if (!empty($variables['file_name_suggestions'])) { + $variables['file_name_suggestions'] = array_reverse($variables['file_name_suggestions']); $extension = twig_extension(); $current_template = basename($template_file); - $suggestions = $variables['theme_hook_suggestions']; - // Only add the original theme hook if it wasn't a directly called - // suggestion. - if (strpos($variables['theme_hook_original'], '__') === FALSE) { - $suggestions[] = $variables['theme_hook_original']; - } + $suggestions = $variables['file_name_suggestions']; foreach ($suggestions as &$suggestion) { $template = strtr($suggestion, '_', '-') . $extension; $prefix = ($template == $current_template) ? 'x' : '*';