summaryrefslogtreecommitdiff
path: root/includes/theme.inc
diff options
context:
space:
mode:
Diffstat (limited to 'includes/theme.inc')
-rw-r--r--includes/theme.inc200
1 files changed, 73 insertions, 127 deletions
diff --git a/includes/theme.inc b/includes/theme.inc
index b8da7ddc6..7f265db74 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -719,23 +719,18 @@ function list_themes($refresh = FALSE) {
* need to be fast, and calling the non-hook-specific preprocess and process
* functions for them would incur a noticeable performance penalty.
*
- * For template-implemented theme hooks, there are two special variables that
- * these preprocess and process functions can set:
- * 'template_file' and 'template_files'. These will be merged together
- * to form a list of 'suggested' alternate template files to use, in
- * reverse order of priority. template_file will always be a higher
- * priority than items in template_files. theme() will then look for these
- * files, one at a time, and use the first one that exists. If none exists,
- * theme() will use the original registered file for the theme hook.
- *
- * For function-implemented theme hooks, there are two special variables that
- * these preprocess and process functions can set:
- * 'theme_function' and 'theme_functions'. These will be merged together
- * to form a list of 'suggested' alternate functions to use, in
- * reverse order of priority. theme_function will always be a higher
- * priority than items in theme_functions. theme() will then call the
- * highest priority function that exists. If none exists, theme() will call
- * the original registered function for the theme hook.
+ * There are two special variables that these preprocess and process functions
+ * can set:
+ * 'theme_hook_suggestion' and 'theme_hook_suggestions'. These will be merged
+ * together to form a list of 'suggested' alternate hooks to use, in
+ * reverse order of priority. theme_hook_suggestion will always be a higher
+ * priority than items in theme_hook_suggestions. theme() will use the
+ * highest priority implementation that exists. If none exists, theme() will
+ * use the implementation for the theme hook it was called with. These
+ * suggestions are similar to and are used for similar reasons as calling
+ * theme() with an array as the $hook parameter (see below). The difference
+ * is whether the suggestions are determined by the code that calls theme() or
+ * by a preprocess or process function.
*
* @param $hook
* The name of the theme hook to call. If the name contains a
@@ -840,10 +835,9 @@ function theme($hook, $variables = array()) {
}
// Invoke the variable processors, if any. The processors may specify
- // alternate suggestions for which function/template should be used.
+ // alternate suggestions for which hook's template/function to use.
if (isset($info['preprocess functions']) || isset($info['process functions'])) {
- $variables['theme_functions'] = array();
- $variables['template_files'] = array();
+ $variables['theme_hook_suggestions'] = array();
foreach (array('preprocess functions', 'process functions') as $phase) {
if (!empty($info[$phase])) {
foreach ($info[$phase] as $processor_function) {
@@ -855,21 +849,28 @@ function theme($hook, $variables = array()) {
}
}
}
- // Function suggestion takes priority over template suggestion.
- // theme_function takes priority over theme_functions.
- // theme_functions are in FILO order (least appropriate to most appropriate).
- // Here, just look for function suggestions. Deal with template
- // suggestions only after determining that the theme call is a template.
+ // 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_functions'])) {
- $suggestions = $variables['theme_functions'];
+ if (!empty($variables['theme_hook_suggestions'])) {
+ $suggestions = $variables['theme_hook_suggestions'];
}
- if (!empty($variables['theme_function'])) {
- $suggestions[] = $variables['theme_function'];
+ if (!empty($variables['theme_hook_suggestion'])) {
+ $suggestions[] = $variables['theme_hook_suggestion'];
}
foreach (array_reverse($suggestions) as $suggestion) {
- if (function_exists($suggestion)) {
- $info['function'] = $suggestion;
+ if (isset($hooks[$suggestion])) {
+ $info = $hooks[$suggestion];
break;
}
}
@@ -886,11 +887,9 @@ function theme($hook, $variables = array()) {
$render_function = 'theme_render_template';
$extension = '.tpl.php';
- // Run through the theme engine variables, if necessary
+ // The theme engine may use a different extension and a different renderer.
global $theme_engine;
if (isset($theme_engine)) {
- // If theme or theme engine is implementing this, it may have
- // a different extension and a different renderer.
if ($info['type'] != 'module') {
if (function_exists($theme_engine . '_render_template')) {
$render_function = $theme_engine . '_render_template';
@@ -902,29 +901,11 @@ function theme($hook, $variables = array()) {
}
}
- // Find which template file exists and can be used. Priority order is:
- // 1. $variables['template_file'].
- // 2. $variables['template_files'] in FILO order (later in array is higher
- // priority).
- // 3. $info['template'].
- $suggestions = array();
- if (isset($variables['template_files'])) {
- $suggestions = $variables['template_files'];
- }
- if (isset($variables['template_file'])) {
- $suggestions[] = $variables['template_file'];
- }
- if ($suggestions) {
- $template_file = drupal_discover_template($info['theme paths'], $suggestions, $extension);
- }
- if (empty($template_file)) {
- $template_file = $info['template'] . $extension;
- if (isset($info['path'])) {
- $template_file = $info['path'] . '/' . $template_file;
- }
+ // Render the output using the template file.
+ $template_file = $info['template'] . $extension;
+ if (isset($info['path'])) {
+ $template_file = $info['path'] . '/' . $template_file;
}
-
- // Render the output using the found template file.
$output = $render_function($template_file, $variables);
}
@@ -934,53 +915,6 @@ function theme($hook, $variables = array()) {
}
/**
- * Determine and return which template file will generate the output.
- *
- * This helper allows the theme system to pick the template at runtime instead
- * of build time.
- *
- * @see template_page_suggestions()
- * @see template_preprocess_block()
- *
- * @param $paths
- * The paths where templates can be found. See _theme_process_registry()
- * 'theme paths' for more information.
- * @param $suggestions
- * The possible template names. These are derived from
- * $variables['template_files'] and $variables['template_file], defined by
- * preprocess functions. Each file is checked on every path in the order of
- * precedence defined by theme().
- * @return
- * The filepath to the template that will generate the output. If none is
- * found, then theme() will use the 'template' as set by
- * _theme_process_registry().
- *
- * @see _theme_process_registry()
- * @see theme()
- */
-function drupal_discover_template($paths, $suggestions, $extension = '.tpl.php') {
- global $theme_engine;
-
- // Remove slashes or null to prevent files from being included from
- // an unexpected location (especially on Windows servers).
- $extension = str_replace(array("/", "\\", "\0"), '', $extension);
-
- // Loop through all paths and suggestions in FIFO order.
- $suggestions = array_reverse($suggestions);
- $paths = array_reverse($paths);
- foreach ($suggestions as $suggestion) {
- if (!empty($suggestion)) {
- $suggestion = str_replace(array("/", "\\", "\0"), '', $suggestion);
- foreach ($paths as $path) {
- if (file_exists($file = $path . '/' . $suggestion . $extension)) {
- return $file;
- }
- }
- }
- }
-}
-
-/**
* Return the path to the current themed element.
*
* It can point to the active theme or the module handling a themed implementation.
@@ -1253,8 +1187,7 @@ function theme_get_setting($setting_name, $theme = NULL) {
* Render a system default template, which is essentially a PHP template.
*
* @param $template_file
- * The filename of the template to render. Note that this will overwrite
- * anything stored in $variables['template_file'] if using a variable processor hook.
+ * The filename of the template to render.
* @param $variables
* A keyed array of variables that will appear in the output.
*
@@ -2346,7 +2279,7 @@ function template_preprocess_html(&$variables) {
}
// Populate the body classes.
- if ($suggestions = template_page_suggestions(arg(), 'page')) {
+ if ($suggestions = theme_get_suggestions(arg(), 'page', '-')) {
foreach ($suggestions as $suggestion) {
if ($suggestion != 'page-front') {
// Add current suggestion to page classes to make it possible to theme
@@ -2390,8 +2323,8 @@ function template_preprocess_html(&$variables) {
$variables['head_title'] = implode(' | ', $head_title);
// Populate the page template suggestions.
- if ($suggestions = template_page_suggestions(arg(), 'html')) {
- $variables['template_files'] = $suggestions;
+ if ($suggestions = theme_get_suggestions(arg(), 'html')) {
+ $variables['theme_hook_suggestions'] = $suggestions;
}
}
@@ -2452,8 +2385,8 @@ function template_preprocess_page(&$variables) {
}
// Populate the page template suggestions.
- if ($suggestions = template_page_suggestions(arg(), 'page')) {
- $variables['template_files'] = $suggestions;
+ if ($suggestions = theme_get_suggestions(arg(), 'page')) {
+ $variables['theme_hook_suggestions'] = $suggestions;
}
}
/**
@@ -2481,26 +2414,39 @@ function template_process_html(&$variables) {
}
/**
- * Generate an array of page template suggestions.
+ * Generate an array of suggestions from path arguments.
+ *
+ * This is typically called for adding to the 'theme_hook_suggestions' or
+ * 'classes_array' variables from within preprocess functions, when wanting to
+ * base the additional suggestions on the path of the current page.
*
* @param $args
* An array of path arguments, such as from function arg().
+ * @param $base
+ * A string identifying the base 'thing' from which more specific suggestions
+ * are derived. For example, 'page' or 'html'.
+ * @param $delimiter
+ * The string used to delimit increasingly specific information. The default
+ * of '__' is appropriate for theme hook suggestions. '-' is appropriate for
+ * extra classes.
*
* @return
- * An array of suggested template files.
+ * An array of suggestions, suitable for adding to
+ * $variables['theme_hook_suggestions'] within a preprocess function or to
+ * $variables['classes_array'] if the suggestions represent extra CSS classes.
*/
-function template_page_suggestions($args, $suggestion) {
+function theme_get_suggestions($args, $base, $delimiter = '__') {
- // Build a list of suggested template files and body classes in order of
+ // Build a list of suggested theme hooks or body classes in order of
// specificity. One suggestion is made for every element of the current path,
// though numeric elements are not carried to subsequent suggestions. For
- // example, http://www.example.com/node/1/edit would result in the following
- // suggestions and body classes:
+ // example, for $base='page', http://www.example.com/node/1/edit would result
+ // in the following suggestions and body classes:
//
- // page-node-edit.tpl.php page-node-edit
- // page-node-1.tpl.php page-node-1
- // page-node.tpl.php page-node
- // page.tpl.php
+ // page__node page-node
+ // page__node__% page-node-%
+ // page__node__1 page-node-1
+ // page__node__edit page-node-edit
$suggestions = array();
foreach ($args as $arg) {
@@ -2509,15 +2455,15 @@ function template_page_suggestions($args, $suggestion) {
// The percent acts as a wildcard for numeric arguments since
// asterisks are not valid filename characters on many filesystems.
if (is_numeric($arg)) {
- $suggestions[] = $suggestion . '-%';
+ $suggestions[] = $base . $delimiter . '%';
}
- $suggestions[] = $suggestion . '-' . $arg;
+ $suggestions[] = $base . $delimiter . $arg;
if (!is_numeric($arg)) {
- $suggestion .= '-' . $arg;
+ $base .= $delimiter . $arg;
}
}
if (drupal_is_front_page()) {
- $suggestions[] = $suggestion . '-front';
+ $suggestions[] = $base . $delimiter . 'front';
}
return $suggestions;
@@ -2529,7 +2475,7 @@ function template_page_suggestions($args, $suggestion) {
* invoked. It is also used in theme_install_page() and theme_update_page() to
* keep all the variables consistent.
*
- * An alternate template file of "maintenance-page-offline.tpl.php" can be
+ * An alternate template file of "maintenance-page--offline.tpl.php" can be
* used when the database is offline to hide errors and completely replace the
* content.
*
@@ -2617,7 +2563,7 @@ function template_preprocess_maintenance_page(&$variables) {
// Dead databases will show error messages so supplying this template will
// allow themers to override the page and the content completely.
if (isset($variables['db_is_active']) && !$variables['db_is_active']) {
- $variables['template_file'] = 'maintenance-page-offline';
+ $variables['theme_hook_suggestion'] = 'maintenance_page__offline';
}
}
@@ -2638,5 +2584,5 @@ function template_preprocess_region(&$variables) {
$region = drupal_region_class($variables['region']);
$variables['classes_array'][] = $region;
- $variables['template_files'][] = $region;
+ $variables['theme_hook_suggestions'][] = 'region__' . $region;
}