webmaster@1: theme) && !empty($themes[$user->theme]->status) ? $user->theme : variable_get('theme_default', 'garland'); webmaster@1: webmaster@1: // Allow modules to override the present theme... only select custom theme webmaster@1: // if it is available in the list of installed themes. webmaster@1: $theme = $custom_theme && $themes[$custom_theme] ? $custom_theme : $theme; webmaster@1: webmaster@1: // Store the identifier for retrieving theme settings with. webmaster@1: $theme_key = $theme; webmaster@1: webmaster@1: // Find all our ancestor themes and put them in an array. webmaster@1: $base_theme = array(); webmaster@1: $ancestor = $theme; webmaster@1: while ($ancestor && isset($themes[$ancestor]->base_theme)) { webmaster@1: $base_theme[] = $new_base_theme = $themes[$themes[$ancestor]->base_theme]; webmaster@1: $ancestor = $themes[$ancestor]->base_theme; webmaster@1: } webmaster@1: _init_theme($themes[$theme], array_reverse($base_theme)); webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Initialize the theme system given already loaded information. This webmaster@1: * function is useful to initialize a theme when no database is present. webmaster@1: * webmaster@1: * @param $theme webmaster@1: * An object with the following information: webmaster@1: * filename webmaster@1: * The .info file for this theme. The 'path' to webmaster@1: * the theme will be in this file's directory. (Required) webmaster@1: * owner webmaster@1: * The path to the .theme file or the .engine file to load for webmaster@1: * the theme. (Required) webmaster@1: * stylesheet webmaster@1: * The primary stylesheet for the theme. (Optional) webmaster@1: * engine webmaster@1: * The name of theme engine to use. (Optional) webmaster@1: * @param $base_theme webmaster@1: * An optional array of objects that represent the 'base theme' if the webmaster@1: * theme is meant to be derivative of another theme. It requires webmaster@1: * the same information as the $theme object. It should be in webmaster@1: * 'oldest first' order, meaning the top level of the chain will webmaster@1: * be first. webmaster@1: * @param $registry_callback webmaster@1: * The callback to invoke to set the theme registry. webmaster@1: */ webmaster@1: function _init_theme($theme, $base_theme = array(), $registry_callback = '_theme_load_registry') { webmaster@1: global $theme_info, $base_theme_info, $theme_engine, $theme_path; webmaster@1: $theme_info = $theme; webmaster@1: $base_theme_info = $base_theme; webmaster@1: webmaster@1: $theme_path = dirname($theme->filename); webmaster@1: webmaster@1: // Prepare stylesheets from this theme as well as all ancestor themes. webmaster@1: // We work it this way so that we can have child themes override parent webmaster@1: // theme stylesheets easily. webmaster@1: $final_stylesheets = array(); webmaster@1: webmaster@1: // Grab stylesheets from base theme webmaster@1: foreach ($base_theme as $base) { webmaster@1: if (!empty($base->stylesheets)) { webmaster@1: foreach ($base->stylesheets as $media => $stylesheets) { webmaster@1: foreach ($stylesheets as $name => $stylesheet) { webmaster@1: $final_stylesheets[$media][$name] = $stylesheet; webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: // Add stylesheets used by this theme. webmaster@1: if (!empty($theme->stylesheets)) { webmaster@1: foreach ($theme->stylesheets as $media => $stylesheets) { webmaster@1: foreach ($stylesheets as $name => $stylesheet) { webmaster@1: $final_stylesheets[$media][$name] = $stylesheet; webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: // And now add the stylesheets properly webmaster@1: foreach ($final_stylesheets as $media => $stylesheets) { webmaster@1: foreach ($stylesheets as $stylesheet) { webmaster@1: drupal_add_css($stylesheet, 'theme', $media); webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: // Do basically the same as the above for scripts webmaster@1: $final_scripts = array(); webmaster@1: webmaster@1: // Grab scripts from base theme webmaster@1: foreach ($base_theme as $base) { webmaster@1: if (!empty($base->scripts)) { webmaster@1: foreach ($base->scripts as $name => $script) { webmaster@1: $final_scripts[$name] = $script; webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: // Add scripts used by this theme. webmaster@1: if (!empty($theme->scripts)) { webmaster@1: foreach ($theme->scripts as $name => $script) { webmaster@1: $final_scripts[$name] = $script; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: // Add scripts used by this theme. webmaster@1: foreach ($final_scripts as $script) { webmaster@1: drupal_add_js($script, 'theme'); webmaster@1: } webmaster@1: webmaster@1: $theme_engine = NULL; webmaster@1: webmaster@1: // Initialize the theme. webmaster@1: if (isset($theme->engine)) { webmaster@1: // Include the engine. webmaster@1: include_once './'. $theme->owner; webmaster@1: webmaster@1: $theme_engine = $theme->engine; webmaster@1: if (function_exists($theme_engine .'_init')) { webmaster@1: foreach ($base_theme as $base) { webmaster@1: call_user_func($theme_engine .'_init', $base); webmaster@1: } webmaster@1: call_user_func($theme_engine .'_init', $theme); webmaster@1: } webmaster@1: } webmaster@1: else { webmaster@1: // include non-engine theme files webmaster@1: foreach ($base_theme as $base) { webmaster@1: // Include the theme file or the engine. webmaster@1: if (!empty($base->owner)) { webmaster@1: include_once './'. $base->owner; webmaster@1: } webmaster@1: } webmaster@1: // and our theme gets one too. webmaster@1: if (!empty($theme->owner)) { webmaster@1: include_once './'. $theme->owner; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: $registry_callback($theme, $base_theme, $theme_engine); webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Retrieve the stored theme registry. If the theme registry is already webmaster@1: * in memory it will be returned; otherwise it will attempt to load the webmaster@1: * registry from cache. If this fails, it will construct the registry and webmaster@1: * cache it. webmaster@1: */ webmaster@1: function theme_get_registry($registry = NULL) { webmaster@1: static $theme_registry = NULL; webmaster@1: if (isset($registry)) { webmaster@1: $theme_registry = $registry; webmaster@1: } webmaster@1: webmaster@1: return $theme_registry; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Store the theme registry in memory. webmaster@1: */ webmaster@1: function _theme_set_registry($registry) { webmaster@1: // Pass through for setting of static variable. webmaster@1: return theme_get_registry($registry); webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Get the theme_registry cache from the database; if it doesn't exist, build webmaster@1: * it. webmaster@1: * webmaster@1: * @param $theme webmaster@1: * The loaded $theme object. webmaster@1: * @param $base_theme webmaster@1: * An array of loaded $theme objects representing the ancestor themes in webmaster@1: * oldest first order. webmaster@1: * @param theme_engine webmaster@1: * The name of the theme engine. webmaster@1: */ webmaster@1: function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL) { webmaster@1: // Check the theme registry cache; if it exists, use it. webmaster@1: $cache = cache_get("theme_registry:$theme->name", 'cache'); webmaster@1: if (isset($cache->data)) { webmaster@1: $registry = $cache->data; webmaster@1: } webmaster@1: else { webmaster@1: // If not, build one and cache it. webmaster@1: $registry = _theme_build_registry($theme, $base_theme, $theme_engine); webmaster@1: _theme_save_registry($theme, $registry); webmaster@1: } webmaster@1: _theme_set_registry($registry); webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Write the theme_registry cache into the database. webmaster@1: */ webmaster@1: function _theme_save_registry($theme, $registry) { webmaster@1: cache_set("theme_registry:$theme->name", $registry); webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Force the system to rebuild the theme registry; this should be called webmaster@1: * when modules are added to the system, or when a dynamic system needs webmaster@1: * to add more theme hooks. webmaster@1: */ webmaster@1: function drupal_rebuild_theme_registry() { webmaster@1: cache_clear_all('theme_registry', 'cache', TRUE); webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Process a single invocation of the theme hook. $type will be one webmaster@11: * of 'module', 'theme_engine', 'base_theme_engine', 'theme', or 'base_theme' webmaster@11: * and it tells us some important information. webmaster@1: * webmaster@1: * Because $cache is a reference, the cache will be continually webmaster@1: * expanded upon; new entries will replace old entries in the webmaster@1: * array_merge, but we are careful to ensure some data is carried webmaster@1: * forward, such as the arguments a theme hook needs. webmaster@1: * webmaster@1: * An override flag can be set for preprocess functions. When detected the webmaster@1: * cached preprocessors for the hook will not be merged with the newly set. webmaster@1: * This can be useful to themes and theme engines by giving them more control webmaster@1: * over how and when the preprocess functions are run. webmaster@1: */ webmaster@1: function _theme_process_registry(&$cache, $name, $type, $theme, $path) { webmaster@15: $result = array(); webmaster@1: $function = $name .'_theme'; webmaster@1: if (function_exists($function)) { webmaster@1: $result = $function($cache, $type, $theme, $path); webmaster@1: webmaster@1: foreach ($result as $hook => $info) { webmaster@1: $result[$hook]['type'] = $type; webmaster@1: $result[$hook]['theme path'] = $path; webmaster@1: // if function and file are left out, default to standard naming webmaster@1: // conventions. webmaster@1: if (!isset($info['template']) && !isset($info['function'])) { webmaster@1: $result[$hook]['function'] = ($type == 'module' ? 'theme_' : $name .'_') . $hook; webmaster@1: } webmaster@1: // If a path is set in the info, use what was set. Otherwise use the webmaster@1: // default path. This is mostly so system.module can declare theme webmaster@1: // functions on behalf of core .include files. webmaster@1: // All files are included to be safe. Conditionally included webmaster@1: // files can prevent them from getting registered. webmaster@1: if (isset($info['file']) && !isset($info['path'])) { webmaster@1: $result[$hook]['file'] = $path .'/'. $info['file']; webmaster@1: include_once($result[$hook]['file']); webmaster@1: } webmaster@1: elseif (isset($info['file']) && isset($info['path'])) { webmaster@1: include_once($info['path'] .'/'. $info['file']); webmaster@1: } webmaster@1: webmaster@1: if (isset($info['template']) && !isset($info['path'])) { webmaster@1: $result[$hook]['template'] = $path .'/'. $info['template']; webmaster@1: } webmaster@1: // If 'arguments' have been defined previously, carry them forward. webmaster@1: // This should happen if a theme overrides a Drupal defined theme webmaster@1: // function, for example. webmaster@1: if (!isset($info['arguments']) && isset($cache[$hook])) { webmaster@1: $result[$hook]['arguments'] = $cache[$hook]['arguments']; webmaster@1: } webmaster@1: // Likewise with theme paths. These are used for template naming suggestions. webmaster@1: // Theme implementations can occur in multiple paths. Suggestions should follow. webmaster@1: if (!isset($info['theme paths']) && isset($cache[$hook])) { webmaster@1: $result[$hook]['theme paths'] = $cache[$hook]['theme paths']; webmaster@1: } webmaster@1: // Check for sub-directories. webmaster@1: $result[$hook]['theme paths'][] = isset($info['path']) ? $info['path'] : $path; webmaster@1: webmaster@1: // Check for default _preprocess_ functions. Ensure arrayness. webmaster@1: if (!isset($info['preprocess functions']) || !is_array($info['preprocess functions'])) { webmaster@1: $info['preprocess functions'] = array(); webmaster@1: $prefixes = array(); webmaster@1: if ($type == 'module') { webmaster@1: // Default preprocessor prefix. webmaster@1: $prefixes[] = 'template'; webmaster@1: // Add all modules so they can intervene with their own preprocessors. This allows them webmaster@1: // to provide preprocess functions even if they are not the owner of the current hook. webmaster@1: $prefixes += module_list(); webmaster@1: } webmaster@11: elseif ($type == 'theme_engine' || $type == 'base_theme_engine') { webmaster@1: // Theme engines get an extra set that come before the normally named preprocessors. webmaster@1: $prefixes[] = $name .'_engine'; webmaster@1: // The theme engine also registers on behalf of the theme. The theme or engine name can be used. webmaster@1: $prefixes[] = $name; webmaster@1: $prefixes[] = $theme; webmaster@1: } webmaster@1: else { webmaster@1: // This applies when the theme manually registers their own preprocessors. webmaster@1: $prefixes[] = $name; webmaster@1: } webmaster@1: webmaster@1: foreach ($prefixes as $prefix) { webmaster@1: if (function_exists($prefix .'_preprocess')) { webmaster@1: $info['preprocess functions'][] = $prefix .'_preprocess'; webmaster@1: } webmaster@7: webmaster@1: if (function_exists($prefix .'_preprocess_'. $hook)) { webmaster@1: $info['preprocess functions'][] = $prefix .'_preprocess_'. $hook; webmaster@1: } webmaster@7: webmaster@7: if (!empty($info['original hook']) && function_exists($prefix .'_preprocess_'. $info['original hook'])) { webmaster@7: $info['preprocess functions'][] = $prefix .'_preprocess_'. $info['original hook']; webmaster@7: } webmaster@1: } webmaster@1: } webmaster@1: // Check for the override flag and prevent the cached preprocess functions from being used. webmaster@1: // This allows themes or theme engines to remove preprocessors set earlier in the registry build. webmaster@1: if (!empty($info['override preprocess functions'])) { webmaster@1: // Flag not needed inside the registry. webmaster@1: unset($result[$hook]['override preprocess functions']); webmaster@1: } webmaster@1: elseif (isset($cache[$hook]['preprocess functions']) && is_array($cache[$hook]['preprocess functions'])) { webmaster@1: $info['preprocess functions'] = array_merge($cache[$hook]['preprocess functions'], $info['preprocess functions']); webmaster@1: } webmaster@7: elseif (isset($info['original hook']) && isset($cache[$info['original hook']]['preprocess functions']) && is_array($cache[$info['original hook']]['preprocess functions'])) { webmaster@7: $info['preprocess functions'] = array_merge($cache[$info['original hook']]['preprocess functions'], $info['preprocess functions']); webmaster@7: } webmaster@1: $result[$hook]['preprocess functions'] = $info['preprocess functions']; webmaster@1: } webmaster@1: webmaster@1: // Merge the newly created theme hooks into the existing cache. webmaster@1: $cache = array_merge($cache, $result); webmaster@1: } webmaster@15: webmaster@15: // Let themes have preprocess functions even if they didn't register a template. webmaster@15: if ($type == 'theme' || $type == 'base_theme') { webmaster@15: foreach ($cache as $hook => $info) { webmaster@15: // Check only if it's a template and not registered by the theme or engine. webmaster@15: if (!empty($info['template']) && empty($result[$hook])) { webmaster@15: if (!isset($info['preprocess functions'])) { webmaster@15: $cache[$hook]['preprocess functions'] = array(); webmaster@15: } webmaster@15: if (function_exists($name .'_preprocess')) { webmaster@15: $cache[$hook]['preprocess functions'][] = $name .'_preprocess'; webmaster@15: } webmaster@15: if (function_exists($name .'_preprocess_'. $hook)) { webmaster@15: $cache[$hook]['preprocess functions'][] = $name .'_preprocess_'. $hook; webmaster@15: } webmaster@15: // Ensure uniqueness. webmaster@15: $cache[$hook]['preprocess functions'] = array_unique($cache[$hook]['preprocess functions']); webmaster@15: } webmaster@15: } webmaster@15: } webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Rebuild the hook theme_registry cache. webmaster@1: * webmaster@1: * @param $theme webmaster@1: * The loaded $theme object. webmaster@1: * @param $base_theme webmaster@1: * An array of loaded $theme objects representing the ancestor themes in webmaster@1: * oldest first order. webmaster@1: * @param theme_engine webmaster@1: * The name of the theme engine. webmaster@1: */ webmaster@1: function _theme_build_registry($theme, $base_theme, $theme_engine) { webmaster@1: $cache = array(); webmaster@1: // First, process the theme hooks advertised by modules. This will webmaster@1: // serve as the basic registry. webmaster@1: foreach (module_implements('theme') as $module) { webmaster@1: _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module)); webmaster@1: } webmaster@1: webmaster@1: // Process each base theme. webmaster@1: foreach ($base_theme as $base) { webmaster@11: // If the base theme uses a theme engine, process its hooks. webmaster@1: $base_path = dirname($base->filename); webmaster@1: if ($theme_engine) { webmaster@1: _theme_process_registry($cache, $theme_engine, 'base_theme_engine', $base->name, $base_path); webmaster@1: } webmaster@1: _theme_process_registry($cache, $base->name, 'base_theme', $base->name, $base_path); webmaster@1: } webmaster@1: webmaster@1: // And then the same thing, but for the theme. webmaster@1: if ($theme_engine) { webmaster@1: _theme_process_registry($cache, $theme_engine, 'theme_engine', $theme->name, dirname($theme->filename)); webmaster@1: } webmaster@1: webmaster@1: // Finally, hooks provided by the theme itself. webmaster@1: _theme_process_registry($cache, $theme->name, 'theme', $theme->name, dirname($theme->filename)); webmaster@1: webmaster@1: // Let modules alter the registry webmaster@1: drupal_alter('theme_registry', $cache); webmaster@1: return $cache; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Provides a list of currently available themes. webmaster@1: * webmaster@1: * If the database is active then it will be retrieved from the database. webmaster@1: * Otherwise it will retrieve a new list. webmaster@1: * webmaster@1: * @param $refresh webmaster@1: * Whether to reload the list of themes from the database. webmaster@1: * @return webmaster@1: * An array of the currently available themes. webmaster@1: */ webmaster@1: function list_themes($refresh = FALSE) { webmaster@1: static $list = array(); webmaster@1: webmaster@1: if ($refresh) { webmaster@1: $list = array(); webmaster@1: } webmaster@1: webmaster@1: if (empty($list)) { webmaster@1: $list = array(); webmaster@1: $themes = array(); webmaster@1: // Extract from the database only when it is available. webmaster@1: // Also check that the site is not in the middle of an install or update. webmaster@1: if (db_is_active() && !defined('MAINTENANCE_MODE')) { webmaster@1: $result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme'); webmaster@1: while ($theme = db_fetch_object($result)) { webmaster@1: if (file_exists($theme->filename)) { webmaster@1: $theme->info = unserialize($theme->info); webmaster@1: $themes[] = $theme; webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: else { webmaster@1: // Scan the installation when the database should not be read. webmaster@1: $themes = _system_theme_data(); webmaster@1: } webmaster@1: webmaster@1: foreach ($themes as $theme) { webmaster@1: foreach ($theme->info['stylesheets'] as $media => $stylesheets) { webmaster@1: foreach ($stylesheets as $stylesheet => $path) { webmaster@7: $theme->stylesheets[$media][$stylesheet] = $path; webmaster@1: } webmaster@1: } webmaster@1: foreach ($theme->info['scripts'] as $script => $path) { webmaster@1: if (file_exists($path)) { webmaster@1: $theme->scripts[$script] = $path; webmaster@1: } webmaster@1: } webmaster@1: if (isset($theme->info['engine'])) { webmaster@1: $theme->engine = $theme->info['engine']; webmaster@1: } webmaster@1: if (isset($theme->info['base theme'])) { webmaster@1: $theme->base_theme = $theme->info['base theme']; webmaster@1: } webmaster@1: // Status is normally retrieved from the database. Add zero values when webmaster@1: // read from the installation directory to prevent notices. webmaster@1: if (!isset($theme->status)) { webmaster@1: $theme->status = 0; webmaster@1: } webmaster@1: $list[$theme->name] = $theme; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: return $list; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Generate the themed output. webmaster@1: * webmaster@1: * All requests for theme hooks must go through this function. It examines webmaster@1: * the request and routes it to the appropriate theme function. The theme webmaster@1: * registry is checked to determine which implementation to use, which may webmaster@1: * be a function or a template. webmaster@1: * webmaster@1: * If the implementation is a function, it is executed and its return value webmaster@1: * passed along. webmaster@1: * webmaster@1: * If the implementation is a template, the arguments are converted to a webmaster@1: * $variables array. This array is then modified by the module implementing webmaster@1: * the hook, theme engine (if applicable) and the theme. The following webmaster@1: * functions may be used to modify the $variables array. They are processed in webmaster@1: * this order when available: webmaster@1: * webmaster@1: * - template_preprocess(&$variables) webmaster@1: * This sets a default set of variables for all template implementations. webmaster@1: * webmaster@1: * - template_preprocess_HOOK(&$variables) webmaster@1: * This is the first preprocessor called specific to the hook; it should be webmaster@1: * implemented by the module that registers it. webmaster@1: * webmaster@1: * - MODULE_preprocess(&$variables) webmaster@1: * This will be called for all templates; it should only be used if there webmaster@1: * is a real need. It's purpose is similar to template_preprocess(). webmaster@1: * webmaster@1: * - MODULE_preprocess_HOOK(&$variables) webmaster@1: * This is for modules that want to alter or provide extra variables for webmaster@1: * theming hooks not registered to itself. For example, if a module named webmaster@1: * "foo" wanted to alter the $submitted variable for the hook "node" a webmaster@1: * preprocess function of foo_preprocess_node() can be created to intercept webmaster@1: * and alter the variable. webmaster@1: * webmaster@1: * - ENGINE_engine_preprocess(&$variables) webmaster@1: * This function should only be implemented by theme engines and exists webmaster@1: * so that it can set necessary variables for all hooks. webmaster@1: * webmaster@1: * - ENGINE_engine_preprocess_HOOK(&$variables) webmaster@1: * This is the same as the previous function, but it is called for a single webmaster@1: * theming hook. webmaster@1: * webmaster@1: * - ENGINE_preprocess(&$variables) webmaster@1: * This is meant to be used by themes that utilize a theme engine. It is webmaster@1: * provided so that the preprocessor is not locked into a specific theme. webmaster@1: * This makes it easy to share and transport code but theme authors must be webmaster@1: * careful to prevent fatal re-declaration errors when using sub-themes that webmaster@1: * have their own preprocessor named exactly the same as its base theme. In webmaster@1: * the default theme engine (PHPTemplate), sub-themes will load their own webmaster@1: * template.php file in addition to the one used for its parent theme. This webmaster@1: * increases the risk for these errors. A good practice is to use the engine webmaster@1: * name for the base theme and the theme name for the sub-themes to minimize webmaster@1: * this possibility. webmaster@1: * webmaster@1: * - ENGINE_preprocess_HOOK(&$variables) webmaster@1: * The same applies from the previous function, but it is called for a webmaster@1: * specific hook. webmaster@1: * webmaster@1: * - THEME_preprocess(&$variables) webmaster@1: * These functions are based upon the raw theme; they should primarily be webmaster@1: * used by themes that do not use an engine or by sub-themes. It serves the webmaster@1: * same purpose as ENGINE_preprocess(). webmaster@1: * webmaster@1: * - THEME_preprocess_HOOK(&$variables) webmaster@1: * The same applies from the previous function, but it is called for a webmaster@1: * specific hook. webmaster@1: * webmaster@1: * There are two special variables that these hooks can set: webmaster@1: * 'template_file' and 'template_files'. These will be merged together webmaster@1: * to form a list of 'suggested' alternate template files to use, in webmaster@1: * reverse order of priority. template_file will always be a higher webmaster@1: * priority than items in template_files. theme() will then look for these webmaster@1: * files, one at a time, and use the first one webmaster@1: * that exists. webmaster@1: * @param $hook webmaster@1: * The name of the theme function to call. May be an array, in which webmaster@1: * case the first hook that actually has an implementation registered webmaster@1: * will be used. This can be used to choose 'fallback' theme implementations, webmaster@1: * so that if the specific theme hook isn't implemented anywhere, a more webmaster@1: * generic one will be used. This can allow themes to create specific theme webmaster@1: * implementations for named objects. webmaster@1: * @param ... webmaster@1: * Additional arguments to pass along to the theme function. webmaster@1: * @return webmaster@1: * An HTML string that generates the themed output. webmaster@1: */ webmaster@1: function theme() { webmaster@1: $args = func_get_args(); webmaster@1: $hook = array_shift($args); webmaster@1: webmaster@1: static $hooks = NULL; webmaster@1: if (!isset($hooks)) { webmaster@1: init_theme(); webmaster@1: $hooks = theme_get_registry(); webmaster@1: } webmaster@1: webmaster@1: if (is_array($hook)) { webmaster@1: foreach ($hook as $candidate) { webmaster@1: if (isset($hooks[$candidate])) { webmaster@1: break; webmaster@1: } webmaster@1: } webmaster@1: $hook = $candidate; webmaster@1: } webmaster@1: webmaster@1: if (!isset($hooks[$hook])) { webmaster@1: return; webmaster@1: } webmaster@1: webmaster@1: $info = $hooks[$hook]; webmaster@1: global $theme_path; webmaster@1: $temp = $theme_path; webmaster@1: // point path_to_theme() to the currently used theme path: webmaster@1: $theme_path = $hooks[$hook]['theme path']; webmaster@1: webmaster@1: // Include a file if the theme function or preprocess function is held elsewhere. webmaster@1: if (!empty($info['file'])) { webmaster@1: $include_file = $info['file']; webmaster@1: if (isset($info['path'])) { webmaster@1: $include_file = $info['path'] .'/'. $include_file; webmaster@1: } webmaster@1: include_once($include_file); webmaster@1: } webmaster@1: if (isset($info['function'])) { webmaster@1: // The theme call is a function. webmaster@1: $output = call_user_func_array($info['function'], $args); webmaster@1: } webmaster@1: else { webmaster@1: // The theme call is a template. webmaster@1: $variables = array( webmaster@1: 'template_files' => array() webmaster@1: ); webmaster@1: if (!empty($info['arguments'])) { webmaster@1: $count = 0; webmaster@1: foreach ($info['arguments'] as $name => $default) { webmaster@1: $variables[$name] = isset($args[$count]) ? $args[$count] : $default; webmaster@1: $count++; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: // default render function and extension. webmaster@1: $render_function = 'theme_render_template'; webmaster@1: $extension = '.tpl.php'; webmaster@1: webmaster@1: // Run through the theme engine variables, if necessary webmaster@1: global $theme_engine; webmaster@1: if (isset($theme_engine)) { webmaster@1: // If theme or theme engine is implementing this, it may have webmaster@1: // a different extension and a different renderer. webmaster@1: if ($hooks[$hook]['type'] != 'module') { webmaster@1: if (function_exists($theme_engine .'_render_template')) { webmaster@1: $render_function = $theme_engine .'_render_template'; webmaster@1: } webmaster@1: $extension_function = $theme_engine .'_extension'; webmaster@1: if (function_exists($extension_function)) { webmaster@1: $extension = $extension_function(); webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: if (isset($info['preprocess functions']) && is_array($info['preprocess functions'])) { webmaster@1: // This construct ensures that we can keep a reference through webmaster@1: // call_user_func_array. webmaster@1: $args = array(&$variables, $hook); webmaster@1: foreach ($info['preprocess functions'] as $preprocess_function) { webmaster@1: if (function_exists($preprocess_function)) { webmaster@1: call_user_func_array($preprocess_function, $args); webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: // Get suggestions for alternate templates out of the variables webmaster@1: // that were set. This lets us dynamically choose a template webmaster@1: // from a list. The order is FILO, so this array is ordered from webmaster@1: // least appropriate first to most appropriate last. webmaster@1: $suggestions = array(); webmaster@1: webmaster@1: if (isset($variables['template_files'])) { webmaster@1: $suggestions = $variables['template_files']; webmaster@1: } webmaster@1: if (isset($variables['template_file'])) { webmaster@1: $suggestions[] = $variables['template_file']; webmaster@1: } webmaster@1: webmaster@1: if ($suggestions) { webmaster@1: $template_file = drupal_discover_template($info['theme paths'], $suggestions, $extension); webmaster@1: } webmaster@1: webmaster@1: if (empty($template_file)) { webmaster@1: $template_file = $hooks[$hook]['template'] . $extension; webmaster@1: if (isset($hooks[$hook]['path'])) { webmaster@1: $template_file = $hooks[$hook]['path'] .'/'. $template_file; webmaster@1: } webmaster@1: } webmaster@1: $output = $render_function($template_file, $variables); webmaster@1: } webmaster@1: // restore path_to_theme() webmaster@1: $theme_path = $temp; webmaster@1: return $output; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Choose which template file to actually render. These are all suggested webmaster@1: * templates from themes and modules. Theming implementations can occur on webmaster@1: * multiple levels. All paths are checked to account for this. webmaster@1: */ webmaster@1: function drupal_discover_template($paths, $suggestions, $extension = '.tpl.php') { webmaster@1: global $theme_engine; webmaster@1: webmaster@1: // Loop through all paths and suggestions in FIFO order. webmaster@1: $suggestions = array_reverse($suggestions); webmaster@1: $paths = array_reverse($paths); webmaster@1: foreach ($suggestions as $suggestion) { webmaster@1: if (!empty($suggestion)) { webmaster@1: foreach ($paths as $path) { webmaster@1: if (file_exists($file = $path .'/'. $suggestion . $extension)) { webmaster@1: return $file; webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: /** webmaster@13: * Return the path to the current themed element. webmaster@13: * webmaster@13: * It can point to the active theme or the module handling a themed implementation. webmaster@13: * For example, when invoked within the scope of a theming call it will depend webmaster@13: * on where the theming function is handled. If implemented from a module, it webmaster@13: * will point to the module. If implemented from the active theme, it will point webmaster@13: * to the active theme. When called outside the scope of a theming call, it will webmaster@13: * always point to the active theme. webmaster@1: */ webmaster@1: function path_to_theme() { webmaster@1: global $theme_path; webmaster@1: webmaster@1: if (!isset($theme_path)) { webmaster@1: init_theme(); webmaster@1: } webmaster@1: webmaster@1: return $theme_path; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Find overridden theme functions. Called by themes and/or theme engines to webmaster@1: * easily discover theme functions. webmaster@1: * webmaster@1: * @param $cache webmaster@1: * The existing cache of theme hooks to test against. webmaster@1: * @param $prefixes webmaster@1: * An array of prefixes to test, in reverse order of importance. webmaster@1: * webmaster@1: * @return $templates webmaster@1: * The functions found, suitable for returning from hook_theme; webmaster@1: */ webmaster@1: function drupal_find_theme_functions($cache, $prefixes) { webmaster@1: $templates = array(); webmaster@1: $functions = get_defined_functions(); webmaster@1: webmaster@1: foreach ($cache as $hook => $info) { webmaster@1: foreach ($prefixes as $prefix) { webmaster@1: if (!empty($info['pattern'])) { webmaster@1: $matches = preg_grep('/^'. $prefix .'_'. $info['pattern'] .'/', $functions['user']); webmaster@1: if ($matches) { webmaster@1: foreach ($matches as $match) { webmaster@1: $new_hook = str_replace($prefix .'_', '', $match); webmaster@1: $templates[$new_hook] = array( webmaster@1: 'function' => $match, webmaster@1: 'arguments' => $info['arguments'], webmaster@7: 'original hook' => $hook, webmaster@1: ); webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: if (function_exists($prefix .'_'. $hook)) { webmaster@1: $templates[$hook] = array( webmaster@1: 'function' => $prefix .'_'. $hook, webmaster@1: ); webmaster@15: // Ensure that the pattern is maintained from base themes to its sub-themes. webmaster@15: // Each sub-theme will have their functions scanned so the pattern must be webmaster@15: // held for subsequent runs. webmaster@15: if (isset($info['pattern'])) { webmaster@15: $templates[$hook]['pattern'] = $info['pattern']; webmaster@15: } webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: return $templates; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Find overridden theme templates. Called by themes and/or theme engines to webmaster@1: * easily discover templates. webmaster@1: * webmaster@1: * @param $cache webmaster@1: * The existing cache of theme hooks to test against. webmaster@1: * @param $extension webmaster@1: * The extension that these templates will have. webmaster@1: * @param $path webmaster@1: * The path to search. webmaster@1: */ webmaster@1: function drupal_find_theme_templates($cache, $extension, $path) { webmaster@1: $templates = array(); webmaster@1: webmaster@1: // Collect paths to all sub-themes grouped by base themes. These will be webmaster@1: // used for filtering. This allows base themes to have sub-themes in its webmaster@1: // folder hierarchy without affecting the base themes template discovery. webmaster@1: $theme_paths = array(); webmaster@1: foreach (list_themes() as $theme_info) { webmaster@1: if (!empty($theme_info->base_theme)) { webmaster@1: $theme_paths[$theme_info->base_theme][$theme_info->name] = dirname($theme_info->filename); webmaster@1: } webmaster@1: } webmaster@1: foreach ($theme_paths as $basetheme => $subthemes) { webmaster@1: foreach ($subthemes as $subtheme => $subtheme_path) { webmaster@1: if (isset($theme_paths[$subtheme])) { webmaster@1: $theme_paths[$basetheme] = array_merge($theme_paths[$basetheme], $theme_paths[$subtheme]); webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: global $theme; webmaster@1: $subtheme_paths = isset($theme_paths[$theme]) ? $theme_paths[$theme] : array(); webmaster@1: webmaster@1: // Escape the periods in the extension. webmaster@1: $regex = str_replace('.', '\.', $extension) .'$'; webmaster@1: // Because drupal_system_listing works the way it does, we check for real webmaster@1: // templates separately from checking for patterns. webmaster@1: $files = drupal_system_listing($regex, $path, 'name', 0); webmaster@1: foreach ($files as $template => $file) { webmaster@1: // Ignore sub-theme templates for the current theme. webmaster@1: if (strpos($file->filename, str_replace($subtheme_paths, '', $file->filename)) !== 0) { webmaster@1: continue; webmaster@1: } webmaster@1: // Chop off the remaining extensions if there are any. $template already webmaster@1: // has the rightmost extension removed, but there might still be more, webmaster@1: // such as with .tpl.php, which still has .tpl in $template at this point. webmaster@1: if (($pos = strpos($template, '.')) !== FALSE) { webmaster@1: $template = substr($template, 0, $pos); webmaster@1: } webmaster@1: // Transform - in filenames to _ to match function naming scheme webmaster@1: // for the purposes of searching. webmaster@1: $hook = strtr($template, '-', '_'); webmaster@1: if (isset($cache[$hook])) { webmaster@1: $templates[$hook] = array( webmaster@1: 'template' => $template, webmaster@1: 'path' => dirname($file->filename), webmaster@1: ); webmaster@1: } webmaster@15: // Ensure that the pattern is maintained from base themes to its sub-themes. webmaster@15: // Each sub-theme will have their templates scanned so the pattern must be webmaster@15: // held for subsequent runs. webmaster@15: if (isset($cache[$hook]['pattern'])) { webmaster@15: $templates[$hook]['pattern'] = $cache[$hook]['pattern']; webmaster@15: } webmaster@1: } webmaster@1: webmaster@1: $patterns = array_keys($files); webmaster@1: webmaster@1: foreach ($cache as $hook => $info) { webmaster@1: if (!empty($info['pattern'])) { webmaster@1: // Transform _ in pattern to - to match file naming scheme webmaster@1: // for the purposes of searching. webmaster@1: $pattern = strtr($info['pattern'], '_', '-'); webmaster@1: webmaster@1: $matches = preg_grep('/^'. $pattern .'/', $patterns); webmaster@1: if ($matches) { webmaster@1: foreach ($matches as $match) { webmaster@1: $file = substr($match, 0, strpos($match, '.')); webmaster@1: // Put the underscores back in for the hook name and register this pattern. webmaster@1: $templates[strtr($file, '-', '_')] = array( webmaster@1: 'template' => $file, webmaster@1: 'path' => dirname($files[$match]->filename), webmaster@1: 'arguments' => $info['arguments'], webmaster@7: 'original hook' => $hook, webmaster@1: ); webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: return $templates; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Retrieve an associative array containing the settings for a theme. webmaster@1: * webmaster@1: * The final settings are arrived at by merging the default settings, webmaster@1: * the site-wide settings, and the settings defined for the specific theme. webmaster@1: * If no $key was specified, only the site-wide theme defaults are retrieved. webmaster@1: * webmaster@1: * The default values for each of settings are also defined in this function. webmaster@1: * To add new settings, add their default values here, and then add form elements webmaster@1: * to system_theme_settings() in system.module. webmaster@1: * webmaster@1: * @param $key webmaster@1: * The template/style value for a given theme. webmaster@1: * webmaster@1: * @return webmaster@1: * An associative array containing theme settings. webmaster@1: */ webmaster@1: function theme_get_settings($key = NULL) { webmaster@1: $defaults = array( webmaster@1: 'mission' => '', webmaster@1: 'default_logo' => 1, webmaster@1: 'logo_path' => '', webmaster@1: 'default_favicon' => 1, webmaster@1: 'favicon_path' => '', webmaster@1: 'primary_links' => 1, webmaster@1: 'secondary_links' => 1, webmaster@1: 'toggle_logo' => 1, webmaster@1: 'toggle_favicon' => 1, webmaster@1: 'toggle_name' => 1, webmaster@1: 'toggle_search' => 1, webmaster@1: 'toggle_slogan' => 0, webmaster@1: 'toggle_mission' => 1, webmaster@1: 'toggle_node_user_picture' => 0, webmaster@1: 'toggle_comment_user_picture' => 0, webmaster@1: 'toggle_primary_links' => 1, webmaster@1: 'toggle_secondary_links' => 1, webmaster@1: ); webmaster@1: webmaster@1: if (module_exists('node')) { webmaster@1: foreach (node_get_types() as $type => $name) { webmaster@1: $defaults['toggle_node_info_'. $type] = 1; webmaster@1: } webmaster@1: } webmaster@1: $settings = array_merge($defaults, variable_get('theme_settings', array())); webmaster@1: webmaster@1: if ($key) { webmaster@1: $settings = array_merge($settings, variable_get(str_replace('/', '_', 'theme_'. $key .'_settings'), array())); webmaster@1: } webmaster@1: webmaster@1: // Only offer search box if search.module is enabled. webmaster@1: if (!module_exists('search') || !user_access('search content')) { webmaster@1: $settings['toggle_search'] = 0; webmaster@1: } webmaster@1: webmaster@1: return $settings; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Retrieve a setting for the current theme. webmaster@1: * This function is designed for use from within themes & engines webmaster@1: * to determine theme settings made in the admin interface. webmaster@1: * webmaster@1: * Caches values for speed (use $refresh = TRUE to refresh cache) webmaster@1: * webmaster@1: * @param $setting_name webmaster@1: * The name of the setting to be retrieved. webmaster@1: * webmaster@1: * @param $refresh webmaster@1: * Whether to reload the cache of settings. webmaster@1: * webmaster@1: * @return webmaster@1: * The value of the requested setting, NULL if the setting does not exist. webmaster@1: */ webmaster@1: function theme_get_setting($setting_name, $refresh = FALSE) { webmaster@1: global $theme_key; webmaster@1: static $settings; webmaster@1: webmaster@1: if (empty($settings) || $refresh) { webmaster@1: $settings = theme_get_settings($theme_key); webmaster@1: webmaster@1: $themes = list_themes(); webmaster@1: $theme_object = $themes[$theme_key]; webmaster@1: webmaster@1: if ($settings['mission'] == '') { webmaster@1: $settings['mission'] = variable_get('site_mission', ''); webmaster@1: } webmaster@1: webmaster@1: if (!$settings['toggle_mission']) { webmaster@1: $settings['mission'] = ''; webmaster@1: } webmaster@1: webmaster@1: if ($settings['toggle_logo']) { webmaster@1: if ($settings['default_logo']) { webmaster@1: $settings['logo'] = base_path() . dirname($theme_object->filename) .'/logo.png'; webmaster@1: } webmaster@1: elseif ($settings['logo_path']) { webmaster@1: $settings['logo'] = base_path() . $settings['logo_path']; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: if ($settings['toggle_favicon']) { webmaster@1: if ($settings['default_favicon']) { webmaster@1: if (file_exists($favicon = dirname($theme_object->filename) .'/favicon.ico')) { webmaster@1: $settings['favicon'] = base_path() . $favicon; webmaster@1: } webmaster@1: else { webmaster@1: $settings['favicon'] = base_path() .'misc/favicon.ico'; webmaster@1: } webmaster@1: } webmaster@1: elseif ($settings['favicon_path']) { webmaster@1: $settings['favicon'] = base_path() . $settings['favicon_path']; webmaster@1: } webmaster@1: else { webmaster@1: $settings['toggle_favicon'] = FALSE; webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Render a system default template, which is essentially a PHP template. webmaster@1: * webmaster@11: * @param $template_file webmaster@11: * The filename of the template to render. Note that this will overwrite webmaster@11: * anything stored in $variables['template_file'] if using a preprocess hook. webmaster@1: * @param $variables webmaster@1: * A keyed array of variables that will appear in the output. webmaster@1: * webmaster@1: * @return webmaster@1: * The output generated by the template. webmaster@1: */ webmaster@11: function theme_render_template($template_file, $variables) { webmaster@1: extract($variables, EXTR_SKIP); // Extract the variables to a local namespace webmaster@1: ob_start(); // Start output buffering webmaster@11: include "./$template_file"; // Include the template file webmaster@1: $contents = ob_get_contents(); // Get the contents of the buffer webmaster@1: ob_end_clean(); // End buffering and discard webmaster@1: return $contents; // Return the contents webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * @defgroup themeable Default theme implementations webmaster@1: * @{ webmaster@1: * Functions and templates that present output to the user, and can be webmaster@1: * implemented by themes. webmaster@1: * webmaster@1: * Drupal's presentation layer is a pluggable system known as the theme webmaster@1: * layer. Each theme can take control over most of Drupal's output, and webmaster@1: * has complete control over the CSS. webmaster@1: * webmaster@1: * Inside Drupal, the theme layer is utilized by the use of the theme() webmaster@1: * function, which is passed the name of a component (the theme hook) webmaster@1: * and several arguments. For example, theme('table', $header, $rows); webmaster@1: * Additionally, the theme() function can take an array of theme webmaster@1: * hooks, which can be used to provide 'fallback' implementations to webmaster@1: * allow for more specific control of output. For example, the function: webmaster@1: * theme(array('table__foo', 'table'), $header, $rows) would look to see if webmaster@1: * 'table__foo' is registered anywhere; if it is not, it would 'fall back' webmaster@1: * to the generic 'table' implementation. This can be used to attach specific webmaster@1: * theme functions to named objects, allowing the themer more control over webmaster@1: * specific types of output. webmaster@1: * webmaster@1: * As of Drupal 6, every theme hook is required to be registered by the webmaster@1: * module that owns it, so that Drupal can tell what to do with it and webmaster@1: * to make it simple for themes to identify and override the behavior webmaster@1: * for these calls. webmaster@1: * webmaster@1: * The theme hooks are registered via hook_theme(), which returns an webmaster@1: * array of arrays with information about the hook. It describes the webmaster@1: * arguments the function or template will need, and provides webmaster@1: * defaults for the template in case they are not filled in. If the default webmaster@1: * implementation is a function, by convention it is named theme_HOOK(). webmaster@1: * webmaster@7: * Each module should provide a default implementation for theme_hooks that webmaster@1: * it registers. This implementation may be either a function or a template; webmaster@1: * if it is a function it must be specified via hook_theme(). By convention, webmaster@1: * default implementations of theme hooks are named theme_HOOK. Default webmaster@1: * template implementations are stored in the module directory. webmaster@1: * webmaster@1: * Drupal's default template renderer is a simple PHP parsing engine that webmaster@1: * includes the template and stores the output. Drupal's theme engines webmaster@1: * can provide alternate template engines, such as XTemplate, Smarty and webmaster@1: * PHPTal. The most common template engine is PHPTemplate (included with webmaster@1: * Drupal and implemented in phptemplate.engine, which uses Drupal's default webmaster@1: * template renderer. webmaster@1: * webmaster@1: * In order to create theme-specific implementations of these hooks, webmaster@1: * themes can implement their own version of theme hooks, either as functions webmaster@1: * or templates. These implementations will be used instead of the default webmaster@1: * implementation. If using a pure .theme without an engine, the .theme is webmaster@1: * required to implement its own version of hook_theme() to tell Drupal what webmaster@1: * it is implementing; themes utilizing an engine will have their well-named webmaster@1: * theming functions automatically registered for them. While this can vary webmaster@1: * based upon the theme engine, the standard set by phptemplate is that theme webmaster@1: * functions should be named either phptemplate_HOOK or THEMENAME_HOOK. For webmaster@1: * example, for Drupal's default theme (Garland) to implement the 'table' hook, webmaster@1: * the phptemplate.engine would find phptemplate_table() or garland_table(). webmaster@1: * The ENGINE_HOOK() syntax is preferred, as this can be used by sub-themes webmaster@1: * (which are themes that share code but use different stylesheets). webmaster@1: * webmaster@1: * The theme system is described and defined in theme.inc. webmaster@1: * webmaster@1: * @see theme() webmaster@1: * @see hook_theme() webmaster@1: */ webmaster@1: webmaster@1: /** webmaster@1: * Formats text for emphasized display in a placeholder inside a sentence. webmaster@1: * Used automatically by t(). webmaster@1: * webmaster@1: * @param $text webmaster@1: * The text to format (plain-text). webmaster@1: * @return webmaster@1: * The formatted text (html). webmaster@1: */ webmaster@1: function theme_placeholder($text) { webmaster@1: return ''. check_plain($text) .''; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed set of status and/or error messages. The messages are grouped webmaster@1: * by type. webmaster@1: * webmaster@1: * @param $display webmaster@1: * (optional) Set to 'status' or 'error' to display only messages of that type. webmaster@1: * webmaster@1: * @return webmaster@1: * A string containing the messages. webmaster@1: */ webmaster@1: function theme_status_messages($display = NULL) { webmaster@1: $output = ''; webmaster@1: foreach (drupal_get_messages($display) as $type => $messages) { webmaster@1: $output .= "
\n"; webmaster@1: if (count($messages) > 1) { webmaster@1: $output .= " \n"; webmaster@1: } webmaster@1: else { webmaster@1: $output .= $messages[0]; webmaster@1: } webmaster@1: $output .= "
\n"; webmaster@1: } webmaster@1: return $output; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed set of links. webmaster@1: * webmaster@1: * @param $links webmaster@1: * A keyed array of links to be themed. webmaster@1: * @param $attributes webmaster@1: * A keyed array of attributes webmaster@1: * @return webmaster@1: * A string containing an unordered list of links. webmaster@1: */ webmaster@1: function theme_links($links, $attributes = array('class' => 'links')) { webmaster@1: $output = ''; webmaster@1: webmaster@1: if (count($links) > 0) { webmaster@1: $output = ''; webmaster@1: webmaster@1: $num_links = count($links); webmaster@1: $i = 1; webmaster@1: webmaster@1: foreach ($links as $key => $link) { webmaster@1: $class = $key; webmaster@1: webmaster@1: // Add first, last and active classes to the list of links to help out themers. webmaster@1: if ($i == 1) { webmaster@1: $class .= ' first'; webmaster@1: } webmaster@1: if ($i == $num_links) { webmaster@1: $class .= ' last'; webmaster@1: } webmaster@5: if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '' && drupal_is_front_page()))) { webmaster@1: $class .= ' active'; webmaster@1: } webmaster@7: $output .= ' $class)) .'>'; webmaster@1: webmaster@1: if (isset($link['href'])) { webmaster@1: // Pass in $link as $options, they share the same keys. webmaster@1: $output .= l($link['title'], $link['href'], $link); webmaster@1: } webmaster@1: else if (!empty($link['title'])) { webmaster@1: // Some links are actually not links, but we wrap these in for adding title and class attributes webmaster@1: if (empty($link['html'])) { webmaster@1: $link['title'] = check_plain($link['title']); webmaster@1: } webmaster@1: $span_attributes = ''; webmaster@1: if (isset($link['attributes'])) { webmaster@1: $span_attributes = drupal_attributes($link['attributes']); webmaster@1: } webmaster@1: $output .= ''. $link['title'] .''; webmaster@1: } webmaster@1: webmaster@1: $i++; webmaster@1: $output .= "\n"; webmaster@1: } webmaster@1: webmaster@1: $output .= ''; webmaster@1: } webmaster@1: webmaster@1: return $output; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed image. webmaster@1: * webmaster@1: * @param $path webmaster@1: * Either the path of the image file (relative to base_path()) or a full URL. webmaster@1: * @param $alt webmaster@1: * The alternative text for text-based browsers. webmaster@1: * @param $title webmaster@1: * The title text is displayed when the image is hovered in some popular browsers. webmaster@1: * @param $attributes webmaster@1: * Associative array of attributes to be placed in the img tag. webmaster@1: * @param $getsize webmaster@1: * If set to TRUE, the image's dimension are fetched and added as width/height attributes. webmaster@1: * @return webmaster@1: * A string containing the image tag. webmaster@1: */ webmaster@1: function theme_image($path, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE) { webmaster@1: if (!$getsize || (is_file($path) && (list($width, $height, $type, $image_attributes) = @getimagesize($path)))) { webmaster@1: $attributes = drupal_attributes($attributes); webmaster@1: $url = (url($path) == $path) ? $path : (base_path() . $path); webmaster@1: return ''. check_plain($alt) .''; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed breadcrumb trail. webmaster@1: * webmaster@1: * @param $breadcrumb webmaster@1: * An array containing the breadcrumb links. webmaster@1: * @return a string containing the breadcrumb output. webmaster@1: */ webmaster@1: function theme_breadcrumb($breadcrumb) { webmaster@1: if (!empty($breadcrumb)) { webmaster@1: return ''; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed help message. webmaster@1: * webmaster@1: * @return a string containing the helptext for the current page. webmaster@1: */ webmaster@1: function theme_help() { webmaster@1: if ($help = menu_get_active_help()) { webmaster@1: return '
'. $help .'
'; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed submenu, typically displayed under the tabs. webmaster@1: * webmaster@1: * @param $links webmaster@1: * An array of links. webmaster@1: */ webmaster@1: function theme_submenu($links) { webmaster@1: return ''; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed table. webmaster@1: * webmaster@1: * @param $header webmaster@1: * An array containing the table headers. Each element of the array can be webmaster@1: * either a localized string or an associative array with the following keys: webmaster@1: * - "data": The localized title of the table column. webmaster@1: * - "field": The database field represented in the table column (required if webmaster@1: * user is to be able to sort on this column). webmaster@1: * - "sort": A default sort order for this column ("asc" or "desc"). webmaster@1: * - Any HTML attributes, such as "colspan", to apply to the column header cell. webmaster@1: * @param $rows webmaster@1: * An array of table rows. Every row is an array of cells, or an associative webmaster@1: * array with the following keys: webmaster@1: * - "data": an array of cells webmaster@1: * - Any HTML attributes, such as "class", to apply to the table row. webmaster@1: * webmaster@1: * Each cell can be either a string or an associative array with the following keys: webmaster@1: * - "data": The string to display in the table cell. webmaster@1: * - "header": Indicates this cell is a header. webmaster@1: * - Any HTML attributes, such as "colspan", to apply to the table cell. webmaster@1: * webmaster@1: * Here's an example for $rows: webmaster@1: * @verbatim webmaster@1: * $rows = array( webmaster@1: * // Simple row webmaster@1: * array( webmaster@1: * 'Cell 1', 'Cell 2', 'Cell 3' webmaster@1: * ), webmaster@1: * // Row with attributes on the row and some of its cells. webmaster@1: * array( webmaster@1: * 'data' => array('Cell 1', array('data' => 'Cell 2', 'colspan' => 2)), 'class' => 'funky' webmaster@1: * ) webmaster@1: * ); webmaster@1: * @endverbatim webmaster@1: * webmaster@1: * @param $attributes webmaster@1: * An array of HTML attributes to apply to the table tag. webmaster@1: * @param $caption webmaster@1: * A localized string to use for the tag. webmaster@1: * @return webmaster@1: * An HTML string representing the table. webmaster@1: */ webmaster@1: function theme_table($header, $rows, $attributes = array(), $caption = NULL) { webmaster@1: webmaster@1: // Add sticky headers, if applicable. webmaster@1: if (count($header)) { webmaster@1: drupal_add_js('misc/tableheader.js'); webmaster@1: // Add 'sticky-enabled' class to the table to identify it for JS. webmaster@1: // This is needed to target tables constructed by this function. webmaster@1: $attributes['class'] = empty($attributes['class']) ? 'sticky-enabled' : ($attributes['class'] .' sticky-enabled'); webmaster@1: } webmaster@1: webmaster@1: $output = '\n"; webmaster@1: webmaster@1: if (isset($caption)) { webmaster@1: $output .= ''. $caption ."\n"; webmaster@1: } webmaster@1: webmaster@1: // Format the table header: webmaster@1: if (count($header)) { webmaster@1: $ts = tablesort_init($header); webmaster@1: // HTML requires that the thead tag has tr tags in it follwed by tbody webmaster@1: // tags. Using ternary operator to check and see if we have any rows. webmaster@1: $output .= (count($rows) ? ' ' : ' '); webmaster@1: foreach ($header as $cell) { webmaster@1: $cell = tablesort_header($cell, $header, $ts); webmaster@1: $output .= _theme_table_cell($cell, TRUE); webmaster@1: } webmaster@1: // Using ternary operator to close the tags based on whether or not there are rows webmaster@1: $output .= (count($rows) ? " \n" : "\n"); webmaster@1: } webmaster@1: else { webmaster@1: $ts = array(); webmaster@1: } webmaster@1: webmaster@1: // Format the table rows: webmaster@1: if (count($rows)) { webmaster@1: $output .= "\n"; webmaster@1: $flip = array('even' => 'odd', 'odd' => 'even'); webmaster@1: $class = 'even'; webmaster@1: foreach ($rows as $number => $row) { webmaster@1: $attributes = array(); webmaster@1: webmaster@1: // Check if we're dealing with a simple or complex row webmaster@1: if (isset($row['data'])) { webmaster@1: foreach ($row as $key => $value) { webmaster@1: if ($key == 'data') { webmaster@1: $cells = $value; webmaster@1: } webmaster@1: else { webmaster@1: $attributes[$key] = $value; webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: else { webmaster@1: $cells = $row; webmaster@1: } webmaster@1: if (count($cells)) { webmaster@1: // Add odd/even class webmaster@1: $class = $flip[$class]; webmaster@1: if (isset($attributes['class'])) { webmaster@1: $attributes['class'] .= ' '. $class; webmaster@1: } webmaster@1: else { webmaster@1: $attributes['class'] = $class; webmaster@1: } webmaster@1: webmaster@1: // Build row webmaster@1: $output .= ' '; webmaster@1: $i = 0; webmaster@1: foreach ($cells as $cell) { webmaster@1: $cell = tablesort_cell($cell, $header, $ts, $i++); webmaster@1: $output .= _theme_table_cell($cell); webmaster@1: } webmaster@1: $output .= " \n"; webmaster@1: } webmaster@1: } webmaster@1: $output .= "\n"; webmaster@1: } webmaster@1: webmaster@1: $output .= "\n"; webmaster@1: return $output; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Returns a header cell for tables that have a select all functionality. webmaster@1: */ webmaster@1: function theme_table_select_header_cell() { webmaster@1: drupal_add_js('misc/tableselect.js'); webmaster@1: webmaster@1: return array('class' => 'select-all'); webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed sort icon. webmaster@1: * webmaster@1: * @param $style webmaster@1: * Set to either asc or desc. This sets which icon to show. webmaster@1: * @return webmaster@1: * A themed sort icon. webmaster@1: */ webmaster@1: function theme_tablesort_indicator($style) { webmaster@1: if ($style == "asc") { webmaster@1: return theme('image', 'misc/arrow-asc.png', t('sort icon'), t('sort ascending')); webmaster@1: } webmaster@1: else { webmaster@1: return theme('image', 'misc/arrow-desc.png', t('sort icon'), t('sort descending')); webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed box. webmaster@1: * webmaster@1: * @param $title webmaster@1: * The subject of the box. webmaster@1: * @param $content webmaster@1: * The content of the box. webmaster@1: * @param $region webmaster@1: * The region in which the box is displayed. webmaster@1: * @return webmaster@1: * A string containing the box output. webmaster@1: */ webmaster@1: function theme_box($title, $content, $region = 'main') { webmaster@1: $output = '

'. $title .'

'. $content .'
'; webmaster@1: return $output; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed marker, useful for marking new or updated webmaster@1: * content. webmaster@1: * webmaster@1: * @param $type webmaster@1: * Number representing the marker type to display webmaster@1: * @see MARK_NEW, MARK_UPDATED, MARK_READ webmaster@1: * @return webmaster@1: * A string containing the marker. webmaster@1: */ webmaster@1: function theme_mark($type = MARK_NEW) { webmaster@1: global $user; webmaster@1: if ($user->uid) { webmaster@1: if ($type == MARK_NEW) { webmaster@1: return ' '. t('new') .''; webmaster@1: } webmaster@1: else if ($type == MARK_UPDATED) { webmaster@1: return ' '. t('updated') .''; webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed list of items. webmaster@1: * webmaster@1: * @param $items webmaster@1: * An array of items to be displayed in the list. If an item is a string, webmaster@1: * then it is used as is. If an item is an array, then the "data" element of webmaster@1: * the array is used as the contents of the list item. If an item is an array webmaster@1: * with a "children" element, those children are displayed in a nested list. webmaster@1: * All other elements are treated as attributes of the list item element. webmaster@1: * @param $title webmaster@1: * The title of the list. webmaster@15: * @param $type webmaster@15: * The type of list to return (e.g. "ul", "ol") webmaster@1: * @param $attributes webmaster@1: * The attributes applied to the list element. webmaster@1: * @return webmaster@1: * A string containing the list output. webmaster@1: */ webmaster@1: function theme_item_list($items = array(), $title = NULL, $type = 'ul', $attributes = NULL) { webmaster@1: $output = '
'; webmaster@1: if (isset($title)) { webmaster@1: $output .= '

'. $title .'

'; webmaster@1: } webmaster@1: webmaster@1: if (!empty($items)) { webmaster@1: $output .= "<$type". drupal_attributes($attributes) .'>'; webmaster@1: $num_items = count($items); webmaster@1: foreach ($items as $i => $item) { webmaster@1: $attributes = array(); webmaster@1: $children = array(); webmaster@1: if (is_array($item)) { webmaster@1: foreach ($item as $key => $value) { webmaster@1: if ($key == 'data') { webmaster@1: $data = $value; webmaster@1: } webmaster@1: elseif ($key == 'children') { webmaster@1: $children = $value; webmaster@1: } webmaster@1: else { webmaster@1: $attributes[$key] = $value; webmaster@1: } webmaster@1: } webmaster@1: } webmaster@1: else { webmaster@1: $data = $item; webmaster@1: } webmaster@1: if (count($children) > 0) { webmaster@1: $data .= theme_item_list($children, NULL, $type, $attributes); // Render nested list webmaster@1: } webmaster@1: if ($i == 0) { webmaster@1: $attributes['class'] = empty($attributes['class']) ? 'first' : ($attributes['class'] .' first'); webmaster@1: } webmaster@1: if ($i == $num_items - 1) { webmaster@1: $attributes['class'] = empty($attributes['class']) ? 'last' : ($attributes['class'] .' last'); webmaster@1: } webmaster@1: $output .= ''. $data ."\n"; webmaster@1: } webmaster@1: $output .= ""; webmaster@1: } webmaster@1: $output .= '
'; webmaster@1: return $output; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Returns code that emits the 'more help'-link. webmaster@1: */ webmaster@1: function theme_more_help_link($url) { webmaster@1: return ''; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return code that emits an XML icon. webmaster@7: * webmaster@1: * For most use cases, this function has been superseded by theme_feed_icon(). webmaster@7: * webmaster@1: * @see theme_feed_icon() webmaster@1: * @param $url webmaster@1: * The url of the feed. webmaster@1: */ webmaster@1: function theme_xml_icon($url) { webmaster@1: if ($image = theme('image', 'misc/xml.png', t('XML feed'), t('XML feed'))) { webmaster@1: return ''. $image .''; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return code that emits an feed icon. webmaster@1: * webmaster@1: * @param $url webmaster@1: * The url of the feed. webmaster@1: * @param $title webmaster@1: * A descriptive title of the feed. webmaster@1: */ webmaster@1: function theme_feed_icon($url, $title) { webmaster@1: if ($image = theme('image', 'misc/feed.png', t('Syndicate content'), $title)) { webmaster@1: return ''. $image .''; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Returns code that emits the 'more' link used on blocks. webmaster@1: * webmaster@1: * @param $url webmaster@1: * The url of the main page webmaster@1: * @param $title webmaster@1: * A descriptive verb for the link, like 'Read more' webmaster@1: */ webmaster@1: function theme_more_link($url, $title) { webmaster@1: return ''; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Execute hook_footer() which is run at the end of the page right before the webmaster@1: * close of the body tag. webmaster@1: * webmaster@1: * @param $main (optional) webmaster@1: * Whether the current page is the front page of the site. webmaster@1: * @return webmaster@1: * A string containing the results of the hook_footer() calls. webmaster@1: */ webmaster@1: function theme_closure($main = 0) { webmaster@1: $footer = module_invoke_all('footer', $main); webmaster@1: return implode("\n", $footer) . drupal_get_js('footer'); webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a set of blocks available for the current user. webmaster@1: * webmaster@1: * @param $region webmaster@1: * Which set of blocks to retrieve. webmaster@1: * @return webmaster@1: * A string containing the themed blocks for this region. webmaster@1: */ webmaster@1: function theme_blocks($region) { webmaster@1: $output = ''; webmaster@1: webmaster@1: if ($list = block_list($region)) { webmaster@1: foreach ($list as $key => $block) { webmaster@1: // $key == module_delta webmaster@1: $output .= theme('block', $block); webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: // Add any content assigned to this region through drupal_set_content() calls. webmaster@1: $output .= drupal_get_content($region); webmaster@1: webmaster@1: return $output; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Format a username. webmaster@1: * webmaster@1: * @param $object webmaster@1: * The user object to format, usually returned from user_load(). webmaster@1: * @return webmaster@1: * A string containing an HTML link to the user's page if the passed object webmaster@1: * suggests that this is a site user. Otherwise, only the username is returned. webmaster@1: */ webmaster@1: function theme_username($object) { webmaster@1: webmaster@1: if ($object->uid && $object->name) { webmaster@1: // Shorten the name when it is too long or it will break many tables. webmaster@1: if (drupal_strlen($object->name) > 20) { webmaster@1: $name = drupal_substr($object->name, 0, 15) .'...'; webmaster@1: } webmaster@1: else { webmaster@1: $name = $object->name; webmaster@1: } webmaster@1: webmaster@1: if (user_access('access user profiles')) { webmaster@5: $output = l($name, 'user/'. $object->uid, array('attributes' => array('title' => t('View user profile.')))); webmaster@1: } webmaster@1: else { webmaster@1: $output = check_plain($name); webmaster@1: } webmaster@1: } webmaster@1: else if ($object->name) { webmaster@1: // Sometimes modules display content composed by people who are webmaster@1: // not registered members of the site (e.g. mailing list or news webmaster@1: // aggregator modules). This clause enables modules to display webmaster@1: // the true author of the content. webmaster@1: if (!empty($object->homepage)) { webmaster@7: $output = l($object->name, $object->homepage, array('attributes' => array('rel' => 'nofollow'))); webmaster@1: } webmaster@1: else { webmaster@1: $output = check_plain($object->name); webmaster@1: } webmaster@1: webmaster@1: $output .= ' ('. t('not verified') .')'; webmaster@1: } webmaster@1: else { webmaster@1: $output = variable_get('anonymous', t('Anonymous')); webmaster@1: } webmaster@1: webmaster@1: return $output; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Return a themed progress bar. webmaster@1: * webmaster@1: * @param $percent webmaster@1: * The percentage of the progress. webmaster@1: * @param $message webmaster@1: * A string containing information to be displayed. webmaster@1: * @return webmaster@1: * A themed HTML string representing the progress bar. webmaster@1: */ webmaster@1: function theme_progress_bar($percent, $message) { webmaster@1: $output = '
'; webmaster@1: $output .= '
'; webmaster@1: $output .= '
'. $percent .'%
'; webmaster@1: $output .= '
'. $message .'
'; webmaster@1: $output .= '
'; webmaster@1: webmaster@1: return $output; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Create a standard indentation div. Used for drag and drop tables. webmaster@1: * webmaster@1: * @param $size webmaster@1: * Optional. The number of indentations to create. webmaster@1: * @return webmaster@1: * A string containing indentations. webmaster@1: */ webmaster@1: function theme_indentation($size = 1) { webmaster@1: $output = ''; webmaster@1: for ($n = 0; $n < $size; $n++) { webmaster@1: $output .= '
 
'; webmaster@1: } webmaster@1: return $output; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * @} End of "defgroup themeable". webmaster@1: */ webmaster@1: webmaster@1: function _theme_table_cell($cell, $header = FALSE) { webmaster@1: $attributes = ''; webmaster@1: webmaster@1: if (is_array($cell)) { webmaster@1: $data = isset($cell['data']) ? $cell['data'] : ''; webmaster@1: $header |= isset($cell['header']); webmaster@1: unset($cell['data']); webmaster@1: unset($cell['header']); webmaster@1: $attributes = drupal_attributes($cell); webmaster@1: } webmaster@1: else { webmaster@1: $data = $cell; webmaster@1: } webmaster@1: webmaster@1: if ($header) { webmaster@1: $output = "$data"; webmaster@1: } webmaster@1: else { webmaster@1: $output = "$data"; webmaster@1: } webmaster@1: webmaster@1: return $output; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Adds a default set of helper variables for preprocess functions and webmaster@1: * templates. This comes in before any other preprocess function which makes webmaster@1: * it possible to be used in default theme implementations (non-overriden webmaster@1: * theme functions). webmaster@1: */ webmaster@1: function template_preprocess(&$variables, $hook) { webmaster@1: global $user; webmaster@1: static $count = array(); webmaster@1: webmaster@1: // Track run count for each hook to provide zebra striping. webmaster@1: // See "template_preprocess_block()" which provides the same feature specific to blocks. webmaster@1: $count[$hook] = isset($count[$hook]) && is_int($count[$hook]) ? $count[$hook] : 1; webmaster@1: $variables['zebra'] = ($count[$hook] % 2) ? 'odd' : 'even'; webmaster@1: $variables['id'] = $count[$hook]++; webmaster@1: webmaster@1: // Tell all templates where they are located. webmaster@1: $variables['directory'] = path_to_theme(); webmaster@1: webmaster@1: // Set default variables that depend on the database. webmaster@1: $variables['is_admin'] = FALSE; webmaster@1: $variables['is_front'] = FALSE; webmaster@1: $variables['logged_in'] = FALSE; webmaster@1: if ($variables['db_is_active'] = db_is_active() && !defined('MAINTENANCE_MODE')) { webmaster@1: // Check for administrators. webmaster@1: if (user_access('access administration pages')) { webmaster@1: $variables['is_admin'] = TRUE; webmaster@1: } webmaster@1: // Flag front page status. webmaster@1: $variables['is_front'] = drupal_is_front_page(); webmaster@1: // Tell all templates by which kind of user they're viewed. webmaster@1: $variables['logged_in'] = ($user->uid > 0); webmaster@1: // Provide user object to all templates webmaster@1: $variables['user'] = $user; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Process variables for page.tpl.php webmaster@1: * webmaster@1: * Most themes utilize their own copy of page.tpl.php. The default is located webmaster@1: * inside "modules/system/page.tpl.php". Look in there for the full list of webmaster@1: * variables. webmaster@1: * webmaster@1: * Uses the arg() function to generate a series of page template suggestions webmaster@1: * based on the current path. webmaster@1: * webmaster@1: * Any changes to variables in this preprocessor should also be changed inside webmaster@1: * template_preprocess_maintenance_page() to keep all them consistent. webmaster@1: * webmaster@1: * The $variables array contains the following arguments: webmaster@1: * - $content webmaster@1: * - $show_blocks webmaster@1: * webmaster@1: * @see page.tpl.php webmaster@1: */ webmaster@1: function template_preprocess_page(&$variables) { webmaster@1: // Add favicon webmaster@1: if (theme_get_setting('toggle_favicon')) { webmaster@1: drupal_set_html_head(''); webmaster@1: } webmaster@1: webmaster@1: global $theme; webmaster@1: // Populate all block regions. webmaster@1: $regions = system_region_list($theme); webmaster@1: // Load all region content assigned via blocks. webmaster@1: foreach (array_keys($regions) as $region) { webmaster@1: // Prevent left and right regions from rendering blocks when 'show_blocks' == FALSE. webmaster@1: if (!(!$variables['show_blocks'] && ($region == 'left' || $region == 'right'))) { webmaster@1: $blocks = theme('blocks', $region); webmaster@1: } webmaster@1: else { webmaster@1: $blocks = ''; webmaster@1: } webmaster@1: // Assign region to a region variable. webmaster@1: isset($variables[$region]) ? $variables[$region] .= $blocks : $variables[$region] = $blocks; webmaster@1: } webmaster@1: webmaster@1: // Set up layout variable. webmaster@1: $variables['layout'] = 'none'; webmaster@1: if (!empty($variables['left'])) { webmaster@1: $variables['layout'] = 'left'; webmaster@1: } webmaster@1: if (!empty($variables['right'])) { webmaster@1: $variables['layout'] = ($variables['layout'] == 'left') ? 'both' : 'right'; webmaster@1: } webmaster@1: webmaster@1: // Set mission when viewing the frontpage. webmaster@1: if (drupal_is_front_page()) { webmaster@1: $mission = filter_xss_admin(theme_get_setting('mission')); webmaster@1: } webmaster@1: webmaster@1: // Construct page title webmaster@1: if (drupal_get_title()) { webmaster@1: $head_title = array(strip_tags(drupal_get_title()), variable_get('site_name', 'Drupal')); webmaster@1: } webmaster@1: else { webmaster@1: $head_title = array(variable_get('site_name', 'Drupal')); webmaster@1: if (variable_get('site_slogan', '')) { webmaster@1: $head_title[] = variable_get('site_slogan', ''); webmaster@1: } webmaster@1: } webmaster@1: $variables['head_title'] = implode(' | ', $head_title); webmaster@1: $variables['base_path'] = base_path(); webmaster@1: $variables['front_page'] = url(); webmaster@1: $variables['breadcrumb'] = theme('breadcrumb', drupal_get_breadcrumb()); webmaster@1: $variables['feed_icons'] = drupal_get_feeds(); webmaster@1: $variables['footer_message'] = filter_xss_admin(variable_get('site_footer', FALSE)); webmaster@1: $variables['head'] = drupal_get_html_head(); webmaster@1: $variables['help'] = theme('help'); webmaster@1: $variables['language'] = $GLOBALS['language']; webmaster@1: $variables['language']->dir = $GLOBALS['language']->direction ? 'rtl' : 'ltr'; webmaster@1: $variables['logo'] = theme_get_setting('logo'); webmaster@1: $variables['messages'] = $variables['show_messages'] ? theme('status_messages') : ''; webmaster@1: $variables['mission'] = isset($mission) ? $mission : ''; webmaster@1: $variables['primary_links'] = theme_get_setting('toggle_primary_links') ? menu_primary_links() : array(); webmaster@1: $variables['secondary_links'] = theme_get_setting('toggle_secondary_links') ? menu_secondary_links() : array(); webmaster@1: $variables['search_box'] = (theme_get_setting('toggle_search') ? drupal_get_form('search_theme_form') : ''); webmaster@1: $variables['site_name'] = (theme_get_setting('toggle_name') ? variable_get('site_name', 'Drupal') : ''); webmaster@1: $variables['site_slogan'] = (theme_get_setting('toggle_slogan') ? variable_get('site_slogan', '') : ''); webmaster@1: $variables['css'] = drupal_add_css(); webmaster@1: $variables['styles'] = drupal_get_css(); webmaster@1: $variables['scripts'] = drupal_get_js(); webmaster@1: $variables['tabs'] = theme('menu_local_tasks'); webmaster@1: $variables['title'] = drupal_get_title(); webmaster@1: // Closure should be filled last. webmaster@1: $variables['closure'] = theme('closure'); webmaster@1: webmaster@1: if ($node = menu_get_object()) { webmaster@1: $variables['node'] = $node; webmaster@1: } webmaster@1: webmaster@1: // Compile a list of classes that are going to be applied to the body element. webmaster@1: // This allows advanced theming based on context (home page, node of certain type, etc.). webmaster@1: $body_classes = array(); webmaster@1: // Add a class that tells us whether we're on the front page or not. webmaster@1: $body_classes[] = $variables['is_front'] ? 'front' : 'not-front'; webmaster@1: // Add a class that tells us whether the page is viewed by an authenticated user or not. webmaster@1: $body_classes[] = $variables['logged_in'] ? 'logged-in' : 'not-logged-in'; webmaster@1: // Add arg(0) to make it possible to theme the page depending on the current page webmaster@1: // type (e.g. node, admin, user, etc.). To avoid illegal characters in the class, webmaster@1: // we're removing everything disallowed. We are not using 'a-z' as that might leave webmaster@1: // in certain international characters (e.g. German umlauts). webmaster@1: $body_classes[] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', 'page-'. form_clean_id(drupal_strtolower(arg(0)))); webmaster@1: // If on an individual node page, add the node type. webmaster@1: if (isset($variables['node']) && $variables['node']->type) { webmaster@1: $body_classes[] = 'node-type-'. form_clean_id($variables['node']->type); webmaster@1: } webmaster@1: // Add information about the number of sidebars. webmaster@1: if ($variables['layout'] == 'both') { webmaster@1: $body_classes[] = 'two-sidebars'; webmaster@1: } webmaster@1: elseif ($variables['layout'] == 'none') { webmaster@1: $body_classes[] = 'no-sidebars'; webmaster@1: } webmaster@1: else { webmaster@1: $body_classes[] = 'one-sidebar sidebar-'. $variables['layout']; webmaster@1: } webmaster@1: // Implode with spaces. webmaster@1: $variables['body_classes'] = implode(' ', $body_classes); webmaster@1: webmaster@1: // Build a list of suggested template files in order of specificity. One webmaster@1: // suggestion is made for every element of the current path, though webmaster@1: // numeric elements are not carried to subsequent suggestions. For example, webmaster@1: // http://www.example.com/node/1/edit would result in the following webmaster@1: // suggestions: webmaster@1: // webmaster@1: // page-node-edit.tpl.php webmaster@1: // page-node-1.tpl.php webmaster@1: // page-node.tpl.php webmaster@1: // page.tpl.php webmaster@1: $i = 0; webmaster@1: $suggestion = 'page'; webmaster@1: $suggestions = array(); webmaster@1: while ($arg = arg($i++)) { webmaster@1: $suggestions[] = $suggestion .'-'. $arg; webmaster@1: if (!is_numeric($arg)) { webmaster@1: $suggestion .= '-'. $arg; webmaster@1: } webmaster@1: } webmaster@1: if (drupal_is_front_page()) { webmaster@1: $suggestions[] = 'page-front'; webmaster@1: } webmaster@1: webmaster@1: if ($suggestions) { webmaster@1: $variables['template_files'] = $suggestions; webmaster@1: } webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Process variables for node.tpl.php webmaster@1: * webmaster@1: * Most themes utilize their own copy of node.tpl.php. The default is located webmaster@1: * inside "modules/node/node.tpl.php". Look in there for the full list of webmaster@1: * variables. webmaster@1: * webmaster@1: * The $variables array contains the following arguments: webmaster@1: * - $node webmaster@1: * - $teaser webmaster@1: * - $page webmaster@1: * webmaster@1: * @see node.tpl.php webmaster@1: */ webmaster@1: function template_preprocess_node(&$variables) { webmaster@1: $node = $variables['node']; webmaster@1: if (module_exists('taxonomy')) { webmaster@1: $variables['taxonomy'] = taxonomy_link('taxonomy terms', $node); webmaster@1: } webmaster@1: else { webmaster@1: $variables['taxonomy'] = array(); webmaster@1: } webmaster@1: webmaster@1: if ($variables['teaser'] && $node->teaser) { webmaster@1: $variables['content'] = $node->teaser; webmaster@1: } webmaster@1: elseif (isset($node->body)) { webmaster@1: $variables['content'] = $node->body; webmaster@1: } webmaster@1: else { webmaster@1: $variables['content'] = ''; webmaster@1: } webmaster@1: webmaster@1: $variables['date'] = format_date($node->created); webmaster@1: $variables['links'] = !empty($node->links) ? theme('links', $node->links, array('class' => 'links inline')) : ''; webmaster@1: $variables['name'] = theme('username', $node); webmaster@1: $variables['node_url'] = url('node/'. $node->nid); webmaster@1: $variables['terms'] = theme('links', $variables['taxonomy'], array('class' => 'links inline')); webmaster@1: $variables['title'] = check_plain($node->title); webmaster@1: webmaster@1: // Flatten the node object's member fields. webmaster@1: $variables = array_merge((array)$node, $variables); webmaster@1: webmaster@1: // Display info only on certain node types. webmaster@1: if (theme_get_setting('toggle_node_info_'. $node->type)) { webmaster@1: $variables['submitted'] = theme('node_submitted', $node); webmaster@1: $variables['picture'] = theme_get_setting('toggle_node_user_picture') ? theme('user_picture', $node) : ''; webmaster@1: } webmaster@1: else { webmaster@1: $variables['submitted'] = ''; webmaster@1: $variables['picture'] = ''; webmaster@1: } webmaster@1: // Clean up name so there are no underscores. webmaster@1: $variables['template_files'][] = 'node-'. $node->type; webmaster@1: } webmaster@1: webmaster@1: /** webmaster@1: * Process variables for block.tpl.php webmaster@1: * webmaster@1: * Prepare the values passed to the theme_block function to be passed webmaster@1: * into a pluggable template engine. Uses block properties to generate a webmaster@1: * series of template file suggestions. If none are found, the default webmaster@1: * block.tpl.php is used. webmaster@1: * webmaster@1: * Most themes utilize their own copy of block.tpl.php. The default is located webmaster@1: * inside "modules/system/block.tpl.php". Look in there for the full list of webmaster@1: * variables. webmaster@1: * webmaster@1: * The $variables array contains the following arguments: webmaster@1: * - $block webmaster@1: * webmaster@1: * @see block.tpl.php webmaster@1: */ webmaster@1: function template_preprocess_block(&$variables) { webmaster@1: static $block_counter = array(); webmaster@1: // All blocks get an independent counter for each region. webmaster@1: if (!isset($block_counter[$variables['block']->region])) { webmaster@1: $block_counter[$variables['block']->region] = 1; webmaster@1: } webmaster@1: // Same with zebra striping. webmaster@1: $variables['block_zebra'] = ($block_counter[$variables['block']->region] % 2) ? 'odd' : 'even'; webmaster@1: $variables['block_id'] = $block_counter[$variables['block']->region]++; webmaster@1: webmaster@1: $variables['template_files'][] = 'block-'. $variables['block']->region; webmaster@1: $variables['template_files'][] = 'block-'. $variables['block']->module; webmaster@1: $variables['template_files'][] = 'block-'. $variables['block']->module .'-'. $variables['block']->delta; webmaster@1: } webmaster@1: