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