[ XREF Home ] [ Index ]

PHP Cross Reference of WordPress Trunk

Provided by Yoast

title

Body

[close]

/wp-includes/ -> theme.php (source)

   1  <?php
   2  /**
   3   * Theme, template, and stylesheet functions.
   4   *
   5   * @package WordPress
   6   * @subpackage Template
   7   */
   8  
   9  /**
  10   * Whether a child theme is in use.
  11   *
  12   * @since 3.0.0
  13   *
  14   * @return bool true if a child theme is in use, false otherwise.
  15   **/
  16  function is_child_theme() {
  17      return ( TEMPLATEPATH !== STYLESHEETPATH );
  18  }
  19  
  20  /**
  21   * Retrieve name of the current stylesheet.
  22   *
  23   * The theme name that the administrator has currently set the front end theme
  24   * as.
  25   *
  26   * For all extensive purposes, the template name and the stylesheet name are
  27   * going to be the same for most cases.
  28   *
  29   * @since 1.5.0
  30   * @uses apply_filters() Calls 'stylesheet' filter on stylesheet name.
  31   *
  32   * @return string Stylesheet name.
  33   */
  34  function get_stylesheet() {
  35      return apply_filters('stylesheet', get_option('stylesheet'));
  36  }
  37  
  38  /**
  39   * Retrieve stylesheet directory path for current theme.
  40   *
  41   * @since 1.5.0
  42   * @uses apply_filters() Calls 'stylesheet_directory' filter on stylesheet directory and theme name.
  43   *
  44   * @return string Path to current theme directory.
  45   */
  46  function get_stylesheet_directory() {
  47      $stylesheet = get_stylesheet();
  48      $theme_root = get_theme_root( $stylesheet );
  49      $stylesheet_dir = "$theme_root/$stylesheet";
  50  
  51      return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
  52  }
  53  
  54  /**
  55   * Retrieve stylesheet directory URI.
  56   *
  57   * @since 1.5.0
  58   *
  59   * @return string
  60   */
  61  function get_stylesheet_directory_uri() {
  62      $stylesheet = get_stylesheet();
  63      $theme_root_uri = get_theme_root_uri( $stylesheet );
  64      $stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
  65  
  66      return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
  67  }
  68  
  69  /**
  70   * Retrieve URI of current theme stylesheet.
  71   *
  72   * The stylesheet file name is 'style.css' which is appended to {@link
  73   * get_stylesheet_directory_uri() stylesheet directory URI} path.
  74   *
  75   * @since 1.5.0
  76   * @uses apply_filters() Calls 'stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
  77   *
  78   * @return string
  79   */
  80  function get_stylesheet_uri() {
  81      $stylesheet_dir_uri = get_stylesheet_directory_uri();
  82      $stylesheet_uri = $stylesheet_dir_uri . '/style.css';
  83      return apply_filters('stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
  84  }
  85  
  86  /**
  87   * Retrieve localized stylesheet URI.
  88   *
  89   * The stylesheet directory for the localized stylesheet files are located, by
  90   * default, in the base theme directory. The name of the locale file will be the
  91   * locale followed by '.css'. If that does not exist, then the text direction
  92   * stylesheet will be checked for existence, for example 'ltr.css'.
  93   *
  94   * The theme may change the location of the stylesheet directory by either using
  95   * the 'stylesheet_directory_uri' filter or the 'locale_stylesheet_uri' filter.
  96   * If you want to change the location of the stylesheet files for the entire
  97   * WordPress workflow, then change the former. If you just have the locale in a
  98   * separate folder, then change the latter.
  99   *
 100   * @since 2.1.0
 101   * @uses apply_filters() Calls 'locale_stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
 102   *
 103   * @return string
 104   */
 105  function get_locale_stylesheet_uri() {
 106      global $wp_locale;
 107      $stylesheet_dir_uri = get_stylesheet_directory_uri();
 108      $dir = get_stylesheet_directory();
 109      $locale = get_locale();
 110      if ( file_exists("$dir/$locale.css") )
 111          $stylesheet_uri = "$stylesheet_dir_uri/$locale.css";
 112      elseif ( !empty($wp_locale->text_direction) && file_exists("$dir/{$wp_locale->text_direction}.css") )
 113          $stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
 114      else
 115          $stylesheet_uri = '';
 116      return apply_filters('locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
 117  }
 118  
 119  /**
 120   * Retrieve name of the current theme.
 121   *
 122   * @since 1.5.0
 123   * @uses apply_filters() Calls 'template' filter on template option.
 124   *
 125   * @return string Template name.
 126   */
 127  function get_template() {
 128      return apply_filters('template', get_option('template'));
 129  }
 130  
 131  /**
 132   * Retrieve current theme directory.
 133   *
 134   * @since 1.5.0
 135   * @uses apply_filters() Calls 'template_directory' filter on template directory path and template name.
 136   *
 137   * @return string Template directory path.
 138   */
 139  function get_template_directory() {
 140      $template = get_template();
 141      $theme_root = get_theme_root( $template );
 142      $template_dir = "$theme_root/$template";
 143  
 144      return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
 145  }
 146  
 147  /**
 148   * Retrieve theme directory URI.
 149   *
 150   * @since 1.5.0
 151   * @uses apply_filters() Calls 'template_directory_uri' filter on template directory URI path and template name.
 152   *
 153   * @return string Template directory URI.
 154   */
 155  function get_template_directory_uri() {
 156      $template = get_template();
 157      $theme_root_uri = get_theme_root_uri( $template );
 158      $template_dir_uri = "$theme_root_uri/$template";
 159  
 160      return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
 161  }
 162  
 163  /**
 164   * Retrieve theme data from parsed theme file.
 165   *
 166   * The description will have the tags filtered with the following HTML elements
 167   * whitelisted. The <b>'a'</b> element with the <em>href</em> and <em>title</em>
 168   * attributes. The <b>abbr</b> element with the <em>title</em> attribute. The
 169   * <b>acronym</b> element with the <em>title</em> attribute allowed. The
 170   * <b>code</b>, <b>em</b>, and <b>strong</b> elements also allowed.
 171   *
 172   * The style.css file must contain theme name, theme URI, and description. The
 173   * data can also contain author URI, author, template (parent template),
 174   * version, status, and finally tags. Some of these are not used by WordPress
 175   * administration panels, but are used by theme directory web sites which list
 176   * the theme.
 177   *
 178   * @since 1.5.0
 179   *
 180   * @param string $theme_file Theme file path.
 181   * @return array Theme data.
 182   */
 183  function get_theme_data( $theme_file ) {
 184      $default_headers = array(
 185          'Name' => 'Theme Name',
 186          'URI' => 'Theme URI',
 187          'Description' => 'Description',
 188          'Author' => 'Author',
 189          'AuthorURI' => 'Author URI',
 190          'Version' => 'Version',
 191          'Template' => 'Template',
 192          'Status' => 'Status',
 193          'Tags' => 'Tags'
 194          );
 195  
 196      $themes_allowed_tags = array(
 197          'a' => array(
 198              'href' => array(),'title' => array()
 199              ),
 200          'abbr' => array(
 201              'title' => array()
 202              ),
 203          'acronym' => array(
 204              'title' => array()
 205              ),
 206          'code' => array(),
 207          'em' => array(),
 208          'strong' => array()
 209      );
 210  
 211      $theme_data = get_file_data( $theme_file, $default_headers, 'theme' );
 212  
 213      $theme_data['Name'] = $theme_data['Title'] = wp_kses( $theme_data['Name'], $themes_allowed_tags );
 214  
 215      $theme_data['URI'] = esc_url( $theme_data['URI'] );
 216  
 217      $theme_data['Description'] = wptexturize( wp_kses( $theme_data['Description'], $themes_allowed_tags ) );
 218  
 219      $theme_data['AuthorURI'] = esc_url( $theme_data['AuthorURI'] );
 220  
 221      $theme_data['Template'] = wp_kses( $theme_data['Template'], $themes_allowed_tags );
 222  
 223      $theme_data['Version'] = wp_kses( $theme_data['Version'], $themes_allowed_tags );
 224  
 225      if ( $theme_data['Status'] == '' )
 226          $theme_data['Status'] = 'publish';
 227      else
 228          $theme_data['Status'] = wp_kses( $theme_data['Status'], $themes_allowed_tags );
 229  
 230      if ( $theme_data['Tags'] == '' )
 231          $theme_data['Tags'] = array();
 232      else
 233          $theme_data['Tags'] = array_map( 'trim', explode( ',', wp_kses( $theme_data['Tags'], array() ) ) );
 234  
 235      if ( $theme_data['Author'] == '' ) {
 236          $theme_data['Author'] = $theme_data['AuthorName'] = __('Anonymous');
 237      } else {
 238          $theme_data['AuthorName'] = wp_kses( $theme_data['Author'], $themes_allowed_tags );
 239          if ( empty( $theme_data['AuthorURI'] ) ) {
 240              $theme_data['Author'] = $theme_data['AuthorName'];
 241          } else {
 242              $theme_data['Author'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $theme_data['AuthorURI'], esc_attr__( 'Visit author homepage' ), $theme_data['AuthorName'] );
 243          }
 244      }
 245  
 246      return $theme_data;
 247  }
 248  
 249  /**
 250   * Retrieve list of themes with theme data in theme directory.
 251   *
 252   * The theme is broken, if it doesn't have a parent theme and is missing either
 253   * style.css and, or index.php. If the theme has a parent theme then it is
 254   * broken, if it is missing style.css; index.php is optional. The broken theme
 255   * list is saved in the {@link $wp_broken_themes} global, which is displayed on
 256   * the theme list in the administration panels.
 257   *
 258   * @since 1.5.0
 259   * @global array $wp_broken_themes Stores the broken themes.
 260   * @global array $wp_themes Stores the working themes.
 261   *
 262   * @return array Theme list with theme data.
 263   */
 264  function get_themes() {
 265      global $wp_themes, $wp_broken_themes;
 266  
 267      if ( isset($wp_themes) )
 268          return $wp_themes;
 269  
 270      if ( !$theme_files = search_theme_directories() )
 271          return false;
 272  
 273      asort( $theme_files );
 274  
 275      $wp_themes = array();
 276  
 277      foreach ( (array) $theme_files as $theme_file ) {
 278          $theme_root = $theme_file['theme_root'];
 279          $theme_file = $theme_file['theme_file'];
 280  
 281          if ( !is_readable("$theme_root/$theme_file") ) {
 282              $wp_broken_themes[$theme_file] = array('Name' => $theme_file, 'Title' => $theme_file, 'Description' => __('File not readable.'));
 283              continue;
 284          }
 285  
 286          $theme_data = get_theme_data("$theme_root/$theme_file");
 287  
 288          $name        = $theme_data['Name'];
 289          $title       = $theme_data['Title'];
 290          $description = wptexturize($theme_data['Description']);
 291          $version     = $theme_data['Version'];
 292          $author      = $theme_data['Author'];
 293          $template    = $theme_data['Template'];
 294          $stylesheet  = dirname($theme_file);
 295  
 296          $screenshot = false;
 297          foreach ( array('png', 'gif', 'jpg', 'jpeg') as $ext ) {
 298              if (file_exists("$theme_root/$stylesheet/screenshot.$ext")) {
 299                  $screenshot = "screenshot.$ext";
 300                  break;
 301              }
 302          }
 303  
 304          if ( empty($name) ) {
 305              $name = dirname($theme_file);
 306              $title = $name;
 307          }
 308  
 309          $parent_template = $template;
 310  
 311          if ( empty($template) ) {
 312              if ( file_exists("$theme_root/$stylesheet/index.php") )
 313                  $template = $stylesheet;
 314              else
 315                  continue;
 316          }
 317  
 318          $template = trim( $template );
 319  
 320          if ( !file_exists("$theme_root/$template/index.php") ) {
 321              $parent_dir = dirname(dirname($theme_file));
 322              if ( file_exists("$theme_root/$parent_dir/$template/index.php") ) {
 323                  $template = "$parent_dir/$template";
 324                  $template_directory = "$theme_root/$template";
 325              } else {
 326                  /**
 327                   * The parent theme doesn't exist in the current theme's folder or sub folder
 328                   * so lets use the theme root for the parent template.
 329                   */
 330                  if ( isset($theme_files[$template]) && file_exists( $theme_files[$template]['theme_root'] . "/$template/index.php" ) ) {
 331                      $template_directory = $theme_files[$template]['theme_root'] . "/$template";
 332                  } else {
 333                      if ( empty( $parent_template) )
 334                          $wp_broken_themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => __('Template is missing.'), 'error' => 'no_template');
 335                      else
 336                          $wp_broken_themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => sprintf( __('The parent theme is missing. Please install the "%s" parent theme.'),  $parent_template ), 'error' => 'no_parent', 'parent' => $parent_template );
 337                      continue;
 338                  }
 339  
 340              }
 341          } else {
 342              $template_directory = trim( $theme_root . '/' . $template );
 343          }
 344  
 345          $stylesheet_files = array();
 346          $template_files = array();
 347  
 348          $stylesheet_dir = @ dir("$theme_root/$stylesheet");
 349          if ( $stylesheet_dir ) {
 350              while ( ($file = $stylesheet_dir->read()) !== false ) {
 351                  if ( !preg_match('|^\.+$|', $file) ) {
 352                      if ( preg_match('|\.css$|', $file) )
 353                          $stylesheet_files[] = "$theme_root/$stylesheet/$file";
 354                      elseif ( preg_match('|\.php$|', $file) )
 355                          $template_files[] = "$theme_root/$stylesheet/$file";
 356                  }
 357              }
 358              @ $stylesheet_dir->close();
 359          }
 360  
 361          $template_dir = @ dir("$template_directory");
 362          if ( $template_dir ) {
 363              while ( ($file = $template_dir->read()) !== false ) {
 364                  if ( preg_match('|^\.+$|', $file) )
 365                      continue;
 366                  if ( preg_match('|\.php$|', $file) ) {
 367                      $template_files[] = "$template_directory/$file";
 368                  } elseif ( is_dir("$template_directory/$file") ) {
 369                      $template_subdir = @ dir("$template_directory/$file");
 370                      if ( !$template_subdir )
 371                          continue;
 372                      while ( ($subfile = $template_subdir->read()) !== false ) {
 373                          if ( preg_match('|^\.+$|', $subfile) )
 374                              continue;
 375                          if ( preg_match('|\.php$|', $subfile) )
 376                              $template_files[] = "$template_directory/$file/$subfile";
 377                      }
 378                      @ $template_subdir->close();
 379                  }
 380              }
 381              @ $template_dir->close();
 382          }
 383  
 384          //Make unique and remove duplicates when stylesheet and template are the same i.e. most themes
 385          $template_files = array_unique($template_files);
 386          $stylesheet_files = array_unique($stylesheet_files);
 387  
 388          $template_dir = $template_directory;
 389          $stylesheet_dir = $theme_root . '/' . $stylesheet;
 390  
 391          if ( empty($template_dir) )
 392              $template_dir = '/';
 393          if ( empty($stylesheet_dir) )
 394              $stylesheet_dir = '/';
 395  
 396          // Check for theme name collision.  This occurs if a theme is copied to
 397          // a new theme directory and the theme header is not updated.  Whichever
 398          // theme is first keeps the name.  Subsequent themes get a suffix applied.
 399          // The Twenty Ten, Default and Classic themes always trump their pretenders.
 400          if ( isset($wp_themes[$name]) ) {
 401              $trump_cards = array(
 402                  'classic'   => 'WordPress Classic',
 403                  'default'   => 'WordPress Default',
 404                  'twentyten' => 'Twenty Ten',
 405              );
 406              if ( isset( $trump_cards[ $stylesheet ] ) && $name == $trump_cards[ $stylesheet ] ) {
 407                  // If another theme has claimed to be one of our default themes, move
 408                  // them aside.
 409                  $suffix = $wp_themes[$name]['Stylesheet'];
 410                  $new_name = "$name/$suffix";
 411                  $wp_themes[$new_name] = $wp_themes[$name];
 412                  $wp_themes[$new_name]['Name'] = $new_name;
 413              } else {
 414                  $name = "$name/$stylesheet";
 415              }
 416          }
 417  
 418          $theme_roots[$stylesheet] = str_replace( WP_CONTENT_DIR, '', $theme_root );
 419          $wp_themes[$name] = array(
 420              'Name' => $name,
 421              'Title' => $title,
 422              'Description' => $description,
 423              'Author' => $author,
 424              'Author Name' => $theme_data['AuthorName'],
 425              'Author URI' => $theme_data['AuthorURI'],
 426              'Version' => $version,
 427              'Template' => $template,
 428              'Stylesheet' => $stylesheet,
 429              'Template Files' => $template_files,
 430              'Stylesheet Files' => $stylesheet_files,
 431              'Template Dir' => $template_dir,
 432              'Stylesheet Dir' => $stylesheet_dir,
 433              'Status' => $theme_data['Status'],
 434              'Screenshot' => $screenshot,
 435              'Tags' => $theme_data['Tags'],
 436              'Theme Root' => $theme_root,
 437              'Theme Root URI' => str_replace( WP_CONTENT_DIR, content_url(), $theme_root ),
 438          );
 439      }
 440  
 441      unset($theme_files);
 442  
 443      /* Store theme roots in the DB */
 444      if ( get_site_transient( 'theme_roots' ) != $theme_roots )
 445          set_site_transient( 'theme_roots', $theme_roots, 7200 ); // cache for two hours
 446      unset($theme_roots);
 447  
 448      /* Resolve theme dependencies. */
 449      $theme_names = array_keys( $wp_themes );
 450      foreach ( (array) $theme_names as $theme_name ) {
 451          $wp_themes[$theme_name]['Parent Theme'] = '';
 452          if ( $wp_themes[$theme_name]['Stylesheet'] != $wp_themes[$theme_name]['Template'] ) {
 453              foreach ( (array) $theme_names as $parent_theme_name ) {
 454                  if ( ($wp_themes[$parent_theme_name]['Stylesheet'] == $wp_themes[$parent_theme_name]['Template']) && ($wp_themes[$parent_theme_name]['Template'] == $wp_themes[$theme_name]['Template']) ) {
 455                      $wp_themes[$theme_name]['Parent Theme'] = $wp_themes[$parent_theme_name]['Name'];
 456                      break;
 457                  }
 458              }
 459          }
 460      }
 461  
 462      return $wp_themes;
 463  }
 464  
 465  /**
 466   * Retrieve theme roots.
 467   *
 468   * @since 2.9.0
 469   *
 470   * @return array|string An arry of theme roots keyed by template/stylesheet or a single theme root if all themes have the same root.
 471   */
 472  function get_theme_roots() {
 473      global $wp_theme_directories;
 474  
 475      if ( count($wp_theme_directories) <= 1 )
 476          return '/themes';
 477  
 478      $theme_roots = get_site_transient( 'theme_roots' );
 479      if ( false === $theme_roots ) {
 480          get_themes();
 481          $theme_roots = get_site_transient( 'theme_roots' ); // this is set in get_theme()
 482      }
 483      return $theme_roots;
 484  }
 485  
 486  /**
 487   * Retrieve theme data.
 488   *
 489   * @since 1.5.0
 490   *
 491   * @param string $theme Theme name.
 492   * @return array|null Null, if theme name does not exist. Theme data, if exists.
 493   */
 494  function get_theme($theme) {
 495      $themes = get_themes();
 496  
 497      if ( array_key_exists($theme, $themes) )
 498          return $themes[$theme];
 499  
 500      return null;
 501  }
 502  
 503  /**
 504   * Retrieve current theme display name.
 505   *
 506   * If the 'current_theme' option has already been set, then it will be returned
 507   * instead. If it is not set, then each theme will be iterated over until both
 508   * the current stylesheet and current template name.
 509   *
 510   * @since 1.5.0
 511   *
 512   * @return string
 513   */
 514  function get_current_theme() {
 515      if ( $theme = get_option('current_theme') )
 516          return $theme;
 517  
 518      $themes = get_themes();
 519      $theme_names = array_keys($themes);
 520      $current_template = get_option('template');
 521      $current_stylesheet = get_option('stylesheet');
 522      $current_theme = 'Twenty Ten';
 523  
 524      if ( $themes ) {
 525          foreach ( (array) $theme_names as $theme_name ) {
 526              if ( $themes[$theme_name]['Stylesheet'] == $current_stylesheet &&
 527                      $themes[$theme_name]['Template'] == $current_template ) {
 528                  $current_theme = $themes[$theme_name]['Name'];
 529                  break;
 530              }
 531          }
 532      }
 533  
 534      update_option('current_theme', $current_theme);
 535  
 536      return $current_theme;
 537  }
 538  
 539  /**
 540   * Register a directory that contains themes.
 541   *
 542   * @since 2.9.0
 543   *
 544   * @param string $directory Either the full filesystem path to a theme folder or a folder within WP_CONTENT_DIR
 545   * @return bool
 546   */
 547  function register_theme_directory( $directory) {
 548      global $wp_theme_directories;
 549  
 550      /* If this folder does not exist, return and do not register */
 551      if ( !file_exists( $directory ) )
 552              /* Try prepending as the theme directory could be relative to the content directory */
 553          $registered_directory = WP_CONTENT_DIR . '/' . $directory;
 554      else
 555          $registered_directory = $directory;
 556  
 557      /* If this folder does not exist, return and do not register */
 558      if ( !file_exists( $registered_directory ) )
 559          return false;
 560  
 561      $wp_theme_directories[] = $registered_directory;
 562  
 563      return true;
 564  }
 565  
 566  /**
 567   * Search all registered theme directories for complete and valid themes.
 568   *
 569   * @since 2.9.0
 570   *
 571   * @return array Valid themes found
 572   */
 573  function search_theme_directories() {
 574      global $wp_theme_directories, $wp_broken_themes;
 575      if ( empty( $wp_theme_directories ) )
 576          return false;
 577  
 578      $theme_files = array();
 579      $wp_broken_themes = array();
 580  
 581      /* Loop the registered theme directories and extract all themes */
 582      foreach ( (array) $wp_theme_directories as $theme_root ) {
 583          $theme_loc = $theme_root;
 584  
 585          /* We don't want to replace all forward slashes, see Trac #4541 */
 586          if ( '/' != WP_CONTENT_DIR )
 587              $theme_loc = str_replace(WP_CONTENT_DIR, '', $theme_root);
 588  
 589          /* Files in the root of the current theme directory and one subdir down */
 590          $themes_dir = @ opendir($theme_root);
 591  
 592          if ( !$themes_dir )
 593              return false;
 594  
 595          while ( ($theme_dir = readdir($themes_dir)) !== false ) {
 596              if ( is_dir($theme_root . '/' . $theme_dir) && is_readable($theme_root . '/' . $theme_dir) ) {
 597                  if ( $theme_dir[0] == '.' || $theme_dir == 'CVS' )
 598                      continue;
 599  
 600                  $stylish_dir = @opendir($theme_root . '/' . $theme_dir);
 601                  $found_stylesheet = false;
 602  
 603                  while ( ($theme_file = readdir($stylish_dir)) !== false ) {
 604                      if ( $theme_file == 'style.css' ) {
 605                          $theme_files[$theme_dir] = array( 'theme_file' => $theme_dir . '/' . $theme_file, 'theme_root' => $theme_root );
 606                          $found_stylesheet = true;
 607                          break;
 608                      }
 609                  }
 610                  @closedir($stylish_dir);
 611  
 612                  if ( !$found_stylesheet ) { // look for themes in that dir
 613                      $subdir = "$theme_root/$theme_dir";
 614                      $subdir_name = $theme_dir;
 615                      $theme_subdirs = @opendir( $subdir );
 616  
 617                      $found_subdir_themes = false;
 618                      while ( ($theme_subdir = readdir($theme_subdirs)) !== false ) {
 619                          if ( is_dir( $subdir . '/' . $theme_subdir) && is_readable($subdir . '/' . $theme_subdir) ) {
 620                              if ( $theme_subdir[0] == '.' || $theme_subdir == 'CVS' )
 621                                  continue;
 622  
 623                              $stylish_dir = @opendir($subdir . '/' . $theme_subdir);
 624                              $found_stylesheet = false;
 625  
 626                              while ( ($theme_file = readdir($stylish_dir)) !== false ) {
 627                                  if ( $theme_file == 'style.css' ) {
 628                                      $theme_files["$theme_dir/$theme_subdir"] = array( 'theme_file' => $subdir_name . '/' . $theme_subdir . '/' . $theme_file, 'theme_root' => $theme_root );
 629                                      $found_stylesheet = true;
 630                                      $found_subdir_themes = true;
 631                                      break;
 632                                  }
 633                              }
 634                              @closedir($stylish_dir);
 635                          }
 636                      }
 637                      @closedir($theme_subdirs);
 638                      if ( !$found_subdir_themes )
 639                          $wp_broken_themes[$theme_dir] = array('Name' => $theme_dir, 'Title' => $theme_dir, 'Description' => __('Stylesheet is missing.'));
 640                  }
 641              }
 642          }
 643          @closedir( $themes_dir );
 644      }
 645      return $theme_files;
 646  }
 647  
 648  /**
 649   * Retrieve path to themes directory.
 650   *
 651   * Does not have trailing slash.
 652   *
 653   * @since 1.5.0
 654   * @uses apply_filters() Calls 'theme_root' filter on path.
 655   *
 656   * @param string $stylesheet_or_template The stylesheet or template name of the theme
 657   * @return string Theme path.
 658   */
 659  function get_theme_root( $stylesheet_or_template = false ) {
 660      if ( $stylesheet_or_template ) {
 661          if ( $theme_root = get_raw_theme_root($stylesheet_or_template) )
 662              $theme_root = WP_CONTENT_DIR . $theme_root;
 663          else
 664              $theme_root = WP_CONTENT_DIR . '/themes';
 665      } else {
 666          $theme_root = WP_CONTENT_DIR . '/themes';
 667      }
 668  
 669      return apply_filters( 'theme_root', $theme_root );
 670  }
 671  
 672  /**
 673   * Retrieve URI for themes directory.
 674   *
 675   * Does not have trailing slash.
 676   *
 677   * @since 1.5.0
 678   *
 679   * @param string $stylesheet_or_template The stylesheet or template name of the theme
 680   * @return string Themes URI.
 681   */
 682  function get_theme_root_uri( $stylesheet_or_template = false ) {
 683      if ( $stylesheet_or_template ) {
 684          if ( $theme_root = get_raw_theme_root($stylesheet_or_template) )
 685              $theme_root_uri = content_url( $theme_root );
 686          else
 687              $theme_root_uri = content_url( 'themes' );
 688      } else {
 689          $theme_root_uri = content_url( 'themes' );
 690      }
 691  
 692      return apply_filters( 'theme_root_uri', $theme_root_uri, get_option('siteurl'), $stylesheet_or_template );
 693  }
 694  
 695  /**
 696   * Get the raw theme root relative to the content directory with no filters applied.
 697   *
 698   * @since 3.1.0
 699   *
 700   * @param string $stylesheet_or_template The stylesheet or template name of the theme
 701   * @return string Theme root
 702   */
 703  function get_raw_theme_root( $stylesheet_or_template, $no_cache = false ) {
 704      global $wp_theme_directories;
 705  
 706      if ( count($wp_theme_directories) <= 1 )
 707          return '/themes';
 708  
 709      $theme_root = false;
 710  
 711      // If requesting the root for the current theme, consult options to avoid calling get_theme_roots()
 712      if ( !$no_cache ) {
 713          if ( get_option('stylesheet') == $stylesheet_or_template )
 714              $theme_root = get_option('stylesheet_root');
 715          elseif ( get_option('template') == $stylesheet_or_template )
 716              $theme_root = get_option('template_root');
 717      }
 718  
 719      if ( empty($theme_root) ) {
 720          $theme_roots = get_theme_roots();
 721          if ( !empty($theme_roots[$stylesheet_or_template]) )
 722              $theme_root = $theme_roots[$stylesheet_or_template];
 723      }
 724  
 725      return $theme_root;
 726  }
 727  
 728  /**
 729   * Retrieve path to a template
 730   *
 731   * Used to quickly retrieve the path of a template without including the file
 732   * extension. It will also check the parent theme, if the file exists, with
 733   * the use of {@link locate_template()}. Allows for more generic template location
 734   * without the use of the other get_*_template() functions.
 735   *
 736   * @since 1.5.0
 737   *
 738   * @param string $type Filename without extension.
 739   * @param array $templates An optional list of template candidates
 740   * @return string Full path to file.
 741   */
 742  function get_query_template( $type, $templates = array() ) {
 743      $type = preg_replace( '|[^a-z0-9-]+|', '', $type );
 744  
 745      if ( empty( $templates ) )
 746          $templates = array("{$type}.php");
 747  
 748      return apply_filters( "{$type}_template", locate_template( $templates ) );
 749  }
 750  
 751  /**
 752   * Retrieve path of index template in current or parent template.
 753   *
 754   * @since 3.0.0
 755   *
 756   * @return string
 757   */
 758  function get_index_template() {
 759      return get_query_template('index');
 760  }
 761  
 762  /**
 763   * Retrieve path of 404 template in current or parent template.
 764   *
 765   * @since 1.5.0
 766   *
 767   * @return string
 768   */
 769  function get_404_template() {
 770      return get_query_template('404');
 771  }
 772  
 773  /**
 774   * Retrieve path of archive template in current or parent template.
 775   *
 776   * @since 1.5.0
 777   *
 778   * @return string
 779   */
 780  function get_archive_template() {
 781      $post_type = get_query_var( 'post_type' );
 782  
 783      $templates = array();
 784  
 785      if ( $post_type )
 786          $templates[] = "archive-{$post_type}.php";
 787      $templates[] = 'archive.php';
 788  
 789      return get_query_template( 'archive', $templates );
 790  }
 791  
 792  /**
 793   * Retrieve path of author template in current or parent template.
 794   *
 795   * @since 1.5.0
 796   *
 797   * @return string
 798   */
 799  function get_author_template() {
 800      $author = get_queried_object();
 801  
 802      $templates = array();
 803  
 804      $templates[] = "author-{$author->user_nicename}.php";
 805      $templates[] = "author-{$author->ID}.php";
 806      $templates[] = 'author.php';
 807  
 808      return get_query_template( 'author', $templates );
 809  }
 810  
 811  /**
 812   * Retrieve path of category template in current or parent template.
 813   *
 814   * Works by first retrieving the current slug for example 'category-default.php' and then
 815   * trying category ID, for example 'category-1.php' and will finally fallback to category.php
 816   * template, if those files don't exist.
 817   *
 818   * @since 1.5.0
 819   * @uses apply_filters() Calls 'category_template' on file path of category template.
 820   *
 821   * @return string
 822   */
 823  function get_category_template() {
 824      $category = get_queried_object();
 825  
 826      $templates = array();
 827  
 828      $templates[] = "category-{$category->slug}.php";
 829      $templates[] = "category-{$category->term_id}.php";
 830      $templates[] = 'category.php';
 831  
 832      return get_query_template( 'category', $templates );
 833  }
 834  
 835  /**
 836   * Retrieve path of tag template in current or parent template.
 837   *
 838   * Works by first retrieving the current tag name, for example 'tag-wordpress.php' and then
 839   * trying tag ID, for example 'tag-1.php' and will finally fallback to tag.php
 840   * template, if those files don't exist.
 841   *
 842   * @since 2.3.0
 843   * @uses apply_filters() Calls 'tag_template' on file path of tag template.
 844   *
 845   * @return string
 846   */
 847  function get_tag_template() {
 848      $tag = get_queried_object();
 849  
 850      $templates = array();
 851  
 852      $templates[] = "tag-{$tag->slug}.php";
 853      $templates[] = "tag-{$tag->term_id}.php";
 854      $templates[] = 'tag.php';
 855  
 856      return get_query_template( 'tag', $templates );
 857  }
 858  
 859  /**
 860   * Retrieve path of taxonomy template in current or parent template.
 861   *
 862   * Retrieves the taxonomy and term, if term is available. The template is
 863   * prepended with 'taxonomy-' and followed by both the taxonomy string and
 864   * the taxonomy string followed by a dash and then followed by the term.
 865   *
 866   * The taxonomy and term template is checked and used first, if it exists.
 867   * Second, just the taxonomy template is checked, and then finally, taxonomy.php
 868   * template is used. If none of the files exist, then it will fall back on to
 869   * index.php.
 870   *
 871   * @since 2.5.0
 872   * @uses apply_filters() Calls 'taxonomy_template' filter on found path.
 873   *
 874   * @return string
 875   */
 876  function get_taxonomy_template() {
 877      $term = get_queried_object();
 878      $taxonomy = $term->taxonomy;
 879  
 880      $templates = array();
 881  
 882      $templates[] = "taxonomy-$taxonomy-{$term->slug}.php";
 883      $templates[] = "taxonomy-$taxonomy.php";
 884      $templates[] = 'taxonomy.php';
 885  
 886      return get_query_template( 'taxonomy', $templates );
 887  }
 888  
 889  /**
 890   * Retrieve path of date template in current or parent template.
 891   *
 892   * @since 1.5.0
 893   *
 894   * @return string
 895   */
 896  function get_date_template() {
 897      return get_query_template('date');
 898  }
 899  
 900  /**
 901   * Retrieve path of home template in current or parent template.
 902   *
 903   * This is the template used for the page containing the blog posts
 904   *
 905   * Attempts to locate 'home.php' first before falling back to 'index.php'.
 906   *
 907   * @since 1.5.0
 908   * @uses apply_filters() Calls 'home_template' on file path of home template.
 909   *
 910   * @return string
 911   */
 912  function get_home_template() {
 913      $templates = array( 'home.php', 'index.php' );
 914  
 915      return get_query_template( 'home', $templates );
 916  }
 917  
 918  /**
 919   * Retrieve path of front-page template in current or parent template.
 920   *
 921   * Looks for 'front-page.php'.
 922   *
 923   * @since 3.0.0
 924   * @uses apply_filters() Calls 'front_page_template' on file path of template.
 925   *
 926   * @return string
 927   */
 928  function get_front_page_template() {
 929      $templates = array('front-page.php');
 930  
 931      return get_query_template( 'front_page', $templates );
 932  }
 933  
 934  /**
 935   * Retrieve path of page template in current or parent template.
 936   *
 937   * Will first look for the specifically assigned page template
 938   * The will search for 'page-{slug}.php' followed by 'page-id.php'
 939   * and finally 'page.php'
 940   *
 941   * @since 1.5.0
 942   *
 943   * @return string
 944   */
 945  function get_page_template() {
 946      $id = get_queried_object_id();
 947      $template = get_post_meta($id, '_wp_page_template', true);
 948      $pagename = get_query_var('pagename');
 949  
 950      if ( !$pagename && $id > 0 ) {
 951          // If a static page is set as the front page, $pagename will not be set. Retrieve it from the queried object
 952          $post = get_queried_object();
 953          $pagename = $post->post_name;
 954      }
 955  
 956      if ( 'default' == $template )
 957          $template = '';
 958  
 959      $templates = array();
 960      if ( !empty($template) && !validate_file($template) )
 961          $templates[] = $template;
 962      if ( $pagename )
 963          $templates[] = "page-$pagename.php";
 964      if ( $id )
 965          $templates[] = "page-$id.php";
 966      $templates[] = 'page.php';
 967  
 968      return get_query_template( 'page', $templates );
 969  }
 970  
 971  /**
 972   * Retrieve path of paged template in current or parent template.
 973   *
 974   * @since 1.5.0
 975   *
 976   * @return string
 977   */
 978  function get_paged_template() {
 979      return get_query_template('paged');
 980  }
 981  
 982  /**
 983   * Retrieve path of search template in current or parent template.
 984   *
 985   * @since 1.5.0
 986   *
 987   * @return string
 988   */
 989  function get_search_template() {
 990      return get_query_template('search');
 991  }
 992  
 993  /**
 994   * Retrieve path of single template in current or parent template.
 995   *
 996   * @since 1.5.0
 997   *
 998   * @return string
 999   */
