theme
Generate the themed output.
All requests for theme hooks must go through this function. It examines the request and routes it to the appropriate theme function. The theme registry is checked to determine which implementation to use, which may be a function or a template.
If the implementation is a template, the following functions may be used to modify the $variables array. They are processed in two distinct phases; "preprocess" and "process" functions. The order listed here is the order in which they execute.
- template_preprocess(&$variables) This sets a default set of variables for all template implementations.
- template_preprocess_HOOK(&$variables) This is the first preprocessor called specific to the hook; it should be implemented by the module that registers it.
- MODULE_preprocess(&$variables) This will be called for all templates; it should only be used if there is a real need. It's purpose is similar to template_preprocess().
- MODULE_preprocess_HOOK(&$variables) This is for modules that want to alter or provide extra variables for theming hooks not registered to itself. For example, if a module named "foo" wanted to alter the $classes_array variable for the hook "node" a preprocess function of foo_preprocess_node() can be created to intercept and alter the variable.
- ENGINE_engine_preprocess(&$variables) This function should only be implemented by theme engines and exists so that it can set necessary variables for all hooks.
- ENGINE_engine_preprocess_HOOK(&$variables) This is the same as the previous function, but it is called for a single theming hook.
- THEME_preprocess(&$variables) This is for themes that want to alter or provide extra variables. For example, if a theme named "foo" wanted to alter the $classes_array variable for the hook "node" a preprocess function of foo_preprocess_node() can be created to intercept and alter the variable.
- THEME_preprocess_HOOK(&$variables) The same applies from the previous function, but it is called for a specific hook.
- template_process(&$variables) This sets a default set of variables for all template implementations.
- template_process_HOOK(&$variables) This is the first processor called specific to the hook; it should be implemented by the module that registers it.
- MODULE_process(&$variables) This will be called for all templates; it should only be used if there is a real need. It's purpose is similar to template_process().
- MODULE_process_HOOK(&$variables) This is for modules that want to alter or provide extra variables for theming hooks not registered to itself. For example, if a module named "foo" wanted to alter the $classes_array variable for the hook "node" a process function of foo_process_node() can be created to intercept and alter the variable.
- ENGINE_engine_process(&$variables) This function should only be implemented by theme engines and exists so that it can set necessary variables for all hooks.
- ENGINE_engine_process_HOOK(&$variables) This is the same as the previous function, but it is called for a single theming hook.
- ENGINE_process(&$variables) This is meant to be used by themes that utilize a theme engine. It is provided so that the processor is not locked into a specific theme. This makes it easy to share and transport code but theme authors must be careful to prevent fatal re-declaration errors when using sub-themes that have their own processor named exactly the same as its base theme. In the default theme engine (PHPTemplate), sub-themes will load their own template.php file in addition to the one used for its parent theme. This increases the risk for these errors. A good practice is to use the engine name for the base theme and the theme name for the sub-themes to minimize this possibility.
- ENGINE_process_HOOK(&$variables) The same applies from the previous function, but it is called for a specific hook.
- THEME_process(&$variables) These functions are based upon the raw theme; they should primarily be used by themes that do not use an engine or by sub-themes. It serves the same purpose as ENGINE_process().
- THEME_process_HOOK(&$variables) The same applies from the previous function, but it is called for a specific hook.
If the implementation is a function, only the hook-specific preprocess and process functions (the ones ending in _HOOK) are called from the above list. This is because theme hooks with function implementations 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.
Parameters
$hook The name of the theme function to call. May be an array, in which case the first hook that actually has an implementation registered will be used. This can be used to choose 'fallback' theme implementations, so that if the specific theme hook isn't implemented anywhere, a more generic one will be used. This can allow themes to create specific theme implementations for named objects.
$variables An associative array of variables to merge with defaults from the theme registry, pass to preprocess and process functions for modification, and finally, pass to the function or template implementing the theme hook. Alternatively, this can be a renderable array, in which case, its properties are mapped to variables expected by the theme hook implementations.
Return value
An HTML string that generates the themed output.
Code
includes/theme.inc, line 756
<?php
function theme($hook, $variables = array()) {
static $hooks = NULL;
if (!isset($hooks)) {
drupal_theme_initialize();
$hooks = theme_get_registry();
}
// If an array of hook candidates were passed, use the first one that has an
// implementation.
if (is_array($hook)) {
foreach ($hook as $candidate) {
if (isset($hooks[$candidate])) {
break;
}
}
$hook = $candidate;
}
if (!isset($hooks[$hook])) {
watchdog('theme', 'Theme key "@key" not found.', array('@key' => $hook), WATCHDOG_WARNING);
return '';
}
$info = $hooks[$hook];
global $theme_path;
$temp = $theme_path;
// point path_to_theme() to the currently used theme path:
$theme_path = $info['theme path'];
// Include a file if the theme function or variable processor is held elsewhere.
if (!empty($info['includes'])) {
foreach ($info['includes'] as $include_file) {
include_once DRUPAL_ROOT . '/' . $include_file;
}
}
// If a renderable array is passed as $variables, then set $variables to
// the arguments expected by the theme function.
if (isset($variables['#theme']) || isset($variables['#theme_wrappers'])) {
$element = $variables;
$variables = array();
if (isset($info['variables'])) {
foreach (array_keys($info['variables']) as $name) {
if (isset($element["#$name"])) {
$variables[$name] = $element["#$name"];
}
}
}
else {
$variables[$info['render element']] = $element;
}
}
// Merge in argument defaults.
if (!empty($info['variables'])) {
$variables += $info['variables'];
}
elseif (!empty($info['render element'])) {
$variables += array($info['render element'] => array());
}
// Invoke the variable processors, if any. The processors may specify
// alternate suggestions for which function/template should be used.
if (isset($info['preprocess functions']) || isset($info['process functions'])) {
$variables['theme_functions'] = array();
$variables['template_files'] = array();
foreach (array('preprocess functions', 'process functions') as $phase) {
if (!empty($info[$phase])) {
foreach ($info[$phase] as $processor_function) {
if (function_exists($processor_function)) {
// We don't want a poorly behaved process function changing $hook.
$hook_clone = $hook;
$processor_function($variables, $hook_clone);
}
}
}
}
// 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.
$suggestions = array();
if (!empty($variables['theme_functions'])) {
$suggestions = $variables['theme_functions'];
}
if (!empty($variables['theme_function'])) {
$suggestions[] = $variables['theme_function'];
}
foreach (array_reverse($suggestions) as $suggestion) {
if (function_exists($suggestion)) {
$info['function'] = $suggestion;
break;
}
}
}
// Generate the output using either a function or a template.
if (isset($info['function'])) {
if (function_exists($info['function'])) {
$output = $info['function']($variables);
}
}
else {
// Default render function and extension.
$render_function = 'theme_render_template';
$extension = '.tpl.php';
// Run through the theme engine variables, if necessary
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';
}
$extension_function = $theme_engine . '_extension';
if (function_exists($extension_function)) {
$extension = $extension_function();
}
}
}
// 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 found template file.
$output = $render_function($template_file, $variables);
}
// restore path_to_theme()
$theme_path = $temp;
return $output;
}
?>Login or register to post comments 