annotate includes/theme.inc @ 7:fff6d4c8c043 6.3

Drupal 6.3
author Franck Deroche <webmaster@defr.org>
date Tue, 23 Dec 2008 14:30:28 +0100
parents 2427550111ae
children 589fb7c02327
rev   line source
webmaster@1 1 <?php
webmaster@7 2 // $Id: theme.inc,v 1.415.2.9 2008/07/09 21:48:28 goba Exp $
webmaster@1 3
webmaster@1 4 /**
webmaster@1 5 * @file
webmaster@1 6 * The theme system, which controls the output of Drupal.
webmaster@1 7 *
webmaster@1 8 * The theme system allows for nearly all output of the Drupal system to be
webmaster@1 9 * customized by user themes.
webmaster@1 10 *
webmaster@1 11 * @see <a href="http://drupal.org/node/253">Theme system</a>
webmaster@1 12 * @see themeable
webmaster@1 13 */
webmaster@1 14
webmaster@1 15 /**
webmaster@1 16 * @name Content markers
webmaster@1 17 * @{
webmaster@1 18 * Markers used by theme_mark() and node_mark() to designate content.
webmaster@1 19 * @see theme_mark(), node_mark()
webmaster@1 20 */
webmaster@1 21 define('MARK_READ', 0);
webmaster@1 22 define('MARK_NEW', 1);
webmaster@1 23 define('MARK_UPDATED', 2);
webmaster@1 24 /**
webmaster@1 25 * @} End of "Content markers".
webmaster@1 26 */
webmaster@1 27
webmaster@1 28 /**
webmaster@1 29 * Initialize the theme system by loading the theme.
webmaster@1 30 */
webmaster@1 31 function init_theme() {
webmaster@1 32 global $theme, $user, $custom_theme, $theme_key;
webmaster@1 33
webmaster@1 34 // If $theme is already set, assume the others are set, too, and do nothing
webmaster@1 35 if (isset($theme)) {
webmaster@1 36 return;
webmaster@1 37 }
webmaster@1 38
webmaster@1 39 drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
webmaster@1 40 $themes = list_themes();
webmaster@1 41
webmaster@1 42 // Only select the user selected theme if it is available in the
webmaster@1 43 // list of enabled themes.
webmaster@1 44 $theme = !empty($user->theme) && !empty($themes[$user->theme]->status) ? $user->theme : variable_get('theme_default', 'garland');
webmaster@1 45
webmaster@1 46 // Allow modules to override the present theme... only select custom theme
webmaster@1 47 // if it is available in the list of installed themes.
webmaster@1 48 $theme = $custom_theme && $themes[$custom_theme] ? $custom_theme : $theme;
webmaster@1 49
webmaster@1 50 // Store the identifier for retrieving theme settings with.
webmaster@1 51 $theme_key = $theme;
webmaster@1 52
webmaster@1 53 // Find all our ancestor themes and put them in an array.
webmaster@1 54 $base_theme = array();
webmaster@1 55 $ancestor = $theme;
webmaster@1 56 while ($ancestor && isset($themes[$ancestor]->base_theme)) {
webmaster@1 57 $base_theme[] = $new_base_theme = $themes[$themes[$ancestor]->base_theme];
webmaster@1 58 $ancestor = $themes[$ancestor]->base_theme;
webmaster@1 59 }
webmaster@1 60 _init_theme($themes[$theme], array_reverse($base_theme));
webmaster@1 61 }
webmaster@1 62
webmaster@1 63 /**
webmaster@1 64 * Initialize the theme system given already loaded information. This
webmaster@1 65 * function is useful to initialize a theme when no database is present.
webmaster@1 66 *
webmaster@1 67 * @param $theme
webmaster@1 68 * An object with the following information:
webmaster@1 69 * filename
webmaster@1 70 * The .info file for this theme. The 'path' to
webmaster@1 71 * the theme will be in this file's directory. (Required)
webmaster@1 72 * owner
webmaster@1 73 * The path to the .theme file or the .engine file to load for
webmaster@1 74 * the theme. (Required)
webmaster@1 75 * stylesheet
webmaster@1 76 * The primary stylesheet for the theme. (Optional)
webmaster@1 77 * engine
webmaster@1 78 * The name of theme engine to use. (Optional)
webmaster@1 79 * @param $base_theme
webmaster@1 80 * An optional array of objects that represent the 'base theme' if the
webmaster@1 81 * theme is meant to be derivative of another theme. It requires
webmaster@1 82 * the same information as the $theme object. It should be in
webmaster@1 83 * 'oldest first' order, meaning the top level of the chain will
webmaster@1 84 * be first.
webmaster@1 85 * @param $registry_callback
webmaster@1 86 * The callback to invoke to set the theme registry.
webmaster@1 87 */
webmaster@1 88 function _init_theme($theme, $base_theme = array(), $registry_callback = '_theme_load_registry') {
webmaster@1 89 global $theme_info, $base_theme_info, $theme_engine, $theme_path;
webmaster@1 90 $theme_info = $theme;
webmaster@1 91 $base_theme_info = $base_theme;
webmaster@1 92
webmaster@1 93 $theme_path = dirname($theme->filename);
webmaster@1 94
webmaster@1 95 // Prepare stylesheets from this theme as well as all ancestor themes.
webmaster@1 96 // We work it this way so that we can have child themes override parent
webmaster@1 97 // theme stylesheets easily.
webmaster@1 98 $final_stylesheets = array();
webmaster@1 99
webmaster@1 100 // Grab stylesheets from base theme
webmaster@1 101 foreach ($base_theme as $base) {
webmaster@1 102 if (!empty($base->stylesheets)) {
webmaster@1 103 foreach ($base->stylesheets as $media => $stylesheets) {
webmaster@1 104 foreach ($stylesheets as $name => $stylesheet) {
webmaster@1 105 $final_stylesheets[$media][$name] = $stylesheet;
webmaster@1 106 }
webmaster@1 107 }
webmaster@1 108 }
webmaster@1 109 }
webmaster@1 110
webmaster@1 111 // Add stylesheets used by this theme.
webmaster@1 112 if (!empty($theme->stylesheets)) {
webmaster@1 113 foreach ($theme->stylesheets as $media => $stylesheets) {
webmaster@1 114 foreach ($stylesheets as $name => $stylesheet) {
webmaster@1 115 $final_stylesheets[$media][$name] = $stylesheet;
webmaster@1 116 }
webmaster@1 117 }
webmaster@1 118 }
webmaster@1 119
webmaster@1 120 // And now add the stylesheets properly
webmaster@1 121 foreach ($final_stylesheets as $media => $stylesheets) {
webmaster@1 122 foreach ($stylesheets as $stylesheet) {
webmaster@1 123 drupal_add_css($stylesheet, 'theme', $media);
webmaster@1 124 }
webmaster@1 125 }
webmaster@1 126
webmaster@1 127 // Do basically the same as the above for scripts
webmaster@1 128 $final_scripts = array();
webmaster@1 129
webmaster@1 130 // Grab scripts from base theme
webmaster@1 131 foreach ($base_theme as $base) {
webmaster@1 132 if (!empty($base->scripts)) {
webmaster@1 133 foreach ($base->scripts as $name => $script) {
webmaster@1 134 $final_scripts[$name] = $script;
webmaster@1 135 }
webmaster@1 136 }
webmaster@1 137 }
webmaster@1 138
webmaster@1 139 // Add scripts used by this theme.
webmaster@1 140 if (!empty($theme->scripts)) {
webmaster@1 141 foreach ($theme->scripts as $name => $script) {
webmaster@1 142 $final_scripts[$name] = $script;
webmaster@1 143 }
webmaster@1 144 }
webmaster@1 145
webmaster@1 146 // Add scripts used by this theme.
webmaster@1 147 foreach ($final_scripts as $script) {
webmaster@1 148 drupal_add_js($script, 'theme');
webmaster@1 149 }
webmaster@1 150
webmaster@1 151 $theme_engine = NULL;
webmaster@1 152
webmaster@1 153 // Initialize the theme.
webmaster@1 154 if (isset($theme->engine)) {
webmaster@1 155 // Include the engine.
webmaster@1 156 include_once './'. $theme->owner;
webmaster@1 157
webmaster@1 158 $theme_engine = $theme->engine;
webmaster@1 159 if (function_exists($theme_engine .'_init')) {
webmaster@1 160 foreach ($base_theme as $base) {
webmaster@1 161 call_user_func($theme_engine .'_init', $base);
webmaster@1 162 }
webmaster@1 163 call_user_func($theme_engine .'_init', $theme);
webmaster@1 164 }
webmaster@1 165 }
webmaster@1 166 else {
webmaster@1 167 // include non-engine theme files
webmaster@1 168 foreach ($base_theme as $base) {
webmaster@1 169 // Include the theme file or the engine.
webmaster@1 170 if (!empty($base->owner)) {
webmaster@1 171 include_once './'. $base->owner;
webmaster@1 172 }
webmaster@1 173 }
webmaster@1 174 // and our theme gets one too.
webmaster@1 175 if (!empty($theme->owner)) {
webmaster@1 176 include_once './'. $theme->owner;
webmaster@1 177 }
webmaster@1 178 }
webmaster@1 179
webmaster@1 180 $registry_callback($theme, $base_theme, $theme_engine);
webmaster@1 181 }
webmaster@1 182
webmaster@1 183 /**
webmaster@1 184 * Retrieve the stored theme registry. If the theme registry is already
webmaster@1 185 * in memory it will be returned; otherwise it will attempt to load the
webmaster@1 186 * registry from cache. If this fails, it will construct the registry and
webmaster@1 187 * cache it.
webmaster@1 188 */
webmaster@1 189 function theme_get_registry($registry = NULL) {
webmaster@1 190 static $theme_registry = NULL;
webmaster@1 191 if (isset($registry)) {
webmaster@1 192 $theme_registry = $registry;
webmaster@1 193 }
webmaster@1 194
webmaster@1 195 return $theme_registry;
webmaster@1 196 }
webmaster@1 197
webmaster@1 198 /**
webmaster@1 199 * Store the theme registry in memory.
webmaster@1 200 */
webmaster@1 201 function _theme_set_registry($registry) {
webmaster@1 202 // Pass through for setting of static variable.
webmaster@1 203 return theme_get_registry($registry);
webmaster@1 204 }
webmaster@1 205
webmaster@1 206 /**
webmaster@1 207 * Get the theme_registry cache from the database; if it doesn't exist, build
webmaster@1 208 * it.
webmaster@1 209 *
webmaster@1 210 * @param $theme
webmaster@1 211 * The loaded $theme object.
webmaster@1 212 * @param $base_theme
webmaster@1 213 * An array of loaded $theme objects representing the ancestor themes in
webmaster@1 214 * oldest first order.
webmaster@1 215 * @param theme_engine
webmaster@1 216 * The name of the theme engine.
webmaster@1 217 */
webmaster@1 218 function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
webmaster@1 219 // Check the theme registry cache; if it exists, use it.
webmaster@1 220 $cache = cache_get("theme_registry:$theme->name", 'cache');
webmaster@1 221 if (isset($cache->data)) {
webmaster@1 222 $registry = $cache->data;
webmaster@1 223 }
webmaster@1 224 else {
webmaster@1 225 // If not, build one and cache it.
webmaster@1 226 $registry = _theme_build_registry($theme, $base_theme, $theme_engine);
webmaster@1 227 _theme_save_registry($theme, $registry);
webmaster@1 228 }
webmaster@1 229 _theme_set_registry($registry);
webmaster@1 230 }
webmaster@1 231
webmaster@1 232 /**
webmaster@1 233 * Write the theme_registry cache into the database.
webmaster@1 234 */
webmaster@1 235 function _theme_save_registry($theme, $registry) {
webmaster@1 236 cache_set("theme_registry:$theme->name", $registry);
webmaster@1 237 }
webmaster@1 238
webmaster@1 239 /**
webmaster@1 240 * Force the system to rebuild the theme registry; this should be called
webmaster@1 241 * when modules are added to the system, or when a dynamic system needs
webmaster@1 242 * to add more theme hooks.
webmaster@1 243 */
webmaster@1 244 function drupal_rebuild_theme_registry() {
webmaster@1 245 cache_clear_all('theme_registry', 'cache', TRUE);
webmaster@1 246 }
webmaster@1 247
webmaster@1 248 /**
webmaster@1 249 * Process a single invocation of the theme hook. $type will be one
webmaster@1 250 * of 'module', 'theme_engine' or 'theme' and it tells us some
webmaster@1 251 * important information.
webmaster@1 252 *
webmaster@1 253 * Because $cache is a reference, the cache will be continually
webmaster@1 254 * expanded upon; new entries will replace old entries in the
webmaster@1 255 * array_merge, but we are careful to ensure some data is carried
webmaster@1 256 * forward, such as the arguments a theme hook needs.
webmaster@1 257 *
webmaster@1 258 * An override flag can be set for preprocess functions. When detected the
webmaster@1 259 * cached preprocessors for the hook will not be merged with the newly set.
webmaster@1 260 * This can be useful to themes and theme engines by giving them more control
webmaster@1 261 * over how and when the preprocess functions are run.
webmaster@1 262 */
webmaster@1 263 function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
webmaster@1 264 $function = $name .'_theme';
webmaster@1 265 if (function_exists($function)) {
webmaster@1 266 $result = $function($cache, $type, $theme, $path);
webmaster@1 267
webmaster@1 268 foreach ($result as $hook => $info) {
webmaster@1 269 $result[$hook]['type'] = $type;
webmaster@1 270 $result[$hook]['theme path'] = $path;
webmaster@1 271 // if function and file are left out, default to standard naming
webmaster@1 272 // conventions.
webmaster@1 273 if (!isset($info['template']) && !isset($info['function'])) {
webmaster@1 274 $result[$hook]['function'] = ($type == 'module' ? 'theme_' : $name .'_') . $hook;
webmaster@1 275 }
webmaster@1 276 // If a path is set in the info, use what was set. Otherwise use the
webmaster@1 277 // default path. This is mostly so system.module can declare theme
webmaster@1 278 // functions on behalf of core .include files.
webmaster@1 279 // All files are included to be safe. Conditionally included
webmaster@1 280 // files can prevent them from getting registered.
webmaster@1 281 if (isset($info['file']) && !isset($info['path'])) {
webmaster@1 282 $result[$hook]['file'] = $path .'/'. $info['file'];
webmaster@1 283 include_once($result[$hook]['file']);
webmaster@1 284 }
webmaster@1 285 elseif (isset($info['file']) && isset($info['path'])) {
webmaster@1 286 include_once($info['path'] .'/'. $info['file']);
webmaster@1 287 }
webmaster@1 288
webmaster@1 289 if (isset($info['template']) && !isset($info['path'])) {
webmaster@1 290 $result[$hook]['template'] = $path .'/'. $info['template'];
webmaster@1 291 }
webmaster@1 292 // If 'arguments' have been defined previously, carry them forward.
webmaster@1 293 // This should happen if a theme overrides a Drupal defined theme
webmaster@1 294 // function, for example.
webmaster@1 295 if (!isset($info['arguments']) && isset($cache[$hook])) {
webmaster@1 296 $result[$hook]['arguments'] = $cache[$hook]['arguments'];
webmaster@1 297 }
webmaster@1 298 // Likewise with theme paths. These are used for template naming suggestions.
webmaster@1 299 // Theme implementations can occur in multiple paths. Suggestions should follow.
webmaster@1 300 if (!isset($info['theme paths']) && isset($cache[$hook])) {
webmaster@1 301 $result[$hook]['theme paths'] = $cache[$hook]['theme paths'];
webmaster@1 302 }
webmaster@1 303 // Check for sub-directories.
webmaster@1 304 $result[$hook]['theme paths'][] = isset($info['path']) ? $info['path'] : $path;
webmaster@1 305
webmaster@1 306 // Check for default _preprocess_ functions. Ensure arrayness.
webmaster@1 307 if (!isset($info['preprocess functions']) || !is_array($info['preprocess functions'])) {
webmaster@1 308 $info['preprocess functions'] = array();
webmaster@1 309 $prefixes = array();
webmaster@1 310 if ($type == 'module') {
webmaster@1 311 // Default preprocessor prefix.
webmaster@1 312 $prefixes[] = 'template';
webmaster@1 313 // Add all modules so they can intervene with their own preprocessors. This allows them
webmaster@1 314 // to provide preprocess functions even if they are not the owner of the current hook.
webmaster@1 315 $prefixes += module_list();
webmaster@1 316 }
webmaster@1 317 elseif ($type == 'theme_engine') {
webmaster@1 318 // Theme engines get an extra set that come before the normally named preprocessors.
webmaster@1 319 $prefixes[] = $name .'_engine';
webmaster@1 320 // The theme engine also registers on behalf of the theme. The theme or engine name can be used.
webmaster@1 321 $prefixes[] = $name;
webmaster@1 322 $prefixes[] = $theme;
webmaster@1 323 }
webmaster@1 324 else {
webmaster@1 325 // This applies when the theme manually registers their own preprocessors.
webmaster@1 326 $prefixes[] = $name;
webmaster@1 327 }
webmaster@1 328
webmaster@1 329 foreach ($prefixes as $prefix) {
webmaster@1 330 if (function_exists($prefix .'_preprocess')) {
webmaster@1 331 $info['preprocess functions'][] = $prefix .'_preprocess';
webmaster@1 332 }
webmaster@7 333
webmaster@1 334 if (function_exists($prefix .'_preprocess_'. $hook)) {
webmaster@1 335 $info['preprocess functions'][] = $prefix .'_preprocess_'. $hook;
webmaster@1 336 }
webmaster@7 337
webmaster@7 338 if (!empty($info['original hook']) && function_exists($prefix .'_preprocess_'. $info['original hook'])) {
webmaster@7 339 $info['preprocess functions'][] = $prefix .'_preprocess_'. $info['original hook'];
webmaster@7 340 }
webmaster@1 341 }
webmaster@1 342 }
webmaster@1 343 // Check for the override flag and prevent the cached preprocess functions from being used.
webmaster@1 344 // This allows themes or theme engines to remove preprocessors set earlier in the registry build.
webmaster@1 345 if (!empty($info['override preprocess functions'])) {
webmaster@1 346 // Flag not needed inside the registry.
webmaster@1 347 unset($result[$hook]['override preprocess functions']);
webmaster@1 348 }
webmaster@1 349 elseif (isset($cache[$hook]['preprocess functions']) && is_array($cache[$hook]['preprocess functions'])) {
webmaster@1 350 $info['preprocess functions'] = array_merge($cache[$hook]['preprocess functions'], $info['preprocess functions']);
webmaster@1 351 }
webmaster@7 352 elseif (isset($info['original hook']) && isset($cache[$info['original hook']]['preprocess functions']) && is_array($cache[$info['original hook']]['preprocess functions'])) {
webmaster@7 353 $info['preprocess functions'] = array_merge($cache[$info['original hook']]['preprocess functions'], $info['preprocess functions']);
webmaster@7 354 }
webmaster@1 355 $result[$hook]['preprocess functions'] = $info['preprocess functions'];
webmaster@1 356 }
webmaster@1 357
webmaster@1 358 // Merge the newly created theme hooks into the existing cache.
webmaster@1 359 $cache = array_merge($cache, $result);
webmaster@1 360 }
webmaster@1 361 }
webmaster@1 362
webmaster@1 363 /**
webmaster@1 364 * Rebuild the hook theme_registry cache.
webmaster@1 365 *
webmaster@1 366 * @param $theme
webmaster@1 367 * The loaded $theme object.
webmaster@1 368 * @param $base_theme
webmaster@1 369 * An array of loaded $theme objects representing the ancestor themes in
webmaster@1 370 * oldest first order.
webmaster@1 371 * @param theme_engine
webmaster@1 372 * The name of the theme engine.
webmaster@1 373 */
webmaster@1 374 function _theme_build_registry($theme, $base_theme, $theme_engine) {
webmaster@1 375 $cache = array();
webmaster@1 376 // First, process the theme hooks advertised by modules. This will
webmaster@1 377 // serve as the basic registry.
webmaster@1 378 foreach (module_implements('theme') as $module) {
webmaster@1 379 _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module));
webmaster@1 380 }
webmaster@1 381
webmaster@1 382 // Process each base theme.
webmaster@1 383 foreach ($base_theme as $base) {
webmaster@1 384 // If the theme uses a theme engine, process its hooks.
webmaster@1 385 $base_path = dirname($base->filename);
webmaster@1 386 if ($theme_engine) {
webmaster@1 387 _theme_process_registry($cache, $theme_engine, 'base_theme_engine', $base->name, $base_path);
webmaster@1 388 }
webmaster@1 389 _theme_process_registry($cache, $base->name, 'base_theme', $base->name, $base_path);
webmaster@1 390 }
webmaster@1 391
webmaster@1 392 // And then the same thing, but for the theme.
webmaster@1 393 if ($theme_engine) {
webmaster@1 394 _theme_process_registry($cache, $theme_engine, 'theme_engine', $theme->name, dirname($theme->filename));
webmaster@1 395 }
webmaster@1 396
webmaster@1 397 // Finally, hooks provided by the theme itself.
webmaster@1 398 _theme_process_registry($cache, $theme->name, 'theme', $theme->name, dirname($theme->filename));
webmaster@1 399
webmaster@1 400 // Let modules alter the registry
webmaster@1 401 drupal_alter('theme_registry', $cache);
webmaster@1 402 return $cache;
webmaster@1 403 }
webmaster@1 404
webmaster@1 405 /**
webmaster@1 406 * Provides a list of currently available themes.
webmaster@1 407 *
webmaster@1 408 * If the database is active then it will be retrieved from the database.
webmaster@1 409 * Otherwise it will retrieve a new list.
webmaster@1 410 *
webmaster@1 411 * @param $refresh
webmaster@1 412 * Whether to reload the list of themes from the database.
webmaster@1 413 * @return
webmaster@1 414 * An array of the currently available themes.
webmaster@1 415 */
webmaster@1 416 function list_themes($refresh = FALSE) {
webmaster@1 417 static $list = array();
webmaster@1 418
webmaster@1 419 if ($refresh) {
webmaster@1 420 $list = array();
webmaster@1 421 }
webmaster@1 422
webmaster@1 423 if (empty($list)) {
webmaster@1 424 $list = array();
webmaster@1 425 $themes = array();
webmaster@1 426 // Extract from the database only when it is available.
webmaster@1 427 // Also check that the site is not in the middle of an install or update.
webmaster@1 428 if (db_is_active() && !defined('MAINTENANCE_MODE')) {
webmaster@1 429 $result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme');
webmaster@1 430 while ($theme = db_fetch_object($result)) {
webmaster@1 431 if (file_exists($theme->filename)) {
webmaster@1 432 $theme->info = unserialize($theme->info);
webmaster@1 433 $themes[] = $theme;
webmaster@1 434 }
webmaster@1 435 }
webmaster@1 436 }
webmaster@1 437 else {
webmaster@1 438 // Scan the installation when the database should not be read.
webmaster@1 439 $themes = _system_theme_data();
webmaster@1 440 }
webmaster@1 441
webmaster@1 442 foreach ($themes as $theme) {
webmaster@1 443 foreach ($theme->info['stylesheets'] as $media => $stylesheets) {
webmaster@1 444 foreach ($stylesheets as $stylesheet => $path) {
webmaster@7 445 $theme->stylesheets[$media][$stylesheet] = $path;
webmaster@1 446 }
webmaster@1 447 }
webmaster@1 448 foreach ($theme->info['scripts'] as $script => $path) {
webmaster@1 449 if (file_exists($path)) {
webmaster@1 450 $theme->scripts[$script] = $path;
webmaster@1 451 }
webmaster@1 452 }
webmaster@1 453 if (isset($theme->info['engine'])) {
webmaster@1 454 $theme->engine = $theme->info['engine'];
webmaster@1 455 }
webmaster@1 456 if (isset($theme->info['base theme'])) {
webmaster@1 457 $theme->base_theme = $theme->info['base theme'];
webmaster@1 458 }
webmaster@1 459 // Status is normally retrieved from the database. Add zero values when
webmaster@1 460 // read from the installation directory to prevent notices.
webmaster@1 461 if (!isset($theme->status)) {
webmaster@1 462 $theme->status = 0;
webmaster@1 463 }
webmaster@1 464 $list[$theme->name] = $theme;
webmaster@1 465 }
webmaster@1 466 }
webmaster@1 467
webmaster@1 468 return $list;
webmaster@1 469 }
webmaster@1 470
webmaster@1 471 /**
webmaster@1 472 * Generate the themed output.
webmaster@1 473 *
webmaster@1 474 * All requests for theme hooks must go through this function. It examines
webmaster@1 475 * the request and routes it to the appropriate theme function. The theme
webmaster@1 476 * registry is checked to determine which implementation to use, which may
webmaster@1 477 * be a function or a template.
webmaster@1 478 *
webmaster@1 479 * If the implementation is a function, it is executed and its return value
webmaster@1 480 * passed along.
webmaster@1 481 *
webmaster@1 482 * If the implementation is a template, the arguments are converted to a
webmaster@1 483 * $variables array. This array is then modified by the module implementing
webmaster@1 484 * the hook, theme engine (if applicable) and the theme. The following
webmaster@1 485 * functions may be used to modify the $variables array. They are processed in
webmaster@1 486 * this order when available:
webmaster@1 487 *
webmaster@1 488 * - template_preprocess(&$variables)
webmaster@1 489 * This sets a default set of variables for all template implementations.
webmaster@1 490 *
webmaster@1 491 * - template_preprocess_HOOK(&$variables)
webmaster@1 492 * This is the first preprocessor called specific to the hook; it should be
webmaster@1 493 * implemented by the module that registers it.
webmaster@1 494 *
webmaster@1 495 * - MODULE_preprocess(&$variables)
webmaster@1 496 * This will be called for all templates; it should only be used if there
webmaster@1 497 * is a real need. It's purpose is similar to template_preprocess().
webmaster@1 498 *
webmaster@1 499 * - MODULE_preprocess_HOOK(&$variables)
webmaster@1 500 * This is for modules that want to alter or provide extra variables for
webmaster@1 501 * theming hooks not registered to itself. For example, if a module named
webmaster@1 502 * "foo" wanted to alter the $submitted variable for the hook "node" a
webmaster@1 503 * preprocess function of foo_preprocess_node() can be created to intercept
webmaster@1 504 * and alter the variable.
webmaster@1 505 *
webmaster@1 506 * - ENGINE_engine_preprocess(&$variables)
webmaster@1 507 * This function should only be implemented by theme engines and exists
webmaster@1 508 * so that it can set necessary variables for all hooks.
webmaster@1 509 *
webmaster@1 510 * - ENGINE_engine_preprocess_HOOK(&$variables)
webmaster@1 511 * This is the same as the previous function, but it is called for a single
webmaster@1 512 * theming hook.
webmaster@1 513 *
webmaster@1 514 * - ENGINE_preprocess(&$variables)
webmaster@1 515 * This is meant to be used by themes that utilize a theme engine. It is
webmaster@1 516 * provided so that the preprocessor is not locked into a specific theme.
webmaster@1 517 * This makes it easy to share and transport code but theme authors must be
webmaster@1 518 * careful to prevent fatal re-declaration errors when using sub-themes that
webmaster@1 519 * have their own preprocessor named exactly the same as its base theme. In
webmaster@1 520 * the default theme engine (PHPTemplate), sub-themes will load their own
webmaster@1 521 * template.php file in addition to the one used for its parent theme. This
webmaster@1 522 * increases the risk for these errors. A good practice is to use the engine
webmaster@1 523 * name for the base theme and the theme name for the sub-themes to minimize
webmaster@1 524 * this possibility.
webmaster@1 525 *
webmaster@1 526 * - ENGINE_preprocess_HOOK(&$variables)
webmaster@1 527 * The same applies from the previous function, but it is called for a
webmaster@1 528 * specific hook.
webmaster@1 529 *
webmaster@1 530 * - THEME_preprocess(&$variables)
webmaster@1 531 * These functions are based upon the raw theme; they should primarily be
webmaster@1 532 * used by themes that do not use an engine or by sub-themes. It serves the
webmaster@1 533 * same purpose as ENGINE_preprocess().
webmaster@1 534 *
webmaster@1 535 * - THEME_preprocess_HOOK(&$variables)
webmaster@1 536 * The same applies from the previous function, but it is called for a
webmaster@1 537 * specific hook.
webmaster@1 538 *
webmaster@1 539 * There are two special variables that these hooks can set:
webmaster@1 540 * 'template_file' and 'template_files'. These will be merged together
webmaster@1 541 * to form a list of 'suggested' alternate template files to use, in
webmaster@1 542 * reverse order of priority. template_file will always be a higher
webmaster@1 543 * priority than items in template_files. theme() will then look for these
webmaster@1 544 * files, one at a time, and use the first one
webmaster@1 545 * that exists.
webmaster@1 546 * @param $hook
webmaster@1 547 * The name of the theme function to call. May be an array, in which
webmaster@1 548 * case the first hook that actually has an implementation registered
webmaster@1 549 * will be used. This can be used to choose 'fallback' theme implementations,
webmaster@1 550 * so that if the specific theme hook isn't implemented anywhere, a more
webmaster@1 551 * generic one will be used. This can allow themes to create specific theme
webmaster@1 552 * implementations for named objects.
webmaster@1 553 * @param ...
webmaster@1 554 * Additional arguments to pass along to the theme function.
webmaster@1 555 * @return
webmaster@1 556 * An HTML string that generates the themed output.
webmaster@1 557 */
webmaster@1 558 function theme() {
webmaster@1 559 $args = func_get_args();
webmaster@1 560 $hook = array_shift($args);
webmaster@1 561
webmaster@1 562 static $hooks = NULL;
webmaster@1 563 if (!isset($hooks)) {
webmaster@1 564 init_theme();
webmaster@1 565 $hooks = theme_get_registry();
webmaster@1 566 }
webmaster@1 567
webmaster@1 568 if (is_array($hook)) {
webmaster@1 569 foreach ($hook as $candidate) {
webmaster@1 570 if (isset($hooks[$candidate])) {
webmaster@1 571 break;
webmaster@1 572 }
webmaster@1 573 }
webmaster@1 574 $hook = $candidate;
webmaster@1 575 }
webmaster@1 576
webmaster@1 577 if (!isset($hooks[$hook])) {
webmaster@1 578 return;
webmaster@1 579 }
webmaster@1 580
webmaster@1 581 $info = $hooks[$hook];
webmaster@1 582 global $theme_path;
webmaster@1 583 $temp = $theme_path;
webmaster@1 584 // point path_to_theme() to the currently used theme path:
webmaster@1 585 $theme_path = $hooks[$hook]['theme path'];
webmaster@1 586
webmaster@1 587 // Include a file if the theme function or preprocess function is held elsewhere.
webmaster@1 588 if (!empty($info['file'])) {
webmaster@1 589 $include_file = $info['file'];
webmaster@1 590 if (isset($info['path'])) {
webmaster@1 591 $include_file = $info['path'] .'/'. $include_file;
webmaster@1 592 }
webmaster@1 593 include_once($include_file);
webmaster@1 594 }
webmaster@1 595 if (isset($info['function'])) {
webmaster@1 596 // The theme call is a function.
webmaster@1 597 $output = call_user_func_array($info['function'], $args);
webmaster@1 598 }
webmaster@1 599 else {
webmaster@1 600 // The theme call is a template.
webmaster@1 601 $variables = array(
webmaster@1 602 'template_files' => array()
webmaster@1 603 );
webmaster@1 604 if (!empty($info['arguments'])) {
webmaster@1 605 $count = 0;
webmaster@1 606 foreach ($info['arguments'] as $name => $default) {
webmaster@1 607 $variables[$name] = isset($args[$count]) ? $args[$count] : $default;
webmaster@1 608 $count++;
webmaster@1 609 }
webmaster@1 610 }
webmaster@1 611
webmaster@1 612 // default render function and extension.
webmaster@1 613 $render_function = 'theme_render_template';
webmaster@1 614 $extension = '.tpl.php';
webmaster@1 615
webmaster@1 616 // Run through the theme engine variables, if necessary
webmaster@1 617 global $theme_engine;
webmaster@1 618 if (isset($theme_engine)) {
webmaster@1 619 // If theme or theme engine is implementing this, it may have
webmaster@1 620 // a different extension and a different renderer.
webmaster@1 621 if ($hooks[$hook]['type'] != 'module') {
webmaster@1 622 if (function_exists($theme_engine .'_render_template')) {
webmaster@1 623 $render_function = $theme_engine .'_render_template';
webmaster@1 624 }
webmaster@1 625 $extension_function = $theme_engine .'_extension';
webmaster@1 626 if (function_exists($extension_function)) {
webmaster@1 627 $extension = $extension_function();
webmaster@1 628 }
webmaster@1 629 }
webmaster@1 630 }
webmaster@1 631
webmaster@1 632 if (isset($info['preprocess functions']) && is_array($info['preprocess functions'])) {
webmaster@1 633 // This construct ensures that we can keep a reference through
webmaster@1 634 // call_user_func_array.
webmaster@1 635 $args = array(&$variables, $hook);
webmaster@1 636 foreach ($info['preprocess functions'] as $preprocess_function) {
webmaster@1 637 if (function_exists($preprocess_function)) {
webmaster@1 638 call_user_func_array($preprocess_function, $args);
webmaster@1 639 }
webmaster@1 640 }
webmaster@1 641 }
webmaster@1 642
webmaster@1 643 // Get suggestions for alternate templates out of the variables
webmaster@1 644 // that were set. This lets us dynamically choose a template
webmaster@1 645 // from a list. The order is FILO, so this array is ordered from
webmaster@1 646 // least appropriate first to most appropriate last.
webmaster@1 647 $suggestions = array();
webmaster@1 648
webmaster@1 649 if (isset($variables['template_files'])) {
webmaster@1 650 $suggestions = $variables['template_files'];
webmaster@1 651 }
webmaster@1 652 if (isset($variables['template_file'])) {
webmaster@1 653 $suggestions[] = $variables['template_file'];
webmaster@1 654 }
webmaster@1 655
webmaster@1 656 if ($suggestions) {
webmaster@1 657 $template_file = drupal_discover_template($info['theme paths'], $suggestions, $extension);
webmaster@1 658 }
webmaster@1 659
webmaster@1 660 if (empty($template_file)) {
webmaster@1 661 $template_file = $hooks[$hook]['template'] . $extension;
webmaster@1 662 if (isset($hooks[$hook]['path'])) {
webmaster@1 663 $template_file = $hooks[$hook]['path'] .'/'. $template_file;
webmaster@1 664 }
webmaster@1 665 }
webmaster@1 666 $output = $render_function($template_file, $variables);
webmaster@1 667 }
webmaster@1 668 // restore path_to_theme()
webmaster@1 669 $theme_path = $temp;
webmaster@1 670 return $output;
webmaster@1 671 }
webmaster@1 672
webmaster@1 673 /**
webmaster@1 674 * Choose which template file to actually render. These are all suggested
webmaster@1 675 * templates from themes and modules. Theming implementations can occur on
webmaster@1 676 * multiple levels. All paths are checked to account for this.
webmaster@1 677 */
webmaster@1 678 function drupal_discover_template($paths, $suggestions, $extension = '.tpl.php') {
webmaster@1 679 global $theme_engine;
webmaster@1 680
webmaster@1 681 // Loop through all paths and suggestions in FIFO order.
webmaster@1 682 $suggestions = array_reverse($suggestions);
webmaster@1 683 $paths = array_reverse($paths);
webmaster@1 684 foreach ($suggestions as $suggestion) {
webmaster@1 685 if (!empty($suggestion)) {
webmaster@1 686 foreach ($paths as $path) {
webmaster@1 687 if (file_exists($file = $path .'/'. $suggestion . $extension)) {
webmaster@1 688 return $file;
webmaster@1 689 }
webmaster@1 690 }
webmaster@1 691 }
webmaster@1 692 }
webmaster@1 693 }
webmaster@1 694
webmaster@1 695 /**
webmaster@1 696 * Return the path to the currently selected theme.
webmaster@1 697 */
webmaster@1 698 function path_to_theme() {
webmaster@1 699 global $theme_path;
webmaster@1 700
webmaster@1 701 if (!isset($theme_path)) {
webmaster@1 702 init_theme();
webmaster@1 703 }
webmaster@1 704
webmaster@1 705 return $theme_path;
webmaster@1 706 }
webmaster@1 707
webmaster@1 708 /**
webmaster@1 709 * Find overridden theme functions. Called by themes and/or theme engines to
webmaster@1 710 * easily discover theme functions.
webmaster@1 711 *
webmaster@1 712 * @param $cache
webmaster@1 713 * The existing cache of theme hooks to test against.
webmaster@1 714 * @param $prefixes
webmaster@1 715 * An array of prefixes to test, in reverse order of importance.
webmaster@1 716 *
webmaster@1 717 * @return $templates
webmaster@1 718 * The functions found, suitable for returning from hook_theme;
webmaster@1 719 */
webmaster@1 720 function drupal_find_theme_functions($cache, $prefixes) {
webmaster@1 721 $templates = array();
webmaster@1 722 $functions = get_defined_functions();
webmaster@1 723
webmaster@1 724 foreach ($cache as $hook => $info) {
webmaster@1 725 foreach ($prefixes as $prefix) {
webmaster@1 726 if (!empty($info['pattern'])) {
webmaster@1 727 $matches = preg_grep('/^'. $prefix .'_'. $info['pattern'] .'/', $functions['user']);
webmaster@1 728 if ($matches) {
webmaster@1 729 foreach ($matches as $match) {
webmaster@1 730 $new_hook = str_replace($prefix .'_', '', $match);
webmaster@1 731 $templates[$new_hook] = array(
webmaster@1 732 'function' => $match,
webmaster@1 733 'arguments' => $info['arguments'],
webmaster@7 734 'original hook' => $hook,
webmaster@1 735 );
webmaster@1 736 }
webmaster@1 737 }
webmaster@1 738 }
webmaster@1 739 if (function_exists($prefix .'_'. $hook)) {
webmaster@1 740 $templates[$hook] = array(
webmaster@1 741 'function' => $prefix .'_'. $hook,
webmaster@1 742 );
webmaster@1 743 }
webmaster@1 744 }
webmaster@1 745 }
webmaster@1 746
webmaster@1 747 return $templates;
webmaster@1 748 }
webmaster@1 749
webmaster@1 750 /**
webmaster@1 751 * Find overridden theme templates. Called by themes and/or theme engines to
webmaster@1 752 * easily discover templates.
webmaster@1 753 *
webmaster@1 754 * @param $cache
webmaster@1 755 * The existing cache of theme hooks to test against.
webmaster@1 756 * @param $extension
webmaster@1 757 * The extension that these templates will have.
webmaster@1 758 * @param $path
webmaster@1 759 * The path to search.
webmaster@1 760 */
webmaster@1 761 function drupal_find_theme_templates($cache, $extension, $path) {
webmaster@1 762 $templates = array();
webmaster@1 763
webmaster@1 764 // Collect paths to all sub-themes grouped by base themes. These will be
webmaster@1 765 // used for filtering. This allows base themes to have sub-themes in its
webmaster@1 766 // folder hierarchy without affecting the base themes template discovery.
webmaster@1 767 $theme_paths = array();
webmaster@1 768 foreach (list_themes() as $theme_info) {
webmaster@1 769 if (!empty($theme_info->base_theme)) {
webmaster@1 770 $theme_paths[$theme_info->base_theme][$theme_info->name] = dirname($theme_info->filename);
webmaster@1 771 }
webmaster@1 772 }
webmaster@1 773 foreach ($theme_paths as $basetheme => $subthemes) {
webmaster@1 774 foreach ($subthemes as $subtheme => $subtheme_path) {
webmaster@1 775 if (isset($theme_paths[$subtheme])) {
webmaster@1 776 $theme_paths[$basetheme] = array_merge($theme_paths[$basetheme], $theme_paths[$subtheme]);
webmaster@1 777 }
webmaster@1 778 }
webmaster@1 779 }
webmaster@1 780 global $theme;
webmaster@1 781 $subtheme_paths = isset($theme_paths[$theme]) ? $theme_paths[$theme] : array();
webmaster@1 782
webmaster@1 783 // Escape the periods in the extension.
webmaster@1 784 $regex = str_replace('.', '\.', $extension) .'$';
webmaster@1 785 // Because drupal_system_listing works the way it does, we check for real
webmaster@1 786 // templates separately from checking for patterns.
webmaster@1 787 $files = drupal_system_listing($regex, $path, 'name', 0);
webmaster@1 788 foreach ($files as $template => $file) {
webmaster@1 789 // Ignore sub-theme templates for the current theme.
webmaster@1 790 if (strpos($file->filename, str_replace($subtheme_paths, '', $file->filename)) !== 0) {
webmaster@1 791 continue;
webmaster@1 792 }
webmaster@1 793 // Chop off the remaining extensions if there are any. $template already
webmaster@1 794 // has the rightmost extension removed, but there might still be more,
webmaster@1 795 // such as with .tpl.php, which still has .tpl in $template at this point.
webmaster@1 796 if (($pos = strpos($template, '.')) !== FALSE) {
webmaster@1 797 $template = substr($template, 0, $pos);
webmaster@1 798 }
webmaster@1 799 // Transform - in filenames to _ to match function naming scheme
webmaster@1 800 // for the purposes of searching.
webmaster@1 801 $hook = strtr($template, '-', '_');
webmaster@1 802 if (isset($cache[$hook])) {
webmaster@1 803 $templates[$hook] = array(
webmaster@1 804 'template' => $template,
webmaster@1 805 'path' => dirname($file->filename),
webmaster@1 806 );
webmaster@1 807 }
webmaster@1 808 }
webmaster@1 809
webmaster@1 810 $patterns = array_keys($files);
webmaster@1 811
webmaster@1 812 foreach ($cache as $hook => $info) {
webmaster@1 813 if (!empty($info['pattern'])) {
webmaster@1 814 // Transform _ in pattern to - to match file naming scheme
webmaster@1 815 // for the purposes of searching.
webmaster@1 816 $pattern = strtr($info['pattern'], '_', '-');
webmaster@1 817
webmaster@1 818 $matches = preg_grep('/^'. $pattern .'/', $patterns);
webmaster@1 819 if ($matches) {
webmaster@1 820 foreach ($matches as $match) {
webmaster@1 821 $file = substr($match, 0, strpos($match, '.'));
webmaster@1 822 // Put the underscores back in for the hook name and register this pattern.
webmaster@1 823 $templates[strtr($file, '-', '_')] = array(
webmaster@1 824 'template' => $file,
webmaster@1 825 'path' => dirname($files[$match]->filename),
webmaster@1 826 'arguments' => $info['arguments'],
webmaster@7 827 'original hook' => $hook,
webmaster@1 828 );
webmaster@1 829 }
webmaster@1 830 }
webmaster@1 831 }
webmaster@1 832 }
webmaster@1 833 return $templates;
webmaster@1 834 }
webmaster@1 835
webmaster@1 836 /**
webmaster@1 837 * Retrieve an associative array containing the settings for a theme.
webmaster@1 838 *
webmaster@1 839 * The final settings are arrived at by merging the default settings,
webmaster@1 840 * the site-wide settings, and the settings defined for the specific theme.
webmaster@1 841 * If no $key was specified, only the site-wide theme defaults are retrieved.
webmaster@1 842 *
webmaster@1 843 * The default values for each of settings are also defined in this function.
webmaster@1 844 * To add new settings, add their default values here, and then add form elements
webmaster@1 845 * to system_theme_settings() in system.module.
webmaster@1 846 *
webmaster@1 847 * @param $key
webmaster@1 848 * The template/style value for a given theme.
webmaster@1 849 *
webmaster@1 850 * @return
webmaster@1 851 * An associative array containing theme settings.
webmaster@1 852 */
webmaster@1 853 function theme_get_settings($key = NULL) {
webmaster@1 854 $defaults = array(
webmaster@1 855 'mission' => '',
webmaster@1 856 'default_logo' => 1,
webmaster@1 857 'logo_path' => '',
webmaster@1 858 'default_favicon' => 1,
webmaster@1 859 'favicon_path' => '',
webmaster@1 860 'primary_links' => 1,
webmaster@1 861 'secondary_links' => 1,
webmaster@1 862 'toggle_logo' => 1,
webmaster@1 863 'toggle_favicon' => 1,
webmaster@1 864 'toggle_name' => 1,
webmaster@1 865 'toggle_search' => 1,
webmaster@1 866 'toggle_slogan' => 0,
webmaster@1 867 'toggle_mission' => 1,
webmaster@1 868 'toggle_node_user_picture' => 0,
webmaster@1 869 'toggle_comment_user_picture' => 0,
webmaster@1 870 'toggle_primary_links' => 1,
webmaster@1 871 'toggle_secondary_links' => 1,
webmaster@1 872 );
webmaster@1 873
webmaster@1 874 if (module_exists('node')) {
webmaster@1 875 foreach (node_get_types() as $type => $name) {
webmaster@1 876 $defaults['toggle_node_info_'. $type] = 1;
webmaster@1 877 }
webmaster@1 878 }
webmaster@1 879 $settings = array_merge($defaults, variable_get('theme_settings', array()));
webmaster@1 880
webmaster@1 881 if ($key) {
webmaster@1 882 $settings = array_merge($settings, variable_get(str_replace('/', '_', 'theme_'. $key .'_settings'), array()));
webmaster@1 883 }
webmaster@1 884
webmaster@1 885 // Only offer search box if search.module is enabled.
webmaster@1 886 if (!module_exists('search') || !user_access('search content')) {
webmaster@1 887 $settings['toggle_search'] = 0;
webmaster@1 888 }
webmaster@1 889
webmaster@1 890 return $settings;
webmaster@1 891 }
webmaster@1 892
webmaster@1 893 /**
webmaster@1 894 * Retrieve a setting for the current theme.
webmaster@1 895 * This function is designed for use from within themes & engines
webmaster@1 896 * to determine theme settings made in the admin interface.
webmaster@1 897 *
webmaster@1 898 * Caches values for speed (use $refresh = TRUE to refresh cache)
webmaster@1 899 *
webmaster@1 900 * @param $setting_name
webmaster@1 901 * The name of the setting to be retrieved.
webmaster@1 902 *
webmaster@1 903 * @param $refresh
webmaster@1 904 * Whether to reload the cache of settings.
webmaster@1 905 *
webmaster@1 906 * @return
webmaster@1 907 * The value of the requested setting, NULL if the setting does not exist.
webmaster@1 908 */
webmaster@1 909 function theme_get_setting($setting_name, $refresh = FALSE) {
webmaster@1 910 global $theme_key;
webmaster@1 911 static $settings;
webmaster@1 912
webmaster@1 913 if (empty($settings) || $refresh) {
webmaster@1 914 $settings = theme_get_settings($theme_key);
webmaster@1 915
webmaster@1 916 $themes = list_themes();
webmaster@1 917 $theme_object = $themes[$theme_key];
webmaster@1 918
webmaster@1 919 if ($settings['mission'] == '') {
webmaster@1 920 $settings['mission'] = variable_get('site_mission', '');
webmaster@1 921 }
webmaster@1 922
webmaster@1 923 if (!$settings['toggle_mission']) {
webmaster@1 924 $settings['mission'] = '';
webmaster@1 925 }
webmaster@1 926
webmaster@1 927 if ($settings['toggle_logo']) {
webmaster@1 928 if ($settings['default_logo']) {
webmaster@1 929 $settings['logo'] = base_path() . dirname($theme_object->filename) .'/logo.png';
webmaster@1 930 }
webmaster@1 931 elseif ($settings['logo_path']) {
webmaster@1 932 $settings['logo'] = base_path() . $settings['logo_path'];
webmaster@1 933 }
webmaster@1 934 }
webmaster@1 935
webmaster@1 936 if ($settings['toggle_favicon']) {
webmaster@1 937 if ($settings['default_favicon']) {
webmaster@1 938 if (file_exists($favicon = dirname($theme_object->filename) .'/favicon.ico')) {
webmaster@1 939 $settings['favicon'] = base_path() . $favicon;
webmaster@1 940 }
webmaster@1 941 else {
webmaster@1 942 $settings['favicon'] = base_path() .'misc/favicon.ico';
webmaster@1 943 }
webmaster@1 944 }
webmaster@1 945 elseif ($settings['favicon_path']) {
webmaster@1 946 $settings['favicon'] = base_path() . $settings['favicon_path'];
webmaster@1 947 }
webmaster@1 948 else {
webmaster@1 949 $settings['toggle_favicon'] = FALSE;
webmaster@1 950 }
webmaster@1 951 }
webmaster@1 952 }
webmaster@1 953
webmaster@1 954 return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL;
webmaster@1 955 }
webmaster@1 956
webmaster@1 957 /**
webmaster@1 958 * Render a system default template, which is essentially a PHP template.
webmaster@1 959 *
webmaster@1 960 * @param $file
webmaster@1 961 * The filename of the template to render.
webmaster@1 962 * @param $variables
webmaster@1 963 * A keyed array of variables that will appear in the output.
webmaster@1 964 *
webmaster@1 965 * @return
webmaster@1 966 * The output generated by the template.
webmaster@1 967 */
webmaster@1 968 function theme_render_template($file, $variables) {
webmaster@1 969 extract($variables, EXTR_SKIP); // Extract the variables to a local namespace
webmaster@1 970 ob_start(); // Start output buffering
webmaster@1 971 include "./$file"; // Include the file
webmaster@1 972 $contents = ob_get_contents(); // Get the contents of the buffer
webmaster@1 973 ob_end_clean(); // End buffering and discard
webmaster@1 974 return $contents; // Return the contents
webmaster@1 975 }
webmaster@1 976
webmaster@1 977 /**
webmaster@1 978 * @defgroup themeable Default theme implementations
webmaster@1 979 * @{
webmaster@1 980 * Functions and templates that present output to the user, and can be
webmaster@1 981 * implemented by themes.
webmaster@1 982 *
webmaster@1 983 * Drupal's presentation layer is a pluggable system known as the theme
webmaster@1 984 * layer. Each theme can take control over most of Drupal's output, and
webmaster@1 985 * has complete control over the CSS.
webmaster@1 986 *
webmaster@1 987 * Inside Drupal, the theme layer is utilized by the use of the theme()
webmaster@1 988 * function, which is passed the name of a component (the theme hook)
webmaster@1 989 * and several arguments. For example, theme('table', $header, $rows);
webmaster@1 990 * Additionally, the theme() function can take an array of theme
webmaster@1 991 * hooks, which can be used to provide 'fallback' implementations to
webmaster@1 992 * allow for more specific control of output. For example, the function:
webmaster@1 993 * theme(array('table__foo', 'table'), $header, $rows) would look to see if
webmaster@1 994 * 'table__foo' is registered anywhere; if it is not, it would 'fall back'
webmaster@1 995 * to the generic 'table' implementation. This can be used to attach specific
webmaster@1 996 * theme functions to named objects, allowing the themer more control over
webmaster@1 997 * specific types of output.
webmaster@1 998 *
webmaster@1 999 * As of Drupal 6, every theme hook is required to be registered by the
webmaster@1 1000 * module that owns it, so that Drupal can tell what to do with it and
webmaster@1 1001 * to make it simple for themes to identify and override the behavior
webmaster@1 1002 * for these calls.
webmaster@1 1003 *
webmaster@1 1004 * The theme hooks are registered via hook_theme(), which returns an
webmaster@1 1005 * array of arrays with information about the hook. It describes the
webmaster@1 1006 * arguments the function or template will need, and provides
webmaster@1 1007 * defaults for the template in case they are not filled in. If the default
webmaster@1 1008 * implementation is a function, by convention it is named theme_HOOK().
webmaster@1 1009 *
webmaster@7 1010 * Each module should provide a default implementation for theme_hooks that
webmaster@1 1011 * it registers. This implementation may be either a function or a template;
webmaster@1 1012 * if it is a function it must be specified via hook_theme(). By convention,
webmaster@1 1013 * default implementations of theme hooks are named theme_HOOK. Default
webmaster@1 1014 * template implementations are stored in the module directory.
webmaster@1 1015 *
webmaster@1 1016 * Drupal's default template renderer is a simple PHP parsing engine that
webmaster@1 1017 * includes the template and stores the output. Drupal's theme engines
webmaster@1 1018 * can provide alternate template engines, such as XTemplate, Smarty and
webmaster@1 1019 * PHPTal. The most common template engine is PHPTemplate (included with
webmaster@1 1020 * Drupal and implemented in phptemplate.engine, which uses Drupal's default
webmaster@1 1021 * template renderer.
webmaster@1 1022 *
webmaster@1 1023 * In order to create theme-specific implementations of these hooks,
webmaster@1 1024 * themes can implement their own version of theme hooks, either as functions
webmaster@1 1025 * or templates. These implementations will be used instead of the default
webmaster@1 1026 * implementation. If using a pure .theme without an engine, the .theme is
webmaster@1 1027 * required to implement its own version of hook_theme() to tell Drupal what
webmaster@1 1028 * it is implementing; themes utilizing an engine will have their well-named
webmaster@1 1029 * theming functions automatically registered for them. While this can vary
webmaster@1 1030 * based upon the theme engine, the standard set by phptemplate is that theme
webmaster@1 1031 * functions should be named either phptemplate_HOOK or THEMENAME_HOOK. For
webmaster@1 1032 * example, for Drupal's default theme (Garland) to implement the 'table' hook,
webmaster@1 1033 * the phptemplate.engine would find phptemplate_table() or garland_table().
webmaster@1 1034 * The ENGINE_HOOK() syntax is preferred, as this can be used by sub-themes
webmaster@1 1035 * (which are themes that share code but use different stylesheets).
webmaster@1 1036 *
webmaster@1 1037 * The theme system is described and defined in theme.inc.
webmaster@1 1038 *
webmaster@1 1039 * @see theme()
webmaster@1 1040 * @see hook_theme()
webmaster@1 1041 */
webmaster@1 1042
webmaster@1 1043 /**
webmaster@1 1044 * Formats text for emphasized display in a placeholder inside a sentence.
webmaster@1 1045 * Used automatically by t().
webmaster@1 1046 *
webmaster@1 1047 * @param $text
webmaster@1 1048 * The text to format (plain-text).
webmaster@1 1049 * @return
webmaster@1 1050 * The formatted text (html).
webmaster@1 1051 */
webmaster@1 1052 function theme_placeholder($text) {
webmaster@1 1053 return '<em>'. check_plain($text) .'</em>';
webmaster@1 1054 }
webmaster@1 1055
webmaster@1 1056 /**
webmaster@1 1057 * Return a themed set of status and/or error messages. The messages are grouped
webmaster@1 1058 * by type.
webmaster@1 1059 *
webmaster@1 1060 * @param $display
webmaster@1 1061 * (optional) Set to 'status' or 'error' to display only messages of that type.
webmaster@1 1062 *
webmaster@1 1063 * @return
webmaster@1 1064 * A string containing the messages.
webmaster@1 1065 */
webmaster@1 1066 function theme_status_messages($display = NULL) {
webmaster@1 1067 $output = '';
webmaster@1 1068 foreach (drupal_get_messages($display) as $type => $messages) {
webmaster@1 1069 $output .= "<div class=\"messages $type\">\n";
webmaster@1 1070 if (count($messages) > 1) {
webmaster@1 1071 $output .= " <ul>\n";
webmaster@1 1072 foreach ($messages as $message) {
webmaster@1 1073 $output .= ' <li>'. $message ."</li>\n";
webmaster@1 1074 }
webmaster@1 1075 $output .= " </ul>\n";
webmaster@1 1076 }
webmaster@1 1077 else {
webmaster@1 1078 $output .= $messages[0];
webmaster@1 1079 }
webmaster@1 1080 $output .= "</div>\n";
webmaster@1 1081 }
webmaster@1 1082 return $output;
webmaster@1 1083 }
webmaster@1 1084
webmaster@1 1085 /**
webmaster@1 1086 * Return a themed set of links.
webmaster@1 1087 *
webmaster@1 1088 * @param $links
webmaster@1 1089 * A keyed array of links to be themed.
webmaster@1 1090 * @param $attributes
webmaster@1 1091 * A keyed array of attributes
webmaster@1 1092 * @return
webmaster@1 1093 * A string containing an unordered list of links.
webmaster@1 1094 */
webmaster@1 1095 function theme_links($links, $attributes = array('class' => 'links')) {
webmaster@1 1096 $output = '';
webmaster@1 1097
webmaster@1 1098 if (count($links) > 0) {
webmaster@1 1099 $output = '<ul'. drupal_attributes($attributes) .'>';
webmaster@1 1100
webmaster@1 1101 $num_links = count($links);
webmaster@1 1102 $i = 1;
webmaster@1 1103
webmaster@1 1104 foreach ($links as $key => $link) {
webmaster@1 1105 $class = $key;
webmaster@1 1106
webmaster@1 1107 // Add first, last and active classes to the list of links to help out themers.
webmaster@1 1108 if ($i == 1) {
webmaster@1 1109 $class .= ' first';
webmaster@1 1110 }
webmaster@1 1111 if ($i == $num_links) {
webmaster@1 1112 $class .= ' last';
webmaster@1 1113 }
webmaster@5 1114 if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))) {
webmaster@1 1115 $class .= ' active';
webmaster@1 1116 }
webmaster@7 1117 $output .= '<li'. drupal_attributes(array('class' => $class)) .'>';
webmaster@1 1118
webmaster@1 1119 if (isset($link['href'])) {
webmaster@1 1120 // Pass in $link as $options, they share the same keys.
webmaster@1 1121 $output .= l($link['title'], $link['href'], $link);
webmaster@1 1122 }
webmaster@1 1123 else if (!empty($link['title'])) {
webmaster@1 1124 // Some links are actually not links, but we wrap these in <span> for adding title and class attributes
webmaster@1 1125 if (empty($link['html'])) {
webmaster@1 1126 $link['title'] = check_plain($link['title']);
webmaster@1 1127 }
webmaster@1 1128 $span_attributes = '';
webmaster@1 1129 if (isset($link['attributes'])) {
webmaster@1 1130 $span_attributes = drupal_attributes($link['attributes']);
webmaster@1 1131 }
webmaster@1 1132 $output .= '<span'. $span_attributes .'>'. $link['title'] .'</span>';
webmaster@1 1133 }
webmaster@1 1134
webmaster@1 1135 $i++;
webmaster@1 1136 $output .= "</li>\n";
webmaster@1 1137 }
webmaster@1 1138
webmaster@1 1139 $output .= '</ul>';
webmaster@1 1140 }
webmaster@1 1141
webmaster@1 1142 return $output;
webmaster@1 1143 }
webmaster@1 1144
webmaster@1 1145 /**
webmaster@1 1146 * Return a themed image.
webmaster@1 1147 *
webmaster@1 1148 * @param $path
webmaster@1 1149 * Either the path of the image file (relative to base_path()) or a full URL.
webmaster@1 1150 * @param $alt
webmaster@1 1151 * The alternative text for text-based browsers.
webmaster@1 1152 * @param $title
webmaster@1 1153 * The title text is displayed when the image is hovered in some popular browsers.
webmaster@1 1154 * @param $attributes
webmaster@1 1155 * Associative array of attributes to be placed in the img tag.
webmaster@1 1156 * @param $getsize
webmaster@1 1157 * If set to TRUE, the image's dimension are fetched and added as width/height attributes.
webmaster@1 1158 * @return
webmaster@1 1159 * A string containing the image tag.
webmaster@1 1160 */
webmaster@1 1161 function theme_image($path, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE) {
webmaster@1 1162 if (!$getsize || (is_file($path) && (list($width, $height, $type, $image_attributes) = @getimagesize($path)))) {
webmaster@1 1163 $attributes = drupal_attributes($attributes);
webmaster@1 1164 $url = (url($path) == $path) ? $path : (base_path() . $path);
webmaster@1 1165 return '<img src="'. check_url($url) .'" alt="'. check_plain($alt) .'" title="'. check_plain($title) .'" '. (isset($image_attributes) ? $image_attributes : '') . $attributes .' />';
webmaster@1 1166 }
webmaster@1 1167 }
webmaster@1 1168
webmaster@1 1169 /**
webmaster@1 1170 * Return a themed breadcrumb trail.
webmaster@1 1171 *
webmaster@1 1172 * @param $breadcrumb
webmaster@1 1173 * An array containing the breadcrumb links.
webmaster@1 1174 * @return a string containing the breadcrumb output.
webmaster@1 1175 */
webmaster@1 1176 function theme_breadcrumb($breadcrumb) {
webmaster@1 1177 if (!empty($breadcrumb)) {
webmaster@1 1178 return '<div class="breadcrumb">'. implode(' » ', $breadcrumb) .'</div>';
webmaster@1 1179 }
webmaster@1 1180 }
webmaster@1 1181
webmaster@1 1182 /**
webmaster@1 1183 * Return a themed help message.
webmaster@1 1184 *
webmaster@1 1185 * @return a string containing the helptext for the current page.
webmaster@1 1186 */
webmaster@1 1187 function theme_help() {
webmaster@1 1188 if ($help = menu_get_active_help()) {
webmaster@1 1189 return '<div class="help">'. $help .'</div>';
webmaster@1 1190 }
webmaster@1 1191 }
webmaster@1 1192
webmaster@1 1193 /**
webmaster@1 1194 * Return a themed submenu, typically displayed under the tabs.
webmaster@1 1195 *
webmaster@1 1196 * @param $links
webmaster@1 1197 * An array of links.
webmaster@1 1198 */
webmaster@1 1199 function theme_submenu($links) {
webmaster@1 1200 return '<div class="submenu">'. implode(' | ', $links) .'</div>';
webmaster@1 1201 }
webmaster@1 1202
webmaster@1 1203 /**
webmaster@1 1204 * Return a themed table.
webmaster@1 1205 *
webmaster@1 1206 * @param $header
webmaster@1 1207 * An array containing the table headers. Each element of the array can be
webmaster@1 1208 * either a localized string or an associative array with the following keys:
webmaster@1 1209 * - "data": The localized title of the table column.
webmaster@1 1210 * - "field": The database field represented in the table column (required if
webmaster@1 1211 * user is to be able to sort on this column).
webmaster@1 1212 * - "sort": A default sort order for this column ("asc" or "desc").
webmaster@1 1213 * - Any HTML attributes, such as "colspan", to apply to the column header cell.
webmaster@1 1214 * @param $rows
webmaster@1 1215 * An array of table rows. Every row is an array of cells, or an associative
webmaster@1 1216 * array with the following keys:
webmaster@1 1217 * - "data": an array of cells
webmaster@1 1218 * - Any HTML attributes, such as "class", to apply to the table row.
webmaster@1 1219 *
webmaster@1 1220 * Each cell can be either a string or an associative array with the following keys:
webmaster@1 1221 * - "data": The string to display in the table cell.
webmaster@1 1222 * - "header": Indicates this cell is a header.
webmaster@1 1223 * - Any HTML attributes, such as "colspan", to apply to the table cell.
webmaster@1 1224 *
webmaster@1 1225 * Here's an example for $rows:
webmaster@1 1226 * @verbatim
webmaster@1 1227 * $rows = array(
webmaster@1 1228 * // Simple row
webmaster@1 1229 * array(
webmaster@1 1230 * 'Cell 1', 'Cell 2', 'Cell 3'
webmaster@1 1231 * ),
webmaster@1 1232 * // Row with attributes on the row and some of its cells.
webmaster@1 1233 * array(
webmaster@1 1234 * 'data' => array('Cell 1', array('data' => 'Cell 2', 'colspan' => 2)), 'class' => 'funky'
webmaster@1 1235 * )
webmaster@1 1236 * );
webmaster@1 1237 * @endverbatim
webmaster@1 1238 *
webmaster@1 1239 * @param $attributes
webmaster@1 1240 * An array of HTML attributes to apply to the table tag.
webmaster@1 1241 * @param $caption
webmaster@1 1242 * A localized string to use for the <caption> tag.
webmaster@1 1243 * @return
webmaster@1 1244 * An HTML string representing the table.
webmaster@1 1245 */
webmaster@1 1246 function theme_table($header, $rows, $attributes = array(), $caption = NULL) {
webmaster@1 1247
webmaster@1 1248 // Add sticky headers, if applicable.
webmaster@1 1249 if (count($header)) {
webmaster@1 1250 drupal_add_js('misc/tableheader.js');
webmaster@1 1251 // Add 'sticky-enabled' class to the table to identify it for JS.
webmaster@1 1252 // This is needed to target tables constructed by this function.
webmaster@1 1253 $attributes['class'] = empty($attributes['class']) ? 'sticky-enabled' : ($attributes['class'] .' sticky-enabled');
webmaster@1 1254 }
webmaster@1 1255
webmaster@1 1256 $output = '<table'. drupal_attributes($attributes) .">\n";
webmaster@1 1257
webmaster@1 1258 if (isset($caption)) {
webmaster@1 1259 $output .= '<caption>'. $caption ."</caption>\n";
webmaster@1 1260 }
webmaster@1 1261
webmaster@1 1262 // Format the table header:
webmaster@1 1263 if (count($header)) {
webmaster@1 1264 $ts = tablesort_init($header);
webmaster@1 1265 // HTML requires that the thead tag has tr tags in it follwed by tbody
webmaster@1 1266 // tags. Using ternary operator to check and see if we have any rows.
webmaster@1 1267 $output .= (count($rows) ? ' <thead><tr>' : ' <tr>');
webmaster@1 1268 foreach ($header as $cell) {
webmaster@1 1269 $cell = tablesort_header($cell, $header, $ts);
webmaster@1 1270 $output .= _theme_table_cell($cell, TRUE);
webmaster@1 1271 }
webmaster@1 1272 // Using ternary operator to close the tags based on whether or not there are rows
webmaster@1 1273 $output .= (count($rows) ? " </tr></thead>\n" : "</tr>\n");
webmaster@1 1274 }
webmaster@1 1275 else {
webmaster@1 1276 $ts = array();
webmaster@1 1277 }
webmaster@1 1278
webmaster@1 1279 // Format the table rows:
webmaster@1 1280 if (count($rows)) {
webmaster@1 1281 $output .= "<tbody>\n";
webmaster@1 1282 $flip = array('even' => 'odd', 'odd' => 'even');
webmaster@1 1283 $class = 'even';
webmaster@1 1284 foreach ($rows as $number => $row) {
webmaster@1 1285 $attributes = array();
webmaster@1 1286
webmaster@1 1287 // Check if we're dealing with a simple or complex row
webmaster@1 1288 if (isset($row['data'])) {
webmaster@1 1289 foreach ($row as $key => $value) {
webmaster@1 1290 if ($key == 'data') {
webmaster@1 1291 $cells = $value;
webmaster@1 1292 }
webmaster@1 1293 else {
webmaster@1 1294 $attributes[$key] = $value;
webmaster@1 1295 }
webmaster@1 1296 }
webmaster@1 1297 }
webmaster@1 1298 else {
webmaster@1 1299 $cells = $row;
webmaster@1 1300 }
webmaster@1 1301 if (count($cells)) {
webmaster@1 1302 // Add odd/even class
webmaster@1 1303 $class = $flip[$class];
webmaster@1 1304 if (isset($attributes['class'])) {
webmaster@1 1305 $attributes['class'] .= ' '. $class;
webmaster@1 1306 }
webmaster@1 1307 else {
webmaster@1 1308 $attributes['class'] = $class;
webmaster@1 1309 }
webmaster@1 1310
webmaster@1 1311 // Build row
webmaster@1 1312 $output .= ' <tr'. drupal_attributes($attributes) .'>';
webmaster@1 1313 $i = 0;
webmaster@1 1314 foreach ($cells as $cell) {
webmaster@1 1315 $cell = tablesort_cell($cell, $header, $ts, $i++);
webmaster@1 1316 $output .= _theme_table_cell($cell);
webmaster@1 1317 }
webmaster@1 1318 $output .= " </tr>\n";
webmaster@1 1319 }
webmaster@1 1320 }
webmaster@1 1321 $output .= "</tbody>\n";
webmaster@1 1322 }
webmaster@1 1323
webmaster@1 1324 $output .= "</table>\n";
webmaster@1 1325 return $output;
webmaster@1 1326 }
webmaster@1 1327
webmaster@1 1328 /**
webmaster@1 1329 * Returns a header cell for tables that have a select all functionality.
webmaster@1 1330 */
webmaster@1 1331 function theme_table_select_header_cell() {
webmaster@1 1332 drupal_add_js('misc/tableselect.js');
webmaster@1 1333
webmaster@1 1334 return array('class' => 'select-all');
webmaster@1 1335 }
webmaster@1 1336
webmaster@1 1337 /**
webmaster@1 1338 * Return a themed sort icon.
webmaster@1 1339 *
webmaster@1 1340 * @param $style
webmaster@1 1341 * Set to either asc or desc. This sets which icon to show.
webmaster@1 1342 * @return
webmaster@1 1343 * A themed sort icon.
webmaster@1 1344 */
webmaster@1 1345 function theme_tablesort_indicator($style) {
webmaster@1 1346 if ($style == "asc") {
webmaster@1 1347 return theme('image', 'misc/arrow-asc.png', t('sort icon'), t('sort ascending'));
webmaster@1 1348 }
webmaster@1 1349 else {
webmaster@1 1350 return theme('image', 'misc/arrow-desc.png', t('sort icon'), t('sort descending'));
webmaster@1 1351 }
webmaster@1 1352 }
webmaster@1 1353
webmaster@1 1354 /**
webmaster@1 1355 * Return a themed box.
webmaster@1 1356 *
webmaster@1 1357 * @param $title
webmaster@1 1358 * The subject of the box.
webmaster@1 1359 * @param $content
webmaster@1 1360 * The content of the box.
webmaster@1 1361 * @param $region
webmaster@1 1362 * The region in which the box is displayed.
webmaster@1 1363 * @return
webmaster@1 1364 * A string containing the box output.
webmaster@1 1365 */
webmaster@1 1366 function theme_box($title, $content, $region = 'main') {
webmaster@1 1367 $output = '<h2 class="title">'. $title .'</h2><div>'. $content .'</div>';
webmaster@1 1368 return $output;
webmaster@1 1369 }
webmaster@1 1370
webmaster@1 1371 /**
webmaster@1 1372 * Return a themed marker, useful for marking new or updated
webmaster@1 1373 * content.
webmaster@1 1374 *
webmaster@1 1375 * @param $type
webmaster@1 1376 * Number representing the marker type to display
webmaster@1 1377 * @see MARK_NEW, MARK_UPDATED, MARK_READ
webmaster@1 1378 * @return
webmaster@1 1379 * A string containing the marker.
webmaster@1 1380 */
webmaster@1 1381 function theme_mark($type = MARK_NEW) {
webmaster@1 1382 global $user;
webmaster@1 1383 if ($user->uid) {
webmaster@1 1384 if ($type == MARK_NEW) {
webmaster@1 1385 return ' <span class="marker">'. t('new') .'</span>';
webmaster@1 1386 }
webmaster@1 1387 else if ($type == MARK_UPDATED) {
webmaster@1 1388 return ' <span class="marker">'. t('updated') .'</span>';
webmaster@1 1389 }
webmaster@1 1390 }
webmaster@1 1391 }
webmaster@1 1392
webmaster@1 1393 /**
webmaster@1 1394 * Return a themed list of items.
webmaster@1 1395 *
webmaster@1 1396 * @param $items
webmaster@1 1397 * An array of items to be displayed in the list. If an item is a string,
webmaster@1 1398 * then it is used as is. If an item is an array, then the "data" element of
webmaster@1 1399 * the array is used as the contents of the list item. If an item is an array
webmaster@1 1400 * with a "children" element, those children are displayed in a nested list.
webmaster@1 1401 * All other elements are treated as attributes of the list item element.
webmaster@1 1402 * @param $title
webmaster@1 1403 * The title of the list.
webmaster@1 1404 * @param $attributes
webmaster@1 1405 * The attributes applied to the list element.
webmaster@1 1406 * @param $type
webmaster@1 1407 * The type of list to return (e.g. "ul", "ol")
webmaster@1 1408 * @return
webmaster@1 1409 * A string containing the list output.
webmaster@1 1410 */
webmaster@1 1411 function theme_item_list($items = array(), $title = NULL, $type = 'ul', $attributes = NULL) {
webmaster@1 1412 $output = '<div class="item-list">';
webmaster@1 1413 if (isset($title)) {
webmaster@1 1414 $output .= '<h3>'. $title .'</h3>';
webmaster@1 1415 }
webmaster@1 1416
webmaster@1 1417 if (!empty($items)) {
webmaster@1 1418 $output .= "<$type". drupal_attributes($attributes) .'>';
webmaster@1 1419 $num_items = count($items);
webmaster@1 1420 foreach ($items as $i => $item) {
webmaster@1 1421 $attributes = array();
webmaster@1 1422 $children = array();
webmaster@1 1423 if (is_array($item)) {
webmaster@1 1424 foreach ($item as $key => $value) {
webmaster@1 1425 if ($key == 'data') {
webmaster@1 1426 $data = $value;
webmaster@1 1427 }
webmaster@1 1428 elseif ($key == 'children') {
webmaster@1 1429 $children = $value;
webmaster@1 1430 }
webmaster@1 1431 else {
webmaster@1 1432 $attributes[$key] = $value;
webmaster@1 1433 }
webmaster@1 1434 }
webmaster@1 1435 }
webmaster@1 1436 else {
webmaster@1 1437 $data = $item;
webmaster@1 1438 }
webmaster@1 1439 if (count($children) > 0) {
webmaster@1 1440 $data .= theme_item_list($children, NULL, $type, $attributes); // Render nested list
webmaster@1 1441 }
webmaster@1 1442 if ($i == 0) {
webmaster@1 1443 $attributes['class'] = empty($attributes['class']) ? 'first' : ($attributes['class'] .' first');
webmaster@1 1444 }
webmaster@1 1445 if ($i == $num_items - 1) {
webmaster@1 1446 $attributes['class'] = empty($attributes['class']) ? 'last' : ($attributes['class'] .' last');
webmaster@1 1447 }
webmaster@1 1448 $output .= '<li'. drupal_attributes($attributes) .'>'. $data ."</li>\n";
webmaster@1 1449 }
webmaster@1 1450 $output .= "</$type>";
webmaster@1 1451 }
webmaster@1 1452 $output .= '</div>';
webmaster@1 1453 return $output;
webmaster@1 1454 }
webmaster@1 1455
webmaster@1 1456 /**
webmaster@1 1457 * Returns code that emits the 'more help'-link.
webmaster@1 1458 */
webmaster@1 1459 function theme_more_help_link($url) {
webmaster@1 1460 return '<div class="more-help-link">'. t('[<a href="@link">more help...</a>]', array('@link' => check_url($url))) .'</div>';
webmaster@1 1461 }
webmaster@1 1462
webmaster@1 1463 /**
webmaster@1 1464 * Return code that emits an XML icon.
webmaster@7 1465 *
webmaster@1 1466 * For most use cases, this function has been superseded by theme_feed_icon().
webmaster@7 1467 *
webmaster@1 1468 * @see theme_feed_icon()
webmaster@1 1469 * @param $url
webmaster@1 1470 * The url of the feed.
webmaster@1 1471 */
webmaster@1 1472 function theme_xml_icon($url) {
webmaster@1 1473 if ($image = theme('image', 'misc/xml.png', t('XML feed'), t('XML feed'))) {
webmaster@1 1474 return '<a href="'. check_url($url) .'" class="xml-icon">'. $image .'</a>';
webmaster@1 1475 }
webmaster@1 1476 }
webmaster@1 1477
webmaster@1 1478 /**
webmaster@1 1479 * Return code that emits an feed icon.
webmaster@1 1480 *
webmaster@1 1481 * @param $url
webmaster@1 1482 * The url of the feed.
webmaster@1 1483 * @param $title
webmaster@1 1484 * A descriptive title of the feed.
webmaster@1 1485 */
webmaster@1 1486 function theme_feed_icon($url, $title) {
webmaster@1 1487 if ($image = theme('image', 'misc/feed.png', t('Syndicate content'), $title)) {
webmaster@1 1488 return '<a href="'. check_url($url) .'" class="feed-icon">'. $image .'</a>';
webmaster@1 1489 }
webmaster@1 1490 }
webmaster@1 1491
webmaster@1 1492 /**
webmaster@1 1493 * Returns code that emits the 'more' link used on blocks.
webmaster@1 1494 *
webmaster@1 1495 * @param $url
webmaster@1 1496 * The url of the main page
webmaster@1 1497 * @param $title
webmaster@1 1498 * A descriptive verb for the link, like 'Read more'
webmaster@1 1499 */
webmaster@1 1500 function theme_more_link($url, $title) {
webmaster@1 1501 return '<div class="more-link">'. t('<a href="@link" title="@title">more</a>', array('@link' => check_url($url), '@title' => $title)) .'</div>';
webmaster@1 1502 }
webmaster@1 1503
webmaster@1 1504 /**
webmaster@1 1505 * Execute hook_footer() which is run at the end of the page right before the
webmaster@1 1506 * close of the body tag.
webmaster@1 1507 *
webmaster@1 1508 * @param $main (optional)
webmaster@1 1509 * Whether the current page is the front page of the site.
webmaster@1 1510 * @return
webmaster@1 1511 * A string containing the results of the hook_footer() calls.
webmaster@1 1512 */
webmaster@1 1513 function theme_closure($main = 0) {
webmaster@1 1514 $footer = module_invoke_all('footer', $main);
webmaster@1 1515 return implode("\n", $footer) . drupal_get_js('footer');
webmaster@1 1516 }
webmaster@1 1517
webmaster@1 1518 /**
webmaster@1 1519 * Return a set of blocks available for the current user.
webmaster@1 1520 *
webmaster@1 1521 * @param $region
webmaster@1 1522 * Which set of blocks to retrieve.
webmaster@1 1523 * @return
webmaster@1 1524 * A string containing the themed blocks for this region.
webmaster@1 1525 */
webmaster@1 1526 function theme_blocks($region) {
webmaster@1 1527 $output = '';
webmaster@1 1528
webmaster@1 1529 if ($list = block_list($region)) {
webmaster@1 1530 foreach ($list as $key => $block) {
webmaster@1 1531 // $key == <i>module</i>_<i>delta</i>
webmaster@1 1532 $output .= theme('block', $block);
webmaster@1 1533 }
webmaster@1 1534 }
webmaster@1 1535
webmaster@1 1536 // Add any content assigned to this region through drupal_set_content() calls.
webmaster@1 1537 $output .= drupal_get_content($region);
webmaster@1 1538
webmaster@1 1539 return $output;
webmaster@1 1540 }
webmaster@1 1541
webmaster@1 1542 /**
webmaster@1 1543 * Format a username.
webmaster@1 1544 *
webmaster@1 1545 * @param $object
webmaster@1 1546 * The user object to format, usually returned from user_load().
webmaster@1 1547 * @return
webmaster@1 1548 * A string containing an HTML link to the user's page if the passed object
webmaster@1 1549 * suggests that this is a site user. Otherwise, only the username is returned.
webmaster@1 1550 */
webmaster@1 1551 function theme_username($object) {
webmaster@1 1552
webmaster@1 1553 if ($object->uid && $object->name) {
webmaster@1 1554 // Shorten the name when it is too long or it will break many tables.
webmaster@1 1555 if (drupal_strlen($object->name) > 20) {
webmaster@1 1556 $name = drupal_substr($object->name, 0, 15) .'...';
webmaster@1 1557 }
webmaster@1 1558 else {
webmaster@1 1559 $name = $object->name;
webmaster@1 1560 }
webmaster@1 1561
webmaster@1 1562 if (user_access('access user profiles')) {
webmaster@5 1563 $output = l($name, 'user/'. $object->uid, array('attributes' => array('title' => t('View user profile.'))));
webmaster@1 1564 }
webmaster@1 1565 else {
webmaster@1 1566 $output = check_plain($name);
webmaster@1 1567 }
webmaster@1 1568 }
webmaster@1 1569 else if ($object->name) {
webmaster@1 1570 // Sometimes modules display content composed by people who are
webmaster@1 1571 // not registered members of the site (e.g. mailing list or news
webmaster@1 1572 // aggregator modules). This clause enables modules to display
webmaster@1 1573 // the true author of the content.
webmaster@1 1574 if (!empty($object->homepage)) {
webmaster@7 1575 $output = l($object->name, $object->homepage, array('attributes' => array('rel' => 'nofollow')));
webmaster@1 1576 }
webmaster@1 1577 else {
webmaster@1 1578 $output = check_plain($object->name);
webmaster@1 1579 }
webmaster@1 1580
webmaster@1 1581 $output .= ' ('. t('not verified') .')';
webmaster@1 1582 }
webmaster@1 1583 else {
webmaster@1 1584 $output = variable_get('anonymous', t('Anonymous'));
webmaster@1 1585 }
webmaster@1 1586
webmaster@1 1587 return $output;
webmaster@1 1588 }
webmaster@1 1589
webmaster@1 1590 /**
webmaster@1 1591 * Return a themed progress bar.
webmaster@1 1592 *
webmaster@1 1593 * @param $percent
webmaster@1 1594 * The percentage of the progress.
webmaster@1 1595 * @param $message
webmaster@1 1596 * A string containing information to be displayed.
webmaster@1 1597 * @return
webmaster@1 1598 * A themed HTML string representing the progress bar.
webmaster@1 1599 */
webmaster@1 1600 function theme_progress_bar($percent, $message) {
webmaster@1 1601 $output = '<div id="progress" class="progress">';
webmaster@1 1602 $output .= '<div class="bar"><div class="filled" style="width: '. $percent .'%"></div></div>';
webmaster@1 1603 $output .= '<div class="percentage">'. $percent .'%</div>';
webmaster@1 1604 $output .= '<div class="message">'. $message .'</div>';
webmaster@1 1605 $output .= '</div>';
webmaster@1 1606
webmaster@1 1607 return $output;
webmaster@1 1608 }
webmaster@1 1609
webmaster@1 1610 /**
webmaster@1 1611 * Create a standard indentation div. Used for drag and drop tables.
webmaster@1 1612 *
webmaster@1 1613 * @param $size
webmaster@1 1614 * Optional. The number of indentations to create.
webmaster@1 1615 * @return
webmaster@1 1616 * A string containing indentations.
webmaster@1 1617 */
webmaster@1 1618 function theme_indentation($size = 1) {
webmaster@1 1619 $output = '';
webmaster@1 1620 for ($n = 0; $n < $size; $n++) {
webmaster@1 1621 $output .= '<div class="indentation">&nbsp;</div>';
webmaster@1 1622 }
webmaster@1 1623 return $output;
webmaster@1 1624 }
webmaster@1 1625
webmaster@1 1626 /**
webmaster@1 1627 * @} End of "defgroup themeable".
webmaster@1 1628 */
webmaster@1 1629
webmaster@1 1630 function _theme_table_cell($cell, $header = FALSE) {
webmaster@1 1631 $attributes = '';
webmaster@1 1632
webmaster@1 1633 if (is_array($cell)) {
webmaster@1 1634 $data = isset($cell['data']) ? $cell['data'] : '';
webmaster@1 1635 $header |= isset($cell['header']);
webmaster@1 1636 unset($cell['data']);
webmaster@1 1637 unset($cell['header']);
webmaster@1 1638 $attributes = drupal_attributes($cell);
webmaster@1 1639 }
webmaster@1 1640 else {
webmaster@1 1641 $data = $cell;
webmaster@1 1642 }
webmaster@1 1643
webmaster@1 1644 if ($header) {
webmaster@1 1645 $output = "<th$attributes>$data</th>";
webmaster@1 1646 }
webmaster@1 1647 else {
webmaster@1 1648 $output = "<td$attributes>$data</td>";
webmaster@1 1649 }
webmaster@1 1650
webmaster@1 1651 return $output;
webmaster@1 1652 }
webmaster@1 1653
webmaster@1 1654 /**
webmaster@1 1655 * Adds a default set of helper variables for preprocess functions and
webmaster@1 1656 * templates. This comes in before any other preprocess function which makes
webmaster@1 1657 * it possible to be used in default theme implementations (non-overriden
webmaster@1 1658 * theme functions).
webmaster@1 1659 */
webmaster@1 1660 function template_preprocess(&$variables, $hook) {
webmaster@1 1661 global $user;
webmaster@1 1662 static $count = array();
webmaster@1 1663
webmaster@1 1664 // Track run count for each hook to provide zebra striping.
webmaster@1 1665 // See "template_preprocess_block()" which provides the same feature specific to blocks.
webmaster@1 1666 $count[$hook] = isset($count[$hook]) && is_int($count[$hook]) ? $count[$hook] : 1;
webmaster@1 1667 $variables['zebra'] = ($count[$hook] % 2) ? 'odd' : 'even';
webmaster@1 1668 $variables['id'] = $count[$hook]++;
webmaster@1 1669
webmaster@1 1670 // Tell all templates where they are located.
webmaster@1 1671 $variables['directory'] = path_to_theme();
webmaster@1 1672
webmaster@1 1673 // Set default variables that depend on the database.
webmaster@1 1674 $variables['is_admin'] = FALSE;
webmaster@1 1675 $variables['is_front'] = FALSE;
webmaster@1 1676 $variables['logged_in'] = FALSE;
webmaster@1 1677 if ($variables['db_is_active'] = db_is_active() && !defined('MAINTENANCE_MODE')) {
webmaster@1 1678 // Check for administrators.
webmaster@1 1679 if (user_access('access administration pages')) {
webmaster@1 1680 $variables['is_admin'] = TRUE;
webmaster@1 1681 }
webmaster@1 1682 // Flag front page status.
webmaster@1 1683 $variables['is_front'] = drupal_is_front_page();
webmaster@1 1684 // Tell all templates by which kind of user they're viewed.
webmaster@1 1685 $variables['logged_in'] = ($user->uid > 0);
webmaster@1 1686 // Provide user object to all templates
webmaster@1 1687 $variables['user'] = $user;
webmaster@1 1688 }
webmaster@1 1689 }
webmaster@1 1690
webmaster@1 1691 /**
webmaster@1 1692 * Process variables for page.tpl.php
webmaster@1 1693 *
webmaster@1 1694 * Most themes utilize their own copy of page.tpl.php. The default is located
webmaster@1 1695 * inside "modules/system/page.tpl.php". Look in there for the full list of
webmaster@1 1696 * variables.
webmaster@1 1697 *
webmaster@1 1698 * Uses the arg() function to generate a series of page template suggestions
webmaster@1 1699 * based on the current path.
webmaster@1 1700 *
webmaster@1 1701 * Any changes to variables in this preprocessor should also be changed inside
webmaster@1 1702 * template_preprocess_maintenance_page() to keep all them consistent.
webmaster@1 1703 *
webmaster@1 1704 * The $variables array contains the following arguments:
webmaster@1 1705 * - $content
webmaster@1 1706 * - $show_blocks
webmaster@1 1707 *
webmaster@1 1708 * @see page.tpl.php
webmaster@1 1709 */
webmaster@1 1710 function template_preprocess_page(&$variables) {
webmaster@1 1711 // Add favicon
webmaster@1 1712 if (theme_get_setting('toggle_favicon')) {
webmaster@1 1713 drupal_set_html_head('<link rel="shortcut icon" href="'. check_url(theme_get_setting('favicon')) .'" type="image/x-icon" />');
webmaster@1 1714 }
webmaster@1 1715
webmaster@1 1716 global $theme;
webmaster@1 1717 // Populate all block regions.
webmaster@1 1718 $regions = system_region_list($theme);
webmaster@1 1719 // Load all region content assigned via blocks.
webmaster@1 1720 foreach (array_keys($regions) as $region) {
webmaster@1 1721 // Prevent left and right regions from rendering blocks when 'show_blocks' == FALSE.
webmaster@1 1722 if (!(!$variables['show_blocks'] && ($region == 'left' || $region == 'right'))) {
webmaster@1 1723 $blocks = theme('blocks', $region);
webmaster@1 1724 }
webmaster@1 1725 else {
webmaster@1 1726 $blocks = '';
webmaster@1 1727 }
webmaster@1 1728 // Assign region to a region variable.
webmaster@1 1729 isset($variables[$region]) ? $variables[$region] .= $blocks : $variables[$region] = $blocks;
webmaster@1 1730 }
webmaster@1 1731
webmaster@1 1732 // Set up layout variable.
webmaster@1 1733 $variables['layout'] = 'none';
webmaster@1 1734 if (!empty($variables['left'])) {
webmaster@1 1735 $variables['layout'] = 'left';
webmaster@1 1736 }
webmaster@1 1737 if (!empty($variables['right'])) {
webmaster@1 1738 $variables['layout'] = ($variables['layout'] == 'left') ? 'both' : 'right';
webmaster@1 1739 }
webmaster@1 1740
webmaster@1 1741 // Set mission when viewing the frontpage.
webmaster@1 1742 if (drupal_is_front_page()) {
webmaster@1 1743 $mission = filter_xss_admin(theme_get_setting('mission'));
webmaster@1 1744 }
webmaster@1 1745
webmaster@1 1746 // Construct page title
webmaster@1 1747 if (drupal_get_title()) {
webmaster@1 1748 $head_title = array(strip_tags(drupal_get_title()), variable_get('site_name', 'Drupal'));
webmaster@1 1749 }
webmaster@1 1750 else {
webmaster@1 1751 $head_title = array(variable_get('site_name', 'Drupal'));
webmaster@1 1752 if (variable_get('site_slogan', '')) {
webmaster@1 1753 $head_title[] = variable_get('site_slogan', '');
webmaster@1 1754 }
webmaster@1 1755 }
webmaster@1 1756 $variables['head_title'] = implode(' | ', $head_title);
webmaster@1 1757 $variables['base_path'] = base_path();
webmaster@1 1758 $variables['front_page'] = url();
webmaster@1 1759 $variables['breadcrumb'] = theme('breadcrumb', drupal_get_breadcrumb());
webmaster@1 1760 $variables['feed_icons'] = drupal_get_feeds();
webmaster@1 1761 $variables['footer_message'] = filter_xss_admin(variable_get('site_footer', FALSE));
webmaster@1 1762 $variables['head'] = drupal_get_html_head();
webmaster@1 1763 $variables['help'] = theme('help');
webmaster@1 1764 $variables['language'] = $GLOBALS['language'];
webmaster@1 1765 $variables['language']->dir = $GLOBALS['language']->direction ? 'rtl' : 'ltr';
webmaster@1 1766 $variables['logo'] = theme_get_setting('logo');
webmaster@1 1767 $variables['messages'] = $variables['show_messages'] ? theme('status_messages') : '';
webmaster@1 1768 $variables['mission'] = isset($mission) ? $mission : '';
webmaster@1 1769 $variables['primary_links'] = theme_get_setting('toggle_primary_links') ? menu_primary_links() : array();
webmaster@1 1770 $variables['secondary_links'] = theme_get_setting('toggle_secondary_links') ? menu_secondary_links() : array();
webmaster@1 1771 $variables['search_box'] = (theme_get_setting('toggle_search') ? drupal_get_form('search_theme_form') : '');
webmaster@1 1772 $variables['site_name'] = (theme_get_setting('toggle_name') ? variable_get('site_name', 'Drupal') : '');
webmaster@1 1773 $variables['site_slogan'] = (theme_get_setting('toggle_slogan') ? variable_get('site_slogan', '') : '');
webmaster@1 1774 $variables['css'] = drupal_add_css();
webmaster@1 1775 $variables['styles'] = drupal_get_css();
webmaster@1 1776 $variables['scripts'] = drupal_get_js();
webmaster@1 1777 $variables['tabs'] = theme('menu_local_tasks');
webmaster@1 1778 $variables['title'] = drupal_get_title();
webmaster@1 1779 // Closure should be filled last.
webmaster@1 1780 $variables['closure'] = theme('closure');
webmaster@1 1781
webmaster@1 1782 if ($node = menu_get_object()) {
webmaster@1 1783 $variables['node'] = $node;
webmaster@1 1784 }
webmaster@1 1785
webmaster@1 1786 // Compile a list of classes that are going to be applied to the body element.
webmaster@1 1787 // This allows advanced theming based on context (home page, node of certain type, etc.).
webmaster@1 1788 $body_classes = array();
webmaster@1 1789 // Add a class that tells us whether we're on the front page or not.
webmaster@1 1790 $body_classes[] = $variables['is_front'] ? 'front' : 'not-front';
webmaster@1 1791 // Add a class that tells us whether the page is viewed by an authenticated user or not.
webmaster@1 1792 $body_classes[] = $variables['logged_in'] ? 'logged-in' : 'not-logged-in';
webmaster@1 1793 // Add arg(0) to make it possible to theme the page depending on the current page
webmaster@1 1794 // type (e.g. node, admin, user, etc.). To avoid illegal characters in the class,
webmaster@1 1795 // we're removing everything disallowed. We are not using 'a-z' as that might leave
webmaster@1 1796 // in certain international characters (e.g. German umlauts).
webmaster@1 1797 $body_classes[] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', 'page-'. form_clean_id(drupal_strtolower(arg(0))));
webmaster@1 1798 // If on an individual node page, add the node type.
webmaster@1 1799 if (isset($variables['node']) && $variables['node']->type) {
webmaster@1 1800 $body_classes[] = 'node-type-'. form_clean_id($variables['node']->type);
webmaster@1 1801 }
webmaster@1 1802 // Add information about the number of sidebars.
webmaster@1 1803 if ($variables['layout'] == 'both') {
webmaster@1 1804 $body_classes[] = 'two-sidebars';
webmaster@1 1805 }
webmaster@1 1806 elseif ($variables['layout'] == 'none') {
webmaster@1 1807 $body_classes[] = 'no-sidebars';
webmaster@1 1808 }
webmaster@1 1809 else {
webmaster@1 1810 $body_classes[] = 'one-sidebar sidebar-'. $variables['layout'];
webmaster@1 1811 }
webmaster@1 1812 // Implode with spaces.
webmaster@1 1813 $variables['body_classes'] = implode(' ', $body_classes);
webmaster@1 1814
webmaster@1 1815 // Build a list of suggested template files in order of specificity. One
webmaster@1 1816 // suggestion is made for every element of the current path, though
webmaster@1 1817 // numeric elements are not carried to subsequent suggestions. For example,
webmaster@1 1818 // http://www.example.com/node/1/edit would result in the following
webmaster@1 1819 // suggestions:
webmaster@1 1820 //
webmaster@1 1821 // page-node-edit.tpl.php
webmaster@1 1822 // page-node-1.tpl.php
webmaster@1 1823 // page-node.tpl.php
webmaster@1 1824 // page.tpl.php
webmaster@1 1825 $i = 0;
webmaster@1 1826 $suggestion = 'page';
webmaster@1 1827 $suggestions = array();
webmaster@1 1828 while ($arg = arg($i++)) {
webmaster@1 1829 $suggestions[] = $suggestion .'-'. $arg;
webmaster@1 1830 if (!is_numeric($arg)) {
webmaster@1 1831 $suggestion .= '-'. $arg;
webmaster@1 1832 }
webmaster@1 1833 }
webmaster@1 1834 if (drupal_is_front_page()) {
webmaster@1 1835 $suggestions[] = 'page-front';
webmaster@1 1836 }
webmaster@1 1837
webmaster@1 1838 if ($suggestions) {
webmaster@1 1839 $variables['template_files'] = $suggestions;
webmaster@1 1840 }
webmaster@1 1841 }
webmaster@1 1842
webmaster@1 1843 /**
webmaster@1 1844 * Process variables for node.tpl.php
webmaster@1 1845 *
webmaster@1 1846 * Most themes utilize their own copy of node.tpl.php. The default is located
webmaster@1 1847 * inside "modules/node/node.tpl.php". Look in there for the full list of
webmaster@1 1848 * variables.
webmaster@1 1849 *
webmaster@1 1850 * The $variables array contains the following arguments:
webmaster@1 1851 * - $node
webmaster@1 1852 * - $teaser
webmaster@1 1853 * - $page
webmaster@1 1854 *
webmaster@1 1855 * @see node.tpl.php
webmaster@1 1856 */
webmaster@1 1857 function template_preprocess_node(&$variables) {
webmaster@1 1858 $node = $variables['node'];
webmaster@1 1859 if (module_exists('taxonomy')) {
webmaster@1 1860 $variables['taxonomy'] = taxonomy_link('taxonomy terms', $node);
webmaster@1 1861 }
webmaster@1 1862 else {
webmaster@1 1863 $variables['taxonomy'] = array();
webmaster@1 1864 }
webmaster@1 1865
webmaster@1 1866 if ($variables['teaser'] && $node->teaser) {
webmaster@1 1867 $variables['content'] = $node->teaser;
webmaster@1 1868 }
webmaster@1 1869 elseif (isset($node->body)) {
webmaster@1 1870 $variables['content'] = $node->body;
webmaster@1 1871 }
webmaster@1 1872 else {
webmaster@1 1873 $variables['content'] = '';
webmaster@1 1874 }
webmaster@1 1875
webmaster@1 1876 $variables['date'] = format_date($node->created);
webmaster@1 1877 $variables['links'] = !empty($node->links) ? theme('links', $node->links, array('class' => 'links inline')) : '';
webmaster@1 1878 $variables['name'] = theme('username', $node);
webmaster@1 1879 $variables['node_url'] = url('node/'. $node->nid);
webmaster@1 1880 $variables['terms'] = theme('links', $variables['taxonomy'], array('class' => 'links inline'));
webmaster@1 1881 $variables['title'] = check_plain($node->title);
webmaster@1 1882
webmaster@1 1883 // Flatten the node object's member fields.
webmaster@1 1884 $variables = array_merge((array)$node, $variables);
webmaster@1 1885
webmaster@1 1886 // Display info only on certain node types.
webmaster@1 1887 if (theme_get_setting('toggle_node_info_'. $node->type)) {
webmaster@1 1888 $variables['submitted'] = theme('node_submitted', $node);
webmaster@1 1889 $variables['picture'] = theme_get_setting('toggle_node_user_picture') ? theme('user_picture', $node) : '';
webmaster@1 1890 }
webmaster@1 1891 else {
webmaster@1 1892 $variables['submitted'] = '';
webmaster@1 1893 $variables['picture'] = '';
webmaster@1 1894 }
webmaster@1 1895 // Clean up name so there are no underscores.
webmaster@1 1896 $variables['template_files'][] = 'node-'. $node->type;
webmaster@1 1897 }
webmaster@1 1898
webmaster@1 1899 /**
webmaster@1 1900 * Process variables for block.tpl.php
webmaster@1 1901 *
webmaster@1 1902 * Prepare the values passed to the theme_block function to be passed
webmaster@1 1903 * into a pluggable template engine. Uses block properties to generate a
webmaster@1 1904 * series of template file suggestions. If none are found, the default
webmaster@1 1905 * block.tpl.php is used.
webmaster@1 1906 *
webmaster@1 1907 * Most themes utilize their own copy of block.tpl.php. The default is located
webmaster@1 1908 * inside "modules/system/block.tpl.php". Look in there for the full list of
webmaster@1 1909 * variables.
webmaster@1 1910 *
webmaster@1 1911 * The $variables array contains the following arguments:
webmaster@1 1912 * - $block
webmaster@1 1913 *
webmaster@1 1914 * @see block.tpl.php
webmaster@1 1915 */
webmaster@1 1916 function template_preprocess_block(&$variables) {
webmaster@1 1917 static $block_counter = array();
webmaster@1 1918 // All blocks get an independent counter for each region.
webmaster@1 1919 if (!isset($block_counter[$variables['block']->region])) {
webmaster@1 1920 $block_counter[$variables['block']->region] = 1;
webmaster@1 1921 }
webmaster@1 1922 // Same with zebra striping.
webmaster@1 1923 $variables['block_zebra'] = ($block_counter[$variables['block']->region] % 2) ? 'odd' : 'even';
webmaster@1 1924 $variables['block_id'] = $block_counter[$variables['block']->region]++;
webmaster@1 1925
webmaster@1 1926 $variables['template_files'][] = 'block-'. $variables['block']->region;
webmaster@1 1927 $variables['template_files'][] = 'block-'. $variables['block']->module;
webmaster@1 1928 $variables['template_files'][] = 'block-'. $variables['block']->module .'-'. $variables['block']->delta;
webmaster@1 1929 }
webmaster@1 1930