diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 6c9bb8f..c8dcc97 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -147,6 +147,7 @@ function drupal_find_theme_functions($cache, $prefixes) { 'function' => $match, $arg_name => $info[$arg_name], 'base hook' => $hook, + 'incomplete preprocess functions' => TRUE, ); } } @@ -262,6 +263,7 @@ function drupal_find_theme_templates($cache, $extension, $path) { 'path' => dirname($files[$match]->uri), $arg_name => $info[$arg_name], 'base hook' => $hook, + 'incomplete preprocess functions' => TRUE, ); } } diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php index 33d880b..8fdc4fd 100644 --- a/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -579,6 +579,43 @@ protected function processExtension(array &$cache, $name, $type, $theme, $path) } /** + * Completes the definition of the requested suggestion hook. + * + * @param string $hook + * The name of the suggestion hook to complete. + * @param array $cache + * The theme registry. + */ + protected function completeSuggestion($hook, array &$cache) { + $previous_hook = $hook; + $incomplete_previous_hook = array(); + while ((!isset($cache[$previous_hook]) || isset($cache[$previous_hook]['incomplete preprocess functions'])) + && $pos = strrpos($previous_hook, '__')) { + if (isset($cache[$previous_hook]) && !$incomplete_previous_hook && isset($cache[$previous_hook]['incomplete preprocess functions'])) { + $incomplete_previous_hook = $cache[$previous_hook]; + unset($incomplete_previous_hook['incomplete preprocess functions']); + } + $previous_hook = substr($previous_hook, 0, $pos); + + // If base hook exists clone of it for the preprocess function + // without a template. + // @see https://www.drupal.org/node/2457295 + if (isset($cache[$previous_hook]) && !isset($cache[$previous_hook]['incomplete preprocess functions'])) { + $cache[$hook] = $incomplete_previous_hook + $cache[$previous_hook]; + if (isset($incomplete_previous_hook['preprocess functions'])) { + $diff = array_diff($incomplete_previous_hook['preprocess functions'], $cache[$previous_hook]['preprocess functions']); + $cache[$hook]['preprocess functions'] = array_merge($cache[$previous_hook]['preprocess functions'], $diff); + } + // If a base hook isn't set, this is the actual base hook. + if (!isset($cache[$previous_hook]['base hook'])) { + $cache[$hook]['base hook'] = $previous_hook; + } + } + return $hook; + } + } + + /** * Completes the theme registry adding discovered functions and hooks. * * @param array $cache @@ -642,21 +679,8 @@ protected function postProcessExtension(array &$cache, ActiveTheme $theme) { // Process non-existing hook and register it. // Look for a previously defined hook that is either a less specific // suggestion hook or the base hook. - $previous_hook = $hook; - while (!isset($cache[$previous_hook]) && $pos = strrpos($previous_hook, '__')) { - $previous_hook = substr($previous_hook, 0, $pos); - // If base hook exists clone of it for the preprocess function - // without a template. - // @see https://www.drupal.org/node/2457295 - if (isset($cache[$previous_hook])) { - $cache[$hook] = $cache[$previous_hook]; - // If a base hook isn't set, this is the actual base hook. - if (!isset($cache[$previous_hook]['base hook'])) { - $cache[$hook]['base hook'] = $previous_hook; - } - $cache[$hook]['preprocess functions'][] = $preprocessor; - } - } + $hook = $this->completeSuggestion($hook, $cache); + $cache[$hook]['preprocess functions'][] = $preprocessor; } } } @@ -667,9 +691,9 @@ protected function postProcessExtension(array &$cache, ActiveTheme $theme) { // The 'base hook' is only applied to derivative hooks already registered // from a pattern. This is typically set from // drupal_find_theme_functions() and drupal_find_theme_templates(). - if (isset($info['base hook']) && isset($cache[$info['base hook']]['preprocess functions'])) { - $diff = array_diff($info['preprocess functions'], $cache[$info['base hook']]['preprocess functions']); - $cache[$hook]['preprocess functions'] = array_merge($cache[$info['base hook']]['preprocess functions'], $diff); + if (isset($info['incomplete preprocess functions'])) { + $hook = $this->completeSuggestion($hook, $cache); + unset($cache[$hook]['incomplete preprocess functions']); } // Optimize the registry.