diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 5f4bcdb..cd59f95 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1056,47 +1056,42 @@ function theme($hook, $variables = array()) { } } - // Provide context for hooks. - $context = array( - '#theme_id' => $original_hook, - '#base_theme_id' => $hook, - '#suggestions' => $suggestions, + // Provide immutable context for subsequent hooks. + $context_original = array( + 'hook' => $hook, + 'original_hook' => $original_hook, + 'suggestions' => $suggestions, ); - $invoke_hooks = array( + // A list of hooks that we'll fire for the given theme hook. + $prepare_hooks = array( 'theme_prepare', 'theme_prepare_' . $hook, ); // If the original theme hook is not the same as the base theme hook, then // invoke the original theme hook suggestion after the base theme hook. if ($hook !== $original_hook) { - $invoke_hooks[] = 'theme_prepare_' . $original_hook; + $prepare_hooks[] = 'theme_prepare_' . $original_hook; } - // Invoke theme_prepare hooks for enabled modules. - foreach ($invoke_hooks as $invoke_hook) { - $variables = NestedArray::mergeDeep($variables, (array) Drupal::moduleHandler()->invokeAll($invoke_hook, array($context))); - } - - // Invoke hooks for the active theme. The active theme takes precedence over + // Invokes hook_theme_prepare(), hook_theme_prepare_THEME_ID() for enabled // modules. - // @todo Replace with Drupal::themeHandler()->invoke() once implemented. - // @see https://drupal.org/node/2029819 - foreach ($invoke_hooks as $invoke_hook) { - $variables = NestedArray::mergeDeep($variables, (array) Drupal::moduleHandler()->themeInvoke($invoke_hook, array($context))); + foreach ($prepare_hooks as $prepare_hook) { + $context = $context_original; + $variables = NestedArray::mergeDeep($variables, (array) Drupal::moduleHandler()->invokeAll($prepare_hook, array($context))); } - // Clone the context so it cannot be altered by modules or themes. - $context_clone = $context; - - // Invoke alter hooks for enabled modules. - // @todo Add Drupal::themeHandler()->alter() invocations once implemented. + // Invokes hook_theme_prepare(), hook_theme_prepare_THEME_ID() for the active + // theme, which takes precedence over modules. + // @todo Replace with Drupal::themeHandler()->invoke() once implemented. // @see https://drupal.org/node/2029819 - foreach ($invoke_hooks as $invoke_hook) { - Drupal::moduleHandler()->alter($invoke_hook, $variables, $context_clone); + foreach ($prepare_hooks as $prepare_hook) { + $context = $context_original; + $variables = NestedArray::mergeDeep($variables, (array) Drupal::moduleHandler()->themeInvoke($prepare_hook, array($context))); } - // @todo Deprecate https://drupal.org/node/2060773 + // Invokes preprocess functions. + // @todo Deprecate @see https://drupal.org/node/2060773 if (isset($info['preprocess functions'])) { foreach ($info['preprocess functions'] as $preprocessor_function) { if (function_exists($preprocessor_function)) { @@ -1105,6 +1100,14 @@ function theme($hook, $variables = array()) { } } + // Invokes hook_theme_prepare_alter(), hook_theme_prepare_THEME_ID_alter() for enabled modules. + // @todo Add Drupal::themeHandler()->alter() invocations once implemented. + // @see https://drupal.org/node/2029819 + foreach ($prepare_hooks as $prepare_hook) { + $context = $context_original; + Drupal::moduleHandler()->alter($prepare_hook, $variables, $context); + } + // Generate the output using either a function or a template. $output = ''; if (isset($info['function'])) { diff --git a/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php b/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php index 34c6793..7d7ac9c 100644 --- a/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php +++ b/core/lib/Drupal/Core/Extension/UpdateModuleHandler.php @@ -24,10 +24,6 @@ public function getImplementations($hook) { if (substr($hook, -6) === '_alter') { return array(); } - // Some system_theme() hooks need to be prepared. - if (substr($hook, 0, 13) === 'theme_prepare') { - return array('system'); - } // theme() is called during updates and fires hooks, so whitelist the // system module. if (substr($hook, 0, 6) == 'theme_') { diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemePrepareTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemePrepareTest.php index d8a7451..8b1ed5d 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemePrepareTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemePrepareTest.php @@ -2,16 +2,15 @@ /** * @file - * Definition of Drupal\system\Tests\Theme\ThemeTest. + * Definition of Drupal\system\Tests\Theme\ThemePrepareTest. */ namespace Drupal\system\Tests\Theme; use Drupal\simpletest\WebTestBase; -use Drupal\test_theme\ThemeClass; /** - * Tests low-level theme functions. + * Tests hook_theme_prepare() and hook_theme_prepare_alter() implementations. */ class ThemePrepareTest extends WebTestBase { @@ -36,19 +35,19 @@ function setUp() { } function testThemePrepare() { - $this->drupalGet('theme-test/prepare', array('query' => array('XDEBUG_SESSION_START' => 'PHPSTORM'))); - $this->assertText('Inserted variable1 via hook_theme_prepare().', 'Inserted variable1 via hook_theme_prepare().'); - $this->assertText('Inserted variable2 via hook_theme_prepare_BASE_THEME_ID().', 'Inserted variable2 via hook_theme_prepare_BASE_THEME_ID().'); - $this->assertText('Inserted themeVariable1 via theme hook_theme_prepare().', 'Inserted themeVariable1 via theme hook_theme_prepare().'); - $this->assertText('Inserted themeVariable2 via theme hook_theme_prepare_BASE_THEME_ID().', 'Inserted themeVariable2 via theme hook_theme_prepare_BASE_THEME_ID().'); + $this->drupalGet('theme-test/prepare'); + $this->assertText('Inserted variable1 via hook_theme_prepare().'); + $this->assertText('Inserted variable2 via hook_theme_prepare_BASE_THEME_ID().'); + $this->assertText('Inserted themeVariable1 via theme hook_theme_prepare().'); + $this->assertText('Inserted themeVariable2 via theme hook_theme_prepare_BASE_THEME_ID().'); } function testThemePrepareAlter() { - $this->drupalGet('theme-test/prepare-alter', array('query' => array('XDEBUG_SESSION_START' => 'PHPSTORM'))); - $this->assertText('Inserted variable1 via hook_theme_prepare() was altered by hook_theme_prepare_alter().', 'Inserted variable1 via hook_theme_prepare() was altered by hook_theme_prepare_alter().'); - $this->assertText('Inserted variable2 via hook_theme_prepare_BASE_THEME_ID() was altered by hook_theme_prepare_BASE_THEME_ID_alter().', 'Inserted variable2 via hook_theme_prepare_BASE_THEME_ID() was altered by hook_theme_prepare_BASE_THEME_ID_alter().'); - $this->assertText('Inserted themeVariable1 via theme hook_theme_prepare() was altered by theme hook_theme_prepare_alter().', 'Inserted themeVariable1 via theme hook_theme_prepare() was altered by theme hook_theme_prepare_alter().'); - $this->assertText('Inserted themeVariable2 via theme hook_theme_prepare_BASE_THEME_ID() was altered by theme hook_theme_prepare_BASE_THEME_ID_alter().', 'Inserted themeVariable2 via theme hook_theme_prepare_BASE_THEME_ID() was altered by theme hook_theme_prepare_BASE_THEME_ID_alter().'); + $this->drupalGet('theme-test/prepare-alter'); + $this->assertText('Inserted variable1 via hook_theme_prepare() was altered by hook_theme_prepare_alter().'); + $this->assertText('Inserted variable2 via hook_theme_prepare_BASE_THEME_ID() was altered by hook_theme_prepare_BASE_THEME_ID_alter().'); + $this->assertText('Inserted themeVariable1 via theme hook_theme_prepare() was altered by theme hook_theme_prepare_alter().'); + $this->assertText('Inserted themeVariable2 via theme hook_theme_prepare_BASE_THEME_ID() was altered by theme hook_theme_prepare_BASE_THEME_ID_alter().'); } } diff --git a/core/modules/system/tests/modules/theme_test/lib/Drupal/theme_test/ThemeTestController.php b/core/modules/system/tests/modules/theme_test/lib/Drupal/theme_test/ThemeTestController.php index 32231ff..1389cea 100644 --- a/core/modules/system/tests/modules/theme_test/lib/Drupal/theme_test/ThemeTestController.php +++ b/core/modules/system/tests/modules/theme_test/lib/Drupal/theme_test/ThemeTestController.php @@ -120,12 +120,18 @@ function functionSuggestionAlter() { return array('#theme' => 'theme_test_function_suggestions'); } + /** + * Menu callback for testing hook_theme_prepare(). + */ function prepare() { return array( '#theme' => 'theme_test_prepare_variable', ); } + /** + * Menu callback for testing hook_theme_prepare_alter(). + */ function prepareAlter() { return array( '#theme' => 'theme_test_prepare_alter_variable',