? DrupalHead.kpf ? files ? node_page_default_1.patch ? node_url.patch ? page_context.patch ? reg2.patch ? registry.patch ? registry_0.patch ? test.php ? theme_reg.patch ? themefuncs.txt ? includes/query.inc ? includes/theme.base.inc ? sites/logrus.com ? sites/all/modules Index: CHANGELOG.txt =================================================================== RCS file: /cvs/drupal/drupal/CHANGELOG.txt,v retrieving revision 1.183 diff -u -p -r1.183 CHANGELOG.txt --- CHANGELOG.txt 28 Mar 2007 14:08:21 -0000 1.183 +++ CHANGELOG.txt 4 Apr 2007 18:21:15 -0000 @@ -2,6 +2,10 @@ Drupal 6.0, xxxx-xx-xx (development version) ---------------------- +- Added the theme registry: + * Modules must implement hook_themes() to register their theme hooks + * Modules can directly provide .tpl.php files for their themes + * PHPTemplate renderer moved into core. - Added versioning support to node terms. - Made it easier to theme the forum overview page. - Drupal works with error reporting set to E_ALL. Index: index.php =================================================================== RCS file: /cvs/drupal/drupal/index.php,v retrieving revision 1.92 diff -u -p -r1.92 index.php --- index.php 11 Feb 2007 09:30:50 -0000 1.92 +++ index.php 4 Apr 2007 18:21:15 -0000 @@ -31,7 +31,6 @@ if (is_int($return)) { elseif (isset($return)) { // Print any value (including an empty string) except NULL or undefined: print theme('page', $return); - } drupal_page_footer(); Index: includes/bootstrap.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v retrieving revision 1.151 diff -u -p -r1.151 bootstrap.inc --- includes/bootstrap.inc 28 Mar 2007 14:08:21 -0000 1.151 +++ includes/bootstrap.inc 4 Apr 2007 18:21:16 -0000 @@ -922,6 +922,15 @@ function drupal_maintenance_theme() { drupal_add_css(drupal_get_path('module', 'system') .'/defaults.css', 'module'); drupal_add_css(drupal_get_path('module', 'system') .'/system.css', 'module'); $theme = ''; + + // Special case registry of theme functions used by the installer + $themes = drupal_common_themes(); + foreach ($themes as $hook => $info) { + if (!isset($info['file']) && !isset($info['function'])) { + $themes[$hook]['function'] = 'theme_' . $hook; + } + } + _theme_set_registry($themes); } /** Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.625 diff -u -p -r1.625 common.inc --- includes/common.inc 29 Mar 2007 23:17:15 -0000 1.625 +++ includes/common.inc 4 Apr 2007 18:21:19 -0000 @@ -2311,3 +2311,193 @@ function int2vancode($i = 0) { $length = strlen($num); return chr($length + ord('0') - 1) . $num; } + +/** + * Provide theme registration for themes across .inc files. + */ +function drupal_common_themes() { + return array( + // theme.inc + 'placeholder' => array( + 'arguments' => array('text' => NULL) + ), + 'page' => array( + 'arguments' => array('content' => NULL, 'show_blocks' => TRUE), + ), + 'maintenance_page' => array( + 'arguments' => array('content' => NULL, 'messages' => TRUE), + ), + 'install_page' => array( + 'arguments' => array('content' => NULL), + ), + 'task_list' => array( + 'arguments' => array('items' => NULL, 'active' => NULL), + ), + 'status_messages' => array( + 'arguments' => array('display' => NULL), + ), + 'links' => array( + 'arguments' => array('links' => NULL, 'attributes' => array('class' => 'links')), + ), + 'image' => array( + 'arguments' => array('path' => NULL, 'alt' => '', 'title' => '', 'attributes' => NULL, 'getsize' => TRUE), + ), + 'breadcrumb' => array( + 'arguments' => array('breadcrumb' => NULL), + ), + 'help' => array( + 'arguments' => array(), + ), + 'node' => array( + 'arguments' => array('node' => NULL, 'teaser' => FALSE, 'page' => FALSE), + ), + 'submenu' => array( + 'arguments' => array('links' => NULL), + ), + 'table' => array( + 'arguments' => array('header' => NULL, 'rows' => NULL, 'attributes' => array(), 'caption' => NULL), + ), + 'table_select_header_cell' => array( + 'arguments' => array(), + ), + 'tablesort_indicator' => array( + 'arguments' => array('style' => NULL), + ), + 'box' => array( + 'arguments' => array('title' => NULL, 'content' => NULL, 'region' => 'main'), + ), + 'block' => array( + 'arguments' => array('block' => NULL), + ), + 'mark' => array( + 'arguments' => array('type' => MARK_NEW), + ), + 'item_list' => array( + 'arguments' => array('items' => array(), 'title' => NULL, 'type' => 'ul', 'attributes' => NULL), + ), + 'more_help_link' => array( + 'arguments' => array('url' => NULL), + ), + 'xml_icon' => array( + 'arguments' => array('url' => NULL), + ), + 'feed_icon' => array( + 'arguments' => array('url' => NULL), + ), + 'closure' => array( + 'arguments' => array('main' => 0), + ), + 'blocks' => array( + 'arguments' => array('region' => NULL), + ), + 'username' => array( + 'arguments' => array('object' => NULL), + ), + 'progress_bar' => array( + 'arguments' => array('percent' => NULL, 'message' => NULL), + ), + // from pager.inc + 'pager' => array( + 'arguments' => array('tags' => array(), 'limit' => 10, 'element' => 0, 'parameters' => array()), + ), + 'pager_first' => array( + 'arguments' => array('text' => NULL, 'limit' => NULL, 'element' => 0, 'parameters' => array()), + ), + 'pager_previous' => array( + 'arguments' => array('text' => NULL, 'limit' => NULL, 'element' => 0, 'interval' => 1, 'parameters' => array()), + ), + 'pager_next' => array( + 'arguments' => array('text' => NULL, 'limit' => NULL, 'element' => 0, 'interval' => 1, 'parameters' => array()), + ), + 'pager_last' => array( + 'arguments' => array('text' => NULL, 'limit' => NULL, 'element' => 0, 'parameters' => array()), + ), + 'pager_list' => array( + 'arguments' => array('limit' => NULL, 'element' => 0, 'quantity' => 5, 'text' => '', 'parameters' => array()), + ), + 'pager_link' => array( + 'arguments' => array('text' => NULL, 'page_new' => NULL, 'element' => NULL, 'parameters' => array(), 'attributes' => array()), + ), + // from locale.inc + 'locale_admin_manage_screen' => array( + 'arguments' => array('form' => NULL), + ), + // from menu.inc + 'menu_item_link' => array( + 'arguments' => array('item' => NULL), + ), + 'menu_tree' => array( + 'arguments' => array('tree' => NULL), + ), + 'menu_item' => array( + 'arguments' => array('link' => NULL, 'has_children' => NULL, 'menu' => ''), + ), + 'menu_local_task' => array( + 'arguments' => array('link' => NULL, 'active' => FALSE), + ), + 'menu_local_tasks' => array( + 'arguments' => array(), + ), + // from form.inc + 'select' => array( + 'arguments' => array('element' => NULL), + ), + 'fieldset' => array( + 'arguments' => array('element' => NULL), + ), + 'radio' => array( + 'arguments' => array('element' => NULL), + ), + 'radios' => array( + 'arguments' => array('element' => NULL), + ), + 'password_confirm' => array( + 'arguments' => array('element' => NULL), + ), + 'date' => array( + 'arguments' => array('element' => NULL), + ), + 'item' => array( + 'arguments' => array('element' => NULL), + ), + 'checkbox' => array( + 'arguments' => array('element' => NULL), + ), + 'checkboxes' => array( + 'arguments' => array('element' => NULL), + ), + 'submit' => array( + 'arguments' => array('element' => NULL), + ), + 'button' => array( + 'arguments' => array('element' => NULL), + ), + 'hidden' => array( + 'arguments' => array('element' => NULL), + ), + 'token' => array( + 'arguments' => array('element' => NULL), + ), + 'textfield' => array( + 'arguments' => array('element' => NULL), + ), + 'form' => array( + 'arguments' => array('element' => NULL), + ), + 'textarea' => array( + 'arguments' => array('element' => NULL), + ), + 'markup' => array( + 'arguments' => array('element' => NULL), + ), + 'password' => array( + 'arguments' => array('element' => NULL), + ), + 'file' => array( + 'arguments' => array('element' => NULL), + ), + 'form_element' => array( + 'arguments' => array('element' => NULL, 'value' => NULL), + ), + ); +} Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.185 diff -u -p -r1.185 form.inc --- includes/form.inc 27 Mar 2007 05:13:53 -0000 1.185 +++ includes/form.inc 4 Apr 2007 18:21:20 -0000 @@ -457,7 +457,9 @@ function drupal_render_form($form_id, &$ // Don't override #theme if someone already set it. if (!isset($form['#theme'])) { - if (theme_get_function($form_id)) { + init_theme(); + $registry = theme_get_registry(); + if (isset($registry[$form_id])) { $form['#theme'] = $form_id; } } Index: includes/theme.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/theme.inc,v retrieving revision 1.344 diff -u -p -r1.344 theme.inc --- includes/theme.inc 27 Mar 2007 05:13:53 -0000 1.344 +++ includes/theme.inc 4 Apr 2007 18:21:21 -0000 @@ -72,6 +72,7 @@ function init_theme() { if (strpos($themes[$theme]->filename, '.theme')) { // file is a theme; include it include_once './' . $themes[$theme]->filename; + _theme_load_registry($theme); } elseif (strpos($themes[$theme]->description, '.engine')) { // file is a template; include its engine @@ -80,10 +81,116 @@ function init_theme() { if (function_exists($theme_engine .'_init')) { call_user_func($theme_engine .'_init', $themes[$theme]); } + _theme_load_registry($theme, $theme_engine); } } /** + * Retrieve the stored theme registry. If the theme registry is already + * in memory it will be returned; otherwise it will attempt to load the + * registry from cache. If this fails, it will construct the registry and + * cache it. + */ +function theme_get_registry($registry = NULL) { + static $theme_registry = NULL; + if (isset($registry)) { + $theme_registry = $registry; + } + + return $theme_registry; +} + +/** + * Store the theme registry in memory. + */ +function _theme_set_registry($registry) { + // Pass through for setting of static variable. + return theme_get_registry($registry); +} + +/** + * Get the theme_registry cache from the database; if it doesn't exist, build + * it. + */ +function _theme_load_registry($theme, $theme_engine = NULL) { + $cache = cache_get("theme_registry:$theme", 'cache'); + if (isset($cache->data)) { + $registry = unserialize($cache->data); + } + else { + $registry = _theme_build_registry($theme, $theme_engine); + _theme_save_registry($theme, $registry); + } + _theme_set_registry($registry); +} + +/** + * Write the theme_registry cache into the database. + */ +function _theme_save_registry($theme, $registry) { + cache_set("theme_registry:$theme", 'cache', serialize($registry)); +} + +/** + * Force the system to rebuild the theme registry; this should be called + * when modules are added to the system, or when a dynamic system needs + * to add more theme hooks. + */ +function drupal_rebuild_theme_registry() { + cache_clear_all('theme_registry', 'cache', TRUE); +} + +/** + * Process a single invocation of the theme hook. + */ +function _theme_process_registry(&$cache, $name, $type) { + $function = $name .'_theme'; + if (function_exists($function)) { + $result = $function($cache); + + // Automatically find paths + $path = drupal_get_path($type, $name); + foreach ($result as $hook => $info) { + $result[$hook]['type'] = $type; + // if function and file are left out, default to standard naming + // conventions. + if (!isset($info['file']) && !isset($info['function'])) { + $result[$hook]['function'] = ($type == 'module' ? 'theme_' : $name .'_') . $hook; + } + if (isset($info['file']) && !isset($info['path'])) { + $result[$hook]['file'] = $path .'/'. $info['file']; + } + // 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']; + } + } + + $cache = array_merge($cache, $result); + } +} + +/** + * Rebuild the hook theme_registry cache. + */ +function _theme_build_registry($theme, $theme_engine) { + $cache = array(); + foreach (module_implements('theme') as $module) { + _theme_process_registry($cache, $module, 'module'); + } + + if ($theme_engine) { + _theme_process_registry($cache, $theme_engine, 'theme_engine'); + } + + _theme_process_registry($cache, $theme, 'theme'); + + return $cache; +} + +/** * Provides a list of currently available themes. * * @param $refresh @@ -140,18 +247,48 @@ function list_theme_engines($refresh = F } /** - * Generate the themed representation of a Drupal object. - * - * All requests for themed functions must go through this function. It examines - * the request and routes it to the appropriate theme function. If the current - * theme does not implement the requested function, then the current theme - * engine is checked. If neither the engine nor theme implement the requested - * function, then the base theme function is called. - * - * For example, to retrieve the HTML that is output by theme_page($output), a - * module should call theme('page', $output). + * Generate the themed output. * - * @param $function + * 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 function, it is executed and its return value + * passed along. + * + * If the implementation is a template, the arguments are converted to a + * $variables array. This array is then modified by the theme engine (if + * applicable) and the theme. The following functions may be used to modify + * the $variables array: + * + * ENGINE_engine_variables(&$variables) + * This function should only be implemented by theme engines and is exists + * so that the theme engine can set necessary variables. It is commonly + * used to set global variables such as $directory and $is_front_page. + * ENGINE_engine_variables_HOOK(&$variables) + * This is the same as the previous function, but is called only per hook. + * ENGINE_variables_HOOK(&$variables) + * ENGINE_variables(&$variables) + * This is meant to be used by themes that utilize a theme engine; as it is + * good practice for these themes to use the theme engine's name for + * their functions so that they may share code. In PHPTemplate, these + * functions will appear in template.php + * THEME_variables_HOOK(&$variables) + * THEME_variables(&$variables) + * These functions are based upon the raw theme; they should primarily be + * used by themes that do not use an engine or by themes that need small + * changes to what has already been established in the theme engine version + * of the function. + * + * 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 + * 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. + * @param $hook * The name of the theme function to call. * @param ... * Additional arguments to pass along to the theme function. @@ -159,48 +296,125 @@ function list_theme_engines($refresh = F * An HTML string that generates the themed output. */ function theme() { - static $functions; $args = func_get_args(); - $function = array_shift($args); + $hook = array_shift($args); - if (!isset($functions[$function])) { - $functions[$function] = theme_get_function($function); + static $hooks = NULL; + if (!isset($hooks)) { + init_theme(); + $hooks = theme_get_registry(); + } + + if (!isset($hooks[$hook])) { + return; } - if ($functions[$function]) { - return call_user_func_array($functions[$function], $args); + + $info = $hooks[$hook]; + + if (isset($info['function'])) { + // The theme call is a function. + // Include a file if this theme function is held elsewhere. + if (!empty($info['file'])) { + include_once($info['file']); + } + return call_user_func_array($info['function'], $args); + } + else { + // The theme call is a template. + $variables = array( + 'template_files' => array() + ); + if (!empty($info['arguments'])) { + $count = 0; + foreach ($info['arguments'] as $name => $default) { + $variables[$name] = isset($args[$count]) ? $args[$count] : $default; + $count++; + } + } + + // default render function and extension. + $render_function = 'theme_render_template'; + $extension = '.tpl.php'; + $variables_list = array(); + + // Run through the theme engine variables, if necessary + global $theme_engine; + if (isset($theme_engine)) { + // Call each of our variable override functions. We allow + // several to create cleaner code. + $variables_list[] = $theme_engine .'_engine_variables'; + $variables_list[] = $theme_engine .'_engine_variables_'. $hook; + $variables_list[] = $theme_engine .'_variables'; + $variables_list[] = $theme_engine .'_variables_'. $hook; + + // If theme or theme engine is implementing this, it may have + // a different extension and a different renderer. + if ($hooks[$hook]['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(); + } + } + } + + // Add theme specific variable substitution: + global $theme; + $variables_list[] = $theme .'_variables'; + $variables_list[] = $theme .'_variables_'. $hook; + + // This construct ensures that we can keep a reference through + // call_user_func_array. + $args = array(&$variables, $hook); + foreach ($variables_list as $variables_function) { + if (function_exists($variables_function)) { + call_user_func_array($variables_function, $args); + } + } + + // Get suggestions for alternate templates out of the variables + // that were set. This lets us dynamically choose a template + // from a list. The order is FILO, so this array is ordered from + // least appropriate first to most appropriate last. + $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($suggestions, $extension); + } + + if (empty($template_file)) { + $template_file = $hooks[$hook]['file'] . $extension; + if (isset($hooks[$hook]['path'])) { + $template_file = $hooks[$hook]['path'] .'/'. $template_file; + } + } + return $render_function($template_file, $variables); } } /** - * Determine if a theme function exists, and if so return which one was found. - * - * @param $function - * The name of the theme function to test. - * @return - * The name of the theme function that should be used, or FALSE if no function exists. + * Choose which template file to actually render; these are all + * suggested templates from the theme. */ -function theme_get_function($function) { - global $theme, $theme_engine; - - // Because theme() is called a lot, calling init_theme() only to have it - // smartly return is a noticeable performance hit. Don't do it. - if (!isset($theme)) { - init_theme(); - } +function drupal_discover_template($suggestions, $extension = '.tpl.php') { + global $theme_engine; - if (($theme != '') && function_exists($theme .'_'. $function)) { - // call theme function - return $theme .'_'. $function; - } - elseif (($theme != '') && isset($theme_engine) && function_exists($theme_engine .'_'. $function)) { - // call engine function - return $theme_engine .'_'. $function; - } - elseif (function_exists('theme_'. $function)){ - // call Drupal function - return 'theme_'. $function; + // Loop through any suggestions in FIFO order. + $suggestions = array_reverse($suggestions); + foreach ($suggestions as $suggestion) { + if (!empty($suggestion) && file_exists($file = path_to_theme() .'/'. $suggestion . $extension)) { + return $file; + } } - return FALSE; } /** @@ -348,16 +562,81 @@ function theme_get_setting($setting_name } /** - * @defgroup themeable Themeable functions + * Render a system default template, which is essentially a PHP template. + * + * @param $file + * The filename of the template to render. + * @param $variables + * A keyed array of variables that will appear in the output. + * + * @return + * The output generated by the template. + */ +function theme_render_template($file, $variables) { + extract($variables, EXTR_SKIP); // Extract the variables to a local namespace + ob_start(); // Start output buffering + include "./$file"; // Include the file + $contents = ob_get_contents(); // Get the contents of the buffer + ob_end_clean(); // End buffering and discard + return $contents; // Return the contents +} + +/** + * @defgroup themeable Default theme implementations * @{ - * Functions that display HTML, and which can be customized by themes. + * Functions and templates that present output to the user, and can be + * implemented by themes. * - * All functions that produce HTML for display should be themeable. This means - * that they should be named with the theme_ prefix, and invoked using theme() - * rather than being called directly. This allows themes to override the display - * of any Drupal object. + * Drupal's presentation layer is a pluggable system known as the theme + * layer. Each theme can take control over most of Drupal's output, and + * has complete control over the CSS. + * + * Inside Drupal, the theme layer is utilized by the use of the theme() + * function, which is passed the name of a component (the theme hook) + * and several arguments. For example, theme('table', $header, $rows); + * + * As of Drupal 6, every theme hook is required to be registered by the + * module that owns it, so that Drupal can tell what to do with it and + * to make it simple for themes to identify and override the behavior + * for these calls. + * + * The theme hooks are registered via hook_theme(), which returns an + * array of arrays with information about the hook. It describes the + * arguments the function or template will need, and provides + * defaults for the template in case they are not filled in. If the default + * implementation is a function, by convention it is named theme_HOOK(). + * + * Each module should provide a default implementation for themes that + * it registers. This implementation may be either a function or a template; + * if it is a function it must be specified via hook_theme(). By convention, + * default implementations of theme hooks are named theme_HOOK. Default + * template implementations are stored in the module directory. + * + * Drupal's default template renderer is a simple PHP parsing engine that + * includes the template and stores the output. Drupal's theme engines + * can provide alternate template engines, such as XTemplate, Smarty and + * PHPTal. The most common template engine is PHPTemplate (included with + * Drupal and implemented in phptemplate.engine, which uses Drupal's default + * template renderer. + * + * In order to create theme-specific implementations of these hooks, + * themes can implement their own version of theme hooks, either as functions + * or templates. These implementations will be used instead of the default + * implementation. If using a pure .theme without an engine, the .theme is + * required to implement its own version of hook_theme() to tell Drupal what + * it is implementing; themes utilizing an engine will have their well-named + * theming functions automatically registered for them. While this can vary + * based upon the theme engine, the standard set by phptemplate is that theme + * functions should be named either phptemplate_HOOK or THEMENAME_HOOK. For + * example, for Drupal's default theme (Garland) to implement the 'table' hook, + * the phptemplate.engine would find phptemplate_table() or garland_table(). + * The ENGINE_HOOK() syntax is preferred, as this can be used by sub-themes + * (which are themes that share code but use different stylesheets). * * The theme system is described and defined in theme.inc. + * + * @see theme() + * @see hook_theme() */ /** @@ -458,9 +737,7 @@ function theme_maintenance_page($content 'content' => $content, ); - // Render simplified PHPTemplate. - include_once './themes/engines/phptemplate/phptemplate.engine'; - $output = _phptemplate_render('misc/maintenance.tpl.php', $variables); + $output = theme_render_template('misc/maintenance.tpl.php', $variables); return $output; } @@ -509,9 +786,7 @@ function theme_install_page($content) { $variables['messages'] .= theme('status_messages', 'status'); } - // Render simplified PHPTemplate. - include_once './themes/engines/phptemplate/phptemplate.engine'; - return _phptemplate_render('misc/maintenance.tpl.php', $variables); + return theme_render_template('misc/maintenance.tpl.php', $variables); } /** Index: modules/aggregator/aggregator.module =================================================================== RCS file: /cvs/drupal/drupal/modules/aggregator/aggregator.module,v retrieving revision 1.333 diff -u -p -r1.333 aggregator.module --- modules/aggregator/aggregator.module 27 Mar 2007 05:13:53 -0000 1.333 +++ modules/aggregator/aggregator.module 4 Apr 2007 18:21:23 -0000 @@ -26,6 +26,29 @@ function aggregator_help($section) { } /** + * Implementation of hook_theme() + */ +function aggregator_theme() { + return array( + 'aggregator_page_list' => array( + 'arguments' => array('form' => NULL), + ), + 'aggregator_feed' => array( + 'arguments' => array('feed' => NULL), + ), + 'aggregator_block_item' => array( + 'arguments' => array('item' => NULL, 'feed' => 0), + ), + 'aggregator_summary_item' => array( + 'arguments' => array('item' => NULL), + ), + 'aggregator_page_item' => array( + 'arguments' => array('item' => NULL), + ), + + ); + +/** * Implementation of hook_menu(). */ function aggregator_menu() { Index: modules/block/block.module =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.module,v retrieving revision 1.254 diff -u -p -r1.254 block.module --- modules/block/block.module 27 Mar 2007 05:13:53 -0000 1.254 +++ modules/block/block.module 4 Apr 2007 18:21:24 -0000 @@ -49,6 +49,17 @@ function block_help($section) { } /** + * Implementation of hook_theme() + */ +function block_theme() { + return array( + 'block_admin_display' => array( + 'arguments' => array('form' => NULL), + ), + ); +} + +/** * Implementation of hook_perm(). */ function block_perm() { Index: modules/book/book.module =================================================================== RCS file: /cvs/drupal/drupal/modules/book/book.module,v retrieving revision 1.414 diff -u -p -r1.414 book.module --- modules/book/book.module 27 Mar 2007 05:13:53 -0000 1.414 +++ modules/book/book.module 4 Apr 2007 18:21:25 -0000 @@ -20,6 +20,23 @@ function book_node_info() { } /** + * Implementation of hook_theme() + */ +function book_theme() { + return array( + 'book_navigation' => array( + 'arguments' => array('node' => NULL), + ), + 'book_export_html' => array( + 'arguments' => array('title' => NULL, 'content' => NULL), + ), + 'book_admin_table' => array( + 'arguments' => array('form' => NULL), + ), + ); +} + +/** * Implementation of hook_perm(). */ function book_perm() { Index: modules/color/color.module =================================================================== RCS file: /cvs/drupal/drupal/modules/color/color.module,v retrieving revision 1.17 diff -u -p -r1.17 color.module --- modules/color/color.module 27 Mar 2007 05:13:53 -0000 1.17 +++ modules/color/color.module 4 Apr 2007 18:21:25 -0000 @@ -2,6 +2,16 @@ // $Id: color.module,v 1.17 2007/03/27 05:13:53 unconed Exp $ /** + * Implementation of hook_theme() + */ +function color_theme() { + return array( + 'color_scheme_form' => array( + 'arguments' => array('form' => NULL), + ), + ); +} +/** * Implementation of hook_form_alter(). */ function color_form_alter(&$form, $form_id) { Index: modules/comment/comment.module =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v retrieving revision 1.534 diff -u -p -r1.534 comment.module --- modules/comment/comment.module 1 Apr 2007 05:04:19 -0000 1.534 +++ modules/comment/comment.module 4 Apr 2007 18:21:27 -0000 @@ -140,6 +140,53 @@ function comment_help($section) { } } +/** + * Implementation of hook_theme() + */ +function comment_theme() { + return array( + 'comment_block' => array( + 'arguments' => array(), + ), + 'comment_admin_overview' => array( + 'arguments' => array('form' => NULL), + ), + 'comment_preview' => array( + 'arguments' => array('comment' => NULL, 'links' => array(), 'visible' => 1), + ), + 'comment_view' => array( + 'arguments' => array('comment' => NULL, 'links' => array(), 'visible' => 1), + ), + 'comment_controls' => array( + 'arguments' => array('form' => NULL), + ), + 'comment' => array( + 'arguments' => array('comment' => NULL, 'links' => array()), + ), + 'comment_folded' => array( + 'arguments' => array('comment' => NULL), + ), + 'comment_flat_collapsed' => array( + 'arguments' => array('comment' => NULL), + ), + 'comment_flat_expanded' => array( + 'arguments' => array('comment' => NULL), + ), + 'comment_thread_collapsed' => array( + 'arguments' => array('comment' => NULL), + ), + 'comment_thread_expanded' => array( + 'arguments' => array('comment' => NULL), + ), + 'comment_post_forbidden' => array( + 'arguments' => array('nid' => NULL), + ), + 'comment_wrapper' => array( + 'arguments' => array('content' => NULL), + ), + ); +} + function _comment_view_access($node, $cid) { return $node && $cid; } Index: modules/drupal/drupal.module =================================================================== RCS file: /cvs/drupal/drupal/modules/drupal/drupal.module,v retrieving revision 1.140 diff -u -p -r1.140 drupal.module --- modules/drupal/drupal.module 27 Feb 2007 12:29:22 -0000 1.140 +++ modules/drupal/drupal.module 4 Apr 2007 18:21:28 -0000 @@ -46,6 +46,17 @@ print drupal_client_page(); } } +/** + * Implementation of hook_theme() + */ +function drupal_theme() { + return array( + 'client_list' => array( + 'arguments' => array('clients' => NULL), + ), + ); +} + function drupal_sites_registry_settings() { // Check if all required fields are present if ((variable_get('site_name', 'Drupal') == 'Drupal') || (variable_get('site_name', 'Drupal') == '')) { Index: modules/filter/filter.module =================================================================== RCS file: /cvs/drupal/drupal/modules/filter/filter.module,v retrieving revision 1.166 diff -u -p -r1.166 filter.module --- modules/filter/filter.module 12 Mar 2007 11:31:02 -0000 1.166 +++ modules/filter/filter.module 4 Apr 2007 18:21:30 -0000 @@ -48,6 +48,26 @@ function filter_help($section) { } /** + * Implementation of hook_theme() + */ +function filter_theme() { + return array( + 'filter_admin_overview' => array( + 'arguments' => array('form' => NULL), + ), + 'filter_admin_order' => array( + 'arguments' => array('form' => NULL), + ), + 'filter_tips' => array( + 'arguments' => array('tips' => NULL, 'long' => FALSE, 'extra' => ''), + ), + 'filter_tips_more_info' => array( + 'arguments' => array(), + ), + ); +} + +/** * Implementation of hook_menu(). */ function filter_menu() { Index: modules/forum/forum.module =================================================================== RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v retrieving revision 1.390 diff -u -p -r1.390 forum.module --- modules/forum/forum.module 28 Mar 2007 14:08:22 -0000 1.390 +++ modules/forum/forum.module 4 Apr 2007 18:21:31 -0000 @@ -29,6 +29,29 @@ function forum_help($section) { } /** + * Implementation of hook_theme() + */ +function forum_theme() { + return array( + 'forum_display' => array( + 'arguments' => array('forums' => NULL, 'topics' => NULL, 'parents' => NULL, 'tid' => NULL, 'sortby' => NULL, 'forum_per_page' => NULL), + ), + 'forum_list' => array( + 'arguments' => array('forums' => NULL, 'parents' => NULL, 'tid' => NULL), + ), + 'forum_topic_list' => array( + 'arguments' => array('tid' => NULL, 'topics' => NULL, 'sortby' => NULL, 'forum_per_page' => NULL), + ), + 'forum_icon' => array( + 'arguments' => array('new_posts' => NULL, 'num_posts' => 0, 'comment_mode' => 0, 'sticky' => 0), + ), + 'forum_topic_navigation' => array( + 'arguments' => array('node' => NULL), + ), + ); +} + +/** * Implementation of hook_menu(). */ function forum_menu() { Index: modules/node/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.module,v retrieving revision 1.795 diff -u -p -r1.795 node.module --- modules/node/node.module 2 Apr 2007 15:15:39 -0000 1.795 +++ modules/node/node.module 4 Apr 2007 18:21:34 -0000 @@ -46,6 +46,38 @@ function node_help($section) { } /** + * Implementation of hook_theme() + */ +function node_theme() { + return array( + 'node_list' => array( + 'arguments' => array('items' => NULL, 'title' => NULL), + ), + 'node_search_admin' => array( + 'arguments' => array('form' => NULL), + ), + 'node_filter_form' => array( + 'arguments' => array('form' => NULL), + ), + 'node_filters' => array( + 'arguments' => array('form' => NULL), + ), + 'node_admin_nodes' => array( + 'arguments' => array('form' => NULL), + ), + 'node_form' => array( + 'arguments' => array('form' => NULL), + ), + 'node_preview' => array( + 'arguments' => array('node' => NULL), + ), + 'node_log_message' => array( + 'arguments' => array('log' => NULL), + ), + ); +} + +/** * Implementation of hook_cron(). */ function node_cron() { @@ -2349,7 +2381,6 @@ function node_revisions() { * Menu callback; Generate a listing of promoted nodes. */ function node_page_default() { - $result = pager_query(db_rewrite_sql('SELECT n.nid, n.sticky, n.created FROM {node} n WHERE n.promote = 1 AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC'), variable_get('default_nodes_main', 10)); if (db_num_rows($result)) { Index: modules/poll/poll.module =================================================================== RCS file: /cvs/drupal/drupal/modules/poll/poll.module,v retrieving revision 1.225 diff -u -p -r1.225 poll.module --- modules/poll/poll.module 27 Mar 2007 05:13:54 -0000 1.225 +++ modules/poll/poll.module 4 Apr 2007 18:21:34 -0000 @@ -21,6 +21,23 @@ function poll_help($section) { } /** + * Implementation of hook_theme() + */ +function poll_theme() { + return array( + 'poll_view_voting' => array( + 'arguments' => array('form' => NULL), + ), + 'poll_results' => array( + 'arguments' => array('title' => NULL, 'results' => NULL, 'votes' => NULL, 'links' => NULL, 'block' => NULL, 'nid' => NULL, 'vote' => NULL), + ), + 'poll_bar' => array( + 'arguments' => array('title' => NULL, 'percentage' => NULL, 'votes' => NULL, 'block' => NULL), + ), + ); +} + +/** * Implementation of hook_access(). */ function poll_access($op, $node) { Index: modules/profile/profile.module =================================================================== RCS file: /cvs/drupal/drupal/modules/profile/profile.module,v retrieving revision 1.196 diff -u -p -r1.196 profile.module --- modules/profile/profile.module 30 Mar 2007 09:38:13 -0000 1.196 +++ modules/profile/profile.module 4 Apr 2007 18:21:35 -0000 @@ -52,6 +52,19 @@ function profile_help($section) { } /** + * Implementation of hook_theme() + */ +function profile_theme() { + return array( + 'profile_block' => array( + 'arguments' => array('account' => NULL, 'fields' => array()), + ), + 'profile_listing' => array( + 'arguments' => array('account' => NULL, 'fields' => array()), + ), ); +} + +/** * Implementation of hook_menu(). */ function profile_menu() { Index: modules/search/search.module =================================================================== RCS file: /cvs/drupal/drupal/modules/search/search.module,v retrieving revision 1.216 diff -u -p -r1.216 search.module --- modules/search/search.module 27 Mar 2007 05:13:54 -0000 1.216 +++ modules/search/search.module 4 Apr 2007 18:21:37 -0000 @@ -112,6 +112,26 @@ function search_help($section) { } /** + * Implementation of hook_theme() + */ +function search_theme() { + return array( + 'search_theme_form' => array( + 'arguments' => array('form' => NULL), + ), + 'search_block_form' => array( + 'arguments' => array('form' => NULL), + ), + 'search_item' => array( + 'arguments' => array('item' => NULL, 'type' => NULL), + ), + 'search_page' => array( + 'arguments' => array('results' => NULL, 'type' => NULL), + ), + ); +} + +/** * Implementation of hook_perm(). */ function search_perm() { Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.460 diff -u -p -r1.460 system.module --- modules/system/system.module 27 Mar 2007 05:13:54 -0000 1.460 +++ modules/system/system.module 4 Apr 2007 18:21:40 -0000 @@ -48,6 +48,37 @@ function system_help($section) { } } +function system_theme() { + return array_merge(drupal_common_themes(), array( + 'system_theme_select_form' => array( + 'arguments' => array('form' => NULL), + ), + 'system_themes_form' => array( + 'arguments' => array('form' => NULL), + ), + 'system_modules' => array( + 'arguments' => array('form' => NULL), + ), + 'system_modules_uninstall' => array( + 'arguments' => array('form' => NULL), + ), + 'status_report' => array( + 'arguments' => array('requirements' => NULL), + ), + 'admin_page' => array( + 'arguments' => array('blocks' => NULL), + ), + 'admin_block' => array( + 'arguments' => array('block' => NULL), + ), + 'admin_block_content' => array( + 'arguments' => array('content' => NULL), + ), + 'system_admin_by_module' => array( + 'arguments' => array('menu_items' => NULL), + ), + )); +} /** * Implementation of hook_perm(). */ @@ -150,7 +181,7 @@ function system_menu() { 'title' => t('Themes'), 'description' => t('Change which theme your site uses or allows users to set.'), 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_themes'), + 'page arguments' => array('system_themes_form'), ); $items['admin/build/themes/select'] = array( 'title' => t('List'), @@ -1137,13 +1168,13 @@ function system_settings_form_submit($fo drupal_set_message(t('The configuration options have been saved.')); } - menu_rebuild(); + drupal_rebuild_theme_registry(); } /** * Menu callback; displays a listing of all themes. */ -function system_themes() { +function system_themes_form() { drupal_clear_css_cache(); $themes = system_theme_data(); @@ -1177,7 +1208,7 @@ function system_themes() { return $form; } -function theme_system_themes($form) { +function theme_system_themes_form($form) { foreach (element_children($form) as $key) { $row = array(); if (isset($form[$key]['description']) && is_array($form[$key]['description'])) { @@ -1199,7 +1230,7 @@ function theme_system_themes($form) { } -function system_themes_submit($form_id, $form_values) { +function system_themes_form_submit($form_id, $form_values) { db_query("UPDATE {system} SET status = 0 WHERE type = 'theme'"); @@ -1513,6 +1544,7 @@ function system_modules_submit($form_id, } if ($old_module_list != $current_module_list) { + drupal_rebuild_theme_registry(); menu_rebuild(); node_types_rebuild(); drupal_set_message(t('The configuration options have been saved.')); Index: modules/taxonomy/taxonomy.module =================================================================== RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v retrieving revision 1.344 diff -u -p -r1.344 taxonomy.module --- modules/taxonomy/taxonomy.module 27 Mar 2007 05:13:54 -0000 1.344 +++ modules/taxonomy/taxonomy.module 4 Apr 2007 18:21:41 -0000 @@ -14,6 +14,17 @@ function taxonomy_perm() { } /** + * Implementation of hook_theme() + */ +function taxonomy_theme() { + return array( + 'taxonomy_term_select' => array( + 'arguments' => array('element' => NULL), + ), + ); +} + +/** * Implementation of hook_link(). * * This hook is extended with $type = 'taxonomy terms' to allow themes to Index: modules/upload/upload.module =================================================================== RCS file: /cvs/drupal/drupal/modules/upload/upload.module,v retrieving revision 1.156 diff -u -p -r1.156 upload.module --- modules/upload/upload.module 27 Mar 2007 05:13:54 -0000 1.156 +++ modules/upload/upload.module 4 Apr 2007 18:21:43 -0000 @@ -23,6 +23,23 @@ function upload_help($section) { } /** + * Implementation of hook_theme() + */ +function upload_theme() { + return array( + 'upload_attachments' => array( + 'arguments' => array('files' => NULL), + ), + 'upload_form_current' => array( + 'arguments' => array('form' => NULL), + ), + 'upload_form_new' => array( + 'arguments' => array('form' => NULL), + ), + ); +} + +/** * Implementation of hook_perm(). */ function upload_perm() { Index: modules/user/user.module =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.module,v retrieving revision 1.763 diff -u -p -r1.763 user.module --- modules/user/user.module 30 Mar 2007 07:45:19 -0000 1.763 +++ modules/user/user.module 4 Apr 2007 18:21:45 -0000 @@ -24,6 +24,38 @@ function user_module_invoke($type, &$arr } } +/** + * Implementation of hook_theme() + */ +function user_theme() { + return array( + 'user_picture' => array( + 'arguments' => array('account' => NULL), + ), + 'user_profile' => array( + 'arguments' => array('account' => NULL, 'fields' => NULL), + ), + 'user_list' => array( + 'arguments' => array('users' => NULL, 'title' => NULL), + ), + 'user_admin_perm' => array( + 'arguments' => array('form' => NULL), + ), + 'user_admin_new_role' => array( + 'arguments' => array('form' => NULL), + ), + 'user_admin_account' => array( + 'arguments' => array('form' => NULL), + ), + 'user_filter_form' => array( + 'arguments' => array('form' => NULL), + ), + 'user_filters' => array( + 'arguments' => array('form' => NULL), + ), + ); +} + function user_external_load($authname) { $result = db_query("SELECT uid FROM {authmap} WHERE authname = '%s'", $authname); Index: modules/watchdog/watchdog.module =================================================================== RCS file: /cvs/drupal/drupal/modules/watchdog/watchdog.module,v retrieving revision 1.171 diff -u -p -r1.171 watchdog.module --- modules/watchdog/watchdog.module 27 Feb 2007 12:29:22 -0000 1.171 +++ modules/watchdog/watchdog.module 4 Apr 2007 18:21:45 -0000 @@ -28,6 +28,17 @@ function watchdog_help($section) { } /** + * Implementation of hook_theme() + */ +function watchdog_theme() { + return array( + 'watchdog_form_overview' => array( + 'arguments' => array('form' => NULL), + ), + ); +} + +/** * Implementation of hook_menu(). */ function watchdog_menu() { Index: themes/chameleon/chameleon.theme =================================================================== RCS file: /cvs/drupal/drupal/themes/chameleon/chameleon.theme,v retrieving revision 1.59 diff -u -p -r1.59 chameleon.theme --- themes/chameleon/chameleon.theme 1 Apr 2007 05:09:58 -0000 1.59 +++ themes/chameleon/chameleon.theme 4 Apr 2007 18:21:46 -0000 @@ -6,6 +6,23 @@ * A slim, CSS-driven theme which does not depend on a template engine like phptemplate */ +/** + * Implementation of hook_theme. Auto-discover theme functions. + */ +function chameleon_theme($existing) { + $templates = array(); + // Check for function overrides. + global $theme; + foreach ($existing as $hook => $info) { + if (function_exists($theme .'_'. $hook)) { + $templates[$hook] = array( + 'function' => $theme .'_'. $hook, + ); + } + } + return $templates; +} + function chameleon_features() { return array( 'toggle_logo', @@ -22,7 +39,7 @@ function chameleon_regions() { } function chameleon_page($content, $show_blocks = TRUE) { - $language = $GLOBALS['locale']; + $language = isset($GLOBALS['language']) ? $GLOBALS['language'] : NULL; if (theme_get_setting('toggle_favicon')) { drupal_set_html_head(''); Index: themes/engines/phptemplate/phptemplate.engine =================================================================== RCS file: /cvs/drupal/drupal/themes/engines/phptemplate/phptemplate.engine,v retrieving revision 1.61 diff -u -p -r1.61 phptemplate.engine --- themes/engines/phptemplate/phptemplate.engine 30 Mar 2007 07:45:19 -0000 1.61 +++ themes/engines/phptemplate/phptemplate.engine 4 Apr 2007 18:21:46 -0000 @@ -9,10 +9,74 @@ function phptemplate_init($template) { $file = dirname($template->filename) . '/template.php'; if (file_exists($file)) { - include_once "./$file"; + include_once "./$file"; } } +/** + * @return + * Array of template features + */ +function phptemplate_features() { + return array( + 'toggle_logo', + 'toggle_comment_user_picture', + 'toggle_favicon', + 'toggle_mission', + 'toggle_name', + 'toggle_node_user_picture', + 'toggle_search', + 'toggle_slogan' + ); +} + +/** + * Implementation of hook_themes to tell Drupal what templates the engine + * and the current theme use. The $existing argument will contain hooks + * pre-defined by Drupal so that we can use that information if + * we need to. + */ +function phptemplate_theme($existing) { + $templates = array( + 'regions' => array('function' => 'phptemplate_regions'), + 'box' => array('file' => 'box'), + 'node' => array('file' => 'node'), + 'comment' => array('file' => 'comment'), + 'block' => array('file' => 'block'), + ); + + // Check for template overrides. + $files = drupal_system_listing('\.tpl\.php$', path_to_theme(), 'name', 0); + + foreach ($files as $template => $file) { + // chop off the .tpl + $template = substr($template, 0, -4); + if (isset($existing[$template])) { + $templates[$template] = array( + 'file' => $template, + 'path' => dirname($file->filename), + ); + } + } + + // Check for function overrides. + global $theme; + foreach ($existing as $hook => $info) { + if (function_exists($theme .'_'. $hook)) { + $templates[$hook] = array( + 'function' => $theme .'_'. $hook, + ); + } + else if (function_exists('phptemplate_'. $hook)) { + $templates[$hook] = array( + 'function' => 'phptemplate_'. $hook, + ); + } + } + + return $templates; +} + function phptemplate_templates($directory = 'themes') { return drupal_system_listing('^page\.tpl\.php$', $directory, 'filename'); } @@ -34,55 +98,6 @@ function phptemplate_regions() { } /** - * Execute a template engine call. - * - * Each call to the template engine has two parts. Namely preparing - * the variables, and then doing something with them. - * - * The first step is done by all template engines / themes, the second - * step is dependent on the engine used. - * - * @param $hook - * The name of the theme function being executed. - * @param $variables - * A sequential array of variables passed to the theme function. - * @param $suggestions - * An array of suggested template files to use. If none of the files are found, the - * default $hook.tpl.php will be used. - * @return - * The HTML generated by the template system. - */ -function _phptemplate_callback($hook, $variables = array(), $suggestions = array()) { - global $theme_engine; - - $variables = array_merge($variables, _phptemplate_default_variables($hook, $variables)); - - // Allow specified variables to be overridden - $variables_function = '_'. $theme_engine .'_variables'; - if (function_exists($variables_function)) { - $variables = array_merge($variables, call_user_func($variables_function, $hook, $variables)); - } - - if (isset($variables['template_files'])) { - $suggestions = array_merge($suggestions, $variables['template_files']); - } - - if (isset($variables['template_file'])) { - $suggestions[] = $variables['template_file']; - } - - $hook_function = '_'. $theme_engine .'_'. $hook; - $default_function = '_'. $theme_engine .'_default'; - if (function_exists($hook_function)) { - return call_user_func($hook_function, $variables, $suggestions); - } - elseif (function_exists($default_function)) { - return call_user_func($default_function, $hook, $variables, $suggestions); - } - -} - -/** * Adds additional helper variables to all templates. * * Counts how many times certain hooks have been called. Sidebar left / right are special cases. @@ -92,66 +107,29 @@ function _phptemplate_callback($hook, $v * @param $variables * A sequential array of variables passed to the theme function. */ -function _phptemplate_default_variables($hook, $variables) { +function phptemplate_engine_variables(&$variables, $hook) { global $theme, $sidebar_indicator; static $count = array(); + // Create variables so anything which is themed can be zebra striped automatically. $count[$hook] = isset($count[$hook]) && is_int($count[$hook]) ? $count[$hook] : 1; $variables['zebra'] = ($count[$hook] % 2) ? 'odd' : 'even'; $variables['id'] = $count[$hook]++; - if ($hook == 'block') { - $count['block_counter'][$sidebar_indicator] = isset($count['block_counter'][$sidebar_indicator]) && is_int($count['block_counter'][$sidebar_indicator]) ? $count['block_counter'][$sidebar_indicator] : 1; - $variables['block_zebra'] = ($count['block_counter'][$sidebar_indicator] % 2) ? 'odd' : 'even'; - $variables['block_id'] = $count['block_counter'][$sidebar_indicator]++; - } - elseif ($hook == 'page') { - $regions = system_region_list($theme); - // Load all region content assigned via blocks. - foreach (array_keys($regions) as $region) { - // Skip blocks in this region that have already been loaded. - // This pre-loading is necessary because phptemplate uses variable names different from - // the region names, e.g., 'sidebar_left' instead of 'left'. - if (!in_array($region, array('left', 'right', 'footer'))) { - isset($variables[$region]) ? $variables[$region] .= theme('blocks', $region) : $variables[$region] = theme('blocks', $region); - } - } - } // Tell all templates where they are located. $variables['directory'] = path_to_theme(); $variables['is_front'] = drupal_is_front_page(); - - return $variables; -} - -/** - * @return - * Array of template features - */ -function phptemplate_features() { - return array( - 'toggle_logo', - 'toggle_comment_user_picture', - 'toggle_favicon', - 'toggle_mission', - 'toggle_name', - 'toggle_node_user_picture', - 'toggle_search', - 'toggle_slogan' - ); } /** - * Prepare the values passed to the theme_page function to be passed - * into a pluggable template engine. Uses the arg() function to - * generate a series of page template files suggestions based on the - * current path. If none are found, the default page.tpl.php is used. + * Prepare the variables passed to the page.tpl.php template Uses the arg() + * function to generate a series of page template files suggestions based on + * the current path. */ -function phptemplate_page($content, $show_blocks = TRUE) { - +function phptemplate_engine_variables_page(&$variables) { /* Set title and breadcrumb to declared values */ if (drupal_is_front_page()) { - $mission = filter_xss_admin(theme_get_setting('mission')); + $variables['mission'] = filter_xss_admin(theme_get_setting('mission')); } /* Add favicon */ @@ -159,26 +137,44 @@ function phptemplate_page($content, $sho drupal_set_html_head(''); } - // Populate sidebars + /** + * Populate sidebars. + */ + $variables['sidebar_left'] = NULL; + $variables['sidebar_right'] = NULL; $layout = 'none'; - if ($show_blocks) { + if ($variables['show_blocks']) { global $sidebar_indicator; /** * Sidebar_indicator tells the block counting code to count sidebars separately. */ $sidebar_indicator = 'left'; - $sidebar_left = theme('blocks', 'left'); - if ($sidebar_left != '') { + $variables['sidebar_left'] = theme('blocks', 'left'); + if ($variables['sidebar_left'] != '') { $layout = 'left'; } $sidebar_indicator = 'right'; - $sidebar_right = theme('blocks', 'right'); - if ($sidebar_right != '') { - $layout = ($layout == 'left') ? 'both' : 'right'; + $variables['sidebar_right'] = theme('blocks', 'right'); + if ($variables['sidebar_right'] != '') { + $variables['layout'] = ($layout == 'left') ? 'both' : 'right'; } $sidebar_indicator = NULL; } + $variables['layout'] = $layout; + + global $theme; + // Populate the rest of the regions. + $regions = system_region_list($theme); + // Load all region content assigned via blocks. + foreach (array_keys($regions) as $region) { + // Skip blocks in this region that have already been loaded. + // This pre-loading is necessary because phptemplate uses variable names different from + // the region names, e.g., 'sidebar_left' instead of 'left'. + if (!in_array($region, array('left', 'right', 'footer'))) { + isset($variables[$region]) ? $variables[$region] .= theme('blocks', $region) : $variables[$region] = theme('blocks', $region); + } + } // Construct page title if (drupal_get_title()) { @@ -190,35 +186,28 @@ function phptemplate_page($content, $sho $head_title[] = variable_get('site_slogan', ''); } } - - $variables = array( - 'base_path' => base_path(), - 'breadcrumb' => theme('breadcrumb', drupal_get_breadcrumb()), - 'closure' => theme('closure'), - 'content' => $content, - 'feed_icons' => drupal_get_feeds(), - 'footer_message' => filter_xss_admin(variable_get('site_footer', FALSE)) . "\n" . theme('blocks', 'footer'), - 'head' => drupal_get_html_head(), - 'head_title' => implode(' | ', $head_title), - 'help' => theme('help'), - 'language' => $GLOBALS['language'], - 'layout' => isset($layout) ? $layout : NULL, - 'logo' => theme_get_setting('logo'), - 'messages' => theme('status_messages'), - 'mission' => isset($mission) ? $mission : '', - 'primary_links' => menu_primary_links(), - 'search_box' => (theme_get_setting('toggle_search') ? drupal_get_form('search_theme_form') : ''), - 'secondary_links' => menu_secondary_links(), - 'sidebar_left' => !empty($sidebar_left) ? $sidebar_left : '', - 'sidebar_right' => !empty($sidebar_right) ? $sidebar_right : '', - 'site_name' => (theme_get_setting('toggle_name') ? variable_get('site_name', 'Drupal') : ''), - 'site_slogan' => (theme_get_setting('toggle_slogan') ? variable_get('site_slogan', '') : ''), - 'css' => drupal_add_css(), - 'styles' => drupal_get_css(), - 'scripts' => drupal_get_js(), - 'tabs' => theme('menu_local_tasks'), - 'title' => drupal_get_title() - ); + $variables['head_title'] = implode(' | ', $head_title); + $variables['base_path'] = base_path(); + $variables['breadcrumb'] = theme('breadcrumb', drupal_get_breadcrumb()); + $variables['closure'] = theme('closure'); + $variables['feed_icons'] = drupal_get_feeds(); + $variables['footer_message'] = filter_xss_admin(variable_get('site_footer', FALSE)) . "\n" . theme('blocks', 'footer'); + $variables['head'] = drupal_get_html_head(); + $variables['help'] = theme('help'); + $variables['language'] = $GLOBALS['language']; + $variables['logo'] = theme_get_setting('logo'); + $variables['messages'] = theme('status_messages'); + $variables['mission'] = isset($mission) ? $mission : ''; + $variables['primary_links'] = menu_primary_links(); + $variables['search_box'] = (theme_get_setting('toggle_search') ? drupal_get_form('search_theme_form') : ''); + $variables['secondary_links'] = menu_secondary_links(); + $variables['site_name'] = (theme_get_setting('toggle_name') ? variable_get('site_name', 'Drupal') : ''); + $variables['site_slogan'] = (theme_get_setting('toggle_slogan') ? variable_get('site_slogan', '') : ''); + $variables['css'] = drupal_add_css(); + $variables['styles'] = drupal_get_css(); + $variables['scripts'] = drupal_get_js(); + $variables['tabs'] = theme('menu_local_tasks'); + $variables['title'] = drupal_get_title(); if ((arg(0) == 'node') && is_numeric(arg(1))) { $variables['node'] = node_load(arg(1)); @@ -236,7 +225,7 @@ function phptemplate_page($content, $sho // page.tpl.php $i = 0; $suggestion = 'page'; - $suggestions = array($suggestion); + $suggestions = array(); while ($arg = arg($i++)) { $suggestions[] = $suggestion . '-' . $arg; if (!is_numeric($arg)) { @@ -247,43 +236,40 @@ function phptemplate_page($content, $sho $suggestions[] = 'page-front'; } - return _phptemplate_callback('page', $variables, $suggestions); + if ($suggestions) { + $variables['template_files'] = $suggestions; + } } /* * Prepare the values passed to the theme_node function to be passed - * into a pluggable template engine. + * into standard template files. */ -function phptemplate_node($node, $teaser = 0, $page = 0) { +function phptemplate_engine_variables_node(&$variables) { + $node = $variables['node']; if (module_exists('taxonomy')) { - $taxonomy = taxonomy_link('taxonomy terms', $node); + $variables['taxonomy'] = taxonomy_link('taxonomy terms', $node); } else { - $taxonomy = array(); + $variables['taxonomy'] = array(); } - if ($teaser && $node->teaser) { - $content = $node->teaser; + + if ($variables['teaser'] && $node->teaser) { + $variables['content'] = $node->teaser; } elseif (isset($node->body)) { - $content = $node->body; + $variables['content'] = $node->body; } else { - $content = ''; + $variables['content'] = ''; } - $variables = array( - 'content' => $content, - 'date' => format_date($node->created), - 'links' => !empty($node->links) ? theme('links', $node->links, array('class' => 'links inline')) : '', - 'name' => theme('username', $node), - 'node' => $node, // we pass the actual node to allow more customization - 'node_url' => url('node/'. $node->nid), - 'page' => $page, - 'taxonomy' => $taxonomy, - 'teaser' => $teaser, - 'terms' => theme('links', $taxonomy, array('class' => 'links inline')), - 'title' => check_plain($node->title) - ); + $variables['date'] = format_date($node->created); + $variables['links'] = !empty($node->links) ? theme('links', $node->links, array('class' => 'links inline')) : ''; + $variables['name'] = theme('username', $node); + $variables['node_url'] = url('node/'. $node->nid); + $variables['terms'] = theme('links', $variables['taxonomy'], array('class' => 'links inline')); + $variables['title'] = check_plain($node->title); // Flatten the node object's member fields. $variables = array_merge((array)$node, $variables); @@ -298,28 +284,28 @@ function phptemplate_node($node, $teaser $variables['picture'] = ''; } - return _phptemplate_callback('node', $variables, array('node-' . $node->type)); + $variables['template_files'][] = 'node-'. $node->type; } /** * Prepare the values passed to the theme_comment function to be passed * into a pluggable template engine. */ -function phptemplate_comment($comment, $links = 0) { - return _phptemplate_callback('comment', array( - 'author' => theme('username', $comment), - 'comment' => $comment, - 'content' => $comment->comment, - 'date' => format_date($comment->timestamp), - 'links' => isset($links) ? theme('links', $links) : '', - 'new' => $comment->new ? t('new') : '', - 'signature' => $comment->signature, - 'picture' => theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', $comment) : '', - 'submitted' => t('Submitted by !a on @b.', +// function phptemplate_comment($comment, $links = 0) { +function phptemplate_engine_variables_comment(&$variables) { + $comment = $variables['comment']; + $variables['author'] = theme('username', $comment); + $variables['comment'] = $comment; + $variables['content'] = $comment->comment; + $variables['date'] = format_date($comment->timestamp); + $variables['links'] = isset($variables['links']) ? theme('links', $variables['links']) : ''; + $variables['new'] = $comment->new ? t('new') : ''; + $variables['picture'] = theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', $comment) : ''; + $variables['signature'] = $comment->signature; + $variables['submitted'] = t('Submitted by !a on @b.', array('!a' => theme('username', $comment), - '@b' => format_date($comment->timestamp))), - 'title' => l($comment->subject, $_GET['q'], array('fragment' => "comment-$comment->cid")) - )); + '@b' => format_date($comment->timestamp))); + $variables['title'] = l($comment->subject, $_GET['q'], array('fragment' => "comment-$comment->cid")); } /** @@ -328,82 +314,14 @@ function phptemplate_comment($comment, $ * series of template file suggestions. If none are found, the default * block.tpl.php is used. */ -function phptemplate_block($block) { - $suggestions[] = 'block'; - $suggestions[] = 'block-' . $block->region; - $suggestions[] = 'block-' . $block->module; - $suggestions[] = 'block-' . $block->module . '-' . $block->delta; - - return _phptemplate_callback('block', array('block' => $block), $suggestions); -} - -/** - * Prepare the values passed to the theme_box function to be passed - * into a pluggable template engine. - */ -function phptemplate_box($title, $content, $region = 'main') { - return _phptemplate_callback('box', array( - 'content' => $content, - 'region' => $region, - 'title' => $title - )); -} - -/** - * Default callback for PHPTemplate. - * - * Load a template file, and pass the variable array to it. - * If the suggested file is not found, PHPTemplate will attempt to use - * a $hook.tpl.php file in the template directory, and failing that a - * $hook.tpl.php in the PHPTemplate directory. - * - * @param $hook - * The name of the theme function being executed. - * @param $variables - * A sequential array of variables passed to the theme function. - * @param $suggestions - * An array of suggested template files to use. - */ -function _phptemplate_default($hook, $variables, $suggestions = array(), $extension = '.tpl.php') { - global $theme_engine; - - // Loop through any suggestions in FIFO order. - $suggestions = array_reverse($suggestions); - foreach ($suggestions as $suggestion) { - if (!empty($suggestion) && file_exists(path_to_theme() .'/'. $suggestion . $extension)) { - $file = path_to_theme() .'/'. $suggestion . $extension; - break; - } - } - - if (!isset($file)) { - if (file_exists(path_to_theme() ."/$hook$extension")) { - $file = path_to_theme() ."/$hook$extension"; - } - else { - if (in_array($hook, array('node', 'block', 'box', 'comment'))) { - $file = path_to_engine() .'/'. $hook . $extension; - } - else { - $variables['hook'] = $hook; - watchdog('error', t('%engine.engine was instructed to override the %name theme function, but no valid template file was found.', array('%engine' => $theme_engine, '%name' => $hook))); - $file = path_to_engine() .'/default'. $extension; - } - } - } - - if (isset($file)) { - return call_user_func('_'. $theme_engine .'_render', $file, $variables); - } +function phptemplate_engine_variables_block(&$variables) { + global $sidebar_indicator; + $count['block_counter'][$sidebar_indicator] = isset($count['block_counter'][$sidebar_indicator]) && is_int($count['block_counter'][$sidebar_indicator]) ? $count['block_counter'][$sidebar_indicator] : 1; + + $variables['block_zebra'] = ($count['block_counter'][$sidebar_indicator] % 2) ? 'odd' : 'even'; + + $variables['block_id'] = $count['block_counter'][$sidebar_indicator]++; + $variables['template_files'][] = 'block-' . $variables['block']->region; + $variables['template_files'][] = 'block-' . $variables['block']->module; + $variables['template_files'][] = 'block-' . $variables['block']->module .'-'. $variables['block']->delta; } - -function _phptemplate_render($file, $variables) { - extract($variables, EXTR_SKIP); // Extract the variables to a local namespace - ob_start(); // Start output buffering - include "./$file"; // Include the file - $contents = ob_get_contents(); // Get the contents of the buffer - ob_end_clean(); // End buffering and discard - return $contents; // Return the contents -} - -?> Index: themes/garland/template.php =================================================================== RCS file: /cvs/drupal/drupal/themes/garland/template.php,v retrieving revision 1.6 diff -u -p -r1.6 template.php --- themes/garland/template.php 20 Mar 2007 19:07:55 -0000 1.6 +++ themes/garland/template.php 4 Apr 2007 18:21:46 -0000 @@ -1,4 +1,6 @@ '; - $output .= "\n"; - $vars['tabs2'] = $output; - } +function phptemplate_variables_page(&$vars) { + if ($secondary = menu_secondary_local_tasks()) { + $output = ''; + $output .= "\n"; + $vars['tabs2'] = $output; + } - // Hook into color.module - if (module_exists('color')) { - _color_page_alter($vars); - } - return $vars; + // Hook into color.module + if (module_exists('color')) { + _color_page_alter($vars); } - return array(); } /**