Index: includes/theme.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/theme.inc,v retrieving revision 1.437 diff -u -p -r1.437 theme.inc --- includes/theme.inc 20 Sep 2008 20:22:23 -0000 1.437 +++ includes/theme.inc 30 Sep 2008 18:11:09 -0000 @@ -304,65 +304,77 @@ function _theme_process_registry(&$cache include_once DRUPAL_ROOT . '/' . $info['path'] . '/' . $info['file']; } - if (isset($info['template']) && !isset($info['path'])) { - $result[$hook]['template'] = $path . '/' . $info['template']; - } // If 'arguments' have been defined previously, carry them forward. // This should happen if a theme overrides a Drupal defined theme // function, for example. if (!isset($info['arguments']) && isset($cache[$hook])) { $result[$hook]['arguments'] = $cache[$hook]['arguments']; } - // Likewise with theme paths. These are used for template naming suggestions. - // Theme implementations can occur in multiple paths. Suggestions should follow. - if (!isset($info['theme paths']) && isset($cache[$hook])) { - $result[$hook]['theme paths'] = $cache[$hook]['theme paths']; - } - // Check for sub-directories. - $result[$hook]['theme paths'][] = isset($info['path']) ? $info['path'] : $path; - - // Check for default _preprocess_ functions. Ensure arrayness. - if (!isset($info['preprocess functions']) || !is_array($info['preprocess functions'])) { - $info['preprocess functions'] = array(); - $prefixes = array(); - if ($type == 'module') { - // Default preprocessor prefix. - $prefixes[] = 'template'; - // Add all modules so they can intervene with their own preprocessors. This allows them - // to provide preprocess functions even if they are not the owner of the current hook. - $prefixes += module_list(); - } - elseif ($type == 'theme_engine' || $type == 'base_theme_engine') { - // Theme engines get an extra set that come before the normally named preprocessors. - $prefixes[] = $name . '_engine'; - // The theme engine also registers on behalf of the theme. The theme or engine name can be used. - $prefixes[] = $name; - $prefixes[] = $theme; - } - else { - // This applies when the theme manually registers their own preprocessors. - $prefixes[] = $name; - } - foreach ($prefixes as $prefix) { - if (function_exists($prefix . '_preprocess')) { - $info['preprocess functions'][] = $prefix . '_preprocess'; + // The following apply only to theming hooks implemented as templates. + if (isset($info['template'])) { + if (!isset($info['path'])) { + $result[$hook]['template'] = $path . '/' . $info['template']; + } + + // Likewise with theme paths. These are used for template naming suggestions. + // Theme implementations can occur in multiple paths. Suggestions should follow. + if (!isset($info['theme paths']) && isset($cache[$hook])) { + $result[$hook]['theme paths'] = $cache[$hook]['theme paths']; + } + // Check for sub-directories. + $result[$hook]['theme paths'][] = isset($info['path']) ? $info['path'] : $path; + + // Preprocess functions work in two distinct phases with the "post_preprocess" + // functions always being executed after normal preprocess functions. + $preprocess_phases = array( + 'preprocess functions' => 'preprocess', + 'post preprocess functions' => 'post_preprocess', + ); + foreach ($preprocess_phases as $phase_key => $preprocess_phase) { + // Check for default _preprocess_ functions. Ensure arrayness. + if (!isset($info[$phase_key . ' functions']) || !is_array($info[$phase_key])) { + $info[$phase_key] = array(); + $prefixes = array(); + if ($type == 'module') { + // Default preprocessor prefix. + $prefixes[] = 'template'; + // Add all modules so they can intervene with their own preprocessors. This allows them + // to provide preprocess functions even if they are not the owner of the current hook. + $prefixes += module_list(); + } + elseif ($type == 'theme_engine' || $type == 'base_theme_engine') { + // Theme engines get an extra set that come before the normally named preprocessors. + $prefixes[] = $name . '_engine'; + // The theme engine also registers on behalf of the theme. The theme or engine name can be used. + $prefixes[] = $name; + $prefixes[] = $theme; + } + else { + // This applies when the theme manually registers their own preprocessors. + $prefixes[] = $name; + } + foreach ($prefixes as $prefix) { + if (function_exists($prefix . '_' . $preprocess_phase)) { + $info[$phase_key][] = $prefix . '_' . $preprocess_phase; + } + if (function_exists($prefix . '_' . $preprocess_phase . '_' . $hook)) { + $info[$phase_key][] = $prefix . '_' . $preprocess_phase . '_' . $hook; + } + } } - if (function_exists($prefix . '_preprocess_' . $hook)) { - $info['preprocess functions'][] = $prefix . '_preprocess_' . $hook; + // Check for the override flag and prevent the cached preprocess functions from being used. + // This allows themes or theme engines to remove preprocessors set earlier in the registry build. + if (!empty($info['override ' . $phase_key])) { + // Flag not needed inside the registry. + unset($result[$hook]['override ' . $phase_key]); } + elseif (isset($cache[$hook][$phase_key]) && is_array($cache[$hook][$phase_key])) { + $info[$phase_key] = array_merge($cache[$hook][$phase_key], $info[$phase_key]); + } + $result[$hook][$phase_key] = $info[$phase_key]; } } - // Check for the override flag and prevent the cached preprocess functions from being used. - // This allows themes or theme engines to remove preprocessors set earlier in the registry build. - if (!empty($info['override preprocess functions'])) { - // Flag not needed inside the registry. - unset($result[$hook]['override preprocess functions']); - } - elseif (isset($cache[$hook]['preprocess functions']) && is_array($cache[$hook]['preprocess functions'])) { - $info['preprocess functions'] = array_merge($cache[$hook]['preprocess functions'], $info['preprocess functions']); - } - $result[$hook]['preprocess functions'] = $info['preprocess functions']; } // Merge the newly created theme hooks into the existing cache. @@ -639,11 +651,12 @@ function theme() { } } - if (isset($info['preprocess functions']) && is_array($info['preprocess functions'])) { - // This construct ensures that we can keep a reference through - // call_user_func_array. - $args = array(&$variables, $hook); - foreach ($info['preprocess functions'] as $preprocess_function) { + // This construct ensures that we can keep a reference through + // call_user_func_array. + $args = array(&$variables, $hook); + // Preprocess in two phases. + foreach (array('preprocess functions', 'post preprocess functions') as $preprocess_phase) { + foreach ($info[$preprocess_phase] as $preprocess_function) { if (drupal_function_exists($preprocess_function)) { call_user_func_array($preprocess_function, $args); } @@ -1743,6 +1756,9 @@ function template_preprocess(&$variables // Tell all templates where they are located. $variables['directory'] = path_to_theme(); + // Initialize html class attribute for the current hook. + $variables['attribute_classes'] = array($hook); + // Set default variables that depend on the database. $variables['is_admin'] = FALSE; $variables['is_front'] = FALSE; @@ -1762,6 +1778,14 @@ function template_preprocess(&$variables } /** + * A default post preprocess function used to alter variables as late as possible. + */ +function template_post_preprocess(&$variables, $hook) { + // Flatten out classes. + $variables['classes'] = implode(' ', str_replace('_', '-', $variables['attribute_classes'])); +} + +/** * Process variables for page.tpl.php * * Most themes utilize their own copy of page.tpl.php. The default is located @@ -1858,32 +1882,29 @@ function template_preprocess_page(&$vari // Compile a list of classes that are going to be applied to the body element. // This allows advanced theming based on context (home page, node of certain type, etc.). - $body_classes = array(); // Add a class that tells us whether we're on the front page or not. - $body_classes[] = $variables['is_front'] ? 'front' : 'not-front'; + $variables['attribute_classes'][] = $variables['is_front'] ? 'front' : 'not-front'; // Add a class that tells us whether the page is viewed by an authenticated user or not. - $body_classes[] = $variables['logged_in'] ? 'logged-in' : 'not-logged-in'; + $variables['attribute_classes'][] = $variables['logged_in'] ? 'logged-in' : 'not-logged-in'; // Add arg(0) to make it possible to theme the page depending on the current page // type (e.g. node, admin, user, etc.). To avoid illegal characters in the class, // we're removing everything disallowed. We are not using 'a-z' as that might leave // in certain international characters (e.g. German umlauts). - $body_classes[] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', 'page-' . form_clean_id(drupal_strtolower(arg(0)))); + $variables['attribute_classes'][] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', 'page-' . form_clean_id(drupal_strtolower(arg(0)))); // If on an individual node page, add the node type. if (isset($variables['node']) && $variables['node']->type) { - $body_classes[] = 'node-type-' . form_clean_id($variables['node']->type); + $variables['attribute_classes'][] = 'node-type-' . form_clean_id($variables['node']->type); } // Add information about the number of sidebars. if ($variables['layout'] == 'both') { - $body_classes[] = 'two-sidebars'; + $variables['attribute_classes'][] = 'two-sidebars'; } elseif ($variables['layout'] == 'none') { - $body_classes[] = 'no-sidebars'; + $variables['attribute_classes'][] = 'no-sidebars'; } else { - $body_classes[] = 'one-sidebar sidebar-' . $variables['layout']; + $variables['attribute_classes'][] = 'one-sidebar sidebar-' . $variables['layout']; } - // Implode with spaces. - $variables['body_classes'] = implode(' ', $body_classes); // Build a list of suggested template files in order of specificity. One // suggestion is made for every element of the current path, though @@ -1955,6 +1976,24 @@ function template_preprocess_node(&$vari // Flatten the node object's member fields. $variables = array_merge((array)$node, $variables); + + // Gather node classes. + $variables['attribute_classes'][] = 'node-' . $node->type; + if ($variables['promote']) { + $variables['attribute_classes'][] = 'node-promoted'; + } + if ($variables['sticky']) { + $variables['attribute_classes'][] = 'node-sticky'; + } + if (!$variables['status']) { + $variables['attribute_classes'][] = 'node-unpublished'; + } + if ($variables['teaser']) { + $variables['attribute_classes'][] = 'node-teaser'; + } + if (isset($variables['preview'])) { + $variables['attribute_classes'][] = 'node-preview'; + } // Display info only on certain node types. if (theme_get_setting('toggle_node_info_' . $node->type)) { @@ -1997,6 +2036,8 @@ function template_preprocess_block(&$var $variables['block_zebra'] = ($block_counter[$variables['block']->region] % 2) ? 'odd' : 'even'; $variables['block_id'] = $block_counter[$variables['block']->region]++; + $variables['attribute_classes'][] = 'block-' . $variables['block']->module; + $variables['template_files'][] = 'block-' . $variables['block']->region; $variables['template_files'][] = 'block-' . $variables['block']->module; $variables['template_files'][] = 'block-' . $variables['block']->module . '-' . $variables['block']->delta; Index: includes/theme.maintenance.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/theme.maintenance.inc,v retrieving revision 1.18 diff -u -p -r1.18 theme.maintenance.inc --- includes/theme.maintenance.inc 20 Sep 2008 20:22:23 -0000 1.18 +++ includes/theme.maintenance.inc 30 Sep 2008 18:11:09 -0000 @@ -265,21 +265,19 @@ function template_preprocess_maintenance $variables['closure'] = ''; // Compile a list of classes that are going to be applied to the body element. - $body_classes = array(); - $body_classes[] = 'in-maintenance'; + $variables['attribute_classes'][] = 'in-maintenance'; if (isset($variables['db_is_active']) && !$variables['db_is_active']) { - $body_classes[] = 'db-offline'; + $variables['attribute_classes'][] = 'db-offline'; } if ($variables['layout'] == 'both') { - $body_classes[] = 'two-sidebars'; + $variables['attribute_classes'][] = 'two-sidebars'; } elseif ($variables['layout'] == 'none') { - $body_classes[] = 'no-sidebars'; + $variables['attribute_classes'][] = 'no-sidebars'; } else { - $body_classes[] = 'one-sidebar sidebar-' . $variables['layout']; + $variables['attribute_classes'][] = 'one-sidebar sidebar-' . $variables['layout']; } - $variables['body_classes'] = implode(' ', $body_classes); // Dead databases will show error messages so supplying this template will // allow themers to override the page and the content completely. Index: modules/comment/comment-folded.tpl.php =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment-folded.tpl.php,v retrieving revision 1.4 diff -u -p -r1.4 comment-folded.tpl.php --- modules/comment/comment-folded.tpl.php 14 May 2008 13:12:40 -0000 1.4 +++ modules/comment/comment-folded.tpl.php 30 Sep 2008 18:11:09 -0000 @@ -11,11 +11,29 @@ * - $author: Comment author. Can be link or plain text. * - $date: Date and time of posting. * - $comment: Full comment object. + * - $classes: String of classes that can be used to style contextually through + * CSS. It can be manipulated through the variable $attribute_classes from + * preprocess functions. The default values can be one or more of the following: + * - comment-folded: The current template type, i.e., "theming hook". + * - comment-by-anonymous: Comment by an unregistered user. + * - comment-by-node-author: Comment by the author of the parent node. + * The following applies only to viewers who are registered users: + * - comment-unpublished: An unpublished comment visible only to administrators. + * - comment-by-viewer: Comment by the user currently viewing the page. + * - comment-new: New comment since last the visit. + * + * These two variables are provided for context: + * - $comment: Full comment object. + * - $node: Node object the comments are attached to. + * + * Other variables: + * - $attribute_classes: Array of html class attribute values. It is flattened + * into a string within the variable $classes. * * @see template_preprocess_comment_folded() * @see theme_comment_folded() */ ?> -
subject ?>
Index: modules/system/box.tpl.php =================================================================== RCS file: /cvs/drupal/drupal/modules/system/box.tpl.php,v retrieving revision 1.3 diff -u -p -r1.3 box.tpl.php --- modules/system/box.tpl.php 16 Dec 2007 21:01:45 -0000 1.3 +++ modules/system/box.tpl.php 30 Sep 2008 18:11:10 -0000 @@ -9,11 +9,19 @@ * Available variables: * - $title: Box title. * - $content: Box content. + * - $classes: String of classes that can be used to style contextually through + * CSS. It can be manipulated through the variable $attribute_classes from + * preprocess functions. The default value has the following: + * - box: The current template type, i.e., "theming hook". + * + * Other variables: + * - $attribute_classes: Array of html class attribute values. It is flattened + * into a string within the variable $classes. * * @see template_preprocess() */ ?> -subject; ?>
" . ($teaser ? l($node->title, "node/$node->nid") : check_plain($node->title)) . "
\n"; Index: themes/garland/block.tpl.php =================================================================== RCS file: /cvs/drupal/drupal/themes/garland/block.tpl.php,v retrieving revision 1.4 diff -u -p -r1.4 block.tpl.php --- themes/garland/block.tpl.php 14 Apr 2008 17:48:46 -0000 1.4 +++ themes/garland/block.tpl.php 30 Sep 2008 18:11:10 -0000 @@ -1,7 +1,7 @@ -subject ?>
Index: themes/garland/comment.tpl.php =================================================================== RCS file: /cvs/drupal/drupal/themes/garland/comment.tpl.php,v retrieving revision 1.11 diff -u -p -r1.11 comment.tpl.php --- themes/garland/comment.tpl.php 14 Apr 2008 17:48:46 -0000 1.11 +++ themes/garland/comment.tpl.php 30 Sep 2008 18:11:10 -0000 @@ -1,7 +1,7 @@ -