[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

   1  <?php
   2  /**
   3   * Theme, template, and stylesheet functions.
   4   *
   5   * @package WordPress
   6   * @subpackage Theme
   7   */
   8  
   9  /**
  10   * Returns an array of WP_Theme objects based on the arguments.
  11   *
  12   * Despite advances over get_themes(), this function is quite expensive, and grows
  13   * linearly with additional themes. Stick to wp_get_theme() if possible.
  14   *
  15   * @since 3.4.0
  16   *
  17   * @param array $args The search arguments. Optional.
  18   * - errors      mixed  True to return themes with errors, false to return themes without errors, null
  19   *                      to return all themes. Defaults to false.
  20   * - allowed     mixed  (Multisite) True to return only allowed themes for a site. False to return only
  21   *                      disallowed themes for a site. 'site' to return only site-allowed themes. 'network'
  22   *                      to return only network-allowed themes. Null to return all themes. Defaults to null.
  23   * - blog_id     int    (Multisite) The blog ID used to calculate which themes are allowed. Defaults to 0,
  24   *                      synonymous for the current blog.
  25   * @return Array of WP_Theme objects.
  26   */
  27  function wp_get_themes( $args = array() ) {
  28      global $wp_theme_directories;
  29  
  30      $defaults = array( 'errors' => false, 'allowed' => null, 'blog_id' => 0 );
  31      $args = wp_parse_args( $args, $defaults );
  32  
  33      $theme_directories = search_theme_directories();
  34  
  35      if ( count( $wp_theme_directories ) > 1 ) {
  36          // Make sure the current theme wins out, in case search_theme_directories() picks the wrong
  37          // one in the case of a conflict. (Normally, last registered theme root wins.)
  38          $current_theme = get_stylesheet();
  39          if ( isset( $theme_directories[ $current_theme ] ) ) {
  40              $root_of_current_theme = get_raw_theme_root( $current_theme );
  41              if ( ! in_array( $root_of_current_theme, $wp_theme_directories ) )
  42                  $root_of_current_theme = WP_CONTENT_DIR . $root_of_current_theme;
  43              $theme_directories[ $current_theme ]['theme_root'] = $root_of_current_theme;
  44          }
  45      }
  46  
  47      if ( empty( $theme_directories ) )
  48          return array();
  49  
  50      if ( is_multisite() && null !== $args['allowed'] ) {
  51          $allowed = $args['allowed'];
  52          if ( 'network' === $allowed )
  53              $theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_network() );
  54          elseif ( 'site' === $allowed )
  55              $theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_site( $args['blog_id'] ) );
  56          elseif ( $allowed )
  57              $theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
  58          else
  59              $theme_directories = array_diff_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
  60      }
  61  
  62      $themes = array();
  63      static $_themes = array();
  64  
  65      foreach ( $theme_directories as $theme => $theme_root ) {
  66          if ( isset( $_themes[ $theme_root['theme_root'] . '/' . $theme ] ) )
  67              $themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ];
  68          else
  69              $themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ] = new WP_Theme( $theme, $theme_root['theme_root'] );
  70      }
  71  
  72      if ( null !== $args['errors'] ) {
  73          foreach ( $themes as $theme => $wp_theme ) {
  74              if ( $wp_theme->errors() != $args['errors'] )
  75                  unset( $themes[ $theme ] );
  76          }
  77      }
  78  
  79      return $themes;
  80  }
  81  
  82  /**
  83   * Gets a WP_Theme object for a theme.
  84   *
  85   * @since 3.4.0
  86   *
  87   * @param string $stylesheet Directory name for the theme. Optional. Defaults to current theme.
  88   * @param string $theme_root Absolute path of the theme root to look in. Optional. If not specified, get_raw_theme_root()
  89   *     is used to calculate the theme root for the $stylesheet provided (or current theme).
  90   * @return WP_Theme Theme object. Be sure to check the object's exists() method if you need to confirm the theme's existence.
  91   */
  92  function wp_get_theme( $stylesheet = null, $theme_root = null ) {
  93      global $wp_theme_directories;
  94  
  95      if ( empty( $stylesheet ) )
  96          $stylesheet = get_stylesheet();
  97  
  98      if ( empty( $theme_root ) ) {
  99          $theme_root = get_raw_theme_root( $stylesheet );
 100          if ( false === $theme_root )
 101              $theme_root = WP_CONTENT_DIR . $theme_root;
 102          elseif ( ! in_array( $theme_root, (array) $wp_theme_directories ) )
 103              $theme_root = WP_CONTENT_DIR . $theme_root;
 104      }
 105  
 106      return new WP_Theme( $stylesheet, $theme_root );
 107  }
 108  
 109  /**
 110   * Whether a child theme is in use.
 111   *
 112   * @since 3.0.0
 113   *
 114   * @return bool true if a child theme is in use, false otherwise.
 115   **/
 116  function is_child_theme() {
 117      return ( TEMPLATEPATH !== STYLESHEETPATH );
 118  }
 119  
 120  /**
 121   * Retrieve name of the current stylesheet.
 122   *
 123   * The theme name that the administrator has currently set the front end theme
 124   * as.
 125   *
 126   * For all extensive purposes, the template name and the stylesheet name are
 127   * going to be the same for most cases.
 128   *
 129   * @since 1.5.0
 130   * @uses apply_filters() Calls 'stylesheet' filter on stylesheet name.
 131   *
 132   * @return string Stylesheet name.
 133   */
 134  function get_stylesheet() {
 135      return apply_filters('stylesheet', get_option('stylesheet'));
 136  }
 137  
 138  /**
 139   * Retrieve stylesheet directory path for current theme.
 140   *
 141   * @since 1.5.0
 142   * @uses apply_filters() Calls 'stylesheet_directory' filter on stylesheet directory and theme name.
 143   *
 144   * @return string Path to current theme directory.
 145   */
 146  function get_stylesheet_directory() {
 147      $stylesheet = get_stylesheet();
 148      $theme_root = get_theme_root( $stylesheet );
 149      $stylesheet_dir = "$theme_root/$stylesheet";
 150  
 151      return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
 152  }
 153  
 154  /**
 155   * Retrieve stylesheet directory URI.
 156   *
 157   * @since 1.5.0
 158   *
 159   * @return string
 160   */
 161  function get_stylesheet_directory_uri() {
 162      $stylesheet = get_stylesheet();
 163      $theme_root_uri = get_theme_root_uri( $stylesheet );
 164      $stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
 165  
 166      return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
 167  }
 168  
 169  /**
 170   * Retrieve URI of current theme stylesheet.
 171   *
 172   * The stylesheet file name is 'style.css' which is appended to {@link
 173   * get_stylesheet_directory_uri() stylesheet directory URI} path.
 174   *
 175   * @since 1.5.0
 176   * @uses apply_filters() Calls 'stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
 177   *
 178   * @return string
 179   */
 180  function get_stylesheet_uri() {
 181      $stylesheet_dir_uri = get_stylesheet_directory_uri();
 182      $stylesheet_uri = $stylesheet_dir_uri . '/style.css';
 183      return apply_filters('stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
 184  }
 185  
 186  /**
 187   * Retrieve localized stylesheet URI.
 188   *
 189   * The stylesheet directory for the localized stylesheet files are located, by
 190   * default, in the base theme directory. The name of the locale file will be the
 191   * locale followed by '.css'. If that does not exist, then the text direction
 192   * stylesheet will be checked for existence, for example 'ltr.css'.
 193   *
 194   * The theme may change the location of the stylesheet directory by either using
 195   * the 'stylesheet_directory_uri' filter or the 'locale_stylesheet_uri' filter.
 196   * If you want to change the location of the stylesheet files for the entire
 197   * WordPress workflow, then change the former. If you just have the locale in a
 198   * separate folder, then change the latter.
 199   *
 200   * @since 2.1.0
 201   * @uses apply_filters() Calls 'locale_stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
 202   *
 203   * @return string
 204   */
 205  function get_locale_stylesheet_uri() {
 206      global $wp_locale;
 207      $stylesheet_dir_uri = get_stylesheet_directory_uri();
 208      $dir = get_stylesheet_directory();
 209      $locale = get_locale();
 210      if ( file_exists("$dir/$locale.css") )
 211          $stylesheet_uri = "$stylesheet_dir_uri/$locale.css";
 212      elseif ( !empty($wp_locale->text_direction) && file_exists("$dir/{$wp_locale->text_direction}.css") )
 213          $stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
 214      else
 215          $stylesheet_uri = '';
 216      return apply_filters('locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
 217  }
 218  
 219  /**
 220   * Retrieve name of the current theme.
 221   *
 222   * @since 1.5.0
 223   * @uses apply_filters() Calls 'template' filter on template option.
 224   *
 225   * @return string Template name.
 226   */
 227  function get_template() {
 228      return apply_filters('template', get_option('template'));
 229  }
 230  
 231  /**
 232   * Retrieve current theme directory.
 233   *
 234   * @since 1.5.0
 235   * @uses apply_filters() Calls 'template_directory' filter on template directory path and template name.
 236   *
 237   * @return string Template directory path.
 238   */
 239  function get_template_directory() {
 240      $template = get_template();
 241      $theme_root = get_theme_root( $template );
 242      $template_dir = "$theme_root/$template";
 243  
 244      return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
 245  }
 246  
 247  /**
 248   * Retrieve theme directory URI.
 249   *
 250   * @since 1.5.0
 251   * @uses apply_filters() Calls 'template_directory_uri' filter on template directory URI path and template name.
 252   *
 253   * @return string Template directory URI.
 254   */
 255  function get_template_directory_uri() {
 256      $template = get_template();
 257      $theme_root_uri = get_theme_root_uri( $template );
 258      $template_dir_uri = "$theme_root_uri/$template";
 259  
 260      return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
 261  }
 262  
 263  /**
 264   * Retrieve theme roots.
 265   *
 266   * @since 2.9.0
 267   *
 268   * @return array|string An array of theme roots keyed by template/stylesheet or a single theme root if all themes have the same root.
 269   */
 270  function get_theme_roots() {
 271      global $wp_theme_directories;
 272  
 273      if ( count($wp_theme_directories) <= 1 )
 274          return '/themes';
 275  
 276      $theme_roots = get_site_transient( 'theme_roots' );
 277      if ( false === $theme_roots ) {
 278          search_theme_directories( true ); // Regenerate the transient.
 279          $theme_roots = get_site_transient( 'theme_roots' );
 280      }
 281      return $theme_roots;
 282  }
 283  
 284  /**
 285   * Register a directory that contains themes.
 286   *
 287   * @since 2.9.0
 288   *
 289   * @param string $directory Either the full filesystem path to a theme folder or a folder within WP_CONTENT_DIR
 290   * @return bool
 291   */
 292  function register_theme_directory( $directory ) {
 293      global $wp_theme_directories;
 294  
 295      if ( ! file_exists( $directory ) ) {
 296          // Try prepending as the theme directory could be relative to the content directory
 297          $directory = WP_CONTENT_DIR . '/' . $directory;
 298          // If this directory does not exist, return and do not register
 299          if ( ! file_exists( $directory ) )
 300              return false;
 301      }
 302  
 303      $wp_theme_directories[] = $directory;
 304  
 305      return true;
 306  }
 307  
 308  /**
 309   * Search all registered theme directories for complete and valid themes.
 310   *
 311   * @since 2.9.0
 312   *
 313   * @param bool $force Optional. Whether to force a new directory scan. Defaults to false.
 314   * @return array Valid themes found
 315   */
 316  function search_theme_directories( $force = false ) {
 317      global $wp_theme_directories;
 318      if ( empty( $wp_theme_directories ) )
 319          return false;
 320  
 321      static $found_themes;
 322      if ( ! $force && isset( $found_themes ) )
 323          return $found_themes;
 324  
 325      $found_themes = array();
 326  
 327      $wp_theme_directories = (array) $wp_theme_directories;
 328  
 329      // Set up maybe-relative, maybe-absolute array of theme directories.
 330      // We always want to return absolute, but we need to cache relative
 331      // use in for get_theme_root().
 332      foreach ( $wp_theme_directories as $theme_root ) {
 333          if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) )
 334              $relative_theme_roots[ str_replace( WP_CONTENT_DIR, '', $theme_root ) ] = $theme_root;
 335          else
 336              $relative_theme_roots[ $theme_root ] = $theme_root;
 337      }
 338  
 339      if ( $cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' ) ) {
 340          $cached_roots = get_site_transient( 'theme_roots' );
 341          if ( is_array( $cached_roots ) ) {
 342              foreach ( $cached_roots as $theme_dir => $theme_root ) {
 343                  // A cached theme root is no longer around, so skip it.
 344                  if ( ! isset( $relative_theme_roots[ $theme_root ] ) )
 345                      continue;
 346                  $found_themes[ $theme_dir ] = array(
 347                      'theme_file' => $theme_dir . '/style.css',
 348                      'theme_root' => $relative_theme_roots[ $theme_root ], // Convert relative to absolute.
 349                  );
 350              }
 351              return $found_themes;
 352          }
 353          if ( ! is_int( $cache_expiration ) )
 354              $cache_expiration = 1800; // half hour
 355      } else {
 356          $cache_expiration = 1800; // half hour
 357      }
 358  
 359      /* Loop the registered theme directories and extract all themes */
 360      foreach ( $wp_theme_directories as $theme_root ) {
 361  
 362          // Start with directories in the root of the current theme directory.
 363          $dirs = @ scandir( $theme_root );
 364          if ( ! $dirs )
 365              return false;
 366          foreach ( $dirs as $dir ) {
 367              if ( ! is_dir( $theme_root . '/' . $dir ) || $dir[0] == '.' || $dir == 'CVS' )
 368                  continue;
 369              if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) {
 370                  // wp-content/themes/a-single-theme
 371                  // wp-content/themes is $theme_root, a-single-theme is $dir
 372                  $found_themes[ $dir ] = array(
 373                      'theme_file' => $dir . '/style.css',
 374                      'theme_root' => $theme_root,
 375                  );
 376              } else {
 377                  $found_theme = false;
 378                  // wp-content/themes/a-folder-of-themes/*
 379                  // wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs
 380                  $sub_dirs = @ scandir( $theme_root . '/' . $dir );
 381                  if ( ! $sub_dirs )
 382                      return false;
 383                  foreach ( $sub_dirs as $sub_dir ) {
 384                      if ( ! is_dir( $theme_root . '/' . $dir ) || $dir[0] == '.' || $dir == 'CVS' )
 385                          continue;
 386                      if ( ! file_exists( $theme_root . '/' . $dir . '/' . $sub_dir . '/style.css' ) )
 387                          continue;
 388                      $found_themes[ $dir . '/' . $sub_dir ] = array(
 389                          'theme_file' => $dir . '/' . $sub_dir . '/style.css',
 390                          'theme_root' => $theme_root,
 391                      );
 392                      $found_theme = true;
 393                  }
 394                  // Never mind the above, it's just a theme missing a style.css.
 395                  // Return it; WP_Theme will catch the error.
 396                  if ( ! $found_theme )
 397                      $found_themes[ $dir ] = array(
 398                          'theme_file' => $dir . '/style.css',
 399                          'theme_root' => $theme_root,
 400                      );
 401              }
 402          }
 403      }
 404  
 405      asort( $found_themes );
 406  
 407      $theme_roots = array();
 408      $relative_theme_roots = array_flip( $relative_theme_roots );
 409  
 410      foreach ( $found_themes as $theme_dir => $theme_data ) {
 411          $theme_roots[ $theme_dir ] = $relative_theme_roots[ $theme_data['theme_root'] ]; // Convert absolute to relative.
 412      }
 413  
 414      if ( $theme_roots != get_site_transient( 'theme_roots' ) )
 415          set_site_transient( 'theme_roots', $theme_roots, $cache_expiration );
 416  
 417      return $found_themes;
 418  }
 419  
 420  /**
 421   * Retrieve path to themes directory.
 422   *
 423   * Does not have trailing slash.
 424   *
 425   * @since 1.5.0
 426   * @uses apply_filters() Calls 'theme_root' filter on path.
 427   *
 428   * @param string $stylesheet_or_template The stylesheet or template name of the theme
 429   * @return string Theme path.
 430   */
 431  function get_theme_root( $stylesheet_or_template = false ) {
 432      global $wp_theme_directories;
 433  
 434      if ( $stylesheet_or_template && $theme_root = get_raw_theme_root( $stylesheet_or_template ) ) {
 435          // Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory.
 436          // This gives relative theme roots the benefit of the doubt when things go haywire.
 437          if ( ! in_array( $theme_root, (array) $wp_theme_directories ) )
 438              $theme_root = WP_CONTENT_DIR . $theme_root;
 439      } else {
 440          $theme_root = WP_CONTENT_DIR . '/themes';
 441      }
 442  
 443      return apply_filters( 'theme_root', $theme_root );
 444  }
 445  
 446  /**
 447   * Retrieve URI for themes directory.
 448   *
 449   * Does not have trailing slash.
 450   *
 451   * @since 1.5.0
 452   *
 453   * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
 454   *     Default is to leverage the main theme root.
 455   * @param string $theme_root Optional. The theme root for which calculations will be based, preventing
 456   *     the need for a get_raw_theme_root() call.
 457   * @return string Themes URI.
 458   */
 459  function get_theme_root_uri( $stylesheet_or_template = false, $theme_root = false ) {
 460      global $wp_theme_directories;
 461  
 462      if ( $stylesheet_or_template && ! $theme_root )
 463          $theme_root = get_raw_theme_root( $stylesheet_or_template );
 464  
 465      if ( $stylesheet_or_template && $theme_root ) {
 466          if ( in_array( $theme_root, (array) $wp_theme_directories ) ) {
 467              // Absolute path. Make an educated guess. YMMV -- but note the filter below.
 468              if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) )
 469                  $theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) );
 470              elseif ( 0 === strpos( $theme_root, ABSPATH ) )
 471                  $theme_root_uri = site_url( str_replace( ABSPATH, '', $theme_root ) );
 472              elseif ( 0 === strpos( $theme_root, WP_PLUGIN_DIR ) || 0 === strpos( $theme_root, WPMU_PLUGIN_DIR ) )
 473                  $theme_root_uri = plugins_url( basename( $theme_root ), $theme_root );
 474              else
 475                  $theme_root_uri = $theme_root;
 476          } else {
 477              $theme_root_uri = content_url( $theme_root );
 478          }
 479      } else {
 480          $theme_root_uri = content_url( 'themes' );
 481      }
 482  
 483      return apply_filters( 'theme_root_uri', $theme_root_uri, get_option('siteurl'), $stylesheet_or_template );
 484  }
 485  
 486  /**
 487   * Get the raw theme root relative to the content directory with no filters applied.
 488   *
 489   * @since 3.1.0
 490   *
 491   * @param string $stylesheet_or_template The stylesheet or template name of the theme
 492   * @param bool $skip_cache Optional. Whether to skip the cache. Defaults to false, meaning the cache is used.
 493   * @return string Theme root
 494   */
 495  function get_raw_theme_root( $stylesheet_or_template, $skip_cache = false ) {
 496      global $wp_theme_directories;
 497  
 498      if ( count($wp_theme_directories) <= 1 )
 499          return '/themes';
 500  
 501      $theme_root = false;
 502  
 503      // If requesting the root for the current theme, consult options to avoid calling get_theme_roots()
 504      if ( ! $skip_cache ) {
 505          if ( get_option('stylesheet') == $stylesheet_or_template )
 506              $theme_root = get_option('stylesheet_root');
 507          elseif ( get_option('template') == $stylesheet_or_template )
 508              $theme_root = get_option('template_root');
 509      }
 510  
 511      if ( empty($theme_root) ) {
 512          $theme_roots = get_theme_roots();
 513          if ( !empty($theme_roots[$stylesheet_or_template]) )
 514              $theme_root = $theme_roots[$stylesheet_or_template];
 515      }
 516  
 517      return $theme_root;
 518  }
 519  
 520  /**
 521   * Display localized stylesheet link element.
 522   *
 523   * @since 2.1.0
 524   */
 525  function locale_stylesheet() {
 526      $stylesheet = get_locale_stylesheet_uri();
 527      if ( empty($stylesheet) )
 528          return;
 529      echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
 530  }
 531  
 532  /**
 533   * Start preview theme output buffer.
 534   *
 535   * Will only preform task if the user has permissions and template and preview
 536   * query variables exist.
 537   *
 538   * @since 2.6.0
 539   */
 540  function preview_theme() {
 541      if ( ! (isset($_GET['template']) && isset($_GET['preview'])) )
 542          return;
 543  
 544      if ( !current_user_can( 'switch_themes' ) )
 545          return;
 546  
 547      // Admin Thickbox requests
 548      if ( isset( $_GET['preview_iframe'] ) )
 549          show_admin_bar( false );
 550  
 551      $_GET['template'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['template']);
 552  
 553      if ( validate_file($_GET['template']) )
 554          return;
 555  
 556      add_filter( 'template', '_preview_theme_template_filter' );
 557  
 558      if ( isset($_GET['stylesheet']) ) {
 559          $_GET['stylesheet'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['stylesheet']);
 560          if ( validate_file($_GET['stylesheet']) )
 561              return;
 562          add_filter( 'stylesheet', '_preview_theme_stylesheet_filter' );
 563      }
 564  
 565      // Prevent theme mods to current theme being used on theme being previewed
 566      add_filter( 'pre_option_theme_mods_' . get_option( 'stylesheet' ), '__return_empty_array' );
 567  
 568      ob_start( 'preview_theme_ob_filter' );
 569  }
 570  add_action('setup_theme', 'preview_theme');
 571  
 572  /**
 573   * Private function to modify the current template when previewing a theme
 574   *
 575   * @since 2.9.0
 576   * @access private
 577   *
 578   * @return string
 579   */
 580  function _preview_theme_template_filter() {
 581      return isset($_GET['template']) ? $_GET['template'] : '';
 582  }
 583  
 584  /**
 585   * Private function to modify the current stylesheet when previewing a theme
 586   *
 587   * @since 2.9.0
 588   * @access private
 589   *
 590   * @return string
 591   */
 592  function _preview_theme_stylesheet_filter() {
 593      return isset($_GET['stylesheet']) ? $_GET['stylesheet'] : '';
 594  }
 595  
 596  /**
 597   * Callback function for ob_start() to capture all links in the theme.
 598   *
 599   * @since 2.6.0
 600   * @access private
 601   *
 602   * @param string $content
 603   * @return string
 604   */
 605  function preview_theme_ob_filter( $content ) {
 606      return preg_replace_callback( "|(<a.*?href=([\"']))(.*?)([\"'].*?>)|", 'preview_theme_ob_filter_callback', $content );
 607  }
 608  
 609  /**
 610   * Manipulates preview theme links in order to control and maintain location.
 611   *
 612   * Callback function for preg_replace_callback() to accept and filter matches.
 613   *
 614   * @since 2.6.0
 615   * @access private
 616   *
 617   * @param array $matches
 618   * @return string
 619   */
 620  function preview_theme_ob_filter_callback( $matches ) {
 621      if ( strpos($matches[4], 'onclick') !== false )
 622          $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.
 623      if (
 624          ( false !== strpos($matches[3], '/wp-admin/') )
 625      ||
 626          ( false !== strpos( $matches[3], '://' ) && 0 !== strpos( $matches[3], home_url() ) )
 627      ||
 628          ( false !== strpos($matches[3], '/feed/') )
 629      ||
 630          ( false !== strpos($matches[3], '/trackback/') )
 631      )
 632          return $matches[1] . "#$matches[2] onclick=$matches[2]return false;" . $matches[4];
 633  
 634      $link = add_query_arg( array( 'preview' => 1, 'template' => $_GET['template'], 'stylesheet' => @$_GET['stylesheet'], 'preview_iframe' => 1 ), $matches[3] );
 635      if ( 0 === strpos($link, 'preview=1') )
 636          $link = "?$link";
 637      return $matches[1] . esc_attr( $link ) . $matches[4];
 638  }
 639  
 640  /**
 641   * Switches current theme to new template and stylesheet names.
 642   *
 643   * @since 2.5.0
 644   * @uses do_action() Calls 'switch_theme' action, passing the new theme.
 645   *
 646   * @param string $template Template name
 647   * @param string $stylesheet Stylesheet name.
 648   */
 649  function switch_theme( $template, $stylesheet ) {
 650      global $wp_theme_directories, $sidebars_widgets;
 651  
 652      if ( is_array( $sidebars_widgets ) )
 653          set_theme_mod( 'sidebars_widgets', array( 'time' => time(), 'data' => $sidebars_widgets ) );
 654  
 655      $old_theme  = wp_get_theme();
 656      $new_theme = wp_get_theme( $stylesheet );
 657      $new_name  = $new_theme->get('Name');
 658  
 659      update_option( 'template', $template );
 660      update_option( 'stylesheet', $stylesheet );
 661  
 662      if ( count( $wp_theme_directories ) > 1 ) {
 663          update_option( 'template_root', get_raw_theme_root( $template, true ) );
 664          update_option( 'stylesheet_root', get_raw_theme_root( $stylesheet, true ) );
 665      }
 666  
 667      update_option( 'current_theme', $new_name );
 668  
 669      if ( is_admin() && false === get_option( 'theme_mods_' . $stylesheet ) ) {
 670          $default_theme_mods = (array) get_option( 'mods_' . $new_name );
 671          add_option( "theme_mods_$stylesheet", $default_theme_mods );
 672      }
 673  
 674      update_option( 'theme_switched', $old_theme->get_stylesheet() );
 675      do_action( 'switch_theme', $new_name, $new_theme );
 676  }
 677  
 678  /**
 679   * Checks that current theme files 'index.php' and 'style.css' exists.
 680   *
 681   * Does not check the default theme, which is the fallback and should always exist.
 682   * Will switch theme to the fallback theme if current theme does not validate.
 683   * You can use the 'validate_current_theme' filter to return false to
 684   * disable this functionality.
 685   *
 686   * @since 1.5.0
 687   * @see WP_DEFAULT_THEME
 688   *
 689   * @return bool
 690   */
 691  function validate_current_theme() {
 692      // Don't validate during an install/upgrade.
 693      if ( defined('WP_INSTALLING') || !apply_filters( 'validate_current_theme', true ) )
 694          return true;
 695  
 696      if ( get_template() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/index.php') ) {
 697          switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
 698          return false;
 699      }
 700  
 701      if ( get_stylesheet() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/style.css') ) {
 702          switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
 703          return false;
 704      }
 705  
 706      if ( is_child_theme() && ! file_exists( get_stylesheet_directory() . '/style.css' ) ) {
 707          switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
 708          return false;
 709      }
 710  
 711      return true;
 712  }
 713  
 714  /**
 715   * Retrieve all theme modifications.
 716   *
 717   * @since 3.1.0
 718   *
 719   * @return array Theme modifications.
 720   */
 721  function get_theme_mods() {
 722      $theme_slug = get_option( 'stylesheet' );
 723      if ( false === ( $mods = get_option( "theme_mods_$theme_slug" ) ) ) {
 724          $theme_name = get_option( 'current_theme' );
 725          if ( false === $theme_name )
 726              $theme_name = wp_get_theme()->get('Name');
 727          $mods = get_option( "mods_$theme_name" ); // Deprecated location.
 728          if ( is_admin() && false !== $mods ) {
 729              update_option( "theme_mods_$theme_slug", $mods );
 730              delete_option( "mods_$theme_name" );
 731          }
 732      }
 733      return $mods;
 734  }
 735  
 736  /**
 737   * Retrieve theme modification value for the current theme.
 738   *
 739   * If the modification name does not exist, then the $default will be passed
 740   * through {@link http://php.net/sprintf sprintf()} PHP function with the first
 741   * string the template directory URI and the second string the stylesheet
 742   * directory URI.
 743   *
 744   * @since 2.1.0
 745   * @uses apply_filters() Calls 'theme_mod_$name' filter on the value.
 746   *
 747   * @param string $name Theme modification name.
 748   * @param bool|string $default
 749   * @return string
 750   */
 751  function get_theme_mod( $name, $default = false ) {
 752      $mods = get_theme_mods();
 753  
 754      if ( isset( $mods[ $name ] ) )
 755          return apply_filters( "theme_mod_$name", $mods[ $name ] );
 756  
 757      if ( is_string( $default ) )
 758          $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
 759  
 760      return apply_filters( "theme_mod_$name", $default );
 761  }
 762  
 763  /**
 764   * Update theme modification value for the current theme.
 765   *
 766   * @since 2.1.0
 767   *
 768   * @param string $name Theme modification name.
 769   * @param string $value theme modification value.
 770   */
 771  function set_theme_mod( $name, $value ) {
 772      $mods = get_theme_mods();
 773  
 774      $mods[ $name ] = $value;
 775  
 776      $theme = get_option( 'stylesheet' );
 777      update_option( "theme_mods_$theme", $mods );
 778  }
 779  
 780  /**
 781   * Remove theme modification name from current theme list.
 782   *
 783   * If removing the name also removes all elements, then the entire option will
 784   * be removed.
 785   *
 786   * @since 2.1.0
 787   *
 788   * @param string $name Theme modification name.
 789   * @return null
 790   */
 791  function remove_theme_mod( $name ) {
 792      $mods = get_theme_mods();
 793  
 794      if ( ! isset( $mods[ $name ] ) )
 795          return;
 796  
 797      unset( $mods[ $name ] );
 798  
 799      if ( empty( $mods ) )
 800          return remove_theme_mods();
 801  
 802      $theme = get_option( 'stylesheet' );
 803      update_option( "theme_mods_$theme", $mods );
 804  }
 805  
 806  /**
 807   * Remove theme modifications option for current theme.
 808   *
 809   * @since 2.1.0
 810   */
 811  function remove_theme_mods() {
 812      delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
 813  
 814      // Old style.
 815      $theme_name = get_option( 'current_theme' );
 816      if ( false === $theme_name )
 817          $theme_name = wp_get_theme()->get('Name');
 818      delete_option( 'mods_' . $theme_name );
 819  }
 820  
 821  /**
 822   * Retrieve text color for custom header.
 823   *
 824   * @since 2.1.0
 825   *
 826   * @return string
 827   */
 828  function get_header_textcolor() {
 829      return get_theme_mod('header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
 830  }
 831  
 832  /**
 833   * Display text color for custom header.
 834   *
 835   * @since 2.1.0
 836   */
 837  function header_textcolor() {
 838      echo get_header_textcolor();
 839  }
 840  
 841  /**
 842   * Whether to display the header text.
 843   *
 844   * @since 3.4.0
 845   *
 846   * @return bool
 847   */
 848  function display_header_text() {
 849      if ( ! current_theme_supports( 'custom-header', 'header-text' ) )
 850          return false;
 851  
 852      $text_color = get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
 853      return 'blank' != $text_color;
 854  }
 855  
 856  /**
 857   * Retrieve header image for custom header.
 858   *
 859   * @since 2.1.0
 860   *
 861   * @return string
 862   */
 863  function get_header_image() {
 864      $url = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
 865  
 866      if ( 'remove-header' == $url )
 867          return false;
 868  
 869      if ( is_random_header_image() )
 870          $url = get_random_header_image();
 871  
 872      if ( is_ssl() )
 873          $url = str_replace( 'http://', 'https://', $url );
 874      else
 875          $url = str_replace( 'https://', 'http://', $url );
 876  
 877      return esc_url_raw( $url );
 878  }
 879  
 880  /**
 881   * Get random header image data from registered images in theme.
 882   *
 883   * @since 3.4.0
 884   *
 885   * @access private
 886   *
 887   * @return string Path to header image
 888   */
 889  
 890  function _get_random_header_data() {
 891      static $_wp_random_header;
 892  
 893      if ( empty( $_wp_random_header ) ) {
 894          global $_wp_default_headers;
 895          $header_image_mod = get_theme_mod( 'header_image', '' );
 896          $headers = array();
 897  
 898          if ( 'random-uploaded-image' == $header_image_mod )
 899              $headers = get_uploaded_header_images();
 900          elseif ( ! empty( $_wp_default_headers ) ) {
 901              if ( 'random-default-image' == $header_image_mod ) {
 902                  $headers = $_wp_default_headers;
 903              } else {
 904                  if ( current_theme_supports( 'custom-header', 'random-default' ) )
 905                      $headers = $_wp_default_headers;
 906              }
 907          }
 908  
 909          if ( empty( $headers ) )
 910              return new stdClass;
 911  
 912          $_wp_random_header = (object) $headers[ array_rand( $headers ) ];
 913  
 914          $_wp_random_header->url =  sprintf( $_wp_random_header->url, get_template_directory_uri(), get_stylesheet_directory_uri() );
 915          $_wp_random_header->thumbnail_url =  sprintf( $_wp_random_header->thumbnail_url, get_template_directory_uri(), get_stylesheet_directory_uri() );
 916      }
 917      return $_wp_random_header;
 918  }
 919  
 920  /**
 921   * Get random header image url from registered images in theme.
 922   *
 923   * @since 3.2.0
 924   *
 925   * @return string Path to header image
 926   */
 927  
 928  function get_random_header_image() {
 929      $random_image = _get_random_header_data();
 930      if ( empty( $random_image->url ) )
 931          return '';
 932      return $random_image->url;
 933  }
 934  
 935  /**
 936   * Check if random header image is in use.
 937   *
 938   * Always true if user expressly chooses the option in Appearance > Header.
 939   * Also true if theme has multiple header images registered, no specific header image
 940   * is chosen, and theme turns on random headers with add_theme_support().
 941   *
 942   * @since 3.2.0
 943   *
 944   * @param string $type The random pool to use. any|default|uploaded
 945   * @return boolean
 946   */
 947  function is_random_header_image( $type = 'any' ) {
 948      $header_image_mod = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
 949  
 950      if ( 'any' == $type ) {
 951          if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) )
 952              return true;
 953      } else {
 954          if ( "random-$type-image" == $header_image_mod )
 955              return true;
 956          elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image() )
 957              return true;
 958      }
 959  
 960      return false;
 961  }
 962  
 963  /**
 964   * Display header image path.
 965   *
 966   * @since 2.1.0
 967   */
 968  function header_image() {
 969      echo get_header_image();
 970  }
 971  
 972  /**
 973   * Get the header images uploaded for the current theme.
 974   *
 975   * @since 3.2.0
 976   *
 977   * @return array
 978   */
 979  function get_uploaded_header_images() {
 980      $header_images = array();
 981  
 982      // @todo caching
 983      $headers = get_posts( array( 'post_type' => 'attachment', 'meta_key' => '_wp_attachment_is_custom_header', 'meta_value' => get_option('stylesheet'), 'orderby' => 'none', 'nopaging' => true ) );
 984  
 985      if ( empty( $headers ) )
 986          return array();
 987  
 988      foreach ( (array) $headers as $header ) {
 989          $url = esc_url_raw( $header->guid );
 990          $header_data = wp_get_attachment_metadata( $header->ID );
 991          $header_index = basename($url);
 992          $header_images[$header_index] = array();
 993          $header_images[$header_index]['attachment_id'] =  $header->ID;
 994          $header_images[$header_index]['url'] =  $url;
 995          $header_images[$header_index]['thumbnail_url'] =  $url;
 996          $header_images[$header_index]['width'] = $header_data['width'];
 997          $header_images[$header_index]['height'] = $header_data['height'];
 998      }
 999  
1000      return $header_images;
1001  }
1002  
1003  /**
1004   * Get the header image data.
1005   *
1006   * @since 3.4.0
1007   *
1008   * @return object
1009   */
1010  function get_custom_header() {
1011      $data = is_random_header_image()? _get_random_header_data() : get_theme_mod( 'header_image_data' );
1012      $default = array(
1013          'url'           => '',
1014          'thumbnail_url' => '',
1015          'width'         => get_theme_support( 'custom-header', 'width' ),
1016          'height'        => get_theme_support( 'custom-header', 'height' ),
1017      );
1018      return (object) wp_parse_args( $data, $default );
1019  }
1020  
1021  /**
1022   * Register a selection of default headers to be displayed by the custom header admin UI.
1023   *
1024   * @since 3.0.0
1025   *
1026   * @param array $headers Array of headers keyed by a string id. The ids point to arrays containing 'url', 'thumbnail_url', and 'description' keys.
1027   */
1028  function register_default_headers( $headers ) {
1029      global $_wp_default_headers;
1030  
1031      $_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
1032  }
1033  
1034  /**
1035   * Unregister default headers.
1036   *
1037   * This function must be called after register_default_headers() has already added the
1038   * header you want to remove.
1039   *
1040   * @see register_default_headers()
1041   * @since 3.0.0
1042   *
1043   * @param string|array $header The header string id (key of array) to remove, or an array thereof.
1044   * @return True on success, false on failure.
1045   */
1046  function unregister_default_headers( $header ) {
1047      global $_wp_default_headers;
1048      if ( is_array( $header ) ) {
1049          array_map( 'unregister_default_headers', $header );
1050      } elseif ( isset( $_wp_default_headers[ $header ] ) ) {
1051          unset( $_wp_default_headers[ $header ] );
1052          return true;
1053      } else {
1054          return false;
1055      }
1056  }
1057  
1058  /**
1059   * Retrieve background image for custom background.
1060   *
1061   * @since 3.0.0
1062   *
1063   * @return string
1064   */
1065  function get_background_image() {
1066      return get_theme_mod('background_image', get_theme_support( 'custom-background', 'default-image' ) );
1067  }
1068  
1069  /**
1070   * Display background image path.
1071   *
1072   * @since 3.0.0
1073   */
1074  function background_image() {
1075      echo get_background_image();
1076  }
1077  
1078  /**
1079   * Retrieve value for custom background color.
1080   *
1081   * @since 3.0.0
1082   *
1083   * @return string
1084   */
1085  function get_background_color() {
1086      return get_theme_mod('background_color', get_theme_support( 'custom-background', 'default-color' ) );
1087  }
1088  
1089  /**
1090   * Display background color value.
1091   *
1092   * @since 3.0.0
1093   */
1094  function background_color() {
1095      echo get_background_color();
1096  }
1097  
1098  /**
1099   * Default custom background callback.
1100   *
1101   * @since 3.0.0
1102   * @access protected
1103   */
1104  function _custom_background_cb() {
1105      $background = get_background_image();
1106      $color = get_background_color();
1107      if ( ! $background && ! $color )
1108          return;
1109  
1110      $style = $color ? "background-color: #$color;" : '';
1111  
1112      if ( $background ) {
1113          $image = " background-image: url('$background');";
1114  
1115          $repeat = get_theme_mod( 'background_repeat', 'repeat' );
1116          if ( ! in_array( $repeat, array( 'no-repeat', 'repeat-x', 'repeat-y', 'repeat' ) ) )
1117              $repeat = 'repeat';
1118          $repeat = " background-repeat: $repeat;";
1119  
1120          $position = get_theme_mod( 'background_position_x', 'left' );
1121          if ( ! in_array( $position, array( 'center', 'right', 'left' ) ) )
1122              $position = 'left';
1123          $position = " background-position: top $position;";
1124  
1125          $attachment = get_theme_mod( 'background_attachment', 'scroll' );
1126          if ( ! in_array( $attachment, array( 'fixed', 'scroll' ) ) )
1127              $attachment = 'scroll';
1128          $attachment = " background-attachment: $attachment;";
1129  
1130          $style .= $image . $repeat . $position . $attachment;
1131      }
1132  ?>
1133  <style type="text/css">
1134  body.custom-background { <?php echo trim( $style ); ?> }
1135  </style>
1136  <?php
1137  }
1138  
1139  /**
1140   * Add callback for custom TinyMCE editor stylesheets.
1141   *
1142   * The parameter $stylesheet is the name of the stylesheet, relative to
1143   * the theme root. It also accepts an array of stylesheets.
1144   * It is optional and defaults to 'editor-style.css'.
1145   *
1146   * This function automatically adds another stylesheet with -rtl prefix, e.g. editor-style-rtl.css.
1147   * If that file doesn't exist, it is removed before adding the stylesheet(s) to TinyMCE.
1148   * If an array of stylesheets is passed to add_editor_style(),
1149   * RTL is only added for the first stylesheet.
1150   *
1151   * Since version 3.4 the TinyMCE body has .rtl CSS class.
1152   * It is a better option to use that class and add any RTL styles to the main stylesheet.
1153   *
1154   * @since 3.0.0
1155   *
1156   * @param mixed $stylesheet Optional. Stylesheet name or array thereof, relative to theme root.
1157   *     Defaults to 'editor-style.css'
1158   */
1159  function add_editor_style( $stylesheet = 'editor-style.css' ) {
1160  
1161      add_theme_support( 'editor-style' );
1162  
1163      if ( ! is_admin() )
1164          return;
1165  
1166      global $editor_styles;
1167      $editor_styles = (array) $editor_styles;
1168      $stylesheet    = (array) $stylesheet;
1169      if ( is_rtl() ) {
1170          $rtl_stylesheet = str_replace('.css', '-rtl.css', $stylesheet[0]);
1171          $stylesheet[] = $rtl_stylesheet;
1172      }
1173  
1174      $editor_styles = array_merge( $editor_styles, $stylesheet );
1175  }
1176  
1177  /**
1178   * Removes all visual editor stylesheets.
1179   *
1180   * @since 3.1.0
1181   *
1182   * @return bool True on success, false if there were no stylesheets to remove.
1183   */
1184  function remove_editor_styles() {
1185      if ( ! current_theme_supports( 'editor-style' ) )
1186          return false;
1187      _remove_theme_support( 'editor-style' );
1188      if ( is_admin() )
1189          $GLOBALS['editor_styles'] = array();
1190      return true;
1191  }
1192  
1193  /**
1194   * Allows a theme to register its support of a certain feature
1195   *
1196   * Must be called in the theme's functions.php file to work.
1197   * If attached to a hook, it must be after_setup_theme.
1198   * The init hook may be too late for some features.
1199   *
1200   * @since 2.9.0
1201   * @param string $feature the feature being added
1202   */
1203  function add_theme_support( $feature ) {
1204      global $_wp_theme_features;
1205  
1206      if ( func_num_args() == 1 )
1207          $args = true;
1208      else
1209          $args = array_slice( func_get_args(), 1 );
1210  
1211      switch ( $feature ) {
1212          case 'post-formats' :
1213              if ( is_array( $args[0] ) )
1214                  $args[0] = array_intersect( $args[0], array_keys( get_post_format_slugs() ) );
1215              break;
1216  
1217          case 'custom-header-uploads' :
1218              return add_theme_support( 'custom-header', array( 'uploads' => true ) );
1219              break;
1220  
1221          case 'custom-header' :
1222              if ( ! is_array( $args ) )
1223                  $args = array( 0 => array() );
1224  
1225              $defaults = array(
1226                  'default-image' => '',
1227                  'random-default' => false,
1228                  'width' => 0,
1229                  'height' => 0,
1230                  'flex-height' => false,
1231                  'flex-width' => false,
1232                  'default-text-color' => '',
1233                  'header-text' => true,
1234                  'uploads' => true,
1235                  'wp-head-callback' => '',
1236                  'admin-head-callback' => '',
1237                  'admin-preview-callback' => '',
1238              );
1239  
1240              $jit = isset( $args[0]['__jit'] );
1241              unset( $args[0]['__jit'] );
1242  
1243              // Merge in data from previous add_theme_support() calls.
1244              // The first value registered wins. (A child theme is set up first.)
1245              if ( isset( $_wp_theme_features['custom-header'] ) )
1246                  $args[0] = wp_parse_args( $_wp_theme_features['custom-header'][0], $args[0] );
1247  
1248              // Load in the defaults at the end, as we need to insure first one wins.
1249              // This will cause all constants to be defined, as each arg will then be set to the default.
1250              if ( $jit )
1251                  $args[0] = wp_parse_args( $args[0], $defaults );
1252  
1253              // If a constant was defined, use that value. Otherwise, define the constant to ensure
1254              // the constant is always accurate (and is not defined later,  overriding our value).
1255              // As stated above, the first value wins.
1256              // Once we get to wp_loaded (just-in-time), define any constants we haven't already.
1257              // Constants are lame. Don't reference them. This is just for backwards compatibility.
1258  
1259              if ( defined( 'NO_HEADER_TEXT' ) )
1260                  $args[0]['header-text'] = ! NO_HEADER_TEXT;
1261              elseif ( isset( $args[0]['header-text'] ) )
1262                  define( 'NO_HEADER_TEXT', empty( $args[0]['header-text'] ) );
1263  
1264              if ( defined( 'HEADER_IMAGE_WIDTH' ) )
1265                  $args[0]['width'] = (int) HEADER_IMAGE_WIDTH;
1266              elseif ( isset( $args[0]['width'] ) )
1267                  define( 'HEADER_IMAGE_WIDTH', (int) $args[0]['width'] );
1268  
1269              if ( defined( 'HEADER_IMAGE_HEIGHT' ) )
1270                  $args[0]['height'] = (int) HEADER_IMAGE_HEIGHT;
1271              elseif ( isset( $args[0]['height'] ) )
1272                  define( 'HEADER_IMAGE_HEIGHT', (int) $args[0]['height'] );
1273  
1274              if ( defined( 'HEADER_TEXTCOLOR' ) )
1275                  $args[0]['default-text-color'] = HEADER_TEXTCOLOR;
1276              elseif ( isset( $args[0]['default-text-color'] ) )
1277                  define( 'HEADER_TEXTCOLOR', $args[0]['default-text-color'] );
1278  
1279              if ( defined( 'HEADER_IMAGE' ) )
1280                  $args[0]['default-image'] = HEADER_IMAGE;
1281              elseif ( isset( $args[0]['default-image'] ) )
1282                  define( 'HEADER_IMAGE', $args[0]['default-image'] );
1283  
1284              if ( $jit && ! empty( $args[0]['default-image'] ) )
1285                  $args[0]['random-default'] = false;
1286  
1287              // If headers are supported, and we still don't have a defined width or height,
1288              // we have implicit flex sizes.
1289              if ( $jit ) {
1290                  if ( empty( $args[0]['width'] ) && empty( $args[0]['flex-width'] ) )
1291                      $args[0]['flex-width'] = true;
1292                  if ( empty( $args[0]['height'] ) && empty( $args[0]['flex-height'] ) )
1293                      $args[0]['flex-height'] = true;
1294              }
1295  
1296              break;
1297  
1298          case 'custom-background' :
1299              if ( ! is_array( $args ) )
1300                  $args = array( 0 => array() );
1301  
1302              $defaults = array(
1303                  'default-image' => '',
1304                  'default-color' => '',
1305                  'wp-head-callback' => '_custom_background_cb',
1306                  'admin-head-callback' => '',
1307                  'admin-preview-callback' => '',
1308              );
1309  
1310              $jit = isset( $args[0]['__jit'] );
1311              unset( $args[0]['__jit'] );
1312  
1313              // Merge in data from previous add_theme_support() calls. The first value registered wins.
1314              if ( isset( $_wp_theme_features['custom-background'] ) )
1315                  $args[0] = wp_parse_args( $_wp_theme_features['custom-background'][0], $args[0] );
1316  
1317              if ( $jit )
1318                  $args[0] = wp_parse_args( $args[0], $defaults );
1319  
1320              if ( defined( 'BACKGROUND_COLOR' ) )
1321                  $args[0]['default-color'] = BACKGROUND_COLOR;
1322              elseif ( isset( $args[0]['default-color'] ) || $jit )
1323                  define( 'BACKGROUND_COLOR', $args[0]['default-color'] );
1324  
1325              if ( defined( 'BACKGROUND_IMAGE' ) )
1326                  $args[0]['default-image'] = BACKGROUND_IMAGE;
1327              elseif ( isset( $args[0]['default-image'] ) || $jit )
1328                  define( 'BACKGROUND_IMAGE', $args[0]['default-image'] );
1329  
1330              break;
1331      }
1332  
1333      $_wp_theme_features[ $feature ] = $args;
1334  }
1335  
1336  /**
1337   * Registers the internal custom header and background routines.
1338   *
1339   * @since 3.4.0
1340   * @access private
1341   */
1342  function _custom_header_background_just_in_time() {
1343      global $custom_image_header, $custom_background;
1344  
1345      if ( current_theme_supports( 'custom-header' ) ) {
1346          // In case any constants were defined after an add_custom_image_header() call, re-run.
1347          add_theme_support( 'custom-header', array( '__jit' => true ) );
1348  
1349          $args = get_theme_support( 'custom-header' );
1350          if ( $args[0]['wp-head-callback'] )
1351              add_action( 'wp_head', $args[0]['wp-head-callback'] );
1352  
1353          if ( is_admin() ) {
1354              require_once ( ABSPATH . 'wp-admin/custom-header.php' );
1355              $custom_image_header = new Custom_Image_Header( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
1356          }
1357      }
1358  
1359      if ( current_theme_supports( 'custom-background' ) ) {
1360          // In case any constants were defined after an add_custom_background() call, re-run.
1361          add_theme_support( 'custom-background', array( '__jit' => true ) );
1362  
1363          $args = get_theme_support( 'custom-background' );
1364          add_action( 'wp_head', $args[0]['wp-head-callback'] );
1365  
1366          if ( is_admin() ) {
1367              require_once ( ABSPATH . 'wp-admin/custom-background.php' );
1368              $custom_background = new Custom_Background( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
1369          }
1370      }
1371  }
1372  add_action( 'wp_loaded', '_custom_header_background_just_in_time' );
1373  
1374  /**
1375   * Gets the theme support arguments passed when registering that support
1376   *
1377   * @since 3.1
1378   * @param string $feature the feature to check
1379   * @return array The array of extra arguments
1380   */
1381  function get_theme_support( $feature ) {
1382      global $_wp_theme_features;
1383      if ( ! isset( $_wp_theme_features[ $feature ] ) )
1384          return false;
1385  
1386      if ( func_num_args() <= 1 )
1387          return $_wp_theme_features[ $feature ];
1388  
1389      $args = array_slice( func_get_args(), 1 );
1390      switch ( $feature ) {
1391          case 'custom-header' :
1392          case 'custom-background' :
1393              if ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) )
1394                  return $_wp_theme_features[ $feature ][0][ $args[0] ];
1395              return false;
1396              break;
1397          default :
1398              return $_wp_theme_features[ $feature ];
1399              break;
1400      }
1401  }
1402  
1403  /**
1404   * Allows a theme to de-register its support of a certain feature
1405   *
1406   * Should be called in the theme's functions.php file. Generally would
1407   * be used for child themes to override support from the parent theme.
1408   *
1409   * @since 3.0.0
1410   * @see add_theme_support()
1411   * @param string $feature the feature being added
1412   * @return bool Whether feature was removed.
1413   */
1414  function remove_theme_support( $feature ) {
1415      // Blacklist: for internal registrations not used directly by themes.
1416      if ( in_array( $feature, array( 'editor-style', 'widgets', 'menus' ) ) )
1417          return false;
1418  
1419      return _remove_theme_support( $feature );
1420  }
1421  
1422  /**
1423   * Do not use. Removes theme support internally, ignorant of the blacklist.
1424   *
1425   * @access private
1426   * @since 3.1.0
1427   */
1428  function _remove_theme_support( $feature ) {
1429      global $_wp_theme_features;
1430  
1431      switch ( $feature ) {
1432          case 'custom-header-uploads' :
1433              if ( ! isset( $_wp_theme_features['custom-header'] ) )
1434                  return false;
1435              add_theme_support( 'custom-header', array( 'uploads' => false ) );
1436              return; // Do not continue - custom-header-uploads no longer exists.
1437      }
1438  
1439      if ( ! isset( $_wp_theme_features[ $feature ] ) )
1440          return false;
1441  
1442      switch ( $feature ) {
1443          case 'custom-header' :
1444              $support = get_theme_support( 'custom-header' );
1445              if ( $support[0]['wp-head-callback'] )
1446                  remove_action( 'wp_head', $support[0]['wp-head-callback'] );
1447              remove_action( 'admin_menu', array( $GLOBALS['custom_image_header'], 'init' ) );
1448              unset( $GLOBALS['custom_image_header'] );
1449              break;
1450  
1451          case 'custom-background' :
1452              $support = get_theme_support( 'custom-background' );
1453              remove_action( 'wp_head', $support[0]['wp-head-callback'] );
1454              remove_action( 'admin_menu', array( $GLOBALS['custom_background'], 'init' ) );
1455              unset( $GLOBALS['custom_background'] );
1456              break;
1457      }
1458  
1459      unset( $_wp_theme_features[ $feature ] );
1460      return true;
1461  }
1462  
1463  /**
1464   * Checks a theme's support for a given feature
1465   *
1466   * @since 2.9.0
1467   * @param string $feature the feature being checked
1468   * @return boolean
1469   */
1470  function current_theme_supports( $feature ) {
1471      global $_wp_theme_features;
1472  
1473      if ( 'custom-header-uploads' == $feature )
1474          return current_theme_supports( 'custom-header', 'uploads' );
1475  
1476      if ( !isset( $_wp_theme_features[$feature] ) )
1477          return false;
1478  
1479      // If no args passed then no extra checks need be performed
1480      if ( func_num_args() <= 1 )
1481          return true;
1482  
1483      $args = array_slice( func_get_args(), 1 );
1484  
1485      switch ( $feature ) {
1486          case 'post-thumbnails':
1487              // post-thumbnails can be registered for only certain content/post types by passing
1488              // an array of types to add_theme_support(). If no array was passed, then
1489              // any type is accepted
1490              if ( true === $_wp_theme_features[$feature] )  // Registered for all types
1491                  return true;
1492              $content_type = $args[0];
1493              return in_array( $content_type, $_wp_theme_features[$feature][0] );
1494              break;
1495  
1496          case 'post-formats':
1497              // specific post formats can be registered by passing an array of types to
1498              // add_theme_support()
1499              $post_format = $args[0];
1500              return in_array( $post_format, $_wp_theme_features[$feature][0] );
1501              break;
1502  
1503          case 'custom-header':
1504              // specific custom header capabilities can be registered by passing
1505              // an array to add_theme_support()
1506              $header_support = $args[0];
1507              return ( isset( $_wp_theme_features[$feature][0][$header_support] ) && $_wp_theme_features[$feature][0][$header_support] );
1508              break;
1509      }
1510  
1511      return apply_filters('current_theme_supports-' . $feature, true, $args, $_wp_theme_features[$feature]);
1512  }
1513  
1514  /**
1515   * Checks a theme's support for a given feature before loading the functions which implement it.
1516   *
1517   * @since 2.9.0
1518   * @param string $feature the feature being checked
1519   * @param string $include the file containing the functions that implement the feature
1520   */
1521  function require_if_theme_supports( $feature, $include) {
1522      if ( current_theme_supports( $feature ) )
1523          require ( $include );
1524  }
1525  
1526  /**
1527   * Checks an attachment being deleted to see if it's a header or background image.
1528   *
1529   * If true it removes the theme modification which would be pointing at the deleted
1530   * attachment
1531   *
1532   * @access private
1533   * @since 3.0.0
1534   * @param int $id the attachment id
1535   */
1536  function _delete_attachment_theme_mod( $id ) {
1537      $attachment_image = wp_get_attachment_url( $id );
1538      $header_image = get_header_image();
1539      $background_image = get_background_image();
1540  
1541      if ( $header_image && $header_image == $attachment_image )
1542          remove_theme_mod( 'header_image' );
1543  
1544      if ( $background_image && $background_image == $attachment_image )
1545          remove_theme_mod( 'background_image' );
1546  }
1547  
1548  add_action( 'delete_attachment', '_delete_attachment_theme_mod' );
1549  
1550  /**
1551   * Checks if a theme has been changed and runs 'after_switch_theme' hook on the next WP load
1552   *
1553   * @since 3.3.0
1554   */
1555  function check_theme_switched() {
1556      if ( $stylesheet = get_option( 'theme_switched' ) ) {
1557          $old_theme = wp_get_theme( $stylesheet );
1558  
1559          if ( $old_theme->exists() )
1560              do_action( 'after_switch_theme', $old_theme->get('Name'), $old_theme );
1561          else
1562              do_action( 'after_switch_theme', $stylesheet );
1563  
1564          update_option( 'theme_switched', false );
1565      }
1566  }
1567  
1568  /**
1569   * Includes and instantiates the WP_Customize_Manager class.
1570   *
1571   * Fires when ?customize=on.
1572   *
1573   * @since 3.4.0
1574   */
1575  function _wp_customize_include() {
1576      // Load on themes.php or ?customize=on
1577      if ( ! ( ( isset( $_REQUEST['customize'] ) && 'on' == $_REQUEST['customize'] ) || 'customize.php' == basename( $_SERVER['PHP_SELF'] ) ) )
1578          return;
1579  
1580      require ( ABSPATH . WPINC . '/class-wp-customize-manager.php' );
1581      // Init Customize class
1582      $GLOBALS['wp_customize'] = new WP_Customize_Manager;
1583  }
1584  add_action( 'plugins_loaded', '_wp_customize_include' );
1585  
1586  /**
1587   * Adds settings for the customize-loader script.
1588   *
1589   * @since 3.4.0
1590   */
1591  function _wp_customize_loader_settings() {
1592      global $wp_scripts;
1593  
1594      $admin_origin = parse_url( admin_url() );
1595      $home_origin  = parse_url( home_url() );
1596      $cross_domain = ( strtolower( $admin_origin[ 'host' ] ) != strtolower( $home_origin[ 'host' ] ) );
1597  
1598      $settings = array(
1599          'url'           => esc_url( admin_url( 'customize.php' ) ),
1600          'isCrossDomain' => $cross_domain,
1601      );
1602  
1603      $script = 'var _wpCustomizeLoaderSettings = ' . json_encode( $settings ) . ';';
1604  
1605      $data = $wp_scripts->get_data( 'customize-loader', 'data' );
1606      if ( $data )
1607          $script = "$data\n$script";
1608  
1609      $wp_scripts->add_data( 'customize-loader', 'data', $script );
1610  }
1611  add_action( 'admin_enqueue_scripts', '_wp_customize_loader_settings' );
1612  
1613  /**
1614   * Returns a URL to load the theme customizer.
1615   *
1616   * @since 3.4.0
1617   */
1618  function wp_customize_url( $stylesheet ) {
1619      return esc_url( admin_url( 'customize.php' ) . '?theme=' . $stylesheet );
1620  }
1621  
1622  /**
1623   * Prints a script to check whether or not the customizer is supported,
1624   * and apply either the no-customize-support or customize-support class
1625   * to the body.
1626   *
1627   * This function MUST be called inside the body tag.
1628   *
1629   * Ideally, call this function immediately after the body tag is opened.
1630   * This prevents a flash of unstyled content.
1631   *
1632   * It is also recommended that you add the "no-customize-support" class
1633   * to the body tag by default.
1634   *
1635   * @since 3.4.0
1636   */
1637  function wp_customize_support_script() {
1638      if ( ! wp_script_is( 'customize-loader', 'queue' ) )
1639          return;
1640  
1641      $admin_origin = parse_url( admin_url() );
1642      $home_origin  = parse_url( home_url() );
1643      $cross_domain = ( strtolower( $admin_origin[ 'host' ] ) != strtolower( $home_origin[ 'host' ] ) );
1644  
1645      ?>
1646      <script type="text/javascript">
1647          (function() {
1648              var request, b = document.body, c = 'className', cs = 'customize-support', rcs = new RegExp('(^|\\s+)(no-)?'+cs+'(\\s+|$)');
1649  
1650  <?php        if ( $cross_domain ): ?>
1651              request = (function(){ var xhr = new XMLHttpRequest(); return ('withCredentials' in xhr); })();
1652  <?php        else: ?>
1653              request = true;
1654  <?php        endif; ?>
1655  
1656              b[c] = b[c].replace( rcs, '' );
1657              b[c] += ( window.postMessage && request ? ' ' : ' no-' ) + cs;
1658          }());
1659      </script>
1660      <?php
1661  }


Generated: Fri May 25 03:56:23 2012 Hosted by follow the white rabbit.