diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 7bff76e..32c7322 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1036,6 +1036,18 @@ function theme($hook, $variables = array()) { 'theme_hook_original' => $original_hook, ); + // Invoke hook_theme_prepare(). + $variables = NestedArray::mergeDeep($variables, Drupal::moduleHandler()->invokeAll('theme_prepare', array($hook, $variables))); + // Invoke hook_theme_prepare_HOOK(). + $variables = NestedArray::mergeDeep($variables, Drupal::moduleHandler()->invokeAll('theme_prepare_' . $hook, array($variables))); + + // Clone the hook, so it cannot be modified via prepare alters. + $hook_clone = $hook; + // Alter variables by invoking hook_theme_prepare_alter($variables, $hook). + Drupal::moduleHandler()->alter('theme_prepare', $variables, $hook_clone); + // Alter variables by invoking hook_theme_prepare_HOOK_alter($variables). + Drupal::moduleHandler()->alter('theme_prepare_' . $hook, $variables); + // Invoke the variable processors, if any. The processors may specify // alternate suggestions for which hook's template/function to use. If the // hook is a suggestion of a base hook, invoke the variable processors of 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 c790a84..acb5f77 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 @@ -31,4 +31,16 @@ function functionTemplateOverridden() { ); } + function prepare() { + return array( + '#theme' => 'theme_test_prepare_variable', + ); + } + + function prepareAlter() { + return array( + '#theme' => 'theme_test_prepare_alter_variable', + ); + } + } 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 51cb6d3..434edef 100644 --- a/core/modules/system/tests/modules/theme_test/theme_test.module +++ b/core/modules/system/tests/modules/theme_test/theme_test.module @@ -27,6 +27,12 @@ function theme_test_theme($existing, $type, $theme, $path) { $items['theme_test_function_template_override'] = array( 'variables' => array(), ); + $items['theme_test_prepare_variable'] = array( + 'variables' => array('element' => array()), + ); + $items['theme_test_prepare_alter_variable'] = array( + 'variables' => array('element' => array()), + ); return $items; } @@ -78,6 +84,14 @@ function theme_test_menu() { 'theme callback' => '_theme_custom_theme', 'route_name' => 'function_template_override', ); + $items['theme-test/prepare'] = array( + 'theme callback' => '_theme_custom_theme', + 'route_name' => 'prepare', + ); + $items['theme-test/prepare-alter'] = array( + 'theme callback' => '_theme_custom_theme', + 'route_name' => 'prepare_alter', + ); return $items; } @@ -197,3 +211,56 @@ function template_preprocess_theme_test_render_element(&$variables) { function theme_theme_test_render_element_children($variables) { return drupal_render($variables['element']); } + +function theme_theme_test_prepare_variable($variables) { + return drupal_render($variables['element']); +} + +function theme_theme_test_prepare_alter_variable($variables) { + return drupal_render($variables['element']); +} + +/** + * Tests prepare and alter hooks. + */ +function theme_test_theme_prepare($hook) { + if ($hook == 'theme_test_prepare_variable' || $hook == 'theme_test_prepare_alter_variable') { + return array( + 'element' => array( + 'variable1' => array( + '#markup' => '

Inserted variable1 via hook_theme_prepare().

', + ), + ) + ); + } +} + +function theme_test_theme_prepare_theme_test_prepare_variable() { + return array( + 'element' => array( + 'variable2' => array( + '#markup' => '

Inserted variable2 via hook_theme_prepare_HOOK().

', + ), + ), + ); +} + +function theme_test_theme_prepare_theme_test_prepare_alter_variable() { + return array( + 'element' => array( + 'variable2' => array( + '#markup' => '

Inserted variable2 via hook_theme_prepare_HOOK().

', + ), + ), + ); +} + +function theme_test_theme_prepare_alter(&$variables, $hook) { + if ($hook == 'theme_test_prepare_alter_variable') { + $variables['element']['variable1']['#markup'] = '

Inserted variable1 via hook_theme_prepare() was altered by hook_theme_prepare_alter().

'; + } +} + +function theme_test_theme_prepare_theme_test_prepare_alter_variable_alter(&$variables) { + $variables['element']['variable2']['#markup'] = '

Inserted variable2 via hook_theme_prepare_HOOK() was altered by hook_theme_prepare_HOOK_alter().

'; +} diff --git a/core/modules/system/tests/modules/theme_test/theme_test.routing.yml b/core/modules/system/tests/modules/theme_test/theme_test.routing.yml index 866171e..1e1dec5 100644 --- a/core/modules/system/tests/modules/theme_test/theme_test.routing.yml +++ b/core/modules/system/tests/modules/theme_test/theme_test.routing.yml @@ -4,3 +4,15 @@ function_template_override: _content: '\Drupal\theme_test\ThemeTestController::functionTemplateOverridden' requirements: _permission: 'access content' +prepare: + pattern: '/theme-test/prepare' + defaults: + _content: '\Drupal\theme_test\ThemeTestController::prepare' + requirements: + _permission: 'access content' +prepare_alter: + pattern: '/theme-test/prepare-alter' + defaults: + _content: '\Drupal\theme_test\ThemeTestController::prepareAlter' + requirements: + _permission: 'access content'