Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.491
diff -u -p -r1.491 theme.inc
--- includes/theme.inc	26 May 2009 10:41:06 -0000	1.491
+++ includes/theme.inc	28 May 2009 01:35:47 -0000
@@ -311,6 +311,14 @@ function drupal_theme_rebuild() {
 function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
   $result = array();
   $function = $name . '_theme';
+
+  // Template functions work in two distinct phases with the process
+  // functions always being executed after the preprocess functions.
+  $template_phases = array(
+    'preprocess functions' => 'preprocess',
+    'process functions'    => 'process',
+  );
+
   if (function_exists($function)) {
     $result = $function($cache, $type, $theme, $path);
 
@@ -335,87 +343,96 @@ 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'])) {
+        // Prepend the current theming path when none is set.
+        if (!isset($info['path'])) {
+          $result[$hook]['template'] = $path . '/' . $info['template'];
+        }
+
+        // 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;
+
+        foreach ($template_phases as $phase_key => $template_phase) {
+          // Check for existing variable processors. Ensure arrayness.
+          if (!isset($info[$phase_key]) || !is_array($info[$phase_key])) {
+            $info[$phase_key] = array();
+            $prefixes = array();
+            if ($type == 'module') {
+              // Default variable processor prefix.
+              $prefixes[] = 'template';
+              // Add all modules so they can intervene with their own variable processors. This allows them
+              // to provide variable processors 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 variable processors.
+              $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 variable processors.
+              $prefixes[] = $name;
+            }
+            foreach ($prefixes as $prefix) {
+              if (function_exists($prefix . '_' . $template_phase)) {
+                $info[$phase_key][] = $prefix . '_' . $template_phase;
+              }
+              if (function_exists($prefix . '_' . $template_phase . '_' . $hook)) {
+                $info[$phase_key][] = $prefix . '_' . $template_phase . '_' . $hook;
+              }
+            }
+          }
+          // Check for the override flag and prevent the cached variable processors from being used.
+          // This allows themes or theme engines to remove variable processors set earlier in the registry build.
+          if (!empty($info['override ' . $phase_key])) {
+            // Flag not needed inside the registry.
+            unset($result[$hook]['override ' . $phase_key]);
           }
-          if (function_exists($prefix . '_preprocess_' . $hook)) {
-            $info['preprocess functions'][] = $prefix . '_preprocess_' . $hook;
+          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.
     $cache = array_merge($cache, $result);
   }
 
-  // Let themes have preprocess functions even if they didn't register a template.
+  // Let themes have variable processors even if they didn't register a template.
   if ($type == 'theme' || $type == 'base_theme') {
     foreach ($cache as $hook => $info) {
       // Check only if it's a template and not registered by the theme or engine.
       if (!empty($info['template']) && empty($result[$hook])) {
-        if (!isset($info['preprocess functions'])) {
-          $cache[$hook]['preprocess functions'] = array();
-        }
-        if (function_exists($name . '_preprocess')) {
-          $cache[$hook]['preprocess functions'][] = $name . '_preprocess';
-        }
-        if (function_exists($name . '_preprocess_' . $hook)) {
-          $cache[$hook]['preprocess functions'][] = $name . '_preprocess_' . $hook;
+        foreach ($template_phases as $phase_key => $template_phase) {
+          if (!isset($info[$phase_key])) {
+            $cache[$hook][$phase_key] = array();
+          }
+          if (function_exists($name . '_' . $template_phase)) {
+            $cache[$hook][$phase_key][] = $name . '_' . $template_phase;
+          }
+          if (function_exists($name . '_' . $template_phase . '_' . $hook)) {
+            $cache[$hook][$phase_key][] = $name . '_' . $template_phase . '_' . $hook;
+          }
+          // Ensure uniqueness.
+          $cache[$hook][$phase_key] = array_unique($cache[$hook][$phase_key]);
         }
-        // Ensure uniqueness.
-        $cache[$hook]['preprocess functions'] = array_unique($cache[$hook]['preprocess functions']);
       }
     }
   }
@@ -558,7 +575,8 @@ function list_themes($refresh = FALSE) {
  * $variables array. This array is then modified by the module implementing
  * the hook, theme engine (if applicable) and the theme. The following
  * functions may be used to modify the $variables array. They are processed in
- * this order when available:
+ * two distinct phases; "preprocess" and "process" functions. The order it is
+ * listed here is the order in which it will execute.
  *
  * - template_preprocess(&$variables)
  *   This sets a default set of variables for all template implementations.
@@ -611,6 +629,57 @@ function list_themes($refresh = FALSE) {
  *   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 $submitted 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.
+ *
  * There are two special variables that these hooks can set:
  *   'template_file' and 'template_files'. These will be merged together
  *   to form a list of 'suggested' alternate template files to use, in
@@ -659,7 +728,7 @@ function theme() {
   // point path_to_theme() to the currently used theme path:
   $theme_path = $info['theme path'];
 
-  // Include a file if the theme function or preprocess function is held elsewhere.
+  // Include a file if the theme function or variable processor is held elsewhere.
   if (!empty($info['file'])) {
     $include_file = $info['file'];
     if (isset($info['path'])) {
@@ -706,13 +775,14 @@ 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) {
-        if (drupal_function_exists($preprocess_function)) {
-          call_user_func_array($preprocess_function, $args);
+    // This construct ensures that we can keep a reference through
+    // call_user_func_array.
+    $args = array(&$variables, $hook);
+    // Template functions in two phases.
+    foreach (array('preprocess functions', 'process functions') as $template_phase) {
+      foreach ($info[$template_phase] as $template_function) {
+        if (drupal_function_exists($template_function)) {
+          call_user_func_array($template_function, $args);
         }
       }
     }
@@ -1064,7 +1134,7 @@ function theme_get_setting($setting_name
  *
  * @param $template_file
  *   The filename of the template to render. Note that this will overwrite
- *   anything stored in $variables['template_file'] if using a preprocess hook.
+ *   anything stored in $variables['template_file'] if using a variable processor hook.
  * @param $variables
  *   A keyed array of variables that will appear in the output.
  *
@@ -1786,10 +1856,9 @@ function _theme_table_cell($cell, $heade
 }
 
 /**
- * Adds a default set of helper variables for preprocess functions and
- * templates. This comes in before any other preprocess function which makes
- * it possible to be used in default theme implementations (non-overriden
- * theme functions).
+ * Adds a default set of helper variables for variable processors and templates.
+ * This comes in before any other preprocess function which makes it possible to
+ * be used in default theme implementations (non-overriden theme functions).
  */
 function template_preprocess(&$variables, $hook) {
   global $user;
@@ -1804,6 +1873,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['classes_array'] = array($hook);
+
   // Set default variables that depend on the database.
   $variables['is_admin']            = FALSE;
   $variables['is_front']            = FALSE;
@@ -1823,6 +1895,14 @@ function template_preprocess(&$variables
 }
 
 /**
+ * A default process function used to alter variables as late as possible.
+ */
+function template_process(&$variables, $hook) {
+  // Flatten out classes.
+  $variables['classes'] = implode(' ', str_replace('_', '-', $variables['classes_array']));
+}
+
+/**
  * Process variables for page.tpl.php
  *
  * Most themes utilize their own copy of page.tpl.php. The default is located
@@ -1916,26 +1996,10 @@ 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['classes_array'][] = $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';
-
-  // If on an individual node page, add the node type to body classes.
-  if (isset($variables['node']) && $variables['node']->type) {
-    $body_classes[] = 'node-type-' . form_clean_id($variables['node']->type);
-  }
-  // Add information about the number of sidebars.
-  if ($variables['layout'] == 'both') {
-    $body_classes[] = 'two-sidebars';
-  }
-  elseif ($variables['layout'] == 'none') {
-    $body_classes[] = 'no-sidebars';
-  }
-  else {
-    $body_classes[] = 'one-sidebar sidebar-' . $variables['layout'];
-  }
+  $variables['classes_array'][] = $variables['logged_in'] ? 'logged-in' : 'not-logged-in';
 
   // Populate the page template suggestions.
   if ($suggestions = template_page_suggestions(arg())) {
@@ -1947,13 +2011,25 @@ function template_preprocess_page(&$vari
         // more specific data like node-12 or node-edit. 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', '', form_clean_id(drupal_strtolower($suggestion)));
+        $variables['classes_array'][] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', form_clean_id(drupal_strtolower($suggestion)));
       }
     }
   }
-  // Implode with spaces.
-  $variables['body_classes'] = implode(' ', $body_classes);
 
+  // If on an individual node page, add the node type to body classes.
+  if (isset($variables['node']) && $variables['node']->type) {
+    $variables['classes_array'][] = 'node-type-' . form_clean_id($variables['node']->type);
+  }
+  // Add information about the number of sidebars.
+  if ($variables['layout'] == 'both') {
+    $variables['classes_array'][] = 'two-sidebars';
+  }
+  elseif ($variables['layout'] == 'none') {
+    $variables['classes_array'][] = 'no-sidebars';
+  }
+  else {
+    $variables['classes_array'][] = 'one-sidebar sidebar-' . $variables['layout'];
+  }
 }
 
 /**
@@ -1994,4 +2070,3 @@ function template_page_suggestions($args
 
   return $suggestions;
 }
-
Index: includes/theme.maintenance.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.maintenance.inc,v
retrieving revision 1.28
diff -u -p -r1.28 theme.maintenance.inc
--- includes/theme.maintenance.inc	21 May 2009 21:12:22 -0000	1.28
+++ includes/theme.maintenance.inc	28 May 2009 01:35:47 -0000
@@ -114,8 +114,11 @@ function theme_install_page($content) {
   $variables['content'] = $content;
   // Delay setting the message variable so it can be processed below.
   $variables['show_messages'] = FALSE;
-  // The maintenance preprocess function is recycled here.
+  // Variable processors invoked manually since this function and theme_update_page()
+  // are exceptions in how it works within the theme system.
+  template_preprocess($variables, 'install_page');
   template_preprocess_maintenance_page($variables);
+  template_process($variables, 'install_page');
 
   // Special handling of error messages
   $messages = drupal_set_message();
@@ -167,8 +170,11 @@ function theme_update_page($content, $sh
   // Assign content and show message flag.
   $variables['content'] = $content;
   $variables['show_messages'] = $show_messages;
-  // The maintenance preprocess function is recycled here.
+  // Variable processors invoked manually since this function and theme_install_page()
+  // are exceptions in how it works within the theme system.
+  template_preprocess($variables, 'update_page');
   template_preprocess_maintenance_page($variables);
+  template_process($variables, 'update_page');
 
   // Special handling of warning messages.
   $messages = drupal_set_message();
@@ -270,21 +276,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['classes_array'][] = 'in-maintenance';
   if (isset($variables['db_is_active']) && !$variables['db_is_active']) {
-    $body_classes[] = 'db-offline';
+    $variables['classes_array'][] = 'db-offline';
   }
   if ($variables['layout'] == 'both') {
-    $body_classes[] = 'two-sidebars';
+    $variables['classes_array'][] = 'two-sidebars';
   }
   elseif ($variables['layout'] == 'none') {
-    $body_classes[] = 'no-sidebars';
+    $variables['classes_array'][] = 'no-sidebars';
   }
   else {
-    $body_classes[] = 'one-sidebar sidebar-' . $variables['layout'];
+    $variables['classes_array'][] = '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/block/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.module,v
retrieving revision 1.337
diff -u -p -r1.337 block.module
--- modules/block/block.module	27 May 2009 18:33:54 -0000	1.337
+++ modules/block/block.module	28 May 2009 01:35:47 -0000
@@ -761,7 +761,9 @@ function template_preprocess_block(&$var
     $variables['block']->content = drupal_render($variables['block']->content);
   }
 
+  $variables['classes_array'][] = '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;
-}
\ No newline at end of file
+}
Index: modules/block/block.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.tpl.php,v
retrieving revision 1.1
diff -u -p -r1.1 block.tpl.php
--- modules/block/block.tpl.php	26 Apr 2009 01:15:04 -0000	1.1
+++ modules/block/block.tpl.php	28 May 2009 01:35:47 -0000
@@ -11,8 +11,17 @@
  * - $block->module: Module that generated the block.
  * - $block->delta: An ID for the block, unique within each module.
  * - $block->region: The block region embedding the current block.
+ * - $classes: String of classes that can be used to style contextually through
+ *   CSS. It can be manipulated through the variable $classes_array from
+ *   preprocess functions. The default values can be one or more of the following:
+ *   - block: The current template type, i.e., "theming hook".
+ *   - block-[module]: The module generating the block. For example, the user module
+ *     is responsible for handling the default user navigation block. In that case
+ *     the class would be "block-user".
  *
  * Helper variables:
+ * - $classes_array: Array of html class attribute values. It is flattened
+ *   into a string within the variable $classes.
  * - $block_zebra: Outputs 'odd' and 'even' dependent on each block region.
  * - $zebra: Same output as $block_zebra but independent of any block region.
  * - $block_id: Counter dependent on each block region.
@@ -25,7 +34,7 @@
  * @see template_preprocess_block()
  */
 ?>
-<div id="block-<?php print $block->module . '-' . $block->delta; ?>" class="block block-<?php print $block->module ?>">
+<div id="block-<?php print $block->module . '-' . $block->delta; ?>" class="<?php print $classes; ?>">
 <?php if ($block->subject): ?>
   <h2><?php print $block->subject ?></h2>
 <?php endif;?>
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	28 May 2009 01:35:47 -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 $classes_array 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:
+ * - $classes_array: 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()
  */
 ?>
-<div class="comment-folded">
+<div class="<?php print $classes; ?>">
   <span class="subject"><?php print $title . ' ' . $new; ?></span><span class="credit"><?php print t('by') . ' ' . $author; ?></span>
 </div>
Index: modules/comment/comment-wrapper.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment-wrapper.tpl.php,v
retrieving revision 1.4
diff -u -p -r1.4 comment-wrapper.tpl.php
--- modules/comment/comment-wrapper.tpl.php	14 May 2008 13:12:40 -0000	1.4
+++ modules/comment/comment-wrapper.tpl.php	28 May 2009 01:35:47 -0000
@@ -8,6 +8,10 @@
  * Available variables:
  * - $content: All comments for a given page. Also contains comment form
  *   if enabled.
+ * - $classes: String of classes that can be used to style contextually through
+ *   CSS. It can be manipulated through the variable $classes_array from
+ *   preprocess functions. The default value has the following:
+ *   - comment-wrapper: The current template type, i.e., "theming hook".
  *
  * The following variables are provided for contextual information.
  * - $node: Node object the comments are attached to.
@@ -18,14 +22,15 @@
  *   - COMMENT_MODE_FLAT_EXPANDED
  *   - COMMENT_MODE_THREADED_COLLAPSED
  *   - COMMENT_MODE_THREADED_EXPANDED
- * - $display_order
- *   - COMMENT_ORDER_NEWEST_FIRST
- *   - COMMENT_ORDER_OLDEST_FIRST
+ *
+ * Other variables:
+ * - $classes_array: Array of html class attribute values. It is flattened
+ *   into a string within the variable $classes.
  *
  * @see template_preprocess_comment_wrapper()
  * @see theme_comment_wrapper()
  */
 ?>
-<div id="comments">
+<div id="comments" class="<?php print $classes; ?>">
   <?php print $content; ?>
 </div>
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.714
diff -u -p -r1.714 comment.module
--- modules/comment/comment.module	27 May 2009 18:33:56 -0000	1.714
+++ modules/comment/comment.module	28 May 2009 01:35:47 -0000
@@ -127,7 +127,7 @@ function comment_theme() {
     ),
     'comment_folded' => array(
       'template' => 'comment-folded',
-      'arguments' => array('comment' => NULL),
+      'arguments' => array('comment' => NULL, 'node' => NULL),
     ),
     'comment_flat_collapsed' => array(
       'arguments' => array('comment' => NULL, 'node' => NULL),
@@ -1830,7 +1830,7 @@ function theme_comment_view($comment, $n
     $output .= theme('comment', $comment, $node, $links);
   }
   else {
-    $output .= theme('comment_folded', $comment);
+    $output .= theme('comment_folded', $comment, $node);
   }
 
   return $output;
@@ -1862,6 +1862,25 @@ function template_preprocess_comment(&$v
   else {
     $variables['status']  = ($comment->status == COMMENT_NOT_PUBLISHED) ? 'comment-unpublished' : 'comment-published';
   }
+  // Gather comment classes.
+  if ($comment->uid === 0) {
+    $variables['classes_array'][] = 'comment-by-anonymous';
+  }
+  else {
+    // Published class is not needed. It is either 'comment-preview' or 'comment-unpublished'.
+    if ($variables['status'] != 'comment-published') {
+      $variables['classes_array'][] = $variables['status'];
+    }
+    if ($comment->uid === $variables['node']->uid) {
+      $variables['classes_array'][] = 'comment-by-node-author';
+    }
+    if ($comment->uid === $variables['user']->uid) {
+      $variables['classes_array'][] = 'comment-by-viewer';
+    }
+    if ($comment->new) {
+      $variables['classes_array'][] = 'comment-new';
+    }
+  }
 }
 
 /**
@@ -1876,6 +1895,25 @@ function template_preprocess_comment_fol
   $variables['date']   = format_date($comment->timestamp);
   $variables['new']    = $comment->new ? t('new') : '';
   $variables['title']  = l($comment->subject, comment_node_url() . '/' . $comment->cid, array('fragment' => "comment-$comment->cid"));
+  // Gather comment classes.
+  if ($comment->uid === 0) {
+    $variables['classes_array'][] = 'comment-by-anonymous';
+  }
+  else {
+    if ($comment->status == COMMENT_NOT_PUBLISHED) {
+      $variables['classes_array'][] = 'comment-unpublished';
+    }
+    if ($comment->uid === $variables['node']->uid) {
+      $variables['classes_array'][] = 'comment-by-node-author';
+    }
+    if ($comment->uid === $variables['user']->uid) {
+      $variables['classes_array'][] = 'comment-by-viewer';
+    }
+    if ($comment->new) {
+      $variables['classes_array'][] = 'comment-new';
+    }
+  }
+  
 }
 
 /**
Index: modules/comment/comment.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.tpl.php,v
retrieving revision 1.8
diff -u -p -r1.8 comment.tpl.php
--- modules/comment/comment.tpl.php	18 Feb 2009 14:28:22 -0000	1.8
+++ modules/comment/comment.tpl.php	28 May 2009 01:35:47 -0000
@@ -17,16 +17,31 @@
  *   comment-unpublished, comment-published or comment-preview.
  * - $submitted: By line with date and time.
  * - $title: Linked title.
+ * - $classes: String of classes that can be used to style contextually through
+ *   CSS. It can be manipulated through the variable $classes_array from
+ *   preprocess functions. The default values can be one or more of the following:
+ *   - comment: 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.
+ *   - comment-preview: When previewing a new or edited comment.
+ *   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.
+ * These two variables are provided for context:
  * - $comment: Full comment object.
  * - $node: Node object the comments are attached to.
  *
+ * Other variables:
+ * - $classes_array: Array of html class attribute values. It is flattened
+ *   into a string within the variable $classes.
+ *
  * @see template_preprocess_comment()
  * @see theme_comment()
  */
 ?>
-<div class="comment<?php print ($comment->new) ? ' comment-new' : ''; print ' ' . $status ?> clearfix">
+<div class="<?php print $classes; ?> clearfix">
   <?php print $picture ?>
 
   <?php if ($comment->new): ?>
Index: modules/field/modules/number/number.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/number/number.module,v
retrieving revision 1.9
diff -u -p -r1.9 number.module
--- modules/field/modules/number/number.module	27 May 2009 18:33:56 -0000	1.9
+++ modules/field/modules/number/number.module	28 May 2009 01:35:47 -0000
@@ -239,7 +239,7 @@ function number_elements() {
     'number' => array(
       '#input' => TRUE,
       '#columns' => array('value'), '#delta' => 0,
-      '#process' => array('number_process'),
+      '#process' => array('number_elements_process'),
     ),
   );
 }
@@ -296,7 +296,7 @@ function number_field_widget_error($elem
  *
  * The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
  */
-function number_process($element, $form_state, $form) {
+function number_elements_process($element, $form_state, $form) {
   $field_name = $element['#field_name'];
   $field = field_info_field($element['#field_name']);
   $instance = field_info_instance($element['#field_name'], $element['#bundle']);
Index: modules/field/modules/options/options.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/options/options.module,v
retrieving revision 1.6
diff -u -p -r1.6 options.module
--- modules/field/modules/options/options.module	27 May 2009 18:33:56 -0000	1.6
+++ modules/field/modules/options/options.module	28 May 2009 01:35:47 -0000
@@ -83,17 +83,17 @@ function options_elements() {
     'options_select' => array(
       '#input' => TRUE,
       '#columns' => array('value'), '#delta' => 0,
-      '#process' => array('options_select_process'),
+      '#process' => array('options_select_elements_process'),
       ),
     'options_buttons' => array(
       '#input' => TRUE,
       '#columns' => array('value'), '#delta' => 0,
-      '#process' => array('options_buttons_process'),
+      '#process' => array('options_buttons_elements_process'),
       ),
     'options_onoff' => array(
       '#input' => TRUE,
       '#columns' => array('value'), '#delta' => 0,
-      '#process' => array('options_onoff_process'),
+      '#process' => array('options_onoff_elements_process'),
       ),
     );
 }
@@ -125,7 +125,7 @@ function options_field_widget_error($ele
  *
  * The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
  */
-function options_buttons_process($element, &$form_state, $form) {
+function options_buttons_elements_process($element, &$form_state, $form) {
   $field = $form['#fields'][$element['#field_name']]['field'];
   $instance = $form['#fields'][$element['#field_name']]['instance'];
   $field_key  = $element['#columns'][0];
@@ -182,7 +182,7 @@ function options_buttons_process($elemen
  *
  * The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
  */
-function options_select_process($element, &$form_state, $form) {
+function options_select_elements_process($element, &$form_state, $form) {
   $field = $form['#fields'][$element['#field_name']]['field'];
   $instance = $form['#fields'][$element['#field_name']]['instance'];
   $field_key  = $element['#columns'][0];
@@ -223,7 +223,7 @@ function options_select_process($element
  * Build the form element. When creating a form using FAPI #process,
  * note that $element['#value'] is already set.
  */
-function options_onoff_process($element, &$form_state, $form) {
+function options_onoff_elements_process($element, &$form_state, $form) {
   $field = $form['#fields'][$element['#field_name']]['field'];
   $instance = $form['#fields'][$element['#field_name']]['instance'];
   $field_key  = $element['#columns'][0];
Index: modules/field/modules/text/text.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/text/text.module,v
retrieving revision 1.8
diff -u -p -r1.8 text.module
--- modules/field/modules/text/text.module	27 May 2009 18:33:56 -0000	1.8
+++ modules/field/modules/text/text.module	28 May 2009 01:35:47 -0000
@@ -238,13 +238,13 @@ function text_elements() {
     'text_textfield' => array(
       '#input' => TRUE,
       '#columns' => array('value'), '#delta' => 0,
-      '#process' => array('text_textfield_process'),
+      '#process' => array('text_textfield_elements_process'),
       '#autocomplete_path' => FALSE,
       ),
     'text_textarea' => array(
       '#input' => TRUE,
       '#columns' => array('value', 'format'), '#delta' => 0,
-      '#process' => array('text_textarea_process'),
+      '#process' => array('text_textarea_elements_process'),
       '#filter_value' => FILTER_FORMAT_DEFAULT,
       ),
   );
@@ -310,7 +310,7 @@ function text_field_widget_error($elemen
  * information needed to adjust the behavior of the 'element' should be
  * extracted in hook_field_widget() above.
  */
-function text_textfield_process($element, $form_state, $form) {
+function text_textfield_elements_process($element, $form_state, $form) {
   $field = $form['#fields'][$element['#field_name']]['field'];
   $instance = $form['#fields'][$element['#field_name']]['instance'];
   $field_key = $element['#columns'][0];
@@ -353,7 +353,7 @@ function text_textfield_process($element
  *
  * The $field and $instance arrays are in $form['#fields'][$element['#field_name']].
  */
-function text_textarea_process($element, $form_state, $form) {
+function text_textarea_elements_process($element, $form_state, $form) {
   $field = $form['#fields'][$element['#field_name']]['field'];
   $instance = $form['#fields'][$element['#field_name']]['instance'];
   $field_key = $element['#columns'][0];
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1060
diff -u -p -r1.1060 node.module
--- modules/node/node.module	27 May 2009 18:33:58 -0000	1.1060
+++ modules/node/node.module	28 May 2009 01:35:47 -0000
@@ -1387,6 +1387,25 @@ function template_preprocess_node(&$vari
     $variables['submitted'] = '';
     $variables['picture'] = '';
   }
+
+  // Gather node classes.
+  $variables['classes_array'][] = 'node-' . $node->type;
+  if ($variables['promote']) {
+    $variables['classes_array'][] = 'node-promoted';
+  }
+  if ($variables['sticky']) {
+    $variables['classes_array'][] = 'node-sticky';
+  }
+  if (!$variables['status']) {
+    $variables['classes_array'][] = 'node-unpublished';
+  }
+  if ($variables['teaser']) {
+    $variables['classes_array'][] = 'node-teaser';
+  }
+  if (isset($variables['preview'])) {
+    $variables['classes_array'][] = 'node-preview';
+  }
+
   // Clean up name so there are no underscores.
   $variables['template_files'][] = 'node-' . str_replace('_', '-', $node->type);
   $variables['template_files'][] = 'node-' . $node->nid;
Index: modules/node/node.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.tpl.php,v
retrieving revision 1.11
diff -u -p -r1.11 node.tpl.php
--- modules/node/node.tpl.php	28 Apr 2009 19:56:00 -0000	1.11
+++ modules/node/node.tpl.php	28 May 2009 01:35:48 -0000
@@ -20,6 +20,19 @@
  * - $terms: the themed list of taxonomy term links output from theme_links().
  * - $submitted: themed submission information output from
  *   theme_node_submitted().
+ * - $classes: String of classes that can be used to style contextually through
+ *   CSS. It can be manipulated through the variable $classes_array from
+ *   preprocess functions. The default values can be one or more of the following:
+ *   - node: The current template type, i.e., "theming hook".
+ *   - node-[type]: The current node type. For example, if the node is a
+ *     "Blog entry" it would result in "node-blog". Note that the machine
+ *     name will often be in a short form of the human readable label.
+ *   - node-teaser: Nodes in teaser form.
+ *   - node-preview: Nodes in preview mode.
+ *   The following are controlled through the node publishing options.
+ *   - node-promoted: Nodes promoted to the front page.
+ *   - node-sticky: Nodes ordered above other non-sticky nodes in teaser listings.
+ *   - node-unpublished: Unpublished nodes visible only to administrators.
  * TODO D7 : document $FIELD_NAME_rendered variables.
  *
  * Other variables:
@@ -28,6 +41,8 @@
  * - $comment_count: Number of comments attached to the node.
  * - $uid: User ID of the node author.
  * - $created: Time the node was published formatted in Unix timestamp.
+ * - $classes_array: Array of html class attribute values. It is flattened
+ *   into a string within the variable $classes.
  * - $zebra: Outputs either "even" or "odd". Useful for zebra striping in
  *   teaser listings.
  * - $id: Position of the node. Increments each time it's output.
@@ -49,7 +64,7 @@
  * @see template_preprocess_node()
  */
 ?>
-<div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?><?php if (!$status) { print ' node-unpublished'; } ?> clearfix">
+<div id="node-<?php print $node->nid; ?>" class="<?php print $classes ?> clearfix">
 
 <?php print $picture ?>
 
Index: modules/system/maintenance-page.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/maintenance-page.tpl.php,v
retrieving revision 1.6
diff -u -p -r1.6 maintenance-page.tpl.php
--- modules/system/maintenance-page.tpl.php	12 May 2009 13:43:44 -0000	1.6
+++ modules/system/maintenance-page.tpl.php	28 May 2009 01:35:48 -0000
@@ -23,7 +23,7 @@
   <?php print $scripts; ?>
   <script type="text/javascript"><?php /* Needed to avoid Flash of Unstyled Content in IE */ ?> </script>
 </head>
-<body class="<?php print $body_classes; ?>">
+<body class="<?php print $classes; ?>">
   <div id="page">
     <div id="header">
       <div id="logo-title">
Index: modules/system/page.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/page.tpl.php,v
retrieving revision 1.21
diff -u -p -r1.21 page.tpl.php
--- modules/system/page.tpl.php	19 May 2009 17:23:16 -0000	1.21
+++ modules/system/page.tpl.php	28 May 2009 01:35:48 -0000
@@ -13,6 +13,8 @@
  * - $css: An array of CSS files for the current page.
  * - $directory: The directory the template is located in, e.g. modules/system
  *   or themes/garland.
+ * - $classes_array: Array of html class attribute values. It is flattened
+ *   into a string within the variable $classes.
  * - $is_front: TRUE if the current page is the front page. Used to toggle the mission statement.
  * - $logged_in: TRUE if the user is registered and signed in.
  * - $is_admin: TRUE if the user has permission to access administration pages.
@@ -29,9 +31,26 @@
  * - $styles: Style tags necessary to import all CSS files for the page.
  * - $scripts: Script tags necessary to load the JavaScript files and settings
  *   for the page.
- * - $body_classes: A set of CSS classes for the BODY tag. This contains flags
- *   indicating the current layout (multiple columns, single column), the current
- *   path, whether the user is logged in, and so on.
+ * - $classes: String of classes that can be used to style contextually through
+ *   CSS. It should be placed within the <body> tag. When selecting through CSS
+ *   it's recommended that you use the body tag, e.g., "body.front". It can be
+ *   manipulated through the variable $classes_array from preprocess functions.
+ *   The default values can be one or more of the following:
+ *   - page: The current template type, i.e., "theming hook".
+ *   - front: Page is the home page.
+ *   - not-front: Page is not the home page.
+ *   - logged-in: The current viewer is logged in.
+ *   - not-logged-in: The current viewer is not logged in.
+ *   - page-[level 1 path]: The internal first level path. For example, viewing
+ *     example.com/user/2 would result in "page-user". Path aliases do not apply.
+ *   - node-type-[node type]: When viewing a single node, the type of that node.
+ *     For example, if the node is a "Blog entry" it would result in "node-type-blog".
+ *     Note that the machine name will often be in a short form of the human readable label.
+ *   The following only apply with the default 'left' and 'right' block regions:
+ *     - two-sidebars: When both sidebars have content.
+ *     - no-sidebars: When no sidebar content exists.
+ *     - one-sidebar and sidebar-left or sidebar-right: A combination of the two classes
+ *       when only one of the two sidebars have content.
  *
  * Site identity:
  * - $front_page: The URL of the front page. Use this instead of $base_path,
@@ -82,7 +101,7 @@
   <?php print $styles; ?>
   <?php print $scripts; ?>
 </head>
-<body class="<?php print $body_classes; ?>">
+<body class="<?php print $classes; ?>">
 
   <div id="page-wrapper"><div id="page">
 
Index: themes/garland/block.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/block.tpl.php,v
retrieving revision 1.5
diff -u -p -r1.5 block.tpl.php
--- themes/garland/block.tpl.php	18 Feb 2009 14:28:25 -0000	1.5
+++ themes/garland/block.tpl.php	28 May 2009 01:35:48 -0000
@@ -1,7 +1,7 @@
 <?php
 // $Id: block.tpl.php,v 1.5 2009/02/18 14:28:25 webchick Exp $
 ?>
-<div id="block-<?php print $block->module . '-' . $block->delta; ?>" class="clearfix block block-<?php print $block->module ?>">
+<div id="block-<?php print $block->module . '-' . $block->delta; ?>" class="<?php print $classes; ?> clearfix">
 
 <?php if (!empty($block->subject)): ?>
   <h2><?php print $block->subject ?></h2>
Index: themes/garland/comment.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/comment.tpl.php,v
retrieving revision 1.12
diff -u -p -r1.12 comment.tpl.php
--- themes/garland/comment.tpl.php	18 Feb 2009 14:28:25 -0000	1.12
+++ themes/garland/comment.tpl.php	28 May 2009 01:35:48 -0000
@@ -1,7 +1,7 @@
 <?php
 // $Id: comment.tpl.php,v 1.12 2009/02/18 14:28:25 webchick Exp $
 ?>
-<div class="comment<?php print ($comment->new) ? ' comment-new' : ''; print ' ' . $status; print ' ' . $zebra; ?>">
+<div class="<?php print $classes . ' ' . $zebra; ?>">
 
   <div class="clearfix">
   <?php if ($submitted): ?>
Index: themes/garland/maintenance-page.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/maintenance-page.tpl.php,v
retrieving revision 1.9
diff -u -p -r1.9 maintenance-page.tpl.php
--- themes/garland/maintenance-page.tpl.php	12 May 2009 13:43:46 -0000	1.9
+++ themes/garland/maintenance-page.tpl.php	28 May 2009 01:35:48 -0000
@@ -24,7 +24,7 @@
       <?php print garland_get_ie_styles(); ?>
     <![endif]-->
   </head>
-  <body class="<?php print $body_classes ?>">
+  <body class="<?php print $classes ?>">
 
 <!-- Layout -->
   <div id="header-region" class="clearfix"><?php print $header; ?></div>
Index: themes/garland/node.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/node.tpl.php,v
retrieving revision 1.9
diff -u -p -r1.9 node.tpl.php
--- themes/garland/node.tpl.php	18 Feb 2009 14:28:25 -0000	1.9
+++ themes/garland/node.tpl.php	28 May 2009 01:35:48 -0000
@@ -1,7 +1,7 @@
 <?php
 // $Id: node.tpl.php,v 1.9 2009/02/18 14:28:25 webchick Exp $
 ?>
-<div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?><?php if (!$status) { print ' node-unpublished'; } ?>">
+<div id="node-<?php print $node->nid; ?>" class="<?php print $classes ?>">
 
 <?php print $picture ?>
 
Index: themes/garland/page.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/page.tpl.php,v
retrieving revision 1.26
diff -u -p -r1.26 page.tpl.php
--- themes/garland/page.tpl.php	12 May 2009 13:43:46 -0000	1.26
+++ themes/garland/page.tpl.php	28 May 2009 01:35:48 -0000
@@ -13,7 +13,7 @@
       <?php print $ie_styles ?>
     <![endif]-->
   </head>
-  <body class="<?php print $body_classes ?>">
+  <body class="<?php print $classes ?>">
 
   <div id="header-region" class="clearfix"><?php print $header ?></div>
 
Index: themes/garland/style.css
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/style.css,v
retrieving revision 1.55
diff -u -p -r1.55 style.css
--- themes/garland/style.css	12 May 2009 08:31:17 -0000	1.55
+++ themes/garland/style.css	28 May 2009 01:35:48 -0000
@@ -690,14 +690,14 @@ ul.links li, ul.inline li {
   float: right; /* LTR */
 }
 
-.preview .node, .preview .comment, .sticky {
+.preview .node, .preview .comment, .node-sticky {
   margin: 0;
   padding: 0.5em 0;
   border: 0;
   background: 0;
 }
 
-.sticky {
+.node-sticky {
   padding: 1em;
   background-color: #fff;
   border: 1px solid #e0e5fb;
