diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php index b1c463c..8d6141b 100644 --- a/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -600,8 +600,8 @@ protected function postProcessExtension(array &$cache, ActiveTheme $theme) { } $prefixes[] = $theme->getName(); - // Collect all variable processor functions in the correct order. - $processors = []; + // Collect all variable preprocess functions in the correct order. + $suggestion_level = []; $matches = []; // Look for functions named according to the pattern and add them if they // have matching hooks in the registry. @@ -612,49 +612,50 @@ protected function postProcessExtension(array &$cache, ActiveTheme $theme) { continue; } // Add the function and the name of the associated theme hook to the list - // of processors if a matching base hook is found. + // of preprocess functions grouped by suggestion specificity if a matching + // base hook is found. foreach ($grouped_functions[$first_prefix] as $candidate) { if (preg_match("/^{$prefix}_preprocess_(((?:[^_]++|_(?!_))+)__.*)/", $candidate, $matches)) { - $processors[$candidate] = $matches[1]; + $level = substr_count($matches[1], '__'); + $suggestion_level[$level][$candidate] = $matches[1]; } } } - // Add missing variable processors. This is needed for hooks that do not + // Add missing variable preprocessors. This is needed for hooks that do not // explicitly register the hook. For example, when a theme contains a - // variable process function but it does not implement a template, it will - // go missing. This will add the expected function. It also allows modules - // or themes to have a variable process function based on a pattern even if - // the hook does not exist. - foreach ($processors as $processor => $hook) { - if (isset($cache[$hook]['preprocess functions']) && !in_array($hook, $cache[$hook]['preprocess functions'])) { - // Add missing processor to existing hook. - $cache[$hook]['preprocess functions'][] = $processor; - } - elseif (!isset($cache[$hook]) && strpos($hook, '__')) { - // Process non-existing hook and register it. - // Search for the base hook. - $base_hook = $hook; - while (!isset($cache[$base_hook]) && $pos = strrpos($base_hook, '__')) { - $base_hook = substr($base_hook, 0, $pos); - // If the current hook is based on a pattern, get the base hook. - if (isset($cache[$hook]['base hook'])) { - $base_hook = $cache[$hook]['base hook']; - } - // If base hook exists clone of it for the preprocess function - // without a template. - // @see https://www.drupal.org/node/2457295 - if (isset($cache[$base_hook])) { - $cache[$hook] = $cache[$base_hook]; - $cache[$hook]['base hook'] = $base_hook; - $cache[$hook]['preprocess functions'][] = $processor; + // variable preprocess function but it does not implement a template, it + // will go missing. This will add the expected function. It also allows + // modules or themes to have a variable process function based on a pattern + // even if the hook does not exist. + for ($level = 1; $level <= count($suggestion_level); $level++) { + foreach ($suggestion_level[$level] as $preprocessor => $hook) { + if (isset($cache[$hook]['preprocess functions']) && !in_array($hook, $cache[$hook]['preprocess functions'])) { + // Add missing preprocessor to existing hook. + $cache[$hook]['preprocess functions'][] = $preprocessor; + } + elseif (!isset($cache[$hook]) && strpos($hook, '__')) { + // 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]; + $cache[$hook]['base hook'] = $previous_hook; + $cache[$hook]['preprocess functions'][] = $preprocessor; + } } } } } - // Inherit all base hook variable processors into pattern hooks. + // Inherit all base hook variable preprocess functions into pattern hooks. // This ensures that derivative hooks have a complete set of variable - // process functions. + // preprocess functions. foreach ($cache as $hook => $info) { // The 'base hook' is only applied to derivative hooks already registered // from a pattern. This is typically set from 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 cacdd73..8b820c3 100644 --- a/core/modules/system/tests/modules/theme_test/theme_test.module +++ b/core/modules/system/tests/modules/theme_test/theme_test.module @@ -116,7 +116,6 @@ function theme_test_preprocess_theme_test_preprocess_suggestions__monkey(&$varia $variables['foo'] = 'Monkey'; } - /** * Prepares variables for test render element templates. *