1000  function get_single_template() {
1001      $object = get_queried_object();
1002  
1003      $templates = array();
1004  
1005      $templates[] = "single-{$object->post_type}.php";
1006      $templates[] = "single.php";
1007  
1008      return get_query_template( 'single', $templates );
1009  }
1010  
1011  /**
1012   * Retrieve path of attachment template in current or parent template.
1013   *
1014   * The attachment path first checks if the first part of the mime type exists.
1015   * The second check is for the second part of the mime type. The last check is
1016   * for both types separated by an underscore. If neither are found then the file
1017   * 'attachment.php' is checked and returned.
1018   *
1019   * Some examples for the 'text/plain' mime type are 'text.php', 'plain.php', and
1020   * finally 'text_plain.php'.
1021   *
1022   * @since 2.0.0
1023   *
1024   * @return string
1025   */
1026  function get_attachment_template() {
1027      global $posts;
1028      $type = explode('/', $posts[0]->post_mime_type);
1029      if ( $template = get_query_template($type[0]) )
1030          return $template;
1031      elseif ( $template = get_query_template($type[1]) )
1032          return $template;
1033      elseif ( $template = get_query_template("$type[0]_$type[1]") )
1034          return $template;
1035      else
1036          return get_query_template('attachment');
1037  }
1038  
1039  /**
1040   * Retrieve path of comment popup template in current or parent template.
1041   *
1042   * Checks for comment popup template in current template, if it exists or in the
1043   * parent template.
1044   *
1045   * @since 1.5.0
1046   * @uses apply_filters() Calls 'comments_popup_template' filter on path.
1047   *
1048   * @return string
1049   */
1050  function get_comments_popup_template() {
1051      $template = get_query_template( 'comments_popup', array( 'comments-popup.php' ) );
1052  
1053      // Backward compat code will be removed in a future release
1054      if ('' == $template)
1055          $template = ABSPATH . WPINC . '/theme-compat/comments-popup.php';
1056  
1057      return $template;
1058  }
1059  
1060  /**
1061   * Retrieve the name of the highest priority template file that exists.
1062   *
1063   * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
1064   * inherit from a parent theme can just overload one file.
1065   *
1066   * @since 2.7.0
1067   *
1068   * @param string|array $template_names Template file(s) to search for, in order.
1069   * @param bool $load If true the template file will be loaded if it is found.
1070   * @param bool $require_once Whether to require_once or require. Default true. Has no effect if $load is false.
1071   * @return string The template filename if one is located.
1072   */
1073  function locate_template($template_names, $load = false, $require_once = true ) {
1074      $located = '';
1075      foreach ( (array) $template_names as $template_name ) {
1076          if ( !$template_name )
1077              continue;
1078          if ( file_exists(STYLESHEETPATH . '/' . $template_name)) {
1079              $located = STYLESHEETPATH . '/' . $template_name;
1080              break;
1081          } else if ( file_exists(TEMPLATEPATH . '/' . $template_name) ) {
1082              $located = TEMPLATEPATH . '/' . $template_name;
1083              break;
1084          }
1085      }
1086  
1087      if ( $load && '' != $located )
1088          load_template( $located, $require_once );
1089  
1090      return $located;
1091  }
1092  
1093  /**
1094   * Require the template file with WordPress environment.
1095   *
1096   * The globals are set up for the template file to ensure that the WordPress
1097   * environment is available from within the function. The query variables are
1098   * also available.
1099   *
1100   * @since 1.5.0
1101   *
1102   * @param string $_template_file Path to template file.
1103   * @param bool $require_once Whether to require_once or require. Default true.
1104   */
1105  function load_template( $_template_file, $require_once = true ) {
1106      global $posts, $post, $wp_did_header, $wp_did_template_redirect, $wp_query, $wp_rewrite, $wpdb, $wp_version, $wp, $id, $comment, $user_ID;
1107  
1108      if ( is_array( $wp_query->query_vars ) )
1109          extract( $wp_query->query_vars, EXTR_SKIP );
1110  
1111      if ( $require_once )
1112          require_once( $_template_file );
1113      else
1114          require( $_template_file );
1115  }
1116  
1117  /**
1118   * Display localized stylesheet link element.
1119   *
1120   * @since 2.1.0
1121   */
1122  function locale_stylesheet() {
1123      $stylesheet = get_locale_stylesheet_uri();
1124      if ( empty($stylesheet) )
1125          return;
1126      echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
1127  }
1128  
1129  /**
1130   * Start preview theme output buffer.
1131   *
1132   * Will only preform task if the user has permissions and template and preview
1133   * query variables exist.
1134   *
1135   * @since 2.6.0
1136   */
1137  function preview_theme() {
1138      if ( ! (isset($_GET['template']) && isset($_GET['preview'])) )
1139          return;
1140  
1141      if ( !current_user_can( 'switch_themes' ) )
1142          return;
1143  
1144      // Admin Thickbox requests
1145      if ( isset( $_GET['preview_iframe'] ) )
1146          show_admin_bar( false );
1147  
1148      $_GET['template'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['template']);
1149  
1150      if ( validate_file($_GET['template']) )
1151          return;
1152  
1153      add_filter( 'template', '_preview_theme_template_filter' );
1154  
1155      if ( isset($_GET['stylesheet']) ) {
1156          $_GET['stylesheet'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['stylesheet']);
1157          if ( validate_file($_GET['stylesheet']) )
1158              return;
1159          add_filter( 'stylesheet', '_preview_theme_stylesheet_filter' );
1160      }
1161  
1162      // Prevent theme mods to current theme being used on theme being previewed
1163      add_filter( 'pre_option_mods_' . get_current_theme(), '__return_empty_array' );
1164  
1165      ob_start( 'preview_theme_ob_filter' );
1166  }
1167  add_action('setup_theme', 'preview_theme');
1168  
1169  /**
1170   * Private function to modify the current template when previewing a theme
1171   *
1172   * @since 2.9.0
1173   * @access private
1174   *
1175   * @return string
1176   */
1177  function _preview_theme_template_filter() {
1178      return isset($_GET['template']) ? $_GET['template'] : '';
1179  }
1180  
1181  /**
1182   * Private function to modify the current stylesheet when previewing a theme
1183   *
1184   * @since 2.9.0
1185   * @access private
1186   *
1187   * @return string
1188   */
1189  function _preview_theme_stylesheet_filter() {
1190      return isset($_GET['stylesheet']) ? $_GET['stylesheet'] : '';
1191  }
1192  
1193  /**
1194   * Callback function for ob_start() to capture all links in the theme.
1195   *
1196   * @since 2.6.0
1197   * @access private
1198   *
1199   * @param string $content
1200   * @return string
1201   */
1202  function preview_theme_ob_filter( $content ) {
1203      return preg_replace_callback( "|(<a.*?href=([\"']))(.*?)([\"'].*?>)|", 'preview_theme_ob_filter_callback', $content );
1204  }
1205  
1206  /**
1207   * Manipulates preview theme links in order to control and maintain location.
1208   *
1209   * Callback function for preg_replace_callback() to accept and filter matches.
1210   *
1211   * @since 2.6.0
1212   * @access private
1213   *
1214   * @param array $matches
1215   * @return string
1216   */
1217  function preview_theme_ob_filter_callback( $matches ) {
1218      if ( strpos($matches[4], 'onclick') !== false )
1219          $matches[4] = preg_replace('#onclick=([\'"]).*?(?<!\\\)\\1#i', '', $matches[4]); //Strip out any onclicks from rest of <a>. (?<!\\\) means to ignore the '" if its escaped by \  to prevent breaking mid-attribute.
1220      if (
1221          ( false !== strpos($matches[3], '/wp-admin/') )
1222      ||
1223          ( false !== strpos( $matches[3], '://' ) && 0 !== strpos( $matches[3], home_url() ) )
1224      ||
1225          ( false !== strpos($matches[3], '/feed/') )
1226      ||
1227          ( false !== strpos($matches[3], '/trackback/') )
1228      )
1229          return $matches[1] . "#$matches[2] onclick=$matches[2]return false;" . $matches[4];
1230  
1231      $link = add_query_arg( array('preview' => 1, 'template' => $_GET['template'], 'stylesheet' => @$_GET['stylesheet'] ), $matches[3] );
1232      if ( 0 === strpos($link, 'preview=1') )
1233          $link = "?$link";
1234      return $matches[1] . esc_attr( $link ) . $matches[4];
1235  }
1236  
1237  /**
1238   * Switches current theme to new template and stylesheet names.
1239   *
1240   * @since 2.5.0
1241   * @uses do_action() Calls 'switch_theme' action on updated theme display name.
1242   *
1243   * @param string $template Template name
1244   * @param string $stylesheet Stylesheet name.
1245   */
1246  function switch_theme($template, $stylesheet) {
1247      global $wp_theme_directories;
1248  
1249      update_option('template', $template);
1250      update_option('stylesheet', $stylesheet);
1251      if ( count($wp_theme_directories) > 1 ) {
1252          update_option('template_root', get_raw_theme_root($template, true));
1253          update_option('stylesheet_root', get_raw_theme_root($stylesheet, true));
1254      }
1255      delete_option('current_theme');
1256      $theme = get_current_theme();
1257      if ( is_admin() && false === get_option( "theme_mods_$stylesheet" ) ) {
1258          $default_theme_mods = (array) get_option( "mods_$theme" );
1259          add_option( "theme_mods_$stylesheet", $default_theme_mods );
1260      }
1261      do_action('switch_theme', $theme);
1262  }
1263  
1264  /**
1265   * Checks that current theme files 'index.php' and 'style.css' exists.
1266   *
1267   * Does not check the default theme, which is the fallback and should always exist.
1268   * Will switch theme to the fallback theme if current theme does not validate.
1269   * You can use the 'validate_current_theme' filter to return FALSE to
1270   * disable this functionality.
1271   *
1272   * @since 1.5.0
1273   * @see WP_DEFAULT_THEME
1274   *
1275   * @return bool
1276   */
1277  function validate_current_theme() {
1278      // Don't validate during an install/upgrade.
1279      if ( defined('WP_INSTALLING') || !apply_filters( 'validate_current_theme', true ) )
1280          return true;
1281  
1282      if ( get_template() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/index.php') ) {
1283          switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
1284          return false;
1285      }
1286  
1287      if ( get_stylesheet() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/style.css') ) {
1288          switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
1289          return false;
1290      }
1291  
1292      if ( is_child_theme() && ! file_exists( get_stylesheet_directory() . '/style.css' ) ) {
1293          switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
1294          return false;
1295      }
1296  
1297      return true;
1298  }
1299  
1300  /**
1301   * Retrieve all theme modifications.
1302   *
1303   * @since 3.1.0
1304   *
1305   * @return array Theme modifications.
1306   */
1307  function get_theme_mods() {
1308      $theme_slug = get_option( 'stylesheet' );
1309      if ( false === ( $mods = get_option( "theme_mods_$theme_slug" ) ) ) {
1310          $theme_name = get_current_theme();
1311          $mods = get_option( "mods_$theme_name" ); // Deprecated location.
1312          if ( is_admin() && false !== $mods ) {
1313              update_option( "theme_mods_$theme_slug", $mods );
1314              delete_option( "mods_$theme_name" );
1315          }
1316      }
1317      return $mods;
1318  }
1319  
1320  /**
1321   * Retrieve theme modification value for the current theme.
1322   *
1323   * If the modification name does not exist, then the $default will be passed
1324   * through {@link http://php.net/sprintf sprintf()} PHP function with the first
1325   * string the template directory URI and the second string the stylesheet
1326   * directory URI.
1327   *
1328   * @since 2.1.0
1329   * @uses apply_filters() Calls 'theme_mod_$name' filter on the value.
1330   *
1331   * @param string $name Theme modification name.
1332   * @param bool|string $default
1333   * @return string
1334   */
1335  function get_theme_mod( $name, $default = false ) {
1336      $mods = get_theme_mods();
1337  
1338      if ( isset( $mods[ $name ] ) )
1339          return apply_filters( "theme_mod_$name", $mods[ $name ] );
1340  
1341      return apply_filters( "theme_mod_$name", sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() ) );
1342  }
1343  
1344  /**
1345   * Update theme modification value for the current theme.
1346   *
1347   * @since 2.1.0
1348   *
1349   * @param string $name Theme modification name.
1350   * @param string $value theme modification value.
1351   */
1352  function set_theme_mod( $name, $value ) {
1353      $mods = get_theme_mods();
1354  
1355      $mods[ $name ] = $value;
1356  
1357      $theme = get_option( 'stylesheet' );
1358      update_option( "theme_mods_$theme", $mods );
1359  }
1360  
1361  /**
1362   * Remove theme modification name from current theme list.
1363   *
1364   * If removing the name also removes all elements, then the entire option will
1365   * be removed.
1366   *
1367   * @since 2.1.0
1368   *
1369   * @param string $name Theme modification name.
1370   * @return null
1371   */
1372  function remove_theme_mod( $name ) {
1373      $mods = get_theme_mods();
1374  
1375      if ( ! isset( $mods[ $name ] ) )
1376          return;
1377  
1378      unset( $mods[ $name ] );
1379  
1380      if ( empty( $mods ) )
1381          return remove_theme_mods();
1382  
1383      $theme = get_option( 'stylesheet' );
1384      update_option( "theme_mods_$theme", $mods );
1385  }
1386  
1387  /**
1388   * Remove theme modifications option for current theme.
1389   *
1390   * @since 2.1.0
1391   */
1392  function remove_theme_mods() {
1393      delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
1394      delete_option( 'mods_' . get_current_theme() );
1395  }
1396  
1397  /**
1398   * Retrieve text color for custom header.
1399   *
1400   * @since 2.1.0
1401   * @uses HEADER_TEXTCOLOR
1402   *
1403   * @return string
1404   */
1405  function get_header_textcolor() {
1406      $default = defined('HEADER_TEXTCOLOR') ? HEADER_TEXTCOLOR : '';
1407  
1408      return get_theme_mod('header_textcolor', $default);
1409  }
1410  
1411  /**
1412   * Display text color for custom header.
1413   *
1414   * @since 2.1.0
1415   */
1416  function header_textcolor() {
1417      echo get_header_textcolor();
1418  }
1419  
1420  /**
1421   * Retrieve header image for custom header.
1422   *
1423   * @since 2.1.0
1424   * @uses HEADER_IMAGE
1425   *
1426   * @return string
1427   */
1428  function get_header_image() {
1429      $default = defined( 'HEADER_IMAGE' ) ? HEADER_IMAGE : '';
1430      $url = get_theme_mod( 'header_image', $default );
1431  
1432      if ( 'remove-header' == $url )
1433          return false;
1434  
1435      if ( is_random_header_image() )
1436          $url = get_random_header_image();
1437  
1438      if ( is_ssl() )
1439          $url = str_replace( 'http://', 'https://', $url );
1440      else
1441          $url = str_replace( 'https://', 'http://', $url );
1442  
1443      return esc_url_raw( $url );
1444  }
1445  
1446  /**
1447   * Get random header image from registered images in theme.
1448   *
1449   * @since 3.2
1450   *
1451   * @return string Path to header image
1452   */
1453  function get_random_header_image() {
1454      global $_wp_default_headers;
1455  
1456      $header_image_mod = get_theme_mod( 'header_image', '' );
1457      $headers = array();
1458  
1459      if ( 'random-uploaded-image' == $header_image_mod )
1460          $headers = get_uploaded_header_images();
1461      elseif ( ! empty( $_wp_default_headers ) )
1462          $headers = $_wp_default_headers;
1463  
1464      if ( empty( $headers ) )
1465          return '';
1466  
1467      $random_image = array_rand( $headers );
1468      $header_url = sprintf( $headers[$random_image]['url'], get_template_directory_uri(), get_stylesheet_directory_uri() );
1469  
1470      return $header_url;
1471  }
1472  
1473  /**
1474   * Check if random header image is in use.
1475   *
1476   * Always true if user expressly chooses the option in Appearance > Header.
1477   * Also true if theme has multiple header images registered and no specific header image is chosen.
1478   *
1479   * @since 3.2
1480   * @uses HEADER_IMAGE
1481   *
1482   * @param string $type The random pool to use. any|default|uploaded
1483   * @return boolean
1484   */
1485  function is_random_header_image( $type = 'any' ) {
1486      $default = defined( 'HEADER_IMAGE' ) ? HEADER_IMAGE : '';
1487      $header_image_mod = get_theme_mod( 'header_image', $default );
1488  
1489      if ( 'any' == $type ) {
1490          if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) )
1491              return true;
1492      } else {
1493          if ( "random-$type-image" == $header_image_mod )
1494              return true;
1495          elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image()  )
1496              return true;
1497      }
1498  
1499      return false;
1500  }
1501  
1502  /**
1503   * Display header image path.
1504   *
1505   * @since 2.1.0
1506   */
1507  function header_image() {
1508      echo get_header_image();
1509  }
1510  
1511  /**
1512   * Get the header images uploaded for the current theme.
1513   *
1514   * @since 3.2.0
1515   *
1516   * @return array
1517   */
1518  function get_uploaded_header_images() {
1519      $header_images = array();
1520  
1521      // @todo caching
1522      $headers = get_posts( array( 'post_type' => 'attachment', 'meta_key' => '_wp_attachment_is_custom_header', 'meta_value' => get_option('stylesheet'), 'orderby' => 'none', 'nopaging' => true ) );
1523  
1524      if ( empty( $headers ) )
1525          return array();
1526  
1527      foreach ( (array) $headers as $header ) {
1528          $url = esc_url_raw( $header->guid );
1529          $header = basename($url);
1530          $header_images[$header] = array();
1531          $header_images[$header]['url'] =  $url;
1532          $header_images[$header]['thumbnail_url'] =  $url;
1533          $header_images[$header]['uploaded'] = true;
1534      }
1535  
1536      return $header_images;
1537  }
1538  
1539  /**
1540   * Add callbacks for image header display.
1541   *
1542   * The parameter $header_callback callback will be required to display the
1543   * content for the 'wp_head' action. The parameter $admin_header_callback
1544   * callback will be added to Custom_Image_Header class and that will be added
1545   * to the 'admin_menu' action.
1546   *
1547   * @since 2.1.0
1548   * @uses Custom_Image_Header Sets up for $admin_header_callback for administration panel display.
1549   *
1550   * @param callback $header_callback Call on 'wp_head' action.
1551   * @param callback $admin_header_callback Call on custom header administration screen.
1552   * @param callback $admin_image_div_callback Output a custom header image div on the custom header administration screen. Optional.
1553   */
1554  function add_custom_image_header( $header_callback, $admin_header_callback, $admin_image_div_callback = '' ) {
1555      if ( ! empty( $header_callback ) )
1556          add_action('wp_head', $header_callback);
1557  
1558      add_theme_support( 'custom-header', array( 'callback' => $header_callback ) );
1559      add_theme_support( 'custom-header-uploads' );
1560  
1561      if ( ! is_admin() )
1562          return;
1563  
1564      global $custom_image_header;
1565  
1566      require_once ( ABSPATH . 'wp-admin/custom-header.php' );
1567      $custom_image_header = new Custom_Image_Header( $admin_header_callback, $admin_image_div_callback );
1568      add_action( 'admin_menu', array( &$custom_image_header, 'init' ) );
1569  }
1570  
1571  /**
1572   * Remove image header support.
1573   *
1574   * @since 3.1.0
1575   * @see add_custom_image_header()
1576   *
1577   * @return bool Whether support was removed.
1578   */
1579  function remove_custom_image_header() {
1580      if ( ! current_theme_supports( 'custom-header' ) )
1581          return false;
1582  
1583      $callback = get_theme_support( 'custom-header' );
1584      remove_action( 'wp_head', $callback[0]['callback'] );
1585      _remove_theme_support( 'custom-header' );
1586      remove_theme_support( 'custom-header-uploads' );
1587  
1588      if ( is_admin() ) {
1589          remove_action( 'admin_menu', array( &$GLOBALS['custom_image_header'], 'init' ) );
1590          unset( $GLOBALS['custom_image_header'] );
1591      }
1592  
1593      return true;
1594  }
1595  
1596  /**
1597   * Register a selection of default headers to be displayed by the custom header admin UI.
1598   *
1599   * @since 3.0.0
1600   *
1601   * @param array $headers Array of headers keyed by a string id. The ids point to arrays containing 'url', 'thumbnail_url', and 'description' keys.
1602   */
1603  function register_default_headers( $headers ) {
1604      global $_wp_default_headers;
1605  
1606      $_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
1607  }
1608  
1609  /**
1610   * Unregister default headers.
1611   *
1612   * This function must be called after register_default_headers() has already added the
1613   * header you want to remove.
1614   *
1615   * @see register_default_headers()
1616   * @since 3.0.0
1617   *
1618   * @param string|array $header The header string id (key of array) to remove, or an array thereof.
1619   * @return True on success, false on failure.
1620   */
1621  function unregister_default_headers( $header ) {
1622      global $_wp_default_headers;
1623      if ( is_array( $header ) ) {
1624          array_map( 'unregister_default_headers', $header );
1625      } elseif ( isset( $_wp_default_headers[ $header ] ) ) {
1626          unset( $_wp_default_headers[ $header ] );
1627          return true;
1628      } else {
1629          return false;
1630      }
1631  }
1632  
1633  /**
1634   * Retrieve background image for custom background.
1635   *
1636   * @since 3.0.0
1637   *
1638   * @return string
1639   */
1640  function get_background_image() {
1641      $default = defined('BACKGROUND_IMAGE') ? BACKGROUND_IMAGE : '';
1642  
1643      return get_theme_mod('background_image', $default);
1644  }
1645  
1646  /**
1647   * Display background image path.
1648   *
1649   * @since 3.0.0
1650   */
1651  function background_image() {
1652      echo get_background_image();
1653  }
1654  
1655  /**
1656   * Retrieve value for custom background color.
1657   *
1658   * @since 3.0.0
1659   * @uses BACKGROUND_COLOR
1660   *
1661   * @return string
1662   */
1663  function get_background_color() {
1664      $default = defined('BACKGROUND_COLOR') ? BACKGROUND_COLOR : '';
1665  
1666      return get_theme_mod('background_color', $default);
1667  }
1668  
1669  /**
1670   * Display background color value.
1671   *
1672   * @since 3.0.0
1673   */
1674  function background_color() {
1675      echo get_background_color();
1676  }
1677  
1678  /**
1679   * Add callbacks for background image display.
1680   *
1681   * The parameter $header_callback callback will be required to display the
1682   * content for the 'wp_head' action. The parameter $admin_header_callback
1683   * callback will be added to Custom_Background class and that will be added
1684   * to the 'admin_menu' action.
1685   *
1686   * @since 3.0.0
1687   * @uses Custom_Background Sets up for $admin_header_callback for administration panel display.
1688   *
1689   * @param callback $header_callback Call on 'wp_head' action.
1690   * @param callback $admin_header_callback Call on custom background administration screen.
1691   * @param callback $admin_image_div_callback Output a custom background image div on the custom background administration screen. Optional.
1692   */
1693  function add_custom_background( $header_callback = '', $admin_header_callback = '', $admin_image_div_callback = '' ) {
1694      if ( isset( $GLOBALS['custom_background'] ) )
1695          return;
1696  
1697      if ( empty( $header_callback ) )
1698          $header_callback = '_custom_background_cb';
1699  
1700      add_action( 'wp_head', $header_callback );
1701  
1702      add_theme_support( 'custom-background', array( 'callback' => $header_callback ) );
1703  
1704      if ( ! is_admin() )
1705          return;
1706      require_once ( ABSPATH . 'wp-admin/custom-background.php' );
1707      $GLOBALS['custom_background'] =& new Custom_Background( $admin_header_callback, $admin_image_div_callback );
1708      add_action( 'admin_menu', array( &$GLOBALS['custom_background'], 'init' ) );
1709  }
1710  
1711  /**
1712   * Remove custom background support.
1713   *
1714   * @since 3.1.0
1715   * @see add_custom_background()
1716   *
1717   * @return bool Whether support was removed.
1718   */
1719  function remove_custom_background() {
1720      if ( ! current_theme_supports( 'custom-background' ) )
1721          return false;
1722  
1723      $callback = get_theme_support( 'custom-background' );
1724      remove_action( 'wp_head', $callback[0]['callback'] );
1725      _remove_theme_support( 'custom-background' );
1726  
1727      if ( is_admin() ) {
1728          remove_action( 'admin_menu', array( &$GLOBALS['custom_background'], 'init' ) );
1729          unset( $GLOBALS['custom_background'] );
1730      }
1731  
1732      return true;
1733  }
1734  
1735  /**
1736   * Default custom background callback.
1737   *
1738   * @since 3.0.0
1739   * @see add_custom_background()
1740   * @access protected
1741   */
1742  function _custom_background_cb() {
1743      $background = get_background_image();
1744      $color = get_background_color();
1745      if ( ! $background && ! $color )
1746          return;
1747  
1748      $style = $color ? "background-color: #$color;" : '';
1749  
1750      if ( $background ) {
1751          $image = " background-image: url('$background');";
1752  
1753          $repeat = get_theme_mod( 'background_repeat', 'repeat' );
1754          if ( ! in_array( $repeat, array( 'no-repeat', 'repeat-x', 'repeat-y', 'repeat' ) ) )
1755              $repeat = 'repeat';
1756          $repeat = " background-repeat: $repeat;";
1757  
1758          $position = get_theme_mod( 'background_position_x', 'left' );
1759          if ( ! in_array( $position, array( 'center', 'right', 'left' ) ) )
1760              $position = 'left';
1761          $position = " background-position: top $position;";
1762  
1763          $attachment = get_theme_mod( 'background_attachment', 'scroll' );
1764          if ( ! in_array( $attachment, array( 'fixed', 'scroll' ) ) )
1765              $attachment = 'scroll';
1766          $attachment = " background-attachment: $attachment;";
1767  
1768          $style .= $image . $repeat . $position . $attachment;
1769      }
1770  ?>
1771  <style type="text/css">
1772  body { <?php echo trim( $style ); ?> }
1773  </style>
1774  <?php
1775  }
1776  
1777  /**
1778   * Add callback for custom TinyMCE editor stylesheets.
1779   *
1780   * The parameter $stylesheet is the name of the stylesheet, relative to
1781   * the theme root. It also accepts an array of stylesheets.
1782   * It is optional and defaults to 'editor-style.css'.
1783   *
1784   * Supports RTL stylesheets automatically by searching for the -rtl prefix, e.g.
1785   * editor-style-rtl.css. If an array of stylesheets is passed to add_editor_style(),
1786   * RTL is only added for the first stylesheet.
1787   *
1788   * @since 3.0.0
1789   *
1790   * @param mixed $stylesheet Optional. Stylesheet name or array thereof, relative to theme root.
1791   *     Defaults to 'editor-style.css'
1792   */
1793  function add_editor_style( $stylesheet = 'editor-style.css' ) {
1794  
1795      add_theme_support( 'editor-style' );
1796  
1797      if ( ! is_admin() )
1798          return;
1799  
1800      global $editor_styles;
1801      $editor_styles = (array) $editor_styles;
1802      $stylesheet    = (array) $stylesheet;
1803      if ( is_rtl() ) {
1804          $rtl_stylesheet = str_replace('.css', '-rtl.css', $stylesheet[0]);
1805          $stylesheet[] = $rtl_stylesheet;
1806      }
1807  
1808      $editor_styles = array_merge( $editor_styles, $stylesheet );
1809  }
1810  
1811  /**
1812   * Removes all visual editor stylesheets.
1813   *
1814   * @since 3.1.0
1815   *
1816   * @return bool True on success, false if there were no stylesheets to remove.
1817   */
1818  function remove_editor_styles() {
1819      if ( ! current_theme_supports( 'editor-style' ) )
1820          return false;
1821      _remove_theme_support( 'editor-style' );
1822      if ( is_admin() )
1823          $GLOBALS['editor_styles'] = array();
1824      return true;
1825  }
1826  
1827  /**
1828   * Allows a theme to register its support of a certain feature
1829   *
1830   * Must be called in the theme's functions.php file to work.
1831   * If attached to a hook, it must be after_setup_theme.
1832   * The init hook may be too late for some features.
1833   *
1834   * @since 2.9.0
1835   * @param string $feature the feature being added
1836   */
1837  function add_theme_support( $feature ) {
1838      global $_wp_theme_features;
1839  
1840      if ( func_num_args() == 1 )
1841          $_wp_theme_features[$feature] = true;
1842      else
1843          $_wp_theme_features[$feature] = array_slice( func_get_args(), 1 );
1844  
1845      if ( $feature == 'post-formats' && is_array( $_wp_theme_features[$feature][0] ) )
1846          $_wp_theme_features[$feature][0] = array_intersect( $_wp_theme_features[$feature][0], array_keys( get_post_format_slugs() ) );
1847  }
1848  
1849  /**
1850   * Gets the theme support arguments passed when registering that support
1851   *
1852   * @since 3.1
1853   * @param string $feature the feature to check
1854   * @return array The array of extra arguments
1855   */
1856  function get_theme_support( $feature ) {
1857      global $_wp_theme_features;
1858      if ( !isset( $_wp_theme_features[$feature] ) )
1859          return false;
1860      else
1861          return $_wp_theme_features[$feature];
1862  }
1863  
1864  /**
1865   * Allows a theme to de-register its support of a certain feature
1866   *
1867   * Should be called in the theme's functions.php file. Generally would
1868   * be used for child themes to override support from the parent theme.
1869   *
1870   * @since 3.0.0
1871   * @see add_theme_support()
1872   * @param string $feature the feature being added
1873   * @return bool Whether feature was removed.
1874   */
1875  function remove_theme_support( $feature ) {
1876      // Blacklist: for internal registrations not used directly by themes.
1877      if ( in_array( $feature, array( 'custom-background', 'custom-header', 'editor-style', 'widgets', 'menus' ) ) )
1878          return false;
1879      return _remove_theme_support( $feature );
1880  }
1881  
1882  /**
1883   * Do not use. Removes theme support internally, ignorant of the blacklist.
1884   *
1885   * @access private
1886   * @since 3.1.0
1887   */
1888  function _remove_theme_support( $feature ) {
1889      global $_wp_theme_features;
1890  
1891      if ( ! isset( $_wp_theme_features[$feature] ) )
1892          return false;
1893      unset( $_wp_theme_features[$feature] );
1894      return true;
1895  }
1896  
1897  /**
1898   * Checks a theme's support for a given feature
1899   *
1900   * @since 2.9.0
1901   * @param string $feature the feature being checked
1902   * @return boolean
1903   */
1904  function current_theme_supports( $feature ) {
1905      global $_wp_theme_features;
1906  
1907      if ( !isset( $_wp_theme_features[$feature] ) )
1908          return false;
1909  
1910      // If no args passed then no extra checks need be performed
1911      if ( func_num_args() <= 1 )
1912          return true;
1913  
1914      $args = array_slice( func_get_args(), 1 );
1915  
1916      // @todo Allow pluggable arg checking
1917      switch ( $feature ) {
1918          case 'post-thumbnails':
1919              // post-thumbnails can be registered for only certain content/post types by passing
1920              // an array of types to add_theme_support().  If no array was passed, then
1921              // any type is accepted
1922              if ( true === $_wp_theme_features[$feature] )  // Registered for all types
1923                  return true;
1924              $content_type = $args[0];
1925              if ( in_array($content_type, $_wp_theme_features[$feature][0]) )
1926                  return true;
1927              else
1928                  return false;
1929              break;
1930      }
1931  
1932      return true;
1933  }
1934  
1935  /**
1936   * Checks a theme's support for a given feature before loading the functions which implement it.
1937   *
1938   * @since 2.9.0
1939   * @param string $feature the feature being checked
1940   * @param string $include the file containing the functions that implement the feature
1941   */
1942  function require_if_theme_supports( $feature, $include) {
1943      if ( current_theme_supports( $feature ) )
1944          require ( $include );
1945  }
1946  
1947  /**
1948   * Checks an attachment being deleted to see if it's a header or background image.
1949   *
1950   * If true it removes the theme modification which would be pointing at the deleted
1951   * attachment
1952   *
1953   * @access private
1954   * @since 3.0.0
1955   * @param int $id the attachment id
1956   */
1957  function _delete_attachment_theme_mod( $id ) {
1958      $attachment_image = wp_get_attachment_url( $id );
1959      $header_image = get_header_image();
1960      $background_image = get_background_image();
1961  
1962      if ( $header_image && $header_image == $attachment_image )
1963          remove_theme_mod( 'header_image' );
1964  
1965      if ( $background_image && $background_image == $attachment_image )
1966          remove_theme_mod( 'background_image' );
1967  }
1968  
1969  add_action( 'delete_attachment', '_delete_attachment_theme_mod' );
1970  
1971  ?>


Generated: Wed Jun 1 08:30:02 2011 Cross-referenced by PHPXref 0.7
Provided by Yoast and awesome WordPress Hosting