PageRenderTime 127ms CodeModel.GetById 3ms app.highlight 109ms RepoModel.GetById 2ms app.codeStats 0ms

/includes/theme.inc

https://bitbucket.org/robbiethegeek/robbie-drupal7
Pascal | 2579 lines | 1498 code | 123 blank | 958 comment | 204 complexity | 3ef1224115552e38fec3098bc9875374 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2// $Id: theme.inc,v 1.618 2010/10/05 19:59:10 dries Exp $
   3
   4/**
   5 * @file
   6 * The theme system, which controls the output of Drupal.
   7 *
   8 * The theme system allows for nearly all output of the Drupal system to be
   9 * customized by user themes.
  10 */
  11
  12/**
  13 * @name Content markers
  14 * @{
  15 * Markers used by theme_mark() and node_mark() to designate content.
  16 * @see theme_mark(), node_mark()
  17 */
  18
  19/**
  20 * Mark content as read.
  21 */
  22define('MARK_READ', 0);
  23
  24/**
  25 * Mark content as being new.
  26 */
  27define('MARK_NEW', 1);
  28
  29/**
  30 * Mark content as being updated.
  31 */
  32define('MARK_UPDATED', 2);
  33
  34/**
  35 * @} End of "Content markers".
  36 */
  37
  38/**
  39 * Determines if a theme is available to use.
  40 *
  41 * @param $theme
  42 *   Either the name of a theme or a full theme object.
  43 *
  44 * @return
  45 *   Boolean TRUE if the theme is enabled or is the site administration theme;
  46 *   FALSE otherwise.
  47 */
  48function drupal_theme_access($theme) {
  49  if (is_object($theme)) {
  50    return _drupal_theme_access($theme);
  51  }
  52  else {
  53    $themes = list_themes();
  54    return isset($themes[$theme]) && _drupal_theme_access($themes[$theme]);
  55  }
  56}
  57
  58/**
  59 * Helper function for determining access to a theme.
  60 *
  61 * @see drupal_theme_access()
  62 */
  63function _drupal_theme_access($theme) {
  64  $admin_theme = variable_get('admin_theme');
  65  return !empty($theme->status) || ($admin_theme && $theme->name == $admin_theme);
  66}
  67
  68/**
  69 * Initialize the theme system by loading the theme.
  70 */
  71function drupal_theme_initialize() {
  72  global $theme, $user, $theme_key;
  73
  74  // If $theme is already set, assume the others are set, too, and do nothing
  75  if (isset($theme)) {
  76    return;
  77  }
  78
  79  drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
  80  $themes = list_themes();
  81
  82  // Only select the user selected theme if it is available in the
  83  // list of themes that can be accessed.
  84  $theme = !empty($user->theme) && drupal_theme_access($user->theme) ? $user->theme : variable_get('theme_default', 'bartik');
  85
  86  // Allow modules to override the theme. Validation has already been performed
  87  // inside menu_get_custom_theme(), so we do not need to check it again here.
  88  $custom_theme = menu_get_custom_theme();
  89  $theme = !empty($custom_theme) ? $custom_theme : $theme;
  90
  91  // Store the identifier for retrieving theme settings with.
  92  $theme_key = $theme;
  93
  94  // Find all our ancestor themes and put them in an array.
  95  $base_theme = array();
  96  $ancestor = $theme;
  97  while ($ancestor && isset($themes[$ancestor]->base_theme)) {
  98    $ancestor = $themes[$ancestor]->base_theme;
  99    $base_theme[] = $themes[$ancestor];
 100  }
 101  _drupal_theme_initialize($themes[$theme], array_reverse($base_theme));
 102
 103  // Themes can have alter functions, so reset the drupal_alter() cache.
 104  drupal_static_reset('drupal_alter');
 105
 106  // Provide the page with information about the theme that's used, so that a
 107  // later AJAX request can be rendered using the same theme.
 108  // @see ajax_base_page_theme()
 109  $setting['ajaxPageState'] = array(
 110    'theme' => $theme_key,
 111    'themeToken' => drupal_get_token($theme_key),
 112  );
 113  drupal_add_js($setting, 'setting');
 114}
 115
 116/**
 117 * Initialize the theme system given already loaded information. This
 118 * function is useful to initialize a theme when no database is present.
 119 *
 120 * @param $theme
 121 *   An object with the following information:
 122 *     filename
 123 *       The .info file for this theme. The 'path' to
 124 *       the theme will be in this file's directory. (Required)
 125 *     owner
 126 *       The path to the .theme file or the .engine file to load for
 127 *       the theme. (Required)
 128 *     stylesheet
 129 *       The primary stylesheet for the theme. (Optional)
 130 *     engine
 131 *       The name of theme engine to use. (Optional)
 132 * @param $base_theme
 133 *    An optional array of objects that represent the 'base theme' if the
 134 *    theme is meant to be derivative of another theme. It requires
 135 *    the same information as the $theme object. It should be in
 136 *    'oldest first' order, meaning the top level of the chain will
 137 *    be first.
 138 * @param $registry_callback
 139 *   The callback to invoke to set the theme registry.
 140 */
 141function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callback = '_theme_load_registry') {
 142  global $theme_info, $base_theme_info, $theme_engine, $theme_path;
 143  $theme_info = $theme;
 144  $base_theme_info = $base_theme;
 145
 146  $theme_path = dirname($theme->filename);
 147
 148  // Prepare stylesheets from this theme as well as all ancestor themes.
 149  // We work it this way so that we can have child themes override parent
 150  // theme stylesheets easily.
 151  $final_stylesheets = array();
 152
 153  // Grab stylesheets from base theme
 154  foreach ($base_theme as $base) {
 155    if (!empty($base->stylesheets)) {
 156      foreach ($base->stylesheets as $media => $stylesheets) {
 157        foreach ($stylesheets as $name => $stylesheet) {
 158          $final_stylesheets[$media][$name] = $stylesheet;
 159        }
 160      }
 161    }
 162  }
 163
 164  // Add stylesheets used by this theme.
 165  if (!empty($theme->stylesheets)) {
 166    foreach ($theme->stylesheets as $media => $stylesheets) {
 167      foreach ($stylesheets as $name => $stylesheet) {
 168        $final_stylesheets[$media][$name] = $stylesheet;
 169      }
 170    }
 171  }
 172
 173  // And now add the stylesheets properly
 174  foreach ($final_stylesheets as $media => $stylesheets) {
 175    foreach ($stylesheets as $stylesheet) {
 176      drupal_add_css($stylesheet, array('group' => CSS_THEME, 'every_page' => TRUE, 'media' => $media));
 177    }
 178  }
 179
 180  // Do basically the same as the above for scripts
 181  $final_scripts = array();
 182
 183  // Grab scripts from base theme
 184  foreach ($base_theme as $base) {
 185    if (!empty($base->scripts)) {
 186      foreach ($base->scripts as $name => $script) {
 187        $final_scripts[$name] = $script;
 188      }
 189    }
 190  }
 191
 192  // Add scripts used by this theme.
 193  if (!empty($theme->scripts)) {
 194    foreach ($theme->scripts as $name => $script) {
 195      $final_scripts[$name] = $script;
 196    }
 197  }
 198
 199  // Add scripts used by this theme.
 200  foreach ($final_scripts as $script) {
 201    drupal_add_js($script, array('group' => JS_THEME, 'every_page' => TRUE));
 202  }
 203
 204  $theme_engine = NULL;
 205
 206  // Initialize the theme.
 207  if (isset($theme->engine)) {
 208    // Include the engine.
 209    include_once DRUPAL_ROOT . '/' . $theme->owner;
 210
 211    $theme_engine = $theme->engine;
 212    if (function_exists($theme_engine . '_init')) {
 213      foreach ($base_theme as $base) {
 214        call_user_func($theme_engine . '_init', $base);
 215      }
 216      call_user_func($theme_engine . '_init', $theme);
 217    }
 218  }
 219  else {
 220    // include non-engine theme files
 221    foreach ($base_theme as $base) {
 222      // Include the theme file or the engine.
 223      if (!empty($base->owner)) {
 224        include_once DRUPAL_ROOT . '/' . $base->owner;
 225      }
 226    }
 227    // and our theme gets one too.
 228    if (!empty($theme->owner)) {
 229      include_once DRUPAL_ROOT . '/' . $theme->owner;
 230    }
 231  }
 232
 233  if (isset($registry_callback)) {
 234    _theme_registry_callback($registry_callback, array($theme, $base_theme, $theme_engine));
 235  }
 236}
 237
 238/**
 239 * Get the theme registry.
 240 *
 241 * @return
 242 *   The theme registry array if it has been stored in memory, NULL otherwise.
 243 */
 244function theme_get_registry() {
 245  static $theme_registry = NULL;
 246
 247  if (!isset($theme_registry)) {
 248    list($callback, $arguments) = _theme_registry_callback();
 249    $theme_registry = call_user_func_array($callback, $arguments);
 250  }
 251
 252  return $theme_registry;
 253}
 254
 255/**
 256 * Set the callback that will be used by theme_get_registry() to fetch the registry.
 257 *
 258 * @param $callback
 259 *   The name of the callback function.
 260 * @param $arguments
 261 *   The arguments to pass to the function.
 262 */
 263function _theme_registry_callback($callback = NULL, array $arguments = array()) {
 264  static $stored;
 265  if (isset($callback)) {
 266    $stored = array($callback, $arguments);
 267  }
 268  return $stored;
 269}
 270
 271/**
 272 * Get the theme_registry cache from the database; if it doesn't exist, build it.
 273 *
 274 * @param $theme
 275 *   The loaded $theme object as returned by list_themes().
 276 * @param $base_theme
 277 *   An array of loaded $theme objects representing the ancestor themes in
 278 *   oldest first order.
 279 * @param theme_engine
 280 *   The name of the theme engine.
 281 */
 282function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
 283  // Check the theme registry cache; if it exists, use it.
 284  $cache = cache_get("theme_registry:$theme->name", 'cache');
 285  if (isset($cache->data)) {
 286    $registry = $cache->data;
 287  }
 288  else {
 289    // If not, build one and cache it.
 290    $registry = _theme_build_registry($theme, $base_theme, $theme_engine);
 291   // Only persist this registry if all modules are loaded. This assures a
 292   // complete set of theme hooks.
 293    if (module_load_all(NULL)) {
 294      _theme_save_registry($theme, $registry);
 295    }
 296  }
 297  return $registry;
 298}
 299
 300/**
 301 * Write the theme_registry cache into the database.
 302 */
 303function _theme_save_registry($theme, $registry) {
 304  cache_set("theme_registry:$theme->name", $registry);
 305}
 306
 307/**
 308 * Force the system to rebuild the theme registry; this should be called
 309 * when modules are added to the system, or when a dynamic system needs
 310 * to add more theme hooks.
 311 */
 312function drupal_theme_rebuild() {
 313  cache_clear_all('theme_registry', 'cache', TRUE);
 314}
 315
 316/**
 317 * Process a single implementation of hook_theme().
 318 *
 319 * @param $cache
 320 *   The theme registry that will eventually be cached; It is an associative
 321 *   array keyed by theme hooks, whose values are associative arrays describing
 322 *   the hook:
 323 *   - 'type': The passed in $type.
 324 *   - 'theme path': The passed in $path.
 325 *   - 'function': The name of the function generating output for this theme
 326 *     hook. Either defined explicitly in hook_theme() or, if neither 'function'
 327 *     nor 'template' is defined, then the default theme function name is used.
 328 *     The default theme function name is the theme hook prefixed by either
 329 *     'theme_' for modules or '$name_' for everything else. If 'function' is
 330 *     defined, 'template' is not used.
 331 *   - 'template': The filename of the template generating output for this
 332 *     theme hook. The template is in the directory defined by the 'path' key of
 333 *     hook_theme() or defaults to $path.
 334 *   - 'variables': The variables for this theme hook as defined in
 335 *     hook_theme(). If there is more than one implementation and 'variables' is
 336 *     not specified in a later one, then the previous definition is kept.
 337 *   - 'render element': The renderable element for this theme hook as defined
 338 *     in hook_theme(). If there is more than one implementation and
 339 *     'render element' is not specified in a later one, then the previous
 340 *     definition is kept.
 341 *   - 'preprocess functions': See theme() for detailed documentation.
 342 *   - 'process functions': See theme() for detailed documentation.
 343 * @param $name
 344 *   The name of the module, theme engine, base theme engine, theme or base
 345 *   theme implementing hook_theme().
 346 * @param $type
 347 *   One of 'module', 'theme_engine', 'base_theme_engine', 'theme', or
 348 *   'base_theme'. Unlike regular hooks that can only be implemented by modules,
 349 *   each of these can implement hook_theme(). _theme_process_registry() is
 350 *   called in aforementioned order and new entries override older ones. For
 351 *   example, if a theme hook is both defined by a module and a theme, then the
 352 *   definition in the theme will be used.
 353 * @param $theme
 354 *   The loaded $theme object as returned from list_themes().
 355 * @param $path
 356 *   The directory where $name is. For example, modules/system or
 357 *   themes/bartik.
 358 *
 359 * @see theme()
 360 * @see _theme_process_registry()
 361 * @see hook_theme()
 362 * @see list_themes()
 363 */
 364function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
 365  $result = array();
 366  $function = $name . '_theme';
 367
 368  // Processor functions work in two distinct phases with the process
 369  // functions always being executed after the preprocess functions.
 370  $variable_process_phases = array(
 371    'preprocess functions' => 'preprocess',
 372    'process functions'    => 'process',
 373  );
 374
 375  if (function_exists($function)) {
 376    $result = $function($cache, $type, $theme, $path);
 377    foreach ($result as $hook => $info) {
 378      $result[$hook]['type'] = $type;
 379      $result[$hook]['theme path'] = $path;
 380      // if function and file are left out, default to standard naming
 381      // conventions.
 382      if (!isset($info['template']) && !isset($info['function'])) {
 383        $result[$hook]['function'] = ($type == 'module' ? 'theme_' : $name . '_') . $hook;
 384      }
 385      // If a path is set in the info, use what was set. Otherwise use the
 386      // default path. This is mostly so system.module can declare theme
 387      // functions on behalf of core .include files.
 388      // All files are included to be safe. Conditionally included
 389      // files can prevent them from getting registered.
 390      if (isset($cache[$hook]['includes'])) {
 391        $result[$hook]['includes'] = $cache[$hook]['includes'];
 392      }
 393      if (isset($info['file'])) {
 394        $include_file = isset($info['path']) ? $info['path'] : $path;
 395        $include_file .= '/' . $info['file'];
 396        include_once DRUPAL_ROOT . '/' . $include_file;
 397        $result[$hook]['includes'][] = $include_file;
 398      }
 399
 400      // If these keys are left unspecified within overridden entries returned
 401      // by hook_theme(), carry them forward from the prior entry. This is so
 402      // that themes don't need to specify this information, since the module
 403      // that registered the theme hook already has.
 404      foreach (array('variables', 'render element', 'pattern', 'base hook') as $key) {
 405        if (!array_key_exists($key, $info) && isset($cache[$hook][$key])) {
 406          $result[$hook][$key] = $cache[$hook][$key];
 407        }
 408      }
 409
 410      // The following apply only to theming hooks implemented as templates.
 411      if (isset($info['template'])) {
 412        // Prepend the current theming path when none is set.
 413        if (!isset($info['path'])) {
 414          $result[$hook]['template'] = $path . '/' . $info['template'];
 415        }
 416      }
 417
 418      // Allow variable processors for all theming hooks, whether the hook is
 419      // implemented as a template or as a function.
 420      foreach ($variable_process_phases as $phase_key => $phase) {
 421        // Check for existing variable processors. Ensure arrayness.
 422        if (!isset($info[$phase_key]) || !is_array($info[$phase_key])) {
 423          $info[$phase_key] = array();
 424          $prefixes = array();
 425          if ($type == 'module') {
 426            // Default variable processor prefix.
 427            $prefixes[] = 'template';
 428            // Add all modules so they can intervene with their own variable
 429            // processors. This allows them to provide variable processors even
 430            // if they are not the owner of the current hook.
 431            $prefixes += module_list();
 432          }
 433          elseif ($type == 'theme_engine' || $type == 'base_theme_engine') {
 434            // Theme engines get an extra set that come before the normally
 435            // named variable processors.
 436            $prefixes[] = $name . '_engine';
 437            // The theme engine registers on behalf of the theme using the
 438            // theme's name.
 439            $prefixes[] = $theme;
 440          }
 441          else {
 442            // This applies when the theme manually registers their own variable
 443            // processors.
 444            $prefixes[] = $name;
 445          }
 446          foreach ($prefixes as $prefix) {
 447            // Only use non-hook-specific variable processors for theming hooks
 448            // implemented as templates. See theme().
 449            if (isset($info['template']) && function_exists($prefix . '_' . $phase)) {
 450              $info[$phase_key][] = $prefix . '_' . $phase;
 451            }
 452            if (function_exists($prefix . '_' . $phase . '_' . $hook)) {
 453              $info[$phase_key][] = $prefix . '_' . $phase . '_' . $hook;
 454            }
 455          }
 456        }
 457        // Check for the override flag and prevent the cached variable
 458        // processors from being used. This allows themes or theme engines to
 459        // remove variable processors set earlier in the registry build.
 460        if (!empty($info['override ' . $phase_key])) {
 461          // Flag not needed inside the registry.
 462          unset($result[$hook]['override ' . $phase_key]);
 463        }
 464        elseif (isset($cache[$hook][$phase_key]) && is_array($cache[$hook][$phase_key])) {
 465          $info[$phase_key] = array_merge($cache[$hook][$phase_key], $info[$phase_key]);
 466        }
 467        $result[$hook][$phase_key] = $info[$phase_key];
 468      }
 469    }
 470
 471    // Merge the newly created theme hooks into the existing cache.
 472    $cache = array_merge($cache, $result);
 473  }
 474
 475  // Let themes have variable processors even if they didn't register a template.
 476  if ($type == 'theme' || $type == 'base_theme') {
 477    foreach ($cache as $hook => $info) {
 478      // Check only if not registered by the theme or engine.
 479      if (empty($result[$hook])) {
 480        foreach ($variable_process_phases as $phase_key => $phase) {
 481          if (!isset($info[$phase_key])) {
 482            $cache[$hook][$phase_key] = array();
 483          }
 484          // Only use non-hook-specific variable processors for theming hooks
 485          // implemented as templates. See theme().
 486          if (isset($info['template']) && function_exists($name . '_' . $phase)) {
 487            $cache[$hook][$phase_key][] = $name . '_' . $phase;
 488          }
 489          if (function_exists($name . '_' . $phase . '_' . $hook)) {
 490            $cache[$hook][$phase_key][] = $name . '_' . $phase . '_' . $hook;
 491            $cache[$hook]['theme path'] = $path;
 492          }
 493          // Ensure uniqueness.
 494          $cache[$hook][$phase_key] = array_unique($cache[$hook][$phase_key]);
 495        }
 496      }
 497    }
 498  }
 499}
 500
 501/**
 502 * Rebuild the theme registry cache.
 503 *
 504 * @param $theme
 505 *   The loaded $theme object as returned by list_themes().
 506 * @param $base_theme
 507 *   An array of loaded $theme objects representing the ancestor themes in
 508 *   oldest first order.
 509 * @param theme_engine
 510 *   The name of the theme engine.
 511 */
 512function _theme_build_registry($theme, $base_theme, $theme_engine) {
 513  $cache = array();
 514  // First, process the theme hooks advertised by modules. This will
 515  // serve as the basic registry.
 516  foreach (module_implements('theme') as $module) {
 517    _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module));
 518  }
 519
 520  // Process each base theme.
 521  foreach ($base_theme as $base) {
 522    // If the base theme uses a theme engine, process its hooks.
 523    $base_path = dirname($base->filename);
 524    if ($theme_engine) {
 525      _theme_process_registry($cache, $theme_engine, 'base_theme_engine', $base->name, $base_path);
 526    }
 527    _theme_process_registry($cache, $base->name, 'base_theme', $base->name, $base_path);
 528  }
 529
 530  // And then the same thing, but for the theme.
 531  if ($theme_engine) {
 532    _theme_process_registry($cache, $theme_engine, 'theme_engine', $theme->name, dirname($theme->filename));
 533  }
 534
 535  // Finally, hooks provided by the theme itself.
 536  _theme_process_registry($cache, $theme->name, 'theme', $theme->name, dirname($theme->filename));
 537
 538  // Let modules alter the registry.
 539  drupal_alter('theme_registry', $cache);
 540
 541  // Optimize the registry to not have empty arrays for functions.
 542  foreach ($cache as $hook => $info) {
 543    foreach (array('preprocess functions', 'process functions') as $phase) {
 544      if (empty($info[$phase])) {
 545        unset($cache[$hook][$phase]);
 546      }
 547    }
 548  }
 549  return $cache;
 550}
 551
 552/**
 553 * Return a list of all currently available themes.
 554 *
 555 * Retrieved from the database, if available and the site is not in maintenance
 556 * mode; otherwise compiled freshly from the filesystem.
 557 *
 558 * @param $refresh
 559 *   Whether to reload the list of themes from the database. Defaults to FALSE.
 560 *
 561 * @return
 562 *   An associative array of the currently available themes. The keys are the
 563 *   names of the themes and the values are objects having the following
 564 *   properties:
 565 *   - 'filename': The name of the .info file.
 566 *   - 'name': The name of the theme.
 567 *   - 'status': 1 for enabled, 0 for disabled themes.
 568 *   - 'info': The contents of the .info file.
 569 *   - 'stylesheets': A two dimensional array, using the first key for the
 570 *     'media' attribute (e.g. 'all'), the second for the name of the file
 571 *     (e.g. style.css). The value is a complete filepath
 572 *     (e.g. themes/bartik/style.css).
 573 *   - 'scripts': An associative array of JavaScripts, using the filename as key
 574 *     and the complete filepath as value.
 575 *   - 'engine': The name of the theme engine.
 576 *   - 'base theme': The name of the base theme.
 577 */
 578function list_themes($refresh = FALSE) {
 579  $list = &drupal_static(__FUNCTION__, array());
 580
 581  if ($refresh) {
 582    $list = array();
 583    system_list_reset();
 584  }
 585
 586  if (empty($list)) {
 587    $list = array();
 588    $themes = array();
 589    // Extract from the database only when it is available.
 590    // Also check that the site is not in the middle of an install or update.
 591    if (!defined('MAINTENANCE_MODE')) {
 592      try {
 593        $themes = system_list('theme');
 594      }
 595      catch (Exception $e) {
 596        // If the database is not available, rebuild the theme data.
 597        $themes = _system_rebuild_theme_data();
 598      }
 599    }
 600    else {
 601      // Scan the installation when the database should not be read.
 602      $themes = _system_rebuild_theme_data();
 603    }
 604
 605    foreach ($themes as $theme) {
 606      foreach ($theme->info['stylesheets'] as $media => $stylesheets) {
 607        foreach ($stylesheets as $stylesheet => $path) {
 608          $theme->stylesheets[$media][$stylesheet] = $path;
 609        }
 610      }
 611      foreach ($theme->info['scripts'] as $script => $path) {
 612        $theme->scripts[$script] = $path;
 613      }
 614      if (isset($theme->info['engine'])) {
 615        $theme->engine = $theme->info['engine'];
 616      }
 617      if (isset($theme->info['base theme'])) {
 618        $theme->base_theme = $theme->info['base theme'];
 619      }
 620      // Status is normally retrieved from the database. Add zero values when
 621      // read from the installation directory to prevent notices.
 622      if (!isset($theme->status)) {
 623        $theme->status = 0;
 624      }
 625      $list[$theme->name] = $theme;
 626    }
 627  }
 628
 629  return $list;
 630}
 631
 632/**
 633 * Generates themed output.
 634 *
 635 * All requests for themed output must go through this function. It examines
 636 * the request and routes it to the appropriate theme function or template, by
 637 * checking the theme registry.
 638 *
 639 * The first argument to this function is the name of the theme hook. For
 640 * instance, to theme a table, the theme hook name is 'table'. By default, this
 641 * theme hook could be implemented by a function called 'theme_table' or a
 642 * template file called 'table.tpl.php', but hook_theme() can override the
 643 * default function or template name.
 644 *
 645 * If the implementation is a template file, several functions are called
 646 * before the template file is invoked, to modify the $variables array. These
 647 * fall into the "preprocessing" phase and the "processing" phase, and are
 648 * executed (if they exist), in the following order (note that in the following
 649 * list, HOOK indicates the theme hook name, MODULE indicates a module name,
 650 * THEME indicates a theme name, and ENGINE indicates a theme engine name):
 651 * - template_preprocess(&$variables, $hook): Creates a default set of variables
 652 *   for all theme hooks.
 653 * - template_preprocess_HOOK(&$variables): Should be implemented by
 654 *   the module that registers the theme hook, to set up default variables.
 655 * - MODULE_preprocess(&$variables, $hook): hook_preprocess() is invoked on all
 656 *   implementing modules.
 657 * - MODULE_preprocess_HOOK(&$variables): hook_preprocess_HOOK() is invoked on
 658 *   all implementing modules, so that modules that didn't define the theme hook
 659 *   can alter the variables.
 660 * - ENGINE_engine_preprocess(&$variables, $hook): Allows the theme engine to
 661 *   set necessary variables for all theme hooks.
 662 * - ENGINE_engine_preprocess_HOOK(&$variables): Allows the theme engine to set
 663 *   necessary variables for the particular theme hook.
 664 * - THEME_preprocess(&$variables, $hook): Allows the theme to set necessary
 665 *   variables for all theme hooks.
 666 * - THEME_preprocess_HOOK(&$variables): Allows the theme to set necessary
 667 *   variables specific to the particular theme hook.
 668 * - template_process(&$variables, $hook): Creates a default set of variables
 669 *   for all theme hooks.
 670 * - template_process_HOOK(&$variables): This is the first processor specific
 671 *   to the theme hook; it should be implemented by the module that registers
 672 *   it.
 673 * - MODULE_process(&$variables, $hook): hook_process() is invoked on all
 674 *   implementing modules.
 675 * - MODULE_process_HOOK(&$variables): hook_process_HOOK() is invoked on
 676 *   on all implementing modules, so that modules that didn't define the theme
 677 *   hook can alter the variables.
 678 * - ENGINE_engine_process(&$variables, $hook): Allows the theme engine to set
 679 *   necessary variables for all theme hooks.
 680 * - ENGINE_engine_process_HOOK(&$variables): Allows the theme engine to set
 681 *   necessary variables for the particular theme hook.
 682 * - ENGINE_process(&$variables, $hook): Allows the theme engine to process the
 683 *   variables.
 684 * - ENGINE_process_HOOK(&$variables): Allows the theme engine to process the
 685 *   variables specific to the theme hook.
 686 * - THEME_process(&$variables, $hook):  Allows the theme to process the
 687 *   variables.
 688 * - THEME_process_HOOK(&$variables):  Allows the theme to process the
 689 *   variables specific to the theme hook.
 690 *
 691 * If the implementation is a function, only the theme-hook-specific preprocess
 692 * and process functions (the ones ending in _HOOK) are called from the
 693 * list above. This is because theme hooks with function implementations
 694 * need to be fast, and calling the non-theme-hook-specific preprocess and
 695 * process functions for them would incur a noticeable performance penalty.
 696 *
 697 * There are two special variables that these preprocess and process functions
 698 * can set: 'theme_hook_suggestion' and 'theme_hook_suggestions'. These will be
 699 * merged together to form a list of 'suggested' alternate theme hooks to use,
 700 * in reverse order of priority. theme_hook_suggestion will always be a higher
 701 * priority than items in theme_hook_suggestions. theme() will use the
 702 * highest priority implementation that exists. If none exists, theme() will
 703 * use the implementation for the theme hook it was called with. These
 704 * suggestions are similar to and are used for similar reasons as calling
 705 * theme() with an array as the $hook parameter (see below). The difference
 706 * is whether the suggestions are determined by the code that calls theme() or
 707 * by a preprocess or process function.
 708 *
 709 * @param $hook
 710 *   The name of the theme hook to call. If the name contains a
 711 *   double-underscore ('__') and there isn't an implementation for the full
 712 *   name, the part before the '__' is checked. This allows a fallback to a more
 713 *   generic implementation. For example, if theme('links__node', ...) is
 714 *   called, but there is no implementation of that theme hook, then the 'links'
 715 *   implementation is used. This process is iterative, so if
 716 *   theme('links__contextual__node', ...) is called, theme() checks for the
 717 *   following implementations, and uses the first one that exists:
 718 *   - links__contextual__node
 719 *   - links__contextual
 720 *   - links
 721 *   This allows themes to create specific theme implementations for named
 722 *   objects and contexts of otherwise generic theme hooks. The $hook parameter
 723 *   may also be an array, in which case the first theme hook that has an
 724 *   implementation is used. This allows for the code that calls theme() to
 725 *   explicitly specify the fallback order in a situation where using the '__'
 726 *   convention is not desired or is insufficient.
 727 * @param $variables
 728 *   An associative array of variables to merge with defaults from the theme
 729 *   registry, pass to preprocess and process functions for modification, and
 730 *   finally, pass to the function or template implementing the theme hook.
 731 *   Alternatively, this can be a renderable array, in which case, its
 732 *   properties are mapped to variables expected by the theme hook
 733 *   implementations.
 734 *
 735 * @return
 736 *   An HTML string representing the themed output.
 737 */
 738function theme($hook, $variables = array()) {
 739  static $hooks = NULL;
 740
 741  // If called before all modules are loaded, we do not necessarily have a full
 742  // theme registry to work with, and therefore cannot process the theme
 743  // request properly. See also _theme_load_registry().
 744  if (!module_load_all(NULL) && !defined('MAINTENANCE_MODE')) {
 745    throw new Exception(t('theme() may not be called until all modules are loaded.'));
 746  }
 747
 748  if (!isset($hooks)) {
 749    drupal_theme_initialize();
 750    $hooks = theme_get_registry();
 751  }
 752
 753  // If an array of hook candidates were passed, use the first one that has an
 754  // implementation.
 755  if (is_array($hook)) {
 756    foreach ($hook as $candidate) {
 757      if (isset($hooks[$candidate])) {
 758        break;
 759      }
 760    }
 761    $hook = $candidate;
 762  }
 763
 764  // If there's no implementation, check for more generic fallbacks. If there's
 765  // still no implementation, log an error and return an empty string.
 766  if (!isset($hooks[$hook])) {
 767    // Iteratively strip everything after the last '__' delimiter, until an
 768    // implementation is found.
 769    while ($pos = strrpos($hook, '__')) {
 770      $hook = substr($hook, 0, $pos);
 771      if (isset($hooks[$hook])) {
 772        break;
 773      }
 774    }
 775    if (!isset($hooks[$hook])) {
 776      // Only log a message when not trying theme suggestions ($hook being an
 777      // array).
 778      if (!isset($candidate)) {
 779        watchdog('theme', 'Theme key "@key" not found.', array('@key' => $hook), WATCHDOG_WARNING);
 780      }
 781      return '';
 782    }
 783  }
 784
 785  $info = $hooks[$hook];
 786  global $theme_path;
 787  $temp = $theme_path;
 788  // point path_to_theme() to the currently used theme path:
 789  $theme_path = $info['theme path'];
 790
 791  // Include a file if the theme function or variable processor is held elsewhere.
 792  if (!empty($info['includes'])) {
 793    foreach ($info['includes'] as $include_file) {
 794      include_once DRUPAL_ROOT . '/' . $include_file;
 795    }
 796  }
 797
 798  // If a renderable array is passed as $variables, then set $variables to
 799  // the arguments expected by the theme function.
 800  if (isset($variables['#theme']) || isset($variables['#theme_wrappers'])) {
 801    $element = $variables;
 802    $variables = array();
 803    if (isset($info['variables'])) {
 804      foreach (array_keys($info['variables']) as $name) {
 805        if (isset($element["#$name"])) {
 806          $variables[$name] = $element["#$name"];
 807        }
 808      }
 809    }
 810    else {
 811      $variables[$info['render element']] = $element;
 812    }
 813  }
 814
 815  // Merge in argument defaults.
 816  if (!empty($info['variables'])) {
 817    $variables += $info['variables'];
 818  }
 819  elseif (!empty($info['render element'])) {
 820    $variables += array($info['render element'] => array());
 821  }
 822
 823  // Invoke the variable processors, if any. The processors may specify
 824  // alternate suggestions for which hook's template/function to use. If the
 825  // hook is a suggestion of a base hook, invoke the variable processors of
 826  // the base hook, but retain the suggestion as a high priority suggestion to
 827  // be used unless overridden by a variable processor function.
 828  if (isset($info['base hook'])) {
 829    $base_hook = $info['base hook'];
 830    $base_hook_info = $hooks[$base_hook];
 831    if (isset($base_hook_info['preprocess functions']) || isset($base_hook_info['process functions'])) {
 832      $variables['theme_hook_suggestion'] = $hook;
 833      $hook = $base_hook;
 834      $info = $base_hook_info;
 835    }
 836  }
 837  if (isset($info['preprocess functions']) || isset($info['process functions'])) {
 838    $variables['theme_hook_suggestions'] = array();
 839    foreach (array('preprocess functions', 'process functions') as $phase) {
 840      if (!empty($info[$phase])) {
 841        foreach ($info[$phase] as $processor_function) {
 842          if (function_exists($processor_function)) {
 843            // We don't want a poorly behaved process function changing $hook.
 844            $hook_clone = $hook;
 845            $processor_function($variables, $hook_clone);
 846          }
 847        }
 848      }
 849    }
 850    // If the preprocess/process functions specified hook suggestions, and the
 851    // suggestion exists in the theme registry, use it instead of the hook that
 852    // theme() was called with. This allows the preprocess/process step to
 853    // route to a more specific theme hook. For example, a function may call
 854    // theme('node', ...), but a preprocess function can add 'node__article' as
 855    // a suggestion, enabling a theme to have an alternate template file for
 856    // article nodes. Suggestions are checked in the following order:
 857    // - The 'theme_hook_suggestion' variable is checked first. It overrides
 858    //   all others.
 859    // - The 'theme_hook_suggestions' variable is checked in FILO order, so the
 860    //   last suggestion added to the array takes precedence over suggestions
 861    //   added earlier.
 862    $suggestions = array();
 863    if (!empty($variables['theme_hook_suggestions'])) {
 864      $suggestions = $variables['theme_hook_suggestions'];
 865    }
 866    if (!empty($variables['theme_hook_suggestion'])) {
 867      $suggestions[] = $variables['theme_hook_suggestion'];
 868    }
 869    foreach (array_reverse($suggestions) as $suggestion) {
 870      if (isset($hooks[$suggestion])) {
 871        $info = $hooks[$suggestion];
 872        break;
 873      }
 874    }
 875  }
 876
 877  // Generate the output using either a function or a template.
 878  $output = '';
 879  if (isset($info['function'])) {
 880    if (function_exists($info['function'])) {
 881      $output = $info['function']($variables);
 882    }
 883  }
 884  else {
 885    // Default render function and extension.
 886    $render_function = 'theme_render_template';
 887    $extension = '.tpl.php';
 888
 889    // The theme engine may use a different extension and a different renderer.
 890    global $theme_engine;
 891    if (isset($theme_engine)) {
 892      if ($info['type'] != 'module') {
 893        if (function_exists($theme_engine . '_render_template')) {
 894          $render_function = $theme_engine . '_render_template';
 895        }
 896        $extension_function = $theme_engine . '_extension';
 897        if (function_exists($extension_function)) {
 898          $extension = $extension_function();
 899        }
 900      }
 901    }
 902
 903    // In some cases, a template implementation may not have had
 904    // template_preprocess() run (for example, if the default implementation is
 905    // a function, but a template overrides that default implementation). In
 906    // these cases, a template should still be able to expect to have access to
 907    // the variables provided by template_preprocess(), so we add them here if
 908    // they don't already exist. We don't want to run template_preprocess()
 909    // twice (it would be inefficient and mess up zebra striping), so we use the
 910    // 'directory' variable to determine if it has already run, which while not
 911    // completely intuitive, is reasonably safe, and allows us to save on the
 912    // overhead of adding some new variable to track that.
 913    if (!isset($variables['directory'])) {
 914      $default_template_variables = array();
 915      template_preprocess($default_template_variables, $hook);
 916      $variables += $default_template_variables;
 917    }
 918
 919    // Render the output using the template file.
 920    $template_file = $info['template'] . $extension;
 921    if (isset($info['path'])) {
 922      $template_file = $info['path'] . '/' . $template_file;
 923    }
 924    $output = $render_function($template_file, $variables);
 925  }
 926
 927  // restore path_to_theme()
 928  $theme_path = $temp;
 929  return $output;
 930}
 931
 932/**
 933 * Return the path to the current themed element.
 934 *
 935 * It can point to the active theme or the module handling a themed implementation.
 936 * For example, when invoked within the scope of a theming call it will depend
 937 * on where the theming function is handled. If implemented from a module, it
 938 * will point to the module. If implemented from the active theme, it will point
 939 * to the active theme. When called outside the scope of a theming call, it will
 940 * always point to the active theme.
 941 */
 942function path_to_theme() {
 943  global $theme_path;
 944
 945  if (!isset($theme_path)) {
 946    drupal_theme_initialize();
 947  }
 948
 949  return $theme_path;
 950}
 951
 952/**
 953 * Allow themes and/or theme engines to easily discover overridden theme functions.
 954 *
 955 * @param $cache
 956 *   The existing cache of theme hooks to test against.
 957 * @param $prefixes
 958 *   An array of prefixes to test, in reverse order of importance.
 959 *
 960 * @return $implementations
 961 *   The functions found, suitable for returning from hook_theme;
 962 */
 963function drupal_find_theme_functions($cache, $prefixes) {
 964  $implementations = array();
 965  $functions = get_defined_functions();
 966
 967  foreach ($cache as $hook => $info) {
 968    foreach ($prefixes as $prefix) {
 969      // Find theme functions that implement possible "suggestion" variants of
 970      // registered theme hooks and add those as new registered theme hooks.
 971      // The 'pattern' key defines a common prefix that all suggestions must
 972      // start with. The default is the name of the hook followed by '__'. An
 973      // 'base hook' key is added to each entry made for a found suggestion,
 974      // so that common functionality can be implemented for all suggestions of
 975      // the same base hook. To keep things simple, deep heirarchy of
 976      // suggestions is not supported: each suggestion's 'base hook' key
 977      // refers to a base hook, not to another suggestion, and all suggestions
 978      // are found using the base hook's pattern, not a pattern from an
 979      // intermediary suggestion.
 980      $pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__');
 981      if (!isset($info['base hook']) && !empty($pattern)) {
 982        $matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $functions['user']);
 983        if ($matches) {
 984          foreach ($matches as $match) {
 985            $new_hook = str_replace($prefix . '_', '', $match);
 986            $arg_name = isset($info['variables']) ? 'variables' : 'render element';
 987            $implementations[$new_hook] = array(
 988              'function' => $match,
 989              $arg_name => $info[$arg_name],
 990              'base hook' => $hook,
 991            );
 992          }
 993        }
 994      }
 995      // Find theme functions that implement registered theme hooks and include
 996      // that in what is returned so that the registry knows that the theme has
 997      // this implementation.
 998      if (function_exists($prefix . '_' . $hook)) {
 999        $implementations[$hook] = array(
1000          'function' => $prefix . '_' . $hook,
1001        );
1002      }
1003    }
1004  }
1005
1006  return $implementations;
1007}
1008
1009/**
1010 * Allow themes and/or theme engines to easily discover overridden templates.
1011 *
1012 * @param $cache
1013 *   The existing cache of theme hooks to test against.
1014 * @param $extension
1015 *   The extension that these templates will have.
1016 * @param $path
1017 *   The path to search.
1018 */
1019function drupal_find_theme_templates($cache, $extension, $path) {
1020  $implementations = array();
1021
1022  // Collect paths to all sub-themes grouped by base themes. These will be
1023  // used for filtering. This allows base themes to have sub-themes in its
1024  // folder hierarchy without affecting the base themes template discovery.
1025  $theme_paths = array();
1026  foreach (list_themes() as $theme_info) {
1027    if (!empty($theme_info->base_theme)) {
1028      $theme_paths[$theme_info->base_theme][$theme_info->name] = dirname($theme_info->filename);
1029    }
1030  }
1031  foreach ($theme_paths as $basetheme => $subthemes) {
1032    foreach ($subthemes as $subtheme => $subtheme_path) {
1033      if (isset($theme_paths[$subtheme])) {
1034        $theme_paths[$basetheme] = array_merge($theme_paths[$basetheme], $theme_paths[$subtheme]);
1035      }
1036    }
1037  }
1038  global $theme;
1039  $subtheme_paths = isset($theme_paths[$theme]) ? $theme_paths[$theme] : array();
1040
1041  // Escape the periods in the extension.
1042  $regex = '/' . str_replace('.', '\.', $extension) . '$/';
1043  // Get a listing of all template files in the path to search.
1044  $files = drupal_system_listing($regex, $path, 'name', 0);
1045
1046  // Find templates that implement registered theme hooks and include that in
1047  // what is returned so that the registry knows that the theme has this
1048  // implementation.
1049  foreach ($files as $template => $file) {
1050    // Ignore sub-theme templates for the current theme.
1051    if (strpos($file->uri, str_replace($subtheme_paths, '', $file->uri)) !== 0) {
1052      continue;
1053    }
1054    // Chop off the remaining extensions if there are any. $template already
1055    // has the rightmost extension removed, but there might still be more,
1056    // such as with .tpl.php, which still has .tpl in $template at this point.
1057    if (($pos = strpos($template, '.')) !== FALSE) {
1058      $template = substr($template, 0, $pos);
1059    }
1060    // Transform - in filenames to _ to match function naming scheme
1061    // for the purposes of searching.
1062    $hook = strtr($template, '-', '_');
1063    if (isset($cache[$hook])) {
1064      $implementations[$hook] = array(
1065        'template' => $template,
1066        'path' => dirname($file->uri),
1067      );
1068    }
1069  }
1070
1071  // Find templates that implement possible "suggestion" variants of registered
1072  // theme hooks and add those as new registered theme hooks. See
1073  // drupal_find_theme_functions() for more information about suggestions and
1074  // the use of 'pattern' and 'base hook'.
1075  $patterns = array_keys($files);
1076  foreach ($cache as $hook => $info) {
1077    $pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__');
1078    if (!isset($info['base hook']) && !empty($pattern)) {
1079      // Transform _ in pattern to - to match file naming scheme
1080      // for the purposes of searching.
1081      $pattern = strtr($pattern, '_', '-');
1082
1083      $matches = preg_grep('/^' . $pattern . '/', $patterns);
1084      if ($matches) {
1085        foreach ($matches as $match) {
1086          $file = substr($match, 0, strpos($match, '.'));
1087          // Put the underscores back in for the hook name and register this pattern.
1088          $arg_name = isset($info['variables']) ? 'variables' : 'render element';
1089          $implementations[strtr($file, '-', '_')] = array(
1090            'template' => $file,
1091            'path' => dirname($files[$match]->uri),
1092            $arg_name => $info[$arg_name],
1093            'base hook' => $hook,
1094          );
1095        }
1096      }
1097    }
1098  }
1099  return $implementations;
1100}
1101
1102/**
1103 * Retrieve a setting for the current theme or for a given theme.
1104 *
1105 * The final setting is obtained from the last value found in the following
1106 * sources:
1107 * - the default global settings specified in this function
1108 * - the default theme-specific settings defined in any base theme's .info file
1109 * - the default theme-specific settings defined in the theme's .info file
1110 * - the saved values from the global theme settings form
1111 * - the saved values from the theme's settings form
1112 * To only retrieve the default global theme setting, an empty string should be
1113 * given for $theme.
1114 *
1115 * @param $setting_name
1116 *   The name of the setting to be retrieved.
1117 * @param $theme
1118 *   The name of a given theme; defaults to the current theme.
1119 *
1120 * @return
1121 *   The value of the requested setting, NULL if the setting does not exist.
1122 */
1123function theme_get_setting($setting_name, $theme = NULL) {
1124  $cache = &drupal_static(__FUNCTION__, array());
1125
1126  // If no key is given, use the current theme if we can determine it.
1127  if (!isset($theme)) {
1128    $theme = !empty($GLOBALS['theme_key']) ? $GLOBALS['theme_key'] : '';
1129  }
1130
1131  if (empty($cache[$theme])) {
1132    // Set the default values for each global setting.
1133    // To add new global settings, add their default values below, and then
1134    // add form elements to system_theme_settings() in system.admin.inc.
1135    $cache[$theme] = array(
1136      'default_logo'                     =>  1,
1137      'logo_path'                        =>  '',
1138      'default_favicon'                  =>  1,
1139      'favicon_path'                     =>  '',
1140      // Use the IANA-registered MIME type for ICO files as default.
1141      'favicon_mimetype'                 =>  'image/vnd.microsoft.icon',
1142    );
1143    // Turn on all default features.
1144    $features = _system_default_theme_features();
1145    foreach ($features as $feature) {
1146      $cache[$theme]['toggle_' . $feature] = 1;
1147    }
1148
1149    // Get the values for the theme-specific settings from the .info files of
1150    // the theme and all its base themes.
1151    if ($theme) {
1152      $themes = list_themes();
1153      $theme_object = $themes[$theme];
1154
1155      // Create a list which includes the current theme and all its base themes.
1156      if (isset($theme_object->base_themes)) {
1157        $theme_keys = array_keys($theme_object->base_themes);
1158        $theme_keys[] = $theme;
1159      }
1160      else {
1161        $theme_keys = array($theme);
1162      }
1163      foreach ($theme_keys as $theme_key) {
1164        if (!empty($themes[$theme_key]->info['settings'])) {
1165          $cache[$theme] = array_merge($cache[$theme], $themes[$theme_key]->info['settings']);
1166        }
1167      }
1168    }
1169
1170    // Get the saved global settings from the database.
1171    $cache[$theme] = array_merge($cache[$theme], variable_get('theme_settings', array()));
1172
1173    if ($theme) {
1174      // Get the saved theme-specific settings from the database.
1175      $cache[$theme] = array_merge($cache[$theme], variable_get('theme_' . $theme . '_settings', array()));
1176
1177      // If the theme does not support a particular feature, override the global
1178      // setting and set the value to NULL.
1179      if (!empty($theme_object->info['features'])) {
1180        foreach ($features as $feature) {
1181          if (!in_array($feature, $theme_object->info['features'])) {
1182            $cache[$theme]['toggle_' . $feature] = NULL;
1183          }
1184        }
1185      }
1186
1187      // Generate the path to the logo image.
1188      if ($cache[$theme]['toggle_logo']) {
1189        if ($cache[$theme]['default_logo']) {
1190          $cache[$theme]['logo'] = file_create_url(dirname($theme_object->filename) . '/logo.png');
1191        }
1192        elseif ($cache[$theme]['logo_path']) {
1193          $cache[$theme]['logo'] = file_create_url($cache[$theme]['logo_path']);
1194        }
1195      }
1196
1197      // Generate the path to the favicon.
1198      if ($cache[$theme]['toggle_favicon']) {
1199        if ($cache[$theme]['default_favicon']) {
1200          if (file_exists($favicon = dirname($theme_object->filename) . '/favicon.ico')) {
1201            $cache[$theme]['favicon'] = file_create_url($favicon);
1202          }
1203          else {
1204            $cache[$theme]['favicon'] = file_create_url('misc/favicon.ico');
1205          }
1206        }
1207        elseif ($cache[$theme]['favicon_path']) {
1208          $cache[$theme]['favicon'] = file_create_url($cache[$theme]['favicon_path']);
1209        }
1210        else {
1211          $cache[$theme]['toggle_favicon'] = FALSE;
1212        }
1213      }
1214    }
1215  }
1216
1217  return isset($cache[$theme][$setting_name]) ? $cache[$theme][$setting_name] : NULL;
1218}
1219
1220/**
1221 * Render a system default template, which is essentially a PHP template.
1222 *
1223 * @param $template_file
1224 *   The filename of the template to render.
1225 * @param $variables
1226 *   A keyed array of variables that will appear in the output.
1227 *
1228 * @return
1229 *   The output generated by the template.
1230 */
1231function theme_render_template($template_file, $variables) {
1232  extract($variables, EXTR_SKIP);               // Extract the variables to a local namespace
1233  ob_start();                                   // Start output buffering
1234  include DRUPAL_ROOT . '/' . $template_file;   // Include the template file
1235  return ob_get_clean();                        // End buffering and return its contents
1236}
1237
1238/**
1239 * Enable a given list of themes.
1240 *
1241 * @param $theme_list
1242 *   An array of theme names.
1243 */
1244function theme_enable($theme_list) {
1245  drupal_clear_css_cache();
1246
1247  foreach ($theme_list as $key) {
1248    db_update('system')
1249      ->fields(array('status' => 1))
1250      ->condition('type', 'theme')
1251      ->condition('name', $key)
1252      ->execute();
1253  }
1254
1255  list_themes(TRUE);
1256  menu_rebuild();
1257  drupal_theme_rebuild();
1258
1259  // Notify locale module about new themes being enabled, so translations can
1260  // be imported. This might start a batch, and only return to the redirect
1261  // path after that.
1262  module_invoke('locale', 'system_update', $theme_list);
1263
1264  // Invoke hook_themes_enabled after the themes have been enabled.
1265  module_invoke_all('themes_enabled', $theme_list);
1266
1267  return;
1268}
1269
1270/**
1271 * Disable a given list of themes.
1272 *
1273 * @param $theme_list
1274 *   An array of theme names.
1275 */
1276function theme_disable($theme_list) {
1277  // Don't disable the default theme.
1278  if ($pos = array_search(variable_get('theme_default', 'bartik'), $theme_list) !== FALSE) {
1279    unset($theme_list[$pos]);
1280    if (empty($theme_list)) {
1281      return;
1282    }
1283  }
1284
1285  drupal_clear_css_cache();
1286
1287  foreach ($theme_list as $key) {
1288    db_update('system')
1289      ->fields(array('status' => 0))
1290      ->condition('type', 'theme')
1291      ->condition('name', $key)
1292      ->execute();
1293  }
1294
1295  list_themes(TRUE);
1296  menu_rebuild();
1297  drupal_theme_rebuild();
1298
1299  // Invoke hook_themes_enabled after the themes have been enabled.
1300  module_invoke_all('themes_disabled', $theme_list);
1301
1302  return;
1303}
1304
1305/**
1306 * @ingroup themeable
1307 * @{
1308 */
1309
1310/**
1311 * Returns HTML for status and/or error messages, grouped by type.
1312 *
1313 * An invisible heading identifies the messages for assistive technology.
1314 * Sighted users see a colored box. See http://www.w3.org/TR/WCAG-TECHS/H69.html
1315 * for info.
1316 *
1317 * @param $variables
1318 *   An associative array containing:
1319 *   - display: (optional) Set to 'status' or 'error' to display only messages
1320 *     of that type.
1321 */
1322function theme_status_messages($variables) {
1323  $display = $variables['display'];
1324  $output = '';
1325
1326  $status_heading = array(
1327    'status' => t('Status message'),
1328    'error' => t('Error message'),
1329    'warning' => t('Warning message'),
1330  );
1331  foreach (drupal_get_messages($display) as $type => $messages) {
1332    $output .= "<div class=\"messages $type\">\n";
1333  

Large files files are truncated, but you can click here to view the full file