From e66371cac17e35d2cb0c9bf48f792193b79f3a7c Mon Sep 17 00:00:00 2001 From: Dries Buytaert <dries@buytaert.net> Date: Sun, 6 May 2007 05:47:52 +0000 Subject: [PATCH] - Patch #137211 by merlinofchaos: move theme information to .info files and improved theme inheritance. --- includes/bootstrap.inc | 1 + includes/form.inc | 2 +- includes/menu.inc | 19 ++ includes/theme.inc | 241 +++++++++++++----- modules/color/color.module | 3 +- modules/system/system.install | 14 +- modules/system/system.module | 154 +++++++---- themes/bluemarine/bluemarine.info | 1 + themes/chameleon/chameleon.theme | 3 +- themes/chameleon/marvin/marvin.info | 1 + themes/engines/phptemplate/phptemplate.engine | 9 +- themes/garland/garland.info | 1 + themes/garland/minnelli/minnelli.info | 1 + themes/pushbutton/pushbutton.info | 1 + update.php | 2 +- 15 files changed, 321 insertions(+), 132 deletions(-) diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 51e75d9c1c9b..377c9711e051 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -975,6 +975,7 @@ function drupal_maintenance_theme() { foreach ($themes as $hook => $info) { if (!isset($info['file']) && !isset($info['function'])) { $themes[$hook]['function'] = 'theme_'. $hook; + $themes[$hook]['theme path'] = 'misc'; } } _theme_set_registry($themes); diff --git a/includes/form.inc b/includes/form.inc index 5de5ded31e19..dce3e22d4782 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -1821,7 +1821,7 @@ function batch_set($batch_definition) { /** * Process the batch. - * + * * Unless the batch has been markes with 'progressive' = FALSE, the function * isses a drupal_goto and thus ends page execution. * diff --git a/includes/menu.inc b/includes/menu.inc index c2ec2eb8132f..1f1d1decedee 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -1055,3 +1055,22 @@ function menu_get_item_by_mid($mid) { } return FALSE; } + +/** + * Returns the rendered local tasks. The default implementation renders + * them as tabs. + * + * @ingroup themeable + */ +function theme_menu_local_tasks() { + $output = ''; + + if ($primary = menu_primary_local_tasks()) { + $output .= "<ul class=\"tabs primary\">\n". $primary ."</ul>\n"; + } + if ($secondary = menu_secondary_local_tasks()) { + $output .= "<ul class=\"tabs secondary\">\n". $secondary ."</ul>\n"; + } + + return $output; +} diff --git a/includes/theme.inc b/includes/theme.inc index 593c2819ef1c..f8f762185fdf 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -27,7 +27,6 @@ /** * Initialize the theme system by loading the theme. - * */ function init_theme() { global $theme, $user, $custom_theme, $theme_engine, $theme_key; @@ -51,38 +50,100 @@ function init_theme() { // Store the identifier for retrieving theme settings with. $theme_key = $theme; - // If we're using a style, load its appropriate theme, - // which is stored in the style's description field. - // Also add the stylesheet using drupal_add_css(). - // Otherwise, load the theme. - if (strpos($themes[$theme]->filename, '.css')) { - // File is a style; loads its CSS. - // Set theme to its template/theme - drupal_add_css($themes[$theme]->filename, 'theme'); - $theme = basename(dirname($themes[$theme]->owner)); + // Find all our ancestor themes and put them in an array. + $base_theme = array(); + $ancestor = $theme; + while ($ancestor && isset($themes[$ancestor]->base_theme)) { + if (isset($themes[$themes[$ancestor]->base_theme])) { + $base_theme[] = $new_base_theme = $themes[$themes[$ancestor]->base_theme]; + // stop if this is final ancestor. + if (!isset($new_base_theme->base_theme)) { + break; + } + $ancestor = $new_base_theme->base_theme; + } + // stop if ancestor didn't exist. + else { + break; + } + } + _init_theme($themes[$theme], array_reverse($base_theme)); +} + +/** + * Initialize the theme system given already loaded information. This + * function is useful to initialize a theme when no database is present. + * + * @param $theme + * An object with the following information: + * filename + * The .info file for this theme. The 'path' to + * the theme will be in this file's directory. (Required) + * owner + * The path to the .theme file or the .engine file to load for + * the theme. (Required) + * stylesheet + * The primary stylesheet for the theme. (Optional) + * engine + * The name of theme engine to use. (Optional) + * @param $base_theme + * An optional array of objects that represent the 'base theme' if the + * theme is meant to be derivative of another theme. It requires + * the same information as the $theme object. It should be in + * 'oldest first' order, meaning the top level of the chain will + * be first. + */ +function _init_theme($theme, $base_theme = array()) { + global $theme_info, $base_theme_info, $theme_engine, $theme_path; + $theme_info = $theme; + $base_theme_info = $base_theme; + + $theme_path = dirname($theme->filename); + + // Add the default stylesheet + if (!empty($theme->stylesheet)) { + drupal_add_css($theme->stylesheet, 'theme'); } else { - // File is a template/theme - // Load its CSS, if it exists - if (file_exists($stylesheet = dirname($themes[$theme]->filename) .'/style.css')) { - drupal_add_css($stylesheet, 'theme'); + // If we don't have a stylesheet of our own, look for the first + // base to have one and use its. + foreach ($base_theme as $base) { + if (!empty($base->stylesheet)) { + drupal_add_css($base->stylesheet, 'theme'); + break; + } } } - 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]->owner, '.engine')) { - // file is a template; include its engine - include_once './'. $themes[$theme]->owner; - $theme_engine = basename($themes[$theme]->owner, '.engine'); + $theme_engine = NULL; + + // Initialize the theme. + if (isset($theme->engine)) { + // Include the engine. + include_once './'. $theme->owner; + + $theme_engine = $theme->engine; if (function_exists($theme_engine .'_init')) { - call_user_func($theme_engine .'_init', $themes[$theme]); + foreach ($base_theme as $base) { + call_user_func($theme_engine .'_init', $base); + } + call_user_func($theme_engine .'_init', $theme); + } + } + else { + // include non-engine theme files + foreach ($base_theme as $base) { + // Include the theme file or the engine. + if (!empty($base->owner)) { + include_once './'. $base->owner; + } + } + // and our theme gets one too. + if (!empty($theme->owner)) { + include_once './'. $theme->owner; } - _theme_load_registry($theme, $theme_engine); } + _theme_load_registry($theme, $base_theme, $theme_engine); } /** @@ -111,14 +172,24 @@ function _theme_set_registry($registry) { /** * Get the theme_registry cache from the database; if it doesn't exist, build * it. + * + * @param $theme + * The loaded $theme object. + * @param $base_theme + * An array of loaded $theme objects representing the ancestor themes in + * oldest first order. + * @param theme_engine + * The name of the theme engine. */ -function _theme_load_registry($theme, $theme_engine = NULL) { - $cache = cache_get("theme_registry:$theme", 'cache'); +function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL) { + // Check the theme registry cache; if it exists, use it. + $cache = cache_get("theme_registry:$theme->name", 'cache'); if (isset($cache->data)) { $registry = $cache->data; } else { - $registry = _theme_build_registry($theme, $theme_engine); + // If not, build one and cache it. + $registry = _theme_build_registry($theme, $base_theme, $theme_engine); _theme_save_registry($theme, $registry); } _theme_set_registry($registry); @@ -128,7 +199,7 @@ function _theme_load_registry($theme, $theme_engine = NULL) { * Write the theme_registry cache into the database. */ function _theme_save_registry($theme, $registry) { - cache_set("theme_registry:$theme", $registry); + cache_set("theme_registry:$theme->name", $registry); } /** @@ -141,22 +212,31 @@ function drupal_rebuild_theme_registry() { } /** - * Process a single invocation of the theme hook. + * Process a single invocation of the theme hook. $type will be one + * of 'module', 'theme_engine' or 'theme' and it tells us some + * important information. + * + * Because $cache is a reference, the cache will be continually + * expanded upon; new entries will replace old entries in the + * array_merge, but we are careful to ensure some data is carried + * forward, such as the arguments a theme hook needs. */ -function _theme_process_registry(&$cache, $name, $type) { +function _theme_process_registry(&$cache, $name, $type, $theme, $path) { $function = $name .'_theme'; if (function_exists($function)) { - $result = $function($cache); + $result = $function($cache, $type, $theme, $path); - // Automatically find paths - $path = drupal_get_path($type, $name); foreach ($result as $hook => $info) { $result[$hook]['type'] = $type; + $result[$hook]['theme path'] = $path; // 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 a path is set in the info, use what was set. Otherwise use the + // default path. This is mostly so system.module can declare theme + // functions on behalf of core .include files. if (isset($info['file']) && !isset($info['path'])) { $result[$hook]['file'] = $path .'/'. $info['file']; } @@ -170,15 +250,7 @@ function _theme_process_registry(&$cache, $name, $type) { if (!isset($info['preprocess functions']) || !is_array($info['preprocess functions'])) { $info['preprocess functions'] = array(); $prefix = ($type == 'module' ? 'template' : $name); - // It would be too much of a performance hit to let every module have - // a generic preprocess function; themes and theme engines can do that. - if ($type != 'module' && function_exists($prefix .'_preprocess')) { - $info['preprocess functions'][] = $prefix .'_preprocess'; - } - if (function_exists($prefix .'_preprocess_'. $hook)) { - $info['preprocess functions'][] = $prefix .'_preprocess_'. $hook; - } - // theme engines get an extra set. + // theme engines get an extra set that come before the normally named preprocess. if ($type == 'theme_engine') { if (function_exists($prefix .'_engine_preprocess')) { $info['preprocess functions'][] = $prefix .'_engine_preprocess'; @@ -187,6 +259,15 @@ function _theme_process_registry(&$cache, $name, $type) { $info['preprocess functions'][] = $prefix .'_engine_preprocess_'. $hook; } } + + // It would be too much of a performance hit to let every module have + // a generic preprocess function; themes and theme engines can do that. + if ($type != 'module' && function_exists($prefix .'_preprocess')) { + $info['preprocess functions'][] = $prefix .'_preprocess'; + } + if (function_exists($prefix .'_preprocess_'. $hook)) { + $info['preprocess functions'][] = $prefix .'_preprocess_'. $hook; + } } if (isset($cache[$hook]['preprocess functions']) && is_array($cache[$hook]['preprocess functions']) && empty($cache[$hook]['override preprocess functions'])) { $info['preprocess functions'] = array_merge($cache[$hook]['preprocess functions'], $info['preprocess functions']); @@ -194,24 +275,47 @@ function _theme_process_registry(&$cache, $name, $type) { $result[$hook]['preprocess functions'] = $info['preprocess functions']; } + // Merge the newly created theme hooks into the existing cache. $cache = array_merge($cache, $result); } } /** * Rebuild the hook theme_registry cache. + * + * @param $theme + * The loaded $theme object. + * @param $base_theme + * An array of loaded $theme objects representing the ancestor themes in + * oldest first order. + * @param theme_engine + * The name of the theme engine. */ -function _theme_build_registry($theme, $theme_engine) { +function _theme_build_registry($theme, $base_theme, $theme_engine) { $cache = array(); + // First, process the theme hooks advertised by modules. This will + // serve as the basic registry. foreach (module_implements('theme') as $module) { - _theme_process_registry($cache, $module, 'module'); + _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module)); } + // Process each base theme. + foreach ($base_theme as $base) { + // If the theme uses a theme engine, process its hooks. + $base_path = dirname($base->filename); + if ($theme_engine) { + _theme_process_registry($cache, $theme_engine, 'base_theme_engine', $base->name, $base_path); + } + _theme_process_registry($cache, $base->name, 'base_theme', $base->name, $base_path); + } + + // And then the same thing, but for the theme. if ($theme_engine) { - _theme_process_registry($cache, $theme_engine, 'theme_engine'); + _theme_process_registry($cache, $theme_engine, 'theme_engine', $theme->name, dirname($theme->filename)); } - _theme_process_registry($cache, $theme, 'theme'); + // Finally, hooks provided by the theme itself. + _theme_process_registry($cache, $theme->name, 'theme', $theme->name, dirname($theme->filename)); return $cache; } @@ -237,6 +341,15 @@ function list_themes($refresh = FALSE) { while ($theme = db_fetch_object($result)) { if (file_exists($theme->filename)) { $theme->info = unserialize($theme->info); + if (isset($theme->info['stylesheet'])) { + $theme->stylesheet = $theme->info['stylesheet']; + } + if (isset($theme->info['engine'])) { + $theme->engine = $theme->info['engine']; + } + if (isset($theme->info['base theme'])) { + $theme->base_theme = $theme->info['base theme']; + } $list[$theme->name] = $theme; } } @@ -344,6 +457,10 @@ function theme() { } $info = $hooks[$hook]; + global $theme_path; + $temp = $theme_path; + // point path_to_theme() to the currently used theme path: + $theme_path = $hooks[$hook]['theme path']; if (isset($info['function'])) { // The theme call is a function. @@ -355,7 +472,7 @@ function theme() { } include_once($function_file); } - return call_user_func_array($info['function'], $args); + $output = call_user_func_array($info['function'], $args); } else { // The theme call is a template. @@ -424,8 +541,11 @@ function theme() { $template_file = $hooks[$hook]['path'] .'/'. $template_file; } } - return $render_function($template_file, $variables); + $output = $render_function($template_file, $variables); } + // restore path_to_theme() + $theme_path = $temp; + return $output; } /** @@ -448,30 +568,13 @@ function drupal_discover_template($suggestions, $extension = '.tpl.php') { * Return the path to the currently selected theme. */ function path_to_theme() { - global $theme; + global $theme_path; - if (!isset($theme)) { + if (!isset($theme_path)) { init_theme(); } - $themes = list_themes(); - - return dirname($themes[$theme]->filename); -} - -/** - * Return the path to the currently selected engine. - */ -function path_to_engine() { - global $theme, $theme_engine; - - if (!isset($theme)) { - init_theme(); - } - - $engines = list_theme_engines(); - - return dirname($engines[$theme_engine]->filename); + return $theme_path; } /** diff --git a/modules/color/color.module b/modules/color/color.module index 9aabcea4bada..04bbb8ff6e42 100644 --- a/modules/color/color.module +++ b/modules/color/color.module @@ -279,7 +279,8 @@ function color_scheme_form_submit($form_id, $values) { */ function _color_rewrite_stylesheet($theme, &$info, &$paths, $palette) { // Load stylesheet - $style = file_get_contents($paths['source'] .'style.css'); + $themes = list_themes(); + $style = file_get_contents($themes[$theme]->stylesheet); // Prepare color conversion table $conversion = $palette; diff --git a/modules/system/system.install b/modules/system/system.install index 7cf9b19797df..c6b55878ea51 100644 --- a/modules/system/system.install +++ b/modules/system/system.install @@ -1109,8 +1109,8 @@ function system_install() { break; } - db_query("INSERT INTO {system} (filename, name, type, owner, status, throttle, bootstrap, schema_version) VALUES ('themes/engines/phptemplate/phptemplate.engine', 'phptemplate', 'theme_engine', '', 1, 0, 0, 0)"); - db_query("INSERT INTO {system} (filename, name, type, owner, status, throttle, bootstrap, schema_version, info) VALUES ('themes/garland/page.tpl.php', 'garland', 'theme', 'themes/engines/phptemplate/phptemplate.engine', 1, 0, 0, 0, '%s')", serialize(drupal_parse_info_file('themes/garland/garland.info') + system_theme_default())); + // Load system theme data appropriately. + system_theme_data(); db_query("INSERT INTO {users} (uid,name,mail) VALUES(0,'','')"); @@ -3864,6 +3864,16 @@ function system_update_6012() { return $ret; } +/** + * Rebuild cache data for theme system changes + */ +function system_update_6013() { + // Rebuild system table contents. + module_rebuild_cache(); + system_theme_data(); +} + + /** * @} End of "defgroup updates-5.x-to-6.x" * The next series of updates should start at 7000. diff --git a/modules/system/system.module b/modules/system/system.module index a18439e07a22..51478a383dfc 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -505,7 +505,9 @@ function system_admin_theme_submit($form_id, $form_values) { function system_theme_select_form($description = '', $default_value = '', $weight = 0) { if (user_access('select different theme')) { $enabled = array(); - foreach (list_themes() as $theme) { + $themes = list_themes(); + + foreach ($themes as $theme) { if ($theme->status) { $enabled[] = $theme; } @@ -526,8 +528,17 @@ function system_theme_select_form($description = '', $default_value = '', $weigh // For the default theme, revert to an empty string so the user's theme updates when the site theme is changed. $info->key = $info->name == variable_get('theme_default', 'garland') ? '' : $info->name; - $info->screenshot = dirname($info->filename) .'/screenshot.png'; - $screenshot = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', array('class' => 'screenshot'), FALSE) : t('no screenshot'); + $screenshot = NULL; + $theme_key = $info->name; + while ($theme_key) { + if (file_exists($themes[$theme_key]->info['screenshot'])) { + $screenshot = $themes[$theme_key]->info['screenshot']; + break; + } + $theme_key = isset($themes[$theme_key]->info['base theme']) ? $themes[$theme_key]->info['base theme'] : NULL; + } + + $screenshot = $screenshot ? theme('image', $screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', array('class' => 'screenshot'), FALSE) : t('no screenshot'); $form['themes'][$info->key]['screenshot'] = array('#value' => $screenshot); $form['themes'][$info->key]['description'] = array('#type' => 'item', '#title' => $info->name, '#value' => dirname($info->filename) . ($info->name == variable_get('theme_default', 'garland') ? '<br /> <em>'. t('(site default theme)') .'</em>' : '')); @@ -964,6 +975,8 @@ function system_theme_default() { 'search', 'slogan' ), + 'stylesheet' => 'style.css', + 'screenshot' => 'screenshot.png', ); } @@ -971,22 +984,12 @@ function system_theme_default() { * Collect data about all currently available themes */ function system_theme_data() { - include_once './includes/install.inc'; - // Find themes - $themes = drupal_system_listing('\.theme$', 'themes'); + $themes = drupal_system_listing('\.info$', 'themes'); // Find theme engines $engines = drupal_system_listing('\.engine$', 'themes/engines'); - // can't iterate over array itself as it uses a copy of the array items - foreach (array_keys($themes) as $key) { - drupal_get_filename('theme', $themes[$key]->name, $themes[$key]->filename); - drupal_load('theme', $themes[$key]->name); - $themes[$key]->owner = $themes[$key]->filename; - $themes[$key]->prefix = $key; - } - // Remove all theme engines from the system table db_query("DELETE FROM {system} WHERE type = 'theme_engine'"); @@ -995,61 +998,106 @@ function system_theme_data() { drupal_get_filename('theme_engine', $engine->name, $engine->filename); drupal_load('theme_engine', $engine->name); db_query("INSERT INTO {system} (name, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', %d, %d, %d)", $engine->name, 'theme_engine', $engine->filename, 1, 0, 0); + } - // Add templates to the site listing - foreach (call_user_func($engine->name .'_templates') as $template) { - // Do not double-insert templates with theme files in their directory, - // but do register their engine data. - if (array_key_exists($template->name, $themes)) { - $themes[$template->name]->template = TRUE; - $themes[$template->name]->owner = $engine->filename; - $themes[$template->name]->prefix = $engine->name; - } - else { - $template->template = TRUE; - $template->name = basename(dirname($template->filename)); - $template->owner = $engine->filename; - $template->prefix = $engine->name; + $defaults = system_theme_default(); - $themes[$template->name] = $template; + $sub_themes = array(); + // Read info files for each theme + foreach ($themes as $key => $theme) { + $themes[$key]->info = drupal_parse_info_file($theme->filename) + $defaults; + if (!empty($themes[$key]->info['base theme'])) { + $sub_themes[] = $key; + } + if (empty($themes[$key]->info['engine'])) { + $filename = dirname($themes[$key]->filename) .'/'. $themes[$key]->name .'.theme'; + if (file_exists($filename)) { + $themes[$key]->owner = $filename; + $themes[$key]->prefix = $key; } } + else { + $engine = $themes[$key]->info['engine']; + if (isset($engines[$engine])) { + $themes[$key]->owner = $engines[$engine]->filename; + $themes[$key]->prefix = $engines[$engine]->name; + $themes[$key]->template = TRUE; + } + } + + // Give the stylesheet proper path information. + if (!empty($themes[$key]->info['stylesheet'])) { + $themes[$key]->info['stylesheet'] = dirname($themes[$key]->filename) .'/'. $themes[$key]->info['stylesheet']; + } + // Give the screenshot proper path information. + if (!empty($themes[$key]->info['screenshot'])) { + $themes[$key]->info['screenshot'] = dirname($themes[$key]->filename) .'/'. $themes[$key]->info['screenshot']; + } } - // Find styles in each theme's directory. - foreach ($themes as $theme) { - foreach (file_scan_directory(dirname($theme->filename), 'style.css$') as $style) { - $style->style = TRUE; - $style->template = isset($theme->template) ? $theme->template : FALSE; - $style->name = basename(dirname($style->filename)); - $style->owner = $theme->filename; - $style->prefix = !empty($theme->template) ? $theme->prefix : $theme->name; - // do not double-insert styles with theme files in their directory - if (array_key_exists($style->name, $themes)) { - continue; + // Now that we've established all our master themes, go back and fill in + // data for subthemes. + foreach ($sub_themes as $key) { + $base_key = system_find_base_theme($themes, $key); + if (!$base_key) { + continue; + } + // Copy the 'owner' and 'engine' over if the top level theme uses a + // theme engine. + if (isset($themes[$base_key]->owner)) { + if (isset($themes[$base_key]->info['engine'])) { + $themes[$key]->info['engine'] = $themes[$base_key]->info['engine']; + $themes[$key]->owner = $themes[$base_key]->owner; + $themes[$key]->prefix = $themes[$base_key]->prefix; + } + else { + $themes[$key]->prefix = $key; } - $themes[$style->name] = $style; } } // Extract current files from database. system_get_files_database($themes, 'theme'); - $defaults = system_theme_default(); - // Read info files for the owner - foreach (array_keys($themes) as $key) { - $themes[$key]->info = drupal_parse_info_file(dirname($themes[$key]->filename) .'/'. $themes[$key]->name .'.info') + $defaults; - } - db_query("DELETE FROM {system} WHERE type = 'theme'"); foreach ($themes as $theme) { + if (!isset($theme->owner)) { + $theme->owner = ''; + } + db_query("INSERT INTO {system} (name, owner, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, serialize($theme->info), 'theme', $theme->filename, isset($theme->status) ? $theme->status : 0, 0, 0); } return $themes; } +/** + * Recursive function to find the top level base theme. Themes can inherit + * templates and function implementations from earlier themes; this function + * finds the top level parent that has no ancestor, or returns NULL if there + * isn't a valid parent. + */ +function system_find_base_theme($themes, $key, $used_keys = array()) { + $base_key = $themes[$key]->info['base theme']; + // Does the base theme exist? + if (!isset($themes[$base_key])) { + return NULL; + } + + // Is the base theme itself a child of another theme? + if (isset($themes[$base_key]->info['base theme'])) { + // Prevent loops. + if ($used_keys[$base_key]) { + return NULL; + } + $used_keys[$base_key] = TRUE; + return system_find_base_theme($themes, $base_key, $used_keys); + } + // If we get here, then this is our parent theme. + return $base_key; +} + /** * Get a list of available regions from a specified theme. * @@ -1190,8 +1238,16 @@ function system_themes_form() { $status = array(); foreach ($themes as $theme) { - $theme->screenshot = dirname($theme->filename) .'/screenshot.png'; - $screenshot = file_exists($theme->screenshot) ? theme('image', $theme->screenshot, t('Screenshot for %theme theme', array('%theme' => $theme->info['name'])), '', array('class' => 'screenshot'), FALSE) : t('no screenshot'); + $screenshot = NULL; + $theme_key = $theme->name; + while ($theme_key) { + if (file_exists($themes[$theme_key]->info['screenshot'])) { + $screenshot = $themes[$theme_key]->info['screenshot']; + break; + } + $theme_key = isset($themes[$theme_key]->info['base theme']) ? $themes[$theme_key]->info['base theme'] : NULL; + } + $screenshot = $screenshot ? theme('image', $screenshot, t('Screenshot for %theme theme', array('%theme' => $theme->info['name'])), '', array('class' => 'screenshot'), FALSE) : t('no screenshot'); $form[$theme->name]['screenshot'] = array('#value' => $screenshot); $form[$theme->name]['info'] = array('#type' => 'value', '#value' => $theme->info); diff --git a/themes/bluemarine/bluemarine.info b/themes/bluemarine/bluemarine.info index 366a5d3bdbdf..15646d9dfea5 100644 --- a/themes/bluemarine/bluemarine.info +++ b/themes/bluemarine/bluemarine.info @@ -2,3 +2,4 @@ name = Bluemarine description = Table-based multi-column theme with a marine and ash color scheme. version = VERSION +engine = phptemplate diff --git a/themes/chameleon/chameleon.theme b/themes/chameleon/chameleon.theme index 1c87653d3380..9d8c24f98459 100644 --- a/themes/chameleon/chameleon.theme +++ b/themes/chameleon/chameleon.theme @@ -9,10 +9,9 @@ /** * Implementation of hook_theme. Auto-discover theme functions. */ -function chameleon_theme($existing) { +function chameleon_theme($existing, $type, $theme, $path) { $templates = array(); // Check for function overrides. - global $theme; foreach ($existing as $hook => $info) { if (function_exists($theme .'_'. $hook)) { $templates[$hook] = array( diff --git a/themes/chameleon/marvin/marvin.info b/themes/chameleon/marvin/marvin.info index d70394ee5a5b..c77d66055b40 100644 --- a/themes/chameleon/marvin/marvin.info +++ b/themes/chameleon/marvin/marvin.info @@ -4,3 +4,4 @@ description = Boxy tabled theme in all grays. regions[left] = Left sidebar regions[right] = Right sidebar version = VERSION +base theme = chameleon diff --git a/themes/engines/phptemplate/phptemplate.engine b/themes/engines/phptemplate/phptemplate.engine index 86f1a002f6bf..4e9c065afbad 100644 --- a/themes/engines/phptemplate/phptemplate.engine +++ b/themes/engines/phptemplate/phptemplate.engine @@ -19,11 +19,11 @@ function phptemplate_init($template) { * pre-defined by Drupal so that we can use that information if * we need to. */ -function phptemplate_theme($existing) { +function phptemplate_theme($existing, $type, $theme, $path) { $templates = array(); // Check for template overrides. - $files = drupal_system_listing('\.tpl\.php$', path_to_theme(), 'name', 0); + $files = drupal_system_listing('\.tpl\.php$', $path, 'name', 0); foreach ($files as $template => $file) { // chop off the .tpl @@ -37,7 +37,6 @@ function phptemplate_theme($existing) { } // Check for function overrides. - global $theme; foreach ($existing as $hook => $info) { if (function_exists($theme .'_'. $hook)) { $templates[$hook] = array( @@ -54,10 +53,6 @@ function phptemplate_theme($existing) { return $templates; } -function phptemplate_templates($directory = 'themes') { - return drupal_system_listing('^page\.tpl\.php$', $directory, 'filename'); -} - /** * Adds additional helper variables to all templates. * diff --git a/themes/garland/garland.info b/themes/garland/garland.info index 68d9c57c171a..740e0342573a 100644 --- a/themes/garland/garland.info +++ b/themes/garland/garland.info @@ -2,3 +2,4 @@ name = Garland description = Tableless, recolorable, multi-column, fluid width theme (default). version = VERSION +engine = phptemplate diff --git a/themes/garland/minnelli/minnelli.info b/themes/garland/minnelli/minnelli.info index 66e0d8fa929a..3fb7d16a60e4 100644 --- a/themes/garland/minnelli/minnelli.info +++ b/themes/garland/minnelli/minnelli.info @@ -2,3 +2,4 @@ name = Minnelli description = Tableless, recolorable, multi-column, fixed width theme. version = VERSION +base theme = garland diff --git a/themes/pushbutton/pushbutton.info b/themes/pushbutton/pushbutton.info index 895373d8677e..cbe4aca15254 100644 --- a/themes/pushbutton/pushbutton.info +++ b/themes/pushbutton/pushbutton.info @@ -2,3 +2,4 @@ name = Pushbutton description = Tabled, multi-column theme in blue and orange tones. version = VERSION +engine = phptemplate diff --git a/update.php b/update.php index c406531619c6..ccda20707e69 100644 --- a/update.php +++ b/update.php @@ -431,7 +431,7 @@ function update_results_page() { if ($GLOBALS['access_check'] == FALSE) { $output .= "<p><strong>Reminder: don't forget to set the <code>\$access_check</code> value at the top of <code>update.php</code> back to <code>TRUE</code>.</strong></p>"; } - + $output .= theme('item_list', $links); // Output a list of queries executed -- GitLab