Commit 414574e1 authored by effulgentsia's avatar effulgentsia

Issue #2559825 by tim.plunkett, Antti J. Salminen, lauriii, aspilicious,...

Issue #2559825 by tim.plunkett, Antti J. Salminen, lauriii, aspilicious, alexpott: Preprocess functions from base hooks not triggered for theme hooks not using the __  pattern
parent aaf99e1e
......@@ -129,10 +129,7 @@ public function processDefinition(&$definition, $plugin_id) {
$template_path .= '/' . implode('/', $template_parts);
}
$definition->setTemplate($template);
// Prepend 'layout__' so the base theme hook will be used.
// @todo Remove this workaround for https://www.drupal.org/node/2559825 in
// https://www.drupal.org/node/2834019.
$definition->setThemeHook('layout__' . strtr($template, '-', '_'));
$definition->setThemeHook(strtr($template, '-', '_'));
$definition->setTemplatePath($template_path);
}
......
......@@ -1138,7 +1138,7 @@ function hook_page_bottom(array &$page_bottom) {
* Instead of this suggestion's implementation being used directly, the base
* hook will be invoked with this implementation as its first suggestion.
* The base hook's files will be included and the base hook's preprocess
* functions will be called in place of any suggestion's preprocess
* functions will be called in addition to any suggestion's preprocess
* functions. If an implementation of hook_theme_suggestions_HOOK() (where
* HOOK is the base hook) changes the suggestion order, a different
* suggestion may be used in place of this suggestion. If after
......
......@@ -606,27 +606,56 @@ protected function processExtension(array &$cache, $name, $type, $theme, $path)
protected function completeSuggestion($hook, array &$cache) {
$previous_hook = $hook;
$incomplete_previous_hook = array();
// Continue looping if the candidate hook doesn't exist or if the candidate
// hook has incomplete preprocess functions, and if the candidate hook is a
// suggestion (has a double underscore).
while ((!isset($cache[$previous_hook]) || isset($cache[$previous_hook]['incomplete preprocess functions']))
&& $pos = strrpos($previous_hook, '__')) {
// Find the first existing candidate hook that has incomplete preprocess
// functions.
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);
$this->mergePreprocessFunctions($hook, $previous_hook, $incomplete_previous_hook, $cache);
}
// 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;
}
// In addition to processing suggestions, include base hooks.
if (isset($cache[$hook]['base hook'])) {
// In order to retain the additions from above, pass in the current hook
// as the parent hook, otherwise it will be overwritten.
$this->mergePreprocessFunctions($hook, $cache[$hook]['base hook'], $cache[$hook], $cache);
}
}
/**
* Merges the source hook's preprocess functions into the destination hook's.
*
* @param string $destination_hook_name
* The name of the hook to merge preprocess functions to.
* @param string $source_hook_name
* The name of the hook to merge preprocess functions from.
* @param array $parent_hook
* The parent hook if it exists. Either an incomplete hook from suggestions
* or a base hook.
* @param array $cache
* The theme registry, as documented in
* \Drupal\Core\Theme\Registry::processExtension().
*/
protected function mergePreprocessFunctions($destination_hook_name, $source_hook_name, $parent_hook, array &$cache) {
// If base hook exists clone of it for the preprocess function
// without a template.
// @see https://www.drupal.org/node/2457295
if (isset($cache[$source_hook_name]) && (!isset($cache[$source_hook_name]['incomplete preprocess functions']) || !isset($cache[$destination_hook_name]['incomplete preprocess functions']))) {
$cache[$destination_hook_name] = $parent_hook + $cache[$source_hook_name];
if (isset($parent_hook['preprocess functions'])) {
$diff = array_diff($parent_hook['preprocess functions'], $cache[$source_hook_name]['preprocess functions']);
$cache[$destination_hook_name]['preprocess functions'] = array_merge($cache[$source_hook_name]['preprocess functions'], $diff);
}
// If a base hook isn't set, this is the actual base hook.
if (!isset($cache[$source_hook_name]['base hook'])) {
$cache[$destination_hook_name]['base hook'] = $source_hook_name;
}
}
}
......
......@@ -119,7 +119,7 @@ public function testGetDefinition() {
$this->assertSame('twocol', $layout_definition->getTemplate());
$this->assertSame("$theme_a_path/templates", $layout_definition->getPath());
$this->assertSame('theme_a/twocol', $layout_definition->getLibrary());
$this->assertSame('layout__twocol', $layout_definition->getThemeHook());
$this->assertSame('twocol', $layout_definition->getThemeHook());
$this->assertSame("$theme_a_path/templates", $layout_definition->getTemplatePath());
$this->assertSame('theme_a', $layout_definition->getProvider());
$this->assertSame('right', $layout_definition->getDefaultRegion());
......@@ -165,7 +165,7 @@ public function testGetDefinition() {
$this->assertSame('plugin-provided-layout', $layout_definition->getTemplate());
$this->assertSame($core_path, $layout_definition->getPath());
$this->assertSame(NULL, $layout_definition->getLibrary());
$this->assertSame('layout__plugin_provided_layout', $layout_definition->getThemeHook());
$this->assertSame('plugin_provided_layout', $layout_definition->getThemeHook());
$this->assertSame("$core_path/templates", $layout_definition->getTemplatePath());
$this->assertSame('core', $layout_definition->getProvider());
$this->assertSame('main', $layout_definition->getDefaultRegion());
......@@ -209,13 +209,13 @@ public function testGetThemeImplementations() {
'layout' => [
'render element' => 'content',
],
'layout__twocol' => [
'twocol' => [
'render element' => 'content',
'base hook' => 'layout',
'template' => 'twocol',
'path' => "$theme_a_path/templates",
],
'layout__plugin_provided_layout' => [
'plugin_provided_layout' => [
'render element' => 'content',
'base hook' => 'layout',
'template' => 'plugin-provided-layout',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment