diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 504030e..1988532 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -595,6 +595,16 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) { // Let modules alter the registry. drupal_alter('theme_registry', $cache); + // Invoke hook_template_suggestions_THEMEFUNC for each theme hook, so + // modules have the ability to provide template suggestions, _before_ + // preprocess functions run. + // Hopefully, we can find a more efficient way of doing this. + foreach ($cache as $hook => &$info) { + foreach (module_implements('template_suggestions_' . $hook) as $module_name) { + $info['template suggestion functions'][] = $module_name . '_template_suggestions_' . $hook; + } + } + // Optimize the registry to not have empty arrays for functions. foreach ($cache as $hook => $info) { foreach (array('preprocess functions', 'process functions') as $phase) { @@ -957,6 +967,7 @@ function theme($hook, $variables = array()) { $variables += array($info['render element'] => array()); } + // 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 @@ -991,33 +1002,30 @@ function theme($hook, $variables = array()) { } } } - // If the preprocess/process functions specified hook suggestions, and the - // suggestion exists in the theme registry, use it instead of the hook that - // theme() was called with. This allows the preprocess/process step to - // route to a more specific theme hook. For example, a function may call - // theme('node', ...), but a preprocess function can add 'node__article' as - // a suggestion, enabling a theme to have an alternate template file for - // article nodes. Suggestions are checked in the following order: - // - The 'theme_hook_suggestion' variable is checked first. It overrides - // all others. - // - The 'theme_hook_suggestions' variable is checked in FILO order, so the - // last suggestion added to the array takes precedence over suggestions - // added earlier. - $suggestions = array(); - if (!empty($variables['theme_hook_suggestions'])) { - $suggestions = $variables['theme_hook_suggestions']; - } - if (!empty($variables['theme_hook_suggestion'])) { - $suggestions[] = $variables['theme_hook_suggestion']; - } - foreach (array_reverse($suggestions) as $suggestion) { - if (isset($hooks[$suggestion])) { - $info = $hooks[$suggestion]; - break; - } + } + + // Invoke template suggestion hooks. + $suggestions = array(); + foreach ($info['template suggestion functions'] as $funcname) { + $suggestions += $funcname($variables); + } + + // Check if each suggestion exists in the theme registry, and if so, + // use it instead of the hook that theme() was called with. This + // allows the preprocess/process step to route to a more specific + // theme hook. For example, a function may call theme('node', ...), + // but a a module can add 'node__article' as a suggestion via + // hook_template_suggestions_HOOK, enabling a theme to have an + // alternate template file for article nodes. + foreach (array_reverse($suggestions) as $suggestion) { + if (isset($hooks[$suggestion])) { + $info = $hooks[$suggestion]; + break; } } + + // Generate the output using either a function or a template. $output = ''; if (isset($info['function'])) { diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 349aab5..0ee758f 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -281,6 +281,17 @@ function node_field_display_node_alter(&$display, $context) { } /** + * Implements hook_template_suggestions_HOOK(). + */ +function node_template_suggestions_node($variables) { + return array( + 'node__' . $variables['nid'], + 'node__' . $variables['type'] . '__' . $variables['langcode'], + 'node__' . $variables['type'], + ); +} + +/** * Entity uri callback. * * @param Drupal\node\Node $node @@ -1383,10 +1394,6 @@ function template_preprocess_node(&$variables) { if (isset($variables['preview'])) { $variables['attributes']['class'][] = 'preview'; } - - // Clean up name so there are no underscores. - $variables['theme_hook_suggestions'][] = 'node__' . $node->type; - $variables['theme_hook_suggestions'][] = 'node__' . $node->nid; } /**