Change record status: 
Project: 
Introduced in branch: 
8.x
Introduced in version: 
8.0-ALPHA3
Description: 

This change helps fix critical issues with Drupal themeing by defining and determining theme suggestions before running preprocess functions.

Whereas modules and themes previously altered $variables['theme_hook_suggestion'] and $variables['theme_hook_suggestions'] in preprocess functions to introduce theme suggestions, modules and themes now define and alter theme suggestions in their own dedicated hooks.

API changes:

Removed the ability to change template suggestions in preprocess functions by altering $variables['theme_hook_suggestion'] and $variables['theme_hook_suggestions'].

New hooks introduced:

Code that altered suggestions in preprocess needs to be moved to suggestion hooks.

Examples:

From the module that is providing the theme hook (implementing hook_theme()):

Suggestions code is moved from template_preprocess_HOOK() to hook_theme_suggestions_HOOK().

Before:

/**
 * Prepares variables for search results templates.
 */
function template_preprocess_search_results(&$variables) {
  $variables['theme_hook_suggestions'][] = 'search_results__' . $variables['plugin_id'];
}

After:

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function search_theme_suggestions_search_results(array $variables) {
  return array('search_results__' . $variables['plugin_id']);
}

Any other module or theme:

Suggestions code is moved from HOOK_preprocess_HOOK() to manipulating the suggestions array in hook_theme_suggestions_HOOK_alter().

Before:

/**
 * Implements hook_preprocess_HOOK() for node templates.
 */
function MYTHEME_preprocess_node(&$variables) {
  $variables['theme_hook_suggestions'][] = 'node__' . 'my_first_suggestion';
  $variables['theme_hook_suggestions'][] = 'node__' . 'my_second_suggestion';
}

After:

/**
 * Implements hook_theme_suggestions_HOOK_alter().
 */
function MYTHEME_theme_suggestions_node_alter(array &$suggestions, array $variables) {
  $suggestions[] = 'node__' . 'my_first_suggestion';
  $suggestions[] = 'node__' . 'my_second_suggestion';
}

Altering $variables['theme_hook_suggestion'] (singular) is now just a matter of adding the suggestion to the end of the suggestions array in hook_theme_suggestions_HOOK_alter(). If you need to ensure that your suggestion is at the end, implement hook_module_implements_alter().

Before:

/**
 * Implements hook_preprocess_HOOK() for node templates.
 */
function MYTHEME_preprocess_node(&$variables) {
  $variables['theme_hook_suggestion'] = 'node__' . 'my_suggestion';
}

After:

/**
 * Implements hook_theme_suggestions_HOOK_alter().
 */
function MYTHEME_theme_suggestions_node_alter(array &$suggestions, array $variables) {
  $suggestions[] = 'node__' . 'my_suggestion';
}

Generic alter hook (to alter/add suggestions for multiple theme hooks):

There is also a generic suggestions alter hook that is invoked for all theme hooks.

Suggestions code is moved from HOOK_preprocess() to manipulating the suggestions array in hook_theme_suggestions_alter().

Before:

/**
 * Implements hook_preprocess().
 */
function MYMODULE_preprocess(&$variables, $hook) {
  if (in_array($hook, array('node', 'taxonomy_term'))) {
    $variables['theme_hook_suggestions'][] = $hook . '__' . 'my_first_suggestion';
    $variables['theme_hook_suggestions'][] = $hook . '__' . 'my_second_suggestion';
  }
}

After:

/**
 * Implements hook_theme_suggestions_alter().
 */
function MYMODULE_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
  if (in_array($hook, array('node', 'taxonomy_term'))) {
    $suggestions[] = $hook . '__' . 'my_first_suggestion';
    $suggestions[] = $hook . '__' . 'my_second_suggestion';
  }
}
Impacts: 
Module developers
Themers
Updates Done (doc team, etc.)
Online documentation: 
Not done
Theming guide: 
Not done
Module developer documentation: 
Not done
Examples project: 
Not done
Coder Review: 
Not done
Coder Upgrade: 
Not done
Other: 
Other updates done
Details: 

Most docs updates are still yet to be completed (or even started).