wp/wp-includes/theme.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
    15  * @since 3.4.0
    15  * @since 3.4.0
    16  *
    16  *
    17  * @global array $wp_theme_directories
    17  * @global array $wp_theme_directories
    18  * @staticvar array $_themes
    18  * @staticvar array $_themes
    19  *
    19  *
    20  * @param array $args The search arguments. Optional.
    20  * @param array $args {
    21  * - errors      mixed  True to return themes with errors, false to return themes without errors, null
    21  *     Optional. The search arguments.
    22  *                      to return all themes. Defaults to false.
    22  *
    23  * - allowed     mixed  (Multisite) True to return only allowed themes for a site. False to return only
    23  *     @type mixed $errors  True to return themes with errors, false to return themes without errors, null to return all themes.
    24  *                      disallowed themes for a site. 'site' to return only site-allowed themes. 'network'
    24  *                          Defaults to false.
    25  *                      to return only network-allowed themes. Null to return all themes. Defaults to null.
    25  *     @type mixed $allowed (Multisite) True to return only allowed themes for a site. False to return only disallowed themes for a site.
    26  * - blog_id     int    (Multisite) The blog ID used to calculate which themes are allowed. Defaults to 0,
    26  *                          'site' to return only site-allowed themes. 'network' to return only network-allowed themes.
    27  *                      synonymous for the current blog.
    27  *                          Null to return all themes. Defaults to null.
    28  * @return array Array of WP_Theme objects.
    28  *     @type int   $blog_id (Multisite) The blog ID used to calculate which themes are allowed.
       
    29  *                          Defaults to 0, synonymous for the current blog.
       
    30  * }
       
    31  * @return WP_Theme[] Array of WP_Theme objects.
    29  */
    32  */
    30 function wp_get_themes( $args = array() ) {
    33 function wp_get_themes( $args = array() ) {
    31 	global $wp_theme_directories;
    34 	global $wp_theme_directories;
    32 
    35 
    33 	$defaults = array( 'errors' => false, 'allowed' => null, 'blog_id' => 0 );
    36 	$defaults = array(
    34 	$args = wp_parse_args( $args, $defaults );
    37 		'errors'  => false,
       
    38 		'allowed' => null,
       
    39 		'blog_id' => 0,
       
    40 	);
       
    41 	$args     = wp_parse_args( $args, $defaults );
    35 
    42 
    36 	$theme_directories = search_theme_directories();
    43 	$theme_directories = search_theme_directories();
    37 
    44 
    38 	if ( is_array( $wp_theme_directories ) && count( $wp_theme_directories ) > 1 ) {
    45 	if ( is_array( $wp_theme_directories ) && count( $wp_theme_directories ) > 1 ) {
    39 		// Make sure the current theme wins out, in case search_theme_directories() picks the wrong
    46 		// Make sure the current theme wins out, in case search_theme_directories() picks the wrong
    40 		// one in the case of a conflict. (Normally, last registered theme root wins.)
    47 		// one in the case of a conflict. (Normally, last registered theme root wins.)
    41 		$current_theme = get_stylesheet();
    48 		$current_theme = get_stylesheet();
    42 		if ( isset( $theme_directories[ $current_theme ] ) ) {
    49 		if ( isset( $theme_directories[ $current_theme ] ) ) {
    43 			$root_of_current_theme = get_raw_theme_root( $current_theme );
    50 			$root_of_current_theme = get_raw_theme_root( $current_theme );
    44 			if ( ! in_array( $root_of_current_theme, $wp_theme_directories ) )
    51 			if ( ! in_array( $root_of_current_theme, $wp_theme_directories ) ) {
    45 				$root_of_current_theme = WP_CONTENT_DIR . $root_of_current_theme;
    52 				$root_of_current_theme = WP_CONTENT_DIR . $root_of_current_theme;
       
    53 			}
    46 			$theme_directories[ $current_theme ]['theme_root'] = $root_of_current_theme;
    54 			$theme_directories[ $current_theme ]['theme_root'] = $root_of_current_theme;
    47 		}
    55 		}
    48 	}
    56 	}
    49 
    57 
    50 	if ( empty( $theme_directories ) )
    58 	if ( empty( $theme_directories ) ) {
    51 		return array();
    59 		return array();
       
    60 	}
    52 
    61 
    53 	if ( is_multisite() && null !== $args['allowed'] ) {
    62 	if ( is_multisite() && null !== $args['allowed'] ) {
    54 		$allowed = $args['allowed'];
    63 		$allowed = $args['allowed'];
    55 		if ( 'network' === $allowed )
    64 		if ( 'network' === $allowed ) {
    56 			$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_network() );
    65 			$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_network() );
    57 		elseif ( 'site' === $allowed )
    66 		} elseif ( 'site' === $allowed ) {
    58 			$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_site( $args['blog_id'] ) );
    67 			$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_site( $args['blog_id'] ) );
    59 		elseif ( $allowed )
    68 		} elseif ( $allowed ) {
    60 			$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
    69 			$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
    61 		else
    70 		} else {
    62 			$theme_directories = array_diff_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
    71 			$theme_directories = array_diff_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
    63 	}
    72 		}
    64 
    73 	}
    65 	$themes = array();
    74 
       
    75 	$themes         = array();
    66 	static $_themes = array();
    76 	static $_themes = array();
    67 
    77 
    68 	foreach ( $theme_directories as $theme => $theme_root ) {
    78 	foreach ( $theme_directories as $theme => $theme_root ) {
    69 		if ( isset( $_themes[ $theme_root['theme_root'] . '/' . $theme ] ) )
    79 		if ( isset( $_themes[ $theme_root['theme_root'] . '/' . $theme ] ) ) {
    70 			$themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ];
    80 			$themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ];
    71 		else
    81 		} else {
    72 			$themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ] = new WP_Theme( $theme, $theme_root['theme_root'] );
    82 			$themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ] = new WP_Theme( $theme, $theme_root['theme_root'] );
       
    83 		}
    73 	}
    84 	}
    74 
    85 
    75 	if ( null !== $args['errors'] ) {
    86 	if ( null !== $args['errors'] ) {
    76 		foreach ( $themes as $theme => $wp_theme ) {
    87 		foreach ( $themes as $theme => $wp_theme ) {
    77 			if ( $wp_theme->errors() != $args['errors'] )
    88 			if ( $wp_theme->errors() != $args['errors'] ) {
    78 				unset( $themes[ $theme ] );
    89 				unset( $themes[ $theme ] );
       
    90 			}
    79 		}
    91 		}
    80 	}
    92 	}
    81 
    93 
    82 	return $themes;
    94 	return $themes;
    83 }
    95 }
    89  *
   101  *
    90  * @global array $wp_theme_directories
   102  * @global array $wp_theme_directories
    91  *
   103  *
    92  * @param string $stylesheet Directory name for the theme. Optional. Defaults to current theme.
   104  * @param string $stylesheet Directory name for the theme. Optional. Defaults to current theme.
    93  * @param string $theme_root Absolute path of the theme root to look in. Optional. If not specified, get_raw_theme_root()
   105  * @param string $theme_root Absolute path of the theme root to look in. Optional. If not specified, get_raw_theme_root()
    94  * 	                         is used to calculate the theme root for the $stylesheet provided (or current theme).
   106  *                           is used to calculate the theme root for the $stylesheet provided (or current theme).
    95  * @return WP_Theme Theme object. Be sure to check the object's exists() method if you need to confirm the theme's existence.
   107  * @return WP_Theme Theme object. Be sure to check the object's exists() method if you need to confirm the theme's existence.
    96  */
   108  */
    97 function wp_get_theme( $stylesheet = null, $theme_root = null ) {
   109 function wp_get_theme( $stylesheet = null, $theme_root = null ) {
    98 	global $wp_theme_directories;
   110 	global $wp_theme_directories;
    99 
   111 
   100 	if ( empty( $stylesheet ) )
   112 	if ( empty( $stylesheet ) ) {
   101 		$stylesheet = get_stylesheet();
   113 		$stylesheet = get_stylesheet();
       
   114 	}
   102 
   115 
   103 	if ( empty( $theme_root ) ) {
   116 	if ( empty( $theme_root ) ) {
   104 		$theme_root = get_raw_theme_root( $stylesheet );
   117 		$theme_root = get_raw_theme_root( $stylesheet );
   105 		if ( false === $theme_root )
   118 		if ( false === $theme_root ) {
   106 			$theme_root = WP_CONTENT_DIR . '/themes';
   119 			$theme_root = WP_CONTENT_DIR . '/themes';
   107 		elseif ( ! in_array( $theme_root, (array) $wp_theme_directories ) )
   120 		} elseif ( ! in_array( $theme_root, (array) $wp_theme_directories ) ) {
   108 			$theme_root = WP_CONTENT_DIR . $theme_root;
   121 			$theme_root = WP_CONTENT_DIR . $theme_root;
       
   122 		}
   109 	}
   123 	}
   110 
   124 
   111 	return new WP_Theme( $stylesheet, $theme_root );
   125 	return new WP_Theme( $stylesheet, $theme_root );
   112 }
   126 }
   113 
   127 
   116  *
   130  *
   117  * @since 3.5.0
   131  * @since 3.5.0
   118  * @param bool $clear_update_cache Whether to clear the Theme updates cache
   132  * @param bool $clear_update_cache Whether to clear the Theme updates cache
   119  */
   133  */
   120 function wp_clean_themes_cache( $clear_update_cache = true ) {
   134 function wp_clean_themes_cache( $clear_update_cache = true ) {
   121 	if ( $clear_update_cache )
   135 	if ( $clear_update_cache ) {
   122 		delete_site_transient( 'update_themes' );
   136 		delete_site_transient( 'update_themes' );
       
   137 	}
   123 	search_theme_directories( true );
   138 	search_theme_directories( true );
   124 	foreach ( wp_get_themes( array( 'errors' => null ) ) as $theme )
   139 	foreach ( wp_get_themes( array( 'errors' => null ) ) as $theme ) {
   125 		$theme->cache_delete();
   140 		$theme->cache_delete();
       
   141 	}
   126 }
   142 }
   127 
   143 
   128 /**
   144 /**
   129  * Whether a child theme is in use.
   145  * Whether a child theme is in use.
   130  *
   146  *
   131  * @since 3.0.0
   147  * @since 3.0.0
   132  *
   148  *
   133  * @return bool true if a child theme is in use, false otherwise.
   149  * @return bool true if a child theme is in use, false otherwise.
   134  **/
   150  */
   135 function is_child_theme() {
   151 function is_child_theme() {
   136 	return ( TEMPLATEPATH !== STYLESHEETPATH );
   152 	return ( TEMPLATEPATH !== STYLESHEETPATH );
   137 }
   153 }
   138 
   154 
   139 /**
   155 /**
   166  * @since 1.5.0
   182  * @since 1.5.0
   167  *
   183  *
   168  * @return string Path to current theme directory.
   184  * @return string Path to current theme directory.
   169  */
   185  */
   170 function get_stylesheet_directory() {
   186 function get_stylesheet_directory() {
   171 	$stylesheet = get_stylesheet();
   187 	$stylesheet     = get_stylesheet();
   172 	$theme_root = get_theme_root( $stylesheet );
   188 	$theme_root     = get_theme_root( $stylesheet );
   173 	$stylesheet_dir = "$theme_root/$stylesheet";
   189 	$stylesheet_dir = "$theme_root/$stylesheet";
   174 
   190 
   175 	/**
   191 	/**
   176 	 * Filters the stylesheet directory path for current theme.
   192 	 * Filters the stylesheet directory path for current theme.
   177 	 *
   193 	 *
   190  * @since 1.5.0
   206  * @since 1.5.0
   191  *
   207  *
   192  * @return string
   208  * @return string
   193  */
   209  */
   194 function get_stylesheet_directory_uri() {
   210 function get_stylesheet_directory_uri() {
   195 	$stylesheet = str_replace( '%2F', '/', rawurlencode( get_stylesheet() ) );
   211 	$stylesheet         = str_replace( '%2F', '/', rawurlencode( get_stylesheet() ) );
   196 	$theme_root_uri = get_theme_root_uri( $stylesheet );
   212 	$theme_root_uri     = get_theme_root_uri( $stylesheet );
   197 	$stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
   213 	$stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
   198 
   214 
   199 	/**
   215 	/**
   200 	 * Filters the stylesheet directory URI.
   216 	 * Filters the stylesheet directory URI.
   201 	 *
   217 	 *
   218  *
   234  *
   219  * @return string
   235  * @return string
   220  */
   236  */
   221 function get_stylesheet_uri() {
   237 function get_stylesheet_uri() {
   222 	$stylesheet_dir_uri = get_stylesheet_directory_uri();
   238 	$stylesheet_dir_uri = get_stylesheet_directory_uri();
   223 	$stylesheet_uri = $stylesheet_dir_uri . '/style.css';
   239 	$stylesheet_uri     = $stylesheet_dir_uri . '/style.css';
   224 	/**
   240 	/**
   225 	 * Filters the URI of the current theme stylesheet.
   241 	 * Filters the URI of the current theme stylesheet.
   226 	 *
   242 	 *
   227 	 * @since 1.5.0
   243 	 * @since 1.5.0
   228 	 *
   244 	 *
   254  * @return string
   270  * @return string
   255  */
   271  */
   256 function get_locale_stylesheet_uri() {
   272 function get_locale_stylesheet_uri() {
   257 	global $wp_locale;
   273 	global $wp_locale;
   258 	$stylesheet_dir_uri = get_stylesheet_directory_uri();
   274 	$stylesheet_dir_uri = get_stylesheet_directory_uri();
   259 	$dir = get_stylesheet_directory();
   275 	$dir                = get_stylesheet_directory();
   260 	$locale = get_locale();
   276 	$locale             = get_locale();
   261 	if ( file_exists("$dir/$locale.css") )
   277 	if ( file_exists( "$dir/$locale.css" ) ) {
   262 		$stylesheet_uri = "$stylesheet_dir_uri/$locale.css";
   278 		$stylesheet_uri = "$stylesheet_dir_uri/$locale.css";
   263 	elseif ( !empty($wp_locale->text_direction) && file_exists("$dir/{$wp_locale->text_direction}.css") )
   279 	} elseif ( ! empty( $wp_locale->text_direction ) && file_exists( "$dir/{$wp_locale->text_direction}.css" ) ) {
   264 		$stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
   280 		$stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
   265 	else
   281 	} else {
   266 		$stylesheet_uri = '';
   282 		$stylesheet_uri = '';
       
   283 	}
   267 	/**
   284 	/**
   268 	 * Filters the localized stylesheet URI.
   285 	 * Filters the localized stylesheet URI.
   269 	 *
   286 	 *
   270 	 * @since 2.1.0
   287 	 * @since 2.1.0
   271 	 *
   288 	 *
   299  * @since 1.5.0
   316  * @since 1.5.0
   300  *
   317  *
   301  * @return string Template directory path.
   318  * @return string Template directory path.
   302  */
   319  */
   303 function get_template_directory() {
   320 function get_template_directory() {
   304 	$template = get_template();
   321 	$template     = get_template();
   305 	$theme_root = get_theme_root( $template );
   322 	$theme_root   = get_theme_root( $template );
   306 	$template_dir = "$theme_root/$template";
   323 	$template_dir = "$theme_root/$template";
   307 
   324 
   308 	/**
   325 	/**
   309 	 * Filters the current theme directory path.
   326 	 * Filters the current theme directory path.
   310 	 *
   327 	 *
   323  * @since 1.5.0
   340  * @since 1.5.0
   324  *
   341  *
   325  * @return string Template directory URI.
   342  * @return string Template directory URI.
   326  */
   343  */
   327 function get_template_directory_uri() {
   344 function get_template_directory_uri() {
   328 	$template = str_replace( '%2F', '/', rawurlencode( get_template() ) );
   345 	$template         = str_replace( '%2F', '/', rawurlencode( get_template() ) );
   329 	$theme_root_uri = get_theme_root_uri( $template );
   346 	$theme_root_uri   = get_theme_root_uri( $template );
   330 	$template_dir_uri = "$theme_root_uri/$template";
   347 	$template_dir_uri = "$theme_root_uri/$template";
   331 
   348 
   332 	/**
   349 	/**
   333 	 * Filters the current theme directory URI.
   350 	 * Filters the current theme directory URI.
   334 	 *
   351 	 *
   412  */
   429  */
   413 function search_theme_directories( $force = false ) {
   430 function search_theme_directories( $force = false ) {
   414 	global $wp_theme_directories;
   431 	global $wp_theme_directories;
   415 	static $found_themes = null;
   432 	static $found_themes = null;
   416 
   433 
   417 	if ( empty( $wp_theme_directories ) )
   434 	if ( empty( $wp_theme_directories ) ) {
   418 		return false;
   435 		return false;
   419 
   436 	}
   420 	if ( ! $force && isset( $found_themes ) )
   437 
       
   438 	if ( ! $force && isset( $found_themes ) ) {
   421 		return $found_themes;
   439 		return $found_themes;
       
   440 	}
   422 
   441 
   423 	$found_themes = array();
   442 	$found_themes = array();
   424 
   443 
   425 	$wp_theme_directories = (array) $wp_theme_directories;
   444 	$wp_theme_directories = (array) $wp_theme_directories;
   426 	$relative_theme_roots = array();
   445 	$relative_theme_roots = array();
   427 
   446 
   428 	// Set up maybe-relative, maybe-absolute array of theme directories.
   447 	// Set up maybe-relative, maybe-absolute array of theme directories.
   429 	// We always want to return absolute, but we need to cache relative
   448 	// We always want to return absolute, but we need to cache relative
   430 	// to use in get_theme_root().
   449 	// to use in get_theme_root().
   431 	foreach ( $wp_theme_directories as $theme_root ) {
   450 	foreach ( $wp_theme_directories as $theme_root ) {
   432 		if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) )
   451 		if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) {
   433 			$relative_theme_roots[ str_replace( WP_CONTENT_DIR, '', $theme_root ) ] = $theme_root;
   452 			$relative_theme_roots[ str_replace( WP_CONTENT_DIR, '', $theme_root ) ] = $theme_root;
   434 		else
   453 		} else {
   435 			$relative_theme_roots[ $theme_root ] = $theme_root;
   454 			$relative_theme_roots[ $theme_root ] = $theme_root;
       
   455 		}
   436 	}
   456 	}
   437 
   457 
   438 	/**
   458 	/**
   439 	 * Filters whether to get the cache of the registered theme directories.
   459 	 * Filters whether to get the cache of the registered theme directories.
   440 	 *
   460 	 *
   446 	if ( $cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' ) ) {
   466 	if ( $cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' ) ) {
   447 		$cached_roots = get_site_transient( 'theme_roots' );
   467 		$cached_roots = get_site_transient( 'theme_roots' );
   448 		if ( is_array( $cached_roots ) ) {
   468 		if ( is_array( $cached_roots ) ) {
   449 			foreach ( $cached_roots as $theme_dir => $theme_root ) {
   469 			foreach ( $cached_roots as $theme_dir => $theme_root ) {
   450 				// A cached theme root is no longer around, so skip it.
   470 				// A cached theme root is no longer around, so skip it.
   451 				if ( ! isset( $relative_theme_roots[ $theme_root ] ) )
   471 				if ( ! isset( $relative_theme_roots[ $theme_root ] ) ) {
   452 					continue;
   472 					continue;
       
   473 				}
   453 				$found_themes[ $theme_dir ] = array(
   474 				$found_themes[ $theme_dir ] = array(
   454 					'theme_file' => $theme_dir . '/style.css',
   475 					'theme_file' => $theme_dir . '/style.css',
   455 					'theme_root' => $relative_theme_roots[ $theme_root ], // Convert relative to absolute.
   476 					'theme_root' => $relative_theme_roots[ $theme_root ], // Convert relative to absolute.
   456 				);
   477 				);
   457 			}
   478 			}
   458 			return $found_themes;
   479 			return $found_themes;
   459 		}
   480 		}
   460 		if ( ! is_int( $cache_expiration ) )
   481 		if ( ! is_int( $cache_expiration ) ) {
   461 			$cache_expiration = 1800; // half hour
   482 			$cache_expiration = 1800; // half hour
       
   483 		}
   462 	} else {
   484 	} else {
   463 		$cache_expiration = 1800; // half hour
   485 		$cache_expiration = 1800; // half hour
   464 	}
   486 	}
   465 
   487 
   466 	/* Loop the registered theme directories and extract all themes */
   488 	/* Loop the registered theme directories and extract all themes */
   471 		if ( ! $dirs ) {
   493 		if ( ! $dirs ) {
   472 			trigger_error( "$theme_root is not readable", E_USER_NOTICE );
   494 			trigger_error( "$theme_root is not readable", E_USER_NOTICE );
   473 			continue;
   495 			continue;
   474 		}
   496 		}
   475 		foreach ( $dirs as $dir ) {
   497 		foreach ( $dirs as $dir ) {
   476 			if ( ! is_dir( $theme_root . '/' . $dir ) || $dir[0] == '.' || $dir == 'CVS' )
   498 			if ( ! is_dir( $theme_root . '/' . $dir ) || $dir[0] == '.' || $dir == 'CVS' ) {
   477 				continue;
   499 				continue;
       
   500 			}
   478 			if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) {
   501 			if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) {
   479 				// wp-content/themes/a-single-theme
   502 				// wp-content/themes/a-single-theme
   480 				// wp-content/themes is $theme_root, a-single-theme is $dir
   503 				// wp-content/themes is $theme_root, a-single-theme is $dir
   481 				$found_themes[ $dir ] = array(
   504 				$found_themes[ $dir ] = array(
   482 					'theme_file' => $dir . '/style.css',
   505 					'theme_file' => $dir . '/style.css',
   490 				if ( ! $sub_dirs ) {
   513 				if ( ! $sub_dirs ) {
   491 					trigger_error( "$theme_root/$dir is not readable", E_USER_NOTICE );
   514 					trigger_error( "$theme_root/$dir is not readable", E_USER_NOTICE );
   492 					continue;
   515 					continue;
   493 				}
   516 				}
   494 				foreach ( $sub_dirs as $sub_dir ) {
   517 				foreach ( $sub_dirs as $sub_dir ) {
   495 					if ( ! is_dir( $theme_root . '/' . $dir . '/' . $sub_dir ) || $dir[0] == '.' || $dir == 'CVS' )
   518 					if ( ! is_dir( $theme_root . '/' . $dir . '/' . $sub_dir ) || $dir[0] == '.' || $dir == 'CVS' ) {
   496 						continue;
   519 						continue;
   497 					if ( ! file_exists( $theme_root . '/' . $dir . '/' . $sub_dir . '/style.css' ) )
   520 					}
       
   521 					if ( ! file_exists( $theme_root . '/' . $dir . '/' . $sub_dir . '/style.css' ) ) {
   498 						continue;
   522 						continue;
       
   523 					}
   499 					$found_themes[ $dir . '/' . $sub_dir ] = array(
   524 					$found_themes[ $dir . '/' . $sub_dir ] = array(
   500 						'theme_file' => $dir . '/' . $sub_dir . '/style.css',
   525 						'theme_file' => $dir . '/' . $sub_dir . '/style.css',
   501 						'theme_root' => $theme_root,
   526 						'theme_root' => $theme_root,
   502 					);
   527 					);
   503 					$found_theme = true;
   528 					$found_theme                           = true;
   504 				}
   529 				}
   505 				// Never mind the above, it's just a theme missing a style.css.
   530 				// Never mind the above, it's just a theme missing a style.css.
   506 				// Return it; WP_Theme will catch the error.
   531 				// Return it; WP_Theme will catch the error.
   507 				if ( ! $found_theme )
   532 				if ( ! $found_theme ) {
   508 					$found_themes[ $dir ] = array(
   533 					$found_themes[ $dir ] = array(
   509 						'theme_file' => $dir . '/style.css',
   534 						'theme_file' => $dir . '/style.css',
   510 						'theme_root' => $theme_root,
   535 						'theme_root' => $theme_root,
   511 					);
   536 					);
       
   537 				}
   512 			}
   538 			}
   513 		}
   539 		}
   514 	}
   540 	}
   515 
   541 
   516 	asort( $found_themes );
   542 	asort( $found_themes );
   517 
   543 
   518 	$theme_roots = array();
   544 	$theme_roots          = array();
   519 	$relative_theme_roots = array_flip( $relative_theme_roots );
   545 	$relative_theme_roots = array_flip( $relative_theme_roots );
   520 
   546 
   521 	foreach ( $found_themes as $theme_dir => $theme_data ) {
   547 	foreach ( $found_themes as $theme_dir => $theme_data ) {
   522 		$theme_roots[ $theme_dir ] = $relative_theme_roots[ $theme_data['theme_root'] ]; // Convert absolute to relative.
   548 		$theme_roots[ $theme_dir ] = $relative_theme_roots[ $theme_data['theme_root'] ]; // Convert absolute to relative.
   523 	}
   549 	}
   524 
   550 
   525 	if ( $theme_roots != get_site_transient( 'theme_roots' ) )
   551 	if ( $theme_roots != get_site_transient( 'theme_roots' ) ) {
   526 		set_site_transient( 'theme_roots', $theme_roots, $cache_expiration );
   552 		set_site_transient( 'theme_roots', $theme_roots, $cache_expiration );
       
   553 	}
   527 
   554 
   528 	return $found_themes;
   555 	return $found_themes;
   529 }
   556 }
   530 
   557 
   531 /**
   558 /**
   544 	global $wp_theme_directories;
   571 	global $wp_theme_directories;
   545 
   572 
   546 	if ( $stylesheet_or_template && $theme_root = get_raw_theme_root( $stylesheet_or_template ) ) {
   573 	if ( $stylesheet_or_template && $theme_root = get_raw_theme_root( $stylesheet_or_template ) ) {
   547 		// Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory.
   574 		// Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory.
   548 		// This gives relative theme roots the benefit of the doubt when things go haywire.
   575 		// This gives relative theme roots the benefit of the doubt when things go haywire.
   549 		if ( ! in_array( $theme_root, (array) $wp_theme_directories ) )
   576 		if ( ! in_array( $theme_root, (array) $wp_theme_directories ) ) {
   550 			$theme_root = WP_CONTENT_DIR . $theme_root;
   577 			$theme_root = WP_CONTENT_DIR . $theme_root;
       
   578 		}
   551 	} else {
   579 	} else {
   552 		$theme_root = WP_CONTENT_DIR . '/themes';
   580 		$theme_root = WP_CONTENT_DIR . '/themes';
   553 	}
   581 	}
   554 
   582 
   555 	/**
   583 	/**
   570  * @since 1.5.0
   598  * @since 1.5.0
   571  *
   599  *
   572  * @global array $wp_theme_directories
   600  * @global array $wp_theme_directories
   573  *
   601  *
   574  * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
   602  * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
   575  * 	                                     Default is to leverage the main theme root.
   603  *                                       Default is to leverage the main theme root.
   576  * @param string $theme_root             Optional. The theme root for which calculations will be based, preventing
   604  * @param string $theme_root             Optional. The theme root for which calculations will be based, preventing
   577  * 	                                     the need for a get_raw_theme_root() call.
   605  *                                       the need for a get_raw_theme_root() call.
   578  * @return string Themes URI.
   606  * @return string Themes URI.
   579  */
   607  */
   580 function get_theme_root_uri( $stylesheet_or_template = false, $theme_root = false ) {
   608 function get_theme_root_uri( $stylesheet_or_template = false, $theme_root = false ) {
   581 	global $wp_theme_directories;
   609 	global $wp_theme_directories;
   582 
   610 
   583 	if ( $stylesheet_or_template && ! $theme_root )
   611 	if ( $stylesheet_or_template && ! $theme_root ) {
   584 		$theme_root = get_raw_theme_root( $stylesheet_or_template );
   612 		$theme_root = get_raw_theme_root( $stylesheet_or_template );
       
   613 	}
   585 
   614 
   586 	if ( $stylesheet_or_template && $theme_root ) {
   615 	if ( $stylesheet_or_template && $theme_root ) {
   587 		if ( in_array( $theme_root, (array) $wp_theme_directories ) ) {
   616 		if ( in_array( $theme_root, (array) $wp_theme_directories ) ) {
   588 			// Absolute path. Make an educated guess. YMMV -- but note the filter below.
   617 			// Absolute path. Make an educated guess. YMMV -- but note the filter below.
   589 			if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) )
   618 			if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) {
   590 				$theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) );
   619 				$theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) );
   591 			elseif ( 0 === strpos( $theme_root, ABSPATH ) )
   620 			} elseif ( 0 === strpos( $theme_root, ABSPATH ) ) {
   592 				$theme_root_uri = site_url( str_replace( ABSPATH, '', $theme_root ) );
   621 				$theme_root_uri = site_url( str_replace( ABSPATH, '', $theme_root ) );
   593 			elseif ( 0 === strpos( $theme_root, WP_PLUGIN_DIR ) || 0 === strpos( $theme_root, WPMU_PLUGIN_DIR ) )
   622 			} elseif ( 0 === strpos( $theme_root, WP_PLUGIN_DIR ) || 0 === strpos( $theme_root, WPMU_PLUGIN_DIR ) ) {
   594 				$theme_root_uri = plugins_url( basename( $theme_root ), $theme_root );
   623 				$theme_root_uri = plugins_url( basename( $theme_root ), $theme_root );
   595 			else
   624 			} else {
   596 				$theme_root_uri = $theme_root;
   625 				$theme_root_uri = $theme_root;
       
   626 			}
   597 		} else {
   627 		} else {
   598 			$theme_root_uri = content_url( $theme_root );
   628 			$theme_root_uri = content_url( $theme_root );
   599 		}
   629 		}
   600 	} else {
   630 	} else {
   601 		$theme_root_uri = content_url( 'themes' );
   631 		$theme_root_uri = content_url( 'themes' );
   634 
   664 
   635 	$theme_root = false;
   665 	$theme_root = false;
   636 
   666 
   637 	// If requesting the root for the current theme, consult options to avoid calling get_theme_roots()
   667 	// If requesting the root for the current theme, consult options to avoid calling get_theme_roots()
   638 	if ( ! $skip_cache ) {
   668 	if ( ! $skip_cache ) {
   639 		if ( get_option('stylesheet') == $stylesheet_or_template )
   669 		if ( get_option( 'stylesheet' ) == $stylesheet_or_template ) {
   640 			$theme_root = get_option('stylesheet_root');
   670 			$theme_root = get_option( 'stylesheet_root' );
   641 		elseif ( get_option('template') == $stylesheet_or_template )
   671 		} elseif ( get_option( 'template' ) == $stylesheet_or_template ) {
   642 			$theme_root = get_option('template_root');
   672 			$theme_root = get_option( 'template_root' );
   643 	}
   673 		}
   644 
   674 	}
   645 	if ( empty($theme_root) ) {
   675 
       
   676 	if ( empty( $theme_root ) ) {
   646 		$theme_roots = get_theme_roots();
   677 		$theme_roots = get_theme_roots();
   647 		if ( !empty($theme_roots[$stylesheet_or_template]) )
   678 		if ( ! empty( $theme_roots[ $stylesheet_or_template ] ) ) {
   648 			$theme_root = $theme_roots[$stylesheet_or_template];
   679 			$theme_root = $theme_roots[ $stylesheet_or_template ];
       
   680 		}
   649 	}
   681 	}
   650 
   682 
   651 	return $theme_root;
   683 	return $theme_root;
   652 }
   684 }
   653 
   685 
   656  *
   688  *
   657  * @since 2.1.0
   689  * @since 2.1.0
   658  */
   690  */
   659 function locale_stylesheet() {
   691 function locale_stylesheet() {
   660 	$stylesheet = get_locale_stylesheet_uri();
   692 	$stylesheet = get_locale_stylesheet_uri();
   661 	if ( empty($stylesheet) )
   693 	if ( empty( $stylesheet ) ) {
   662 		return;
   694 		return;
       
   695 	}
   663 	echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
   696 	echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
   664 }
   697 }
   665 
   698 
   666 /**
   699 /**
   667  * Switches the theme.
   700  * Switches the theme.
   689 	} elseif ( is_array( $sidebars_widgets ) ) {
   722 	} elseif ( is_array( $sidebars_widgets ) ) {
   690 		$_sidebars_widgets = $sidebars_widgets;
   723 		$_sidebars_widgets = $sidebars_widgets;
   691 	}
   724 	}
   692 
   725 
   693 	if ( is_array( $_sidebars_widgets ) ) {
   726 	if ( is_array( $_sidebars_widgets ) ) {
   694 		set_theme_mod( 'sidebars_widgets', array( 'time' => time(), 'data' => $_sidebars_widgets ) );
   727 		set_theme_mod(
       
   728 			'sidebars_widgets',
       
   729 			array(
       
   730 				'time' => time(),
       
   731 				'data' => $_sidebars_widgets,
       
   732 			)
       
   733 		);
   695 	}
   734 	}
   696 
   735 
   697 	$nav_menu_locations = get_theme_mod( 'nav_menu_locations' );
   736 	$nav_menu_locations = get_theme_mod( 'nav_menu_locations' );
   698 	update_option( 'theme_switch_menu_locations', $nav_menu_locations );
   737 	update_option( 'theme_switch_menu_locations', $nav_menu_locations );
   699 
   738 
   702 	}
   741 	}
   703 
   742 
   704 	$old_theme = wp_get_theme();
   743 	$old_theme = wp_get_theme();
   705 	$new_theme = wp_get_theme( $stylesheet );
   744 	$new_theme = wp_get_theme( $stylesheet );
   706 	$template  = $new_theme->get_template();
   745 	$template  = $new_theme->get_template();
       
   746 
       
   747 	if ( wp_is_recovery_mode() ) {
       
   748 		$paused_themes = wp_paused_themes();
       
   749 		$paused_themes->delete( $old_theme->get_stylesheet() );
       
   750 		$paused_themes->delete( $old_theme->get_template() );
       
   751 	}
   707 
   752 
   708 	update_option( 'template', $template );
   753 	update_option( 'template', $template );
   709 	update_option( 'stylesheet', $stylesheet );
   754 	update_option( 'stylesheet', $stylesheet );
   710 
   755 
   711 	if ( count( $wp_theme_directories ) > 1 ) {
   756 	if ( count( $wp_theme_directories ) > 1 ) {
   714 	} else {
   759 	} else {
   715 		delete_option( 'template_root' );
   760 		delete_option( 'template_root' );
   716 		delete_option( 'stylesheet_root' );
   761 		delete_option( 'stylesheet_root' );
   717 	}
   762 	}
   718 
   763 
   719 	$new_name  = $new_theme->get('Name');
   764 	$new_name = $new_theme->get( 'Name' );
   720 
   765 
   721 	update_option( 'current_theme', $new_name );
   766 	update_option( 'current_theme', $new_name );
   722 
   767 
   723 	// Migrate from the old mods_{name} option to theme_mods_{slug}.
   768 	// Migrate from the old mods_{name} option to theme_mods_{slug}.
   724 	if ( is_admin() && false === get_option( 'theme_mods_' . $stylesheet ) ) {
   769 	if ( is_admin() && false === get_option( 'theme_mods_' . $stylesheet ) ) {
   774 	 *
   819 	 *
   775 	 * @since 2.7.0
   820 	 * @since 2.7.0
   776 	 *
   821 	 *
   777 	 * @param bool $validate Whether to validate the current theme. Default true.
   822 	 * @param bool $validate Whether to validate the current theme. Default true.
   778 	 */
   823 	 */
   779 	if ( wp_installing() || ! apply_filters( 'validate_current_theme', true ) )
   824 	if ( wp_installing() || ! apply_filters( 'validate_current_theme', true ) ) {
   780 		return true;
   825 		return true;
       
   826 	}
   781 
   827 
   782 	if ( ! file_exists( get_template_directory() . '/index.php' ) ) {
   828 	if ( ! file_exists( get_template_directory() . '/index.php' ) ) {
   783 		// Invalid.
   829 		// Invalid.
   784 	} elseif ( ! file_exists( get_template_directory() . '/style.css' ) ) {
   830 	} elseif ( ! file_exists( get_template_directory() . '/style.css' ) ) {
   785 		// Invalid.
   831 		// Invalid.
   821  *
   867  *
   822  * @return array|void Theme modifications.
   868  * @return array|void Theme modifications.
   823  */
   869  */
   824 function get_theme_mods() {
   870 function get_theme_mods() {
   825 	$theme_slug = get_option( 'stylesheet' );
   871 	$theme_slug = get_option( 'stylesheet' );
   826 	$mods = get_option( "theme_mods_$theme_slug" );
   872 	$mods       = get_option( "theme_mods_$theme_slug" );
   827 	if ( false === $mods ) {
   873 	if ( false === $mods ) {
   828 		$theme_name = get_option( 'current_theme' );
   874 		$theme_name = get_option( 'current_theme' );
   829 		if ( false === $theme_name )
   875 		if ( false === $theme_name ) {
   830 			$theme_name = wp_get_theme()->get('Name');
   876 			$theme_name = wp_get_theme()->get( 'Name' );
       
   877 		}
   831 		$mods = get_option( "mods_$theme_name" ); // Deprecated location.
   878 		$mods = get_option( "mods_$theme_name" ); // Deprecated location.
   832 		if ( is_admin() && false !== $mods ) {
   879 		if ( is_admin() && false !== $mods ) {
   833 			update_option( "theme_mods_$theme_slug", $mods );
   880 			update_option( "theme_mods_$theme_slug", $mods );
   834 			delete_option( "mods_$theme_name" );
   881 			delete_option( "mods_$theme_name" );
   835 		}
   882 		}
   847  *
   894  *
   848  * @since 2.1.0
   895  * @since 2.1.0
   849  *
   896  *
   850  * @param string      $name    Theme modification name.
   897  * @param string      $name    Theme modification name.
   851  * @param bool|string $default
   898  * @param bool|string $default
   852  * @return string
   899  * @return mixed
   853  */
   900  */
   854 function get_theme_mod( $name, $default = false ) {
   901 function get_theme_mod( $name, $default = false ) {
   855 	$mods = get_theme_mods();
   902 	$mods = get_theme_mods();
   856 
   903 
   857 	if ( isset( $mods[$name] ) ) {
   904 	if ( isset( $mods[ $name ] ) ) {
   858 		/**
   905 		/**
   859 		 * Filters the theme modification, or 'theme_mod', value.
   906 		 * Filters the theme modification, or 'theme_mod', value.
   860 		 *
   907 		 *
   861 		 * The dynamic portion of the hook name, `$name`, refers to
   908 		 * The dynamic portion of the hook name, `$name`, refers to
   862 		 * the key name of the modification array. For example,
   909 		 * the key name of the modification array. For example,
   865 		 *
   912 		 *
   866 		 * @since 2.2.0
   913 		 * @since 2.2.0
   867 		 *
   914 		 *
   868 		 * @param string $current_mod The value of the current theme modification.
   915 		 * @param string $current_mod The value of the current theme modification.
   869 		 */
   916 		 */
   870 		return apply_filters( "theme_mod_{$name}", $mods[$name] );
   917 		return apply_filters( "theme_mod_{$name}", $mods[ $name ] );
   871 	}
   918 	}
   872 
   919 
   873 	if ( is_string( $default ) )
   920 	if ( is_string( $default ) ) {
   874 		$default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
   921 		$default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
       
   922 	}
   875 
   923 
   876 	/** This filter is documented in wp-includes/theme.php */
   924 	/** This filter is documented in wp-includes/theme.php */
   877 	return apply_filters( "theme_mod_{$name}", $default );
   925 	return apply_filters( "theme_mod_{$name}", $default );
   878 }
   926 }
   879 
   927 
   884  *
   932  *
   885  * @param string $name  Theme modification name.
   933  * @param string $name  Theme modification name.
   886  * @param mixed  $value Theme modification value.
   934  * @param mixed  $value Theme modification value.
   887  */
   935  */
   888 function set_theme_mod( $name, $value ) {
   936 function set_theme_mod( $name, $value ) {
   889 	$mods = get_theme_mods();
   937 	$mods      = get_theme_mods();
   890 	$old_value = isset( $mods[ $name ] ) ? $mods[ $name ] : false;
   938 	$old_value = isset( $mods[ $name ] ) ? $mods[ $name ] : false;
   891 
   939 
   892 	/**
   940 	/**
   893 	 * Filters the theme mod value on save.
   941 	 * Filters the theme mod value on save.
   894 	 *
   942 	 *
   918  * @param string $name Theme modification name.
   966  * @param string $name Theme modification name.
   919  */
   967  */
   920 function remove_theme_mod( $name ) {
   968 function remove_theme_mod( $name ) {
   921 	$mods = get_theme_mods();
   969 	$mods = get_theme_mods();
   922 
   970 
   923 	if ( ! isset( $mods[ $name ] ) )
   971 	if ( ! isset( $mods[ $name ] ) ) {
   924 		return;
   972 		return;
       
   973 	}
   925 
   974 
   926 	unset( $mods[ $name ] );
   975 	unset( $mods[ $name ] );
   927 
   976 
   928 	if ( empty( $mods ) ) {
   977 	if ( empty( $mods ) ) {
   929 		remove_theme_mods();
   978 		remove_theme_mods();
   941 function remove_theme_mods() {
   990 function remove_theme_mods() {
   942 	delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
   991 	delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
   943 
   992 
   944 	// Old style.
   993 	// Old style.
   945 	$theme_name = get_option( 'current_theme' );
   994 	$theme_name = get_option( 'current_theme' );
   946 	if ( false === $theme_name )
   995 	if ( false === $theme_name ) {
   947 		$theme_name = wp_get_theme()->get('Name');
   996 		$theme_name = wp_get_theme()->get( 'Name' );
       
   997 	}
   948 	delete_option( 'mods_' . $theme_name );
   998 	delete_option( 'mods_' . $theme_name );
   949 }
   999 }
   950 
  1000 
   951 /**
  1001 /**
   952  * Retrieves the custom header text color in 3- or 6-digit hexadecimal form.
  1002  * Retrieves the custom header text color in 3- or 6-digit hexadecimal form.
   954  * @since 2.1.0
  1004  * @since 2.1.0
   955  *
  1005  *
   956  * @return string Header text color in 3- or 6-digit hexadecimal form (minus the hash symbol).
  1006  * @return string Header text color in 3- or 6-digit hexadecimal form (minus the hash symbol).
   957  */
  1007  */
   958 function get_header_textcolor() {
  1008 function get_header_textcolor() {
   959 	return get_theme_mod('header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
  1009 	return get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
   960 }
  1010 }
   961 
  1011 
   962 /**
  1012 /**
   963  * Displays the custom header text color in 3- or 6-digit hexadecimal form (minus the hash symbol).
  1013  * Displays the custom header text color in 3- or 6-digit hexadecimal form (minus the hash symbol).
   964  *
  1014  *
   974  * @since 3.4.0
  1024  * @since 3.4.0
   975  *
  1025  *
   976  * @return bool
  1026  * @return bool
   977  */
  1027  */
   978 function display_header_text() {
  1028 function display_header_text() {
   979 	if ( ! current_theme_supports( 'custom-header', 'header-text' ) )
  1029 	if ( ! current_theme_supports( 'custom-header', 'header-text' ) ) {
   980 		return false;
  1030 		return false;
       
  1031 	}
   981 
  1032 
   982 	$text_color = get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
  1033 	$text_color = get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
   983 	return 'blank' !== $text_color;
  1034 	return 'blank' !== $text_color;
   984 }
  1035 }
   985 
  1036 
  1004  * @return string|false
  1055  * @return string|false
  1005  */
  1056  */
  1006 function get_header_image() {
  1057 function get_header_image() {
  1007 	$url = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
  1058 	$url = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
  1008 
  1059 
  1009 	if ( 'remove-header' == $url )
  1060 	if ( 'remove-header' == $url ) {
  1010 		return false;
  1061 		return false;
  1011 
  1062 	}
  1012 	if ( is_random_header_image() )
  1063 
       
  1064 	if ( is_random_header_image() ) {
  1013 		$url = get_random_header_image();
  1065 		$url = get_random_header_image();
       
  1066 	}
  1014 
  1067 
  1015 	return esc_url_raw( set_url_scheme( $url ) );
  1068 	return esc_url_raw( set_url_scheme( $url ) );
  1016 }
  1069 }
  1017 
  1070 
  1018 /**
  1071 /**
  1023  * @param array $attr Optional. Additional attributes for the image tag. Can be used
  1076  * @param array $attr Optional. Additional attributes for the image tag. Can be used
  1024  *                              to override the default attributes. Default empty.
  1077  *                              to override the default attributes. Default empty.
  1025  * @return string HTML image element markup or empty string on failure.
  1078  * @return string HTML image element markup or empty string on failure.
  1026  */
  1079  */
  1027 function get_header_image_tag( $attr = array() ) {
  1080 function get_header_image_tag( $attr = array() ) {
  1028 	$header = get_custom_header();
  1081 	$header      = get_custom_header();
  1029 	$header->url = get_header_image();
  1082 	$header->url = get_header_image();
  1030 
  1083 
  1031 	if ( ! $header->url ) {
  1084 	if ( ! $header->url ) {
  1032 		return '';
  1085 		return '';
  1033 	}
  1086 	}
  1034 
  1087 
  1035 	$width = absint( $header->width );
  1088 	$width  = absint( $header->width );
  1036 	$height = absint( $header->height );
  1089 	$height = absint( $header->height );
  1037 
  1090 
  1038 	$attr = wp_parse_args(
  1091 	$attr = wp_parse_args(
  1039 		$attr,
  1092 		$attr,
  1040 		array(
  1093 		array(
  1041 			'src' => $header->url,
  1094 			'src'    => $header->url,
  1042 			'width' => $width,
  1095 			'width'  => $width,
  1043 			'height' => $height,
  1096 			'height' => $height,
  1044 			'alt' => get_bloginfo( 'name' ),
  1097 			'alt'    => get_bloginfo( 'name' ),
  1045 		)
  1098 		)
  1046 	);
  1099 	);
  1047 
  1100 
  1048 	// Generate 'srcset' and 'sizes' if not already present.
  1101 	// Generate 'srcset' and 'sizes' if not already present.
  1049 	if ( empty( $attr['srcset'] ) && ! empty( $header->attachment_id ) ) {
  1102 	if ( empty( $attr['srcset'] ) && ! empty( $header->attachment_id ) ) {
  1050 		$image_meta = get_post_meta( $header->attachment_id, '_wp_attachment_metadata', true );
  1103 		$image_meta = get_post_meta( $header->attachment_id, '_wp_attachment_metadata', true );
  1051 		$size_array = array( $width, $height );
  1104 		$size_array = array( $width, $height );
  1052 
  1105 
  1053 		if ( is_array( $image_meta ) ) {
  1106 		if ( is_array( $image_meta ) ) {
  1054 			$srcset = wp_calculate_image_srcset( $size_array, $header->url, $image_meta, $header->attachment_id );
  1107 			$srcset = wp_calculate_image_srcset( $size_array, $header->url, $image_meta, $header->attachment_id );
  1055 			$sizes = ! empty( $attr['sizes'] ) ? $attr['sizes'] : wp_calculate_image_sizes( $size_array, $header->url, $image_meta, $header->attachment_id );
  1108 			$sizes  = ! empty( $attr['sizes'] ) ? $attr['sizes'] : wp_calculate_image_sizes( $size_array, $header->url, $image_meta, $header->attachment_id );
  1056 
  1109 
  1057 			if ( $srcset && $sizes ) {
  1110 			if ( $srcset && $sizes ) {
  1058 				$attr['srcset'] = $srcset;
  1111 				$attr['srcset'] = $srcset;
  1059 				$attr['sizes'] = $sizes;
  1112 				$attr['sizes']  = $sizes;
  1060 			}
  1113 			}
  1061 		}
  1114 		}
  1062 	}
  1115 	}
  1063 
  1116 
  1064 	$attr = array_map( 'esc_attr', $attr );
  1117 	$attr = array_map( 'esc_attr', $attr );
  1109 	static $_wp_random_header = null;
  1162 	static $_wp_random_header = null;
  1110 
  1163 
  1111 	if ( empty( $_wp_random_header ) ) {
  1164 	if ( empty( $_wp_random_header ) ) {
  1112 		global $_wp_default_headers;
  1165 		global $_wp_default_headers;
  1113 		$header_image_mod = get_theme_mod( 'header_image', '' );
  1166 		$header_image_mod = get_theme_mod( 'header_image', '' );
  1114 		$headers = array();
  1167 		$headers          = array();
  1115 
  1168 
  1116 		if ( 'random-uploaded-image' == $header_image_mod )
  1169 		if ( 'random-uploaded-image' == $header_image_mod ) {
  1117 			$headers = get_uploaded_header_images();
  1170 			$headers = get_uploaded_header_images();
  1118 		elseif ( ! empty( $_wp_default_headers ) ) {
  1171 		} elseif ( ! empty( $_wp_default_headers ) ) {
  1119 			if ( 'random-default-image' == $header_image_mod ) {
  1172 			if ( 'random-default-image' == $header_image_mod ) {
  1120 				$headers = $_wp_default_headers;
  1173 				$headers = $_wp_default_headers;
  1121 			} else {
  1174 			} else {
  1122 				if ( current_theme_supports( 'custom-header', 'random-default' ) )
  1175 				if ( current_theme_supports( 'custom-header', 'random-default' ) ) {
  1123 					$headers = $_wp_default_headers;
  1176 					$headers = $_wp_default_headers;
  1124 			}
  1177 				}
  1125 		}
  1178 			}
  1126 
  1179 		}
  1127 		if ( empty( $headers ) )
  1180 
       
  1181 		if ( empty( $headers ) ) {
  1128 			return new stdClass;
  1182 			return new stdClass;
       
  1183 		}
  1129 
  1184 
  1130 		$_wp_random_header = (object) $headers[ array_rand( $headers ) ];
  1185 		$_wp_random_header = (object) $headers[ array_rand( $headers ) ];
  1131 
  1186 
  1132 		$_wp_random_header->url =  sprintf( $_wp_random_header->url, get_template_directory_uri(), get_stylesheet_directory_uri() );
  1187 		$_wp_random_header->url           = sprintf( $_wp_random_header->url, get_template_directory_uri(), get_stylesheet_directory_uri() );
  1133 		$_wp_random_header->thumbnail_url =  sprintf( $_wp_random_header->thumbnail_url, get_template_directory_uri(), get_stylesheet_directory_uri() );
  1188 		$_wp_random_header->thumbnail_url = sprintf( $_wp_random_header->thumbnail_url, get_template_directory_uri(), get_stylesheet_directory_uri() );
  1134 	}
  1189 	}
  1135 	return $_wp_random_header;
  1190 	return $_wp_random_header;
  1136 }
  1191 }
  1137 
  1192 
  1138 /**
  1193 /**
  1142  *
  1197  *
  1143  * @return string Path to header image
  1198  * @return string Path to header image
  1144  */
  1199  */
  1145 function get_random_header_image() {
  1200 function get_random_header_image() {
  1146 	$random_image = _get_random_header_data();
  1201 	$random_image = _get_random_header_data();
  1147 	if ( empty( $random_image->url ) )
  1202 	if ( empty( $random_image->url ) ) {
  1148 		return '';
  1203 		return '';
       
  1204 	}
  1149 	return $random_image->url;
  1205 	return $random_image->url;
  1150 }
  1206 }
  1151 
  1207 
  1152 /**
  1208 /**
  1153  * Check if random header image is in use.
  1209  * Check if random header image is in use.
  1163  */
  1219  */
  1164 function is_random_header_image( $type = 'any' ) {
  1220 function is_random_header_image( $type = 'any' ) {
  1165 	$header_image_mod = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
  1221 	$header_image_mod = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
  1166 
  1222 
  1167 	if ( 'any' == $type ) {
  1223 	if ( 'any' == $type ) {
  1168 		if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) )
  1224 		if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) ) {
  1169 			return true;
  1225 			return true;
       
  1226 		}
  1170 	} else {
  1227 	} else {
  1171 		if ( "random-$type-image" == $header_image_mod )
  1228 		if ( "random-$type-image" == $header_image_mod ) {
  1172 			return true;
  1229 			return true;
  1173 		elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image() )
  1230 		} elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image() ) {
  1174 			return true;
  1231 			return true;
       
  1232 		}
  1175 	}
  1233 	}
  1176 
  1234 
  1177 	return false;
  1235 	return false;
  1178 }
  1236 }
  1179 
  1237 
  1198  */
  1256  */
  1199 function get_uploaded_header_images() {
  1257 function get_uploaded_header_images() {
  1200 	$header_images = array();
  1258 	$header_images = array();
  1201 
  1259 
  1202 	// @todo caching
  1260 	// @todo caching
  1203 	$headers = get_posts( array( 'post_type' => 'attachment', 'meta_key' => '_wp_attachment_is_custom_header', 'meta_value' => get_option('stylesheet'), 'orderby' => 'none', 'nopaging' => true ) );
  1261 	$headers = get_posts(
  1204 
  1262 		array(
  1205 	if ( empty( $headers ) )
  1263 			'post_type'  => 'attachment',
       
  1264 			'meta_key'   => '_wp_attachment_is_custom_header',
       
  1265 			'meta_value' => get_option( 'stylesheet' ),
       
  1266 			'orderby'    => 'none',
       
  1267 			'nopaging'   => true,
       
  1268 		)
       
  1269 	);
       
  1270 
       
  1271 	if ( empty( $headers ) ) {
  1206 		return array();
  1272 		return array();
       
  1273 	}
  1207 
  1274 
  1208 	foreach ( (array) $headers as $header ) {
  1275 	foreach ( (array) $headers as $header ) {
  1209 		$url = esc_url_raw( wp_get_attachment_url( $header->ID ) );
  1276 		$url          = esc_url_raw( wp_get_attachment_url( $header->ID ) );
  1210 		$header_data = wp_get_attachment_metadata( $header->ID );
  1277 		$header_data  = wp_get_attachment_metadata( $header->ID );
  1211 		$header_index = $header->ID;
  1278 		$header_index = $header->ID;
  1212 
  1279 
  1213 		$header_images[$header_index] = array();
  1280 		$header_images[ $header_index ]                      = array();
  1214 		$header_images[$header_index]['attachment_id'] = $header->ID;
  1281 		$header_images[ $header_index ]['attachment_id']     = $header->ID;
  1215 		$header_images[$header_index]['url'] =  $url;
  1282 		$header_images[ $header_index ]['url']               = $url;
  1216 		$header_images[$header_index]['thumbnail_url'] = $url;
  1283 		$header_images[ $header_index ]['thumbnail_url']     = $url;
  1217 		$header_images[$header_index]['alt_text'] = get_post_meta( $header->ID, '_wp_attachment_image_alt', true );
  1284 		$header_images[ $header_index ]['alt_text']          = get_post_meta( $header->ID, '_wp_attachment_image_alt', true );
  1218 		$header_images[$header_index]['attachment_parent'] = isset( $header_data['attachment_parent'] ) ? $header_data['attachment_parent'] : '';
  1285 		$header_images[ $header_index ]['attachment_parent'] = isset( $header_data['attachment_parent'] ) ? $header_data['attachment_parent'] : '';
  1219 
  1286 
  1220 		if ( isset( $header_data['width'] ) )
  1287 		if ( isset( $header_data['width'] ) ) {
  1221 			$header_images[$header_index]['width'] = $header_data['width'];
  1288 			$header_images[ $header_index ]['width'] = $header_data['width'];
  1222 		if ( isset( $header_data['height'] ) )
  1289 		}
  1223 			$header_images[$header_index]['height'] = $header_data['height'];
  1290 		if ( isset( $header_data['height'] ) ) {
       
  1291 			$header_images[ $header_index ]['height'] = $header_data['height'];
       
  1292 		}
  1224 	}
  1293 	}
  1225 
  1294 
  1226 	return $header_images;
  1295 	return $header_images;
  1227 }
  1296 }
  1228 
  1297 
  1242 		$data = _get_random_header_data();
  1311 		$data = _get_random_header_data();
  1243 	} else {
  1312 	} else {
  1244 		$data = get_theme_mod( 'header_image_data' );
  1313 		$data = get_theme_mod( 'header_image_data' );
  1245 		if ( ! $data && current_theme_supports( 'custom-header', 'default-image' ) ) {
  1314 		if ( ! $data && current_theme_supports( 'custom-header', 'default-image' ) ) {
  1246 			$directory_args = array( get_template_directory_uri(), get_stylesheet_directory_uri() );
  1315 			$directory_args = array( get_template_directory_uri(), get_stylesheet_directory_uri() );
  1247 			$data = array();
  1316 			$data           = array();
  1248 			$data['url'] = $data['thumbnail_url'] = vsprintf( get_theme_support( 'custom-header', 'default-image' ), $directory_args );
  1317 			$data['url']    = $data['thumbnail_url'] = vsprintf( get_theme_support( 'custom-header', 'default-image' ), $directory_args );
  1249 			if ( ! empty( $_wp_default_headers ) ) {
  1318 			if ( ! empty( $_wp_default_headers ) ) {
  1250 				foreach ( (array) $_wp_default_headers as $default_header ) {
  1319 				foreach ( (array) $_wp_default_headers as $default_header ) {
  1251 					$url = vsprintf( $default_header['url'], $directory_args );
  1320 					$url = vsprintf( $default_header['url'], $directory_args );
  1252 					if ( $data['url'] == $url ) {
  1321 					if ( $data['url'] == $url ) {
  1253 						$data = $default_header;
  1322 						$data                  = $default_header;
  1254 						$data['url'] = $url;
  1323 						$data['url']           = $url;
  1255 						$data['thumbnail_url'] = vsprintf( $data['thumbnail_url'], $directory_args );
  1324 						$data['thumbnail_url'] = vsprintf( $data['thumbnail_url'], $directory_args );
  1256 						break;
  1325 						break;
  1257 					}
  1326 					}
  1258 				}
  1327 				}
  1259 			}
  1328 			}
  1333  * @since 4.7.0
  1402  * @since 4.7.0
  1334  *
  1403  *
  1335  * @return string|false Header video URL or false if there is no video.
  1404  * @return string|false Header video URL or false if there is no video.
  1336  */
  1405  */
  1337 function get_header_video_url() {
  1406 function get_header_video_url() {
  1338 	$id = absint( get_theme_mod( 'header_video' ) );
  1407 	$id  = absint( get_theme_mod( 'header_video' ) );
  1339 	$url = esc_url( get_theme_mod( 'external_header_video' ) );
  1408 	$url = esc_url( get_theme_mod( 'external_header_video' ) );
  1340 
  1409 
  1341 	if ( $id ) {
  1410 	if ( $id ) {
  1342 		// Get the file URL from the attachment ID.
  1411 		// Get the file URL from the attachment ID.
  1343 		$url = wp_get_attachment_url( $id );
  1412 		$url = wp_get_attachment_url( $id );
  1392 		'minWidth'  => 900,
  1461 		'minWidth'  => 900,
  1393 		'minHeight' => 500,
  1462 		'minHeight' => 500,
  1394 		'l10n'      => array(
  1463 		'l10n'      => array(
  1395 			'pause'      => __( 'Pause' ),
  1464 			'pause'      => __( 'Pause' ),
  1396 			'play'       => __( 'Play' ),
  1465 			'play'       => __( 'Play' ),
  1397 			'pauseSpeak' => __( 'Video is paused.'),
  1466 			'pauseSpeak' => __( 'Video is paused.' ),
  1398 			'playSpeak'  => __( 'Video is playing.'),
  1467 			'playSpeak'  => __( 'Video is playing.' ),
  1399 		),
  1468 		),
  1400 	);
  1469 	);
  1401 
  1470 
  1402 	if ( preg_match( '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#', $video_url ) ) {
  1471 	if ( preg_match( '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#', $video_url ) ) {
  1403 		$settings['mimeType'] = 'video/x-youtube';
  1472 		$settings['mimeType'] = 'video/x-youtube';
  1404 	} elseif ( ! empty( $video_type['type'] ) ) {
  1473 	} elseif ( ! empty( $video_type['type'] ) ) {
  1405 		$settings['mimeType'] = $video_type['type'];
  1474 		$settings['mimeType'] = $video_type['type'];
  1406 	}
  1475 	}
  1407 
  1476 
       
  1477 	/**
       
  1478 	 * Filters header video settings.
       
  1479 	 *
       
  1480 	 * @since 4.7.0
       
  1481 	 *
       
  1482 	 * @param array $settings An array of header video settings.
       
  1483 	 */
  1408 	return apply_filters( 'header_video_settings', $settings );
  1484 	return apply_filters( 'header_video_settings', $settings );
  1409 }
  1485 }
  1410 
  1486 
  1411 /**
  1487 /**
  1412  * Check whether a custom header is set or not.
  1488  * Check whether a custom header is set or not.
  1502  * @since 3.0.0
  1578  * @since 3.0.0
  1503  *
  1579  *
  1504  * @return string
  1580  * @return string
  1505  */
  1581  */
  1506 function get_background_image() {
  1582 function get_background_image() {
  1507 	return get_theme_mod('background_image', get_theme_support( 'custom-background', 'default-image' ) );
  1583 	return get_theme_mod( 'background_image', get_theme_support( 'custom-background', 'default-image' ) );
  1508 }
  1584 }
  1509 
  1585 
  1510 /**
  1586 /**
  1511  * Display background image path.
  1587  * Display background image path.
  1512  *
  1588  *
  1522  * @since 3.0.0
  1598  * @since 3.0.0
  1523  *
  1599  *
  1524  * @return string
  1600  * @return string
  1525  */
  1601  */
  1526 function get_background_color() {
  1602 function get_background_color() {
  1527 	return get_theme_mod('background_color', get_theme_support( 'custom-background', 'default-color' ) );
  1603 	return get_theme_mod( 'background_color', get_theme_support( 'custom-background', 'default-color' ) );
  1528 }
  1604 }
  1529 
  1605 
  1530 /**
  1606 /**
  1531  * Display background color value.
  1607  * Display background color value.
  1532  *
  1608  *
  1606 
  1682 
  1607 		$attachment = " background-attachment: $attachment;";
  1683 		$attachment = " background-attachment: $attachment;";
  1608 
  1684 
  1609 		$style .= $image . $position . $size . $repeat . $attachment;
  1685 		$style .= $image . $position . $size . $repeat . $attachment;
  1610 	}
  1686 	}
  1611 ?>
  1687 	?>
  1612 <style type="text/css" id="custom-background-css">
  1688 <style type="text/css" id="custom-background-css">
  1613 body.custom-background { <?php echo trim( $style ); ?> }
  1689 body.custom-background { <?php echo trim( $style ); ?> }
  1614 </style>
  1690 </style>
  1615 <?php
  1691 	<?php
  1616 }
  1692 }
  1617 
  1693 
  1618 /**
  1694 /**
  1619  * Render the Custom CSS style element.
  1695  * Render the Custom CSS style element.
  1620  *
  1696  *
  1621  * @since 4.7.0
  1697  * @since 4.7.0
  1622  */
  1698  */
  1623 function wp_custom_css_cb() {
  1699 function wp_custom_css_cb() {
  1624 	$styles = wp_get_custom_css();
  1700 	$styles = wp_get_custom_css();
  1625 	if ( $styles || is_customize_preview() ) : ?>
  1701 	if ( $styles || is_customize_preview() ) :
       
  1702 		?>
  1626 		<style type="text/css" id="wp-custom-css">
  1703 		<style type="text/css" id="wp-custom-css">
  1627 			<?php echo strip_tags( $styles ); // Note that esc_html() cannot be used because `div &gt; span` is not interpreted properly. ?>
  1704 			<?php echo strip_tags( $styles ); // Note that esc_html() cannot be used because `div &gt; span` is not interpreted properly. ?>
  1628 		</style>
  1705 		</style>
  1629 	<?php endif;
  1706 		<?php
       
  1707 	endif;
  1630 }
  1708 }
  1631 
  1709 
  1632 /**
  1710 /**
  1633  * Fetch the `custom_css` post for a given theme.
  1711  * Fetch the `custom_css` post for a given theme.
  1634  *
  1712  *
  1663 		}
  1741 		}
  1664 
  1742 
  1665 		// `-1` indicates no post exists; no query necessary.
  1743 		// `-1` indicates no post exists; no query necessary.
  1666 		if ( ! $post && -1 !== $post_id ) {
  1744 		if ( ! $post && -1 !== $post_id ) {
  1667 			$query = new WP_Query( $custom_css_query_vars );
  1745 			$query = new WP_Query( $custom_css_query_vars );
  1668 			$post = $query->post;
  1746 			$post  = $query->post;
  1669 			/*
  1747 			/*
  1670 			 * Cache the lookup. See wp_update_custom_css_post().
  1748 			 * Cache the lookup. See wp_update_custom_css_post().
  1671 			 * @todo This should get cleared if a custom_css post is added/removed.
  1749 			 * @todo This should get cleared if a custom_css post is added/removed.
  1672 			 */
  1750 			 */
  1673 			set_theme_mod( 'custom_css_post_id', $post ? $post->ID : -1 );
  1751 			set_theme_mod( 'custom_css_post_id', $post ? $post->ID : -1 );
  1674 		}
  1752 		}
  1675 	} else {
  1753 	} else {
  1676 		$query = new WP_Query( $custom_css_query_vars );
  1754 		$query = new WP_Query( $custom_css_query_vars );
  1677 		$post = $query->post;
  1755 		$post  = $query->post;
  1678 	}
  1756 	}
  1679 
  1757 
  1680 	return $post;
  1758 	return $post;
  1681 }
  1759 }
  1682 
  1760 
  1728  *     @type string $stylesheet   Stylesheet (child theme) to update. Optional, defaults to current theme/stylesheet.
  1806  *     @type string $stylesheet   Stylesheet (child theme) to update. Optional, defaults to current theme/stylesheet.
  1729  * }
  1807  * }
  1730  * @return WP_Post|WP_Error Post on success, error on failure.
  1808  * @return WP_Post|WP_Error Post on success, error on failure.
  1731  */
  1809  */
  1732 function wp_update_custom_css_post( $css, $args = array() ) {
  1810 function wp_update_custom_css_post( $css, $args = array() ) {
  1733 	$args = wp_parse_args( $args, array(
  1811 	$args = wp_parse_args(
  1734 		'preprocessed' => '',
  1812 		$args,
  1735 		'stylesheet' => get_stylesheet(),
  1813 		array(
  1736 	) );
  1814 			'preprocessed' => '',
       
  1815 			'stylesheet'   => get_stylesheet(),
       
  1816 		)
       
  1817 	);
  1737 
  1818 
  1738 	$data = array(
  1819 	$data = array(
  1739 		'css' => $css,
  1820 		'css'          => $css,
  1740 		'preprocessed' => $args['preprocessed'],
  1821 		'preprocessed' => $args['preprocessed'],
  1741 	);
  1822 	);
  1742 
  1823 
  1743 	/**
  1824 	/**
  1744 	 * Filters the `css` (`post_content`) and `preprocessed` (`post_content_filtered`) args for a `custom_css` post being updated.
  1825 	 * Filters the `css` (`post_content`) and `preprocessed` (`post_content_filtered`) args for a `custom_css` post being updated.
  1774 	 * }
  1855 	 * }
  1775 	 */
  1856 	 */
  1776 	$data = apply_filters( 'update_custom_css_data', $data, array_merge( $args, compact( 'css' ) ) );
  1857 	$data = apply_filters( 'update_custom_css_data', $data, array_merge( $args, compact( 'css' ) ) );
  1777 
  1858 
  1778 	$post_data = array(
  1859 	$post_data = array(
  1779 		'post_title' => $args['stylesheet'],
  1860 		'post_title'            => $args['stylesheet'],
  1780 		'post_name' => sanitize_title( $args['stylesheet'] ),
  1861 		'post_name'             => sanitize_title( $args['stylesheet'] ),
  1781 		'post_type' => 'custom_css',
  1862 		'post_type'             => 'custom_css',
  1782 		'post_status' => 'publish',
  1863 		'post_status'           => 'publish',
  1783 		'post_content' => $data['css'],
  1864 		'post_content'          => $data['css'],
  1784 		'post_content_filtered' => $data['preprocessed'],
  1865 		'post_content_filtered' => $data['preprocessed'],
  1785 	);
  1866 	);
  1786 
  1867 
  1787 	// Update post if it already exists, otherwise create a new one.
  1868 	// Update post if it already exists, otherwise create a new one.
  1788 	$post = wp_get_custom_css_post( $args['stylesheet'] );
  1869 	$post = wp_get_custom_css_post( $args['stylesheet'] );
  1789 	if ( $post ) {
  1870 	if ( $post ) {
  1790 		$post_data['ID'] = $post->ID;
  1871 		$post_data['ID'] = $post->ID;
  1791 		$r = wp_update_post( wp_slash( $post_data ), true );
  1872 		$r               = wp_update_post( wp_slash( $post_data ), true );
  1792 	} else {
  1873 	} else {
  1793 		$r = wp_insert_post( wp_slash( $post_data ), true );
  1874 		$r = wp_insert_post( wp_slash( $post_data ), true );
  1794 
  1875 
  1795 		if ( ! is_wp_error( $r ) ) {
  1876 		if ( ! is_wp_error( $r ) ) {
  1796 			if ( get_stylesheet() === $args['stylesheet'] ) {
  1877 			if ( get_stylesheet() === $args['stylesheet'] ) {
  1828  * @since 3.0.0
  1909  * @since 3.0.0
  1829  *
  1910  *
  1830  * @global array $editor_styles
  1911  * @global array $editor_styles
  1831  *
  1912  *
  1832  * @param array|string $stylesheet Optional. Stylesheet name or array thereof, relative to theme root.
  1913  * @param array|string $stylesheet Optional. Stylesheet name or array thereof, relative to theme root.
  1833  * 	                               Defaults to 'editor-style.css'
  1914  *                                 Defaults to 'editor-style.css'
  1834  */
  1915  */
  1835 function add_editor_style( $stylesheet = 'editor-style.css' ) {
  1916 function add_editor_style( $stylesheet = 'editor-style.css' ) {
  1836 	add_theme_support( 'editor-style' );
  1917 	add_theme_support( 'editor-style' );
  1837 
  1918 
  1838 	if ( ! is_admin() )
  1919 	if ( ! is_admin() ) {
  1839 		return;
  1920 		return;
       
  1921 	}
  1840 
  1922 
  1841 	global $editor_styles;
  1923 	global $editor_styles;
  1842 	$editor_styles = (array) $editor_styles;
  1924 	$editor_styles = (array) $editor_styles;
  1843 	$stylesheet    = (array) $stylesheet;
  1925 	$stylesheet    = (array) $stylesheet;
  1844 	if ( is_rtl() ) {
  1926 	if ( is_rtl() ) {
  1845 		$rtl_stylesheet = str_replace('.css', '-rtl.css', $stylesheet[0]);
  1927 		$rtl_stylesheet = str_replace( '.css', '-rtl.css', $stylesheet[0] );
  1846 		$stylesheet[] = $rtl_stylesheet;
  1928 		$stylesheet[]   = $rtl_stylesheet;
  1847 	}
  1929 	}
  1848 
  1930 
  1849 	$editor_styles = array_merge( $editor_styles, $stylesheet );
  1931 	$editor_styles = array_merge( $editor_styles, $stylesheet );
  1850 }
  1932 }
  1851 
  1933 
  1857  * @global array $editor_styles
  1939  * @global array $editor_styles
  1858  *
  1940  *
  1859  * @return bool True on success, false if there were no stylesheets to remove.
  1941  * @return bool True on success, false if there were no stylesheets to remove.
  1860  */
  1942  */
  1861 function remove_editor_styles() {
  1943 function remove_editor_styles() {
  1862 	if ( ! current_theme_supports( 'editor-style' ) )
  1944 	if ( ! current_theme_supports( 'editor-style' ) ) {
  1863 		return false;
  1945 		return false;
       
  1946 	}
  1864 	_remove_theme_support( 'editor-style' );
  1947 	_remove_theme_support( 'editor-style' );
  1865 	if ( is_admin() )
  1948 	if ( is_admin() ) {
  1866 		$GLOBALS['editor_styles'] = array();
  1949 		$GLOBALS['editor_styles'] = array();
       
  1950 	}
  1867 	return true;
  1951 	return true;
  1868 }
  1952 }
  1869 
  1953 
  1870 /**
  1954 /**
  1871  * Retrieve any registered editor stylesheets
  1955  * Retrieve any registered editor stylesheets
  1881 	// load editor_style.css if the current theme supports it
  1965 	// load editor_style.css if the current theme supports it
  1882 	if ( ! empty( $GLOBALS['editor_styles'] ) && is_array( $GLOBALS['editor_styles'] ) ) {
  1966 	if ( ! empty( $GLOBALS['editor_styles'] ) && is_array( $GLOBALS['editor_styles'] ) ) {
  1883 		$editor_styles = $GLOBALS['editor_styles'];
  1967 		$editor_styles = $GLOBALS['editor_styles'];
  1884 
  1968 
  1885 		$editor_styles = array_unique( array_filter( $editor_styles ) );
  1969 		$editor_styles = array_unique( array_filter( $editor_styles ) );
  1886 		$style_uri = get_stylesheet_directory_uri();
  1970 		$style_uri     = get_stylesheet_directory_uri();
  1887 		$style_dir = get_stylesheet_directory();
  1971 		$style_dir     = get_stylesheet_directory();
  1888 
  1972 
  1889 		// Support externally referenced styles (like, say, fonts).
  1973 		// Support externally referenced styles (like, say, fonts).
  1890 		foreach ( $editor_styles as $key => $file ) {
  1974 		foreach ( $editor_styles as $key => $file ) {
  1891 			if ( preg_match( '~^(https?:)?//~', $file ) ) {
  1975 			if ( preg_match( '~^(https?:)?//~', $file ) ) {
  1892 				$stylesheets[] = esc_url_raw( $file );
  1976 				$stylesheets[] = esc_url_raw( $file );
  1937 	} else {
  2021 	} else {
  1938 		$config = array();
  2022 		$config = array();
  1939 	}
  2023 	}
  1940 
  2024 
  1941 	$core_content = array(
  2025 	$core_content = array(
  1942 		'widgets' => array(
  2026 		'widgets'   => array(
  1943 			'text_business_info' => array( 'text', array(
  2027 			'text_business_info' => array(
  1944 				'title' => _x( 'Find Us', 'Theme starter content' ),
  2028 				'text',
  1945 				'text' => join( '', array(
  2029 				array(
  1946 					'<strong>' . _x( 'Address', 'Theme starter content' ) . "</strong>\n",
  2030 					'title'  => _x( 'Find Us', 'Theme starter content' ),
  1947 					_x( '123 Main Street', 'Theme starter content' ) . "\n" . _x( 'New York, NY 10001', 'Theme starter content' ) . "\n\n",
  2031 					'text'   => join(
  1948 					'<strong>' . _x( 'Hours', 'Theme starter content' ) . "</strong>\n",
  2032 						'',
  1949 					_x( 'Monday&mdash;Friday: 9:00AM&ndash;5:00PM', 'Theme starter content' ) . "\n" . _x( 'Saturday &amp; Sunday: 11:00AM&ndash;3:00PM', 'Theme starter content' )
  2033 						array(
  1950 				) ),
  2034 							'<strong>' . _x( 'Address', 'Theme starter content' ) . "</strong>\n",
  1951 				'filter' => true,
  2035 							_x( '123 Main Street', 'Theme starter content' ) . "\n" . _x( 'New York, NY 10001', 'Theme starter content' ) . "\n\n",
  1952 				'visual' => true,
  2036 							'<strong>' . _x( 'Hours', 'Theme starter content' ) . "</strong>\n",
  1953 			) ),
  2037 							_x( 'Monday&mdash;Friday: 9:00AM&ndash;5:00PM', 'Theme starter content' ) . "\n" . _x( 'Saturday &amp; Sunday: 11:00AM&ndash;3:00PM', 'Theme starter content' ),
  1954 			'text_about' => array( 'text', array(
  2038 						)
  1955 				'title' => _x( 'About This Site', 'Theme starter content' ),
  2039 					),
  1956 				'text' => _x( 'This may be a good place to introduce yourself and your site or include some credits.', 'Theme starter content' ),
  2040 					'filter' => true,
  1957 				'filter' => true,
  2041 					'visual' => true,
  1958 				'visual' => true,
  2042 				),
  1959 			) ),
  2043 			),
  1960 			'archives' => array( 'archives', array(
  2044 			'text_about'         => array(
  1961 				'title' => _x( 'Archives', 'Theme starter content' ),
  2045 				'text',
  1962 			) ),
  2046 				array(
  1963 			'calendar' => array( 'calendar', array(
  2047 					'title'  => _x( 'About This Site', 'Theme starter content' ),
  1964 				'title' => _x( 'Calendar', 'Theme starter content' ),
  2048 					'text'   => _x( 'This may be a good place to introduce yourself and your site or include some credits.', 'Theme starter content' ),
  1965 			) ),
  2049 					'filter' => true,
  1966 			'categories' => array( 'categories', array(
  2050 					'visual' => true,
  1967 				'title' => _x( 'Categories', 'Theme starter content' ),
  2051 				),
  1968 			) ),
  2052 			),
  1969 			'meta' => array( 'meta', array(
  2053 			'archives'           => array(
  1970 				'title' => _x( 'Meta', 'Theme starter content' ),
  2054 				'archives',
  1971 			) ),
  2055 				array(
  1972 			'recent-comments' => array( 'recent-comments', array(
  2056 					'title' => _x( 'Archives', 'Theme starter content' ),
  1973 				'title' => _x( 'Recent Comments', 'Theme starter content' ),
  2057 				),
  1974 			) ),
  2058 			),
  1975 			'recent-posts' => array( 'recent-posts', array(
  2059 			'calendar'           => array(
  1976 				'title' => _x( 'Recent Posts', 'Theme starter content' ),
  2060 				'calendar',
  1977 			) ),
  2061 				array(
  1978 			'search' => array( 'search', array(
  2062 					'title' => _x( 'Calendar', 'Theme starter content' ),
  1979 				'title' => _x( 'Search', 'Theme starter content' ),
  2063 				),
  1980 			) ),
  2064 			),
       
  2065 			'categories'         => array(
       
  2066 				'categories',
       
  2067 				array(
       
  2068 					'title' => _x( 'Categories', 'Theme starter content' ),
       
  2069 				),
       
  2070 			),
       
  2071 			'meta'               => array(
       
  2072 				'meta',
       
  2073 				array(
       
  2074 					'title' => _x( 'Meta', 'Theme starter content' ),
       
  2075 				),
       
  2076 			),
       
  2077 			'recent-comments'    => array(
       
  2078 				'recent-comments',
       
  2079 				array(
       
  2080 					'title' => _x( 'Recent Comments', 'Theme starter content' ),
       
  2081 				),
       
  2082 			),
       
  2083 			'recent-posts'       => array(
       
  2084 				'recent-posts',
       
  2085 				array(
       
  2086 					'title' => _x( 'Recent Posts', 'Theme starter content' ),
       
  2087 				),
       
  2088 			),
       
  2089 			'search'             => array(
       
  2090 				'search',
       
  2091 				array(
       
  2092 					'title' => _x( 'Search', 'Theme starter content' ),
       
  2093 				),
       
  2094 			),
  1981 		),
  2095 		),
  1982 		'nav_menus' => array(
  2096 		'nav_menus' => array(
  1983 			'link_home' => array(
  2097 			'link_home'       => array(
  1984 				'type' => 'custom',
  2098 				'type'  => 'custom',
  1985 				'title' => _x( 'Home', 'Theme starter content' ),
  2099 				'title' => _x( 'Home', 'Theme starter content' ),
  1986 				'url' => home_url( '/' ),
  2100 				'url'   => home_url( '/' ),
  1987 			),
  2101 			),
  1988 			'page_home' => array( // Deprecated in favor of link_home.
  2102 			'page_home'       => array( // Deprecated in favor of link_home.
  1989 				'type' => 'post_type',
  2103 				'type'      => 'post_type',
  1990 				'object' => 'page',
  2104 				'object'    => 'page',
  1991 				'object_id' => '{{home}}',
  2105 				'object_id' => '{{home}}',
  1992 			),
  2106 			),
  1993 			'page_about' => array(
  2107 			'page_about'      => array(
  1994 				'type' => 'post_type',
  2108 				'type'      => 'post_type',
  1995 				'object' => 'page',
  2109 				'object'    => 'page',
  1996 				'object_id' => '{{about}}',
  2110 				'object_id' => '{{about}}',
  1997 			),
  2111 			),
  1998 			'page_blog' => array(
  2112 			'page_blog'       => array(
  1999 				'type' => 'post_type',
  2113 				'type'      => 'post_type',
  2000 				'object' => 'page',
  2114 				'object'    => 'page',
  2001 				'object_id' => '{{blog}}',
  2115 				'object_id' => '{{blog}}',
  2002 			),
  2116 			),
  2003 			'page_news' => array(
  2117 			'page_news'       => array(
  2004 				'type' => 'post_type',
  2118 				'type'      => 'post_type',
  2005 				'object' => 'page',
  2119 				'object'    => 'page',
  2006 				'object_id' => '{{news}}',
  2120 				'object_id' => '{{news}}',
  2007 			),
  2121 			),
  2008 			'page_contact' => array(
  2122 			'page_contact'    => array(
  2009 				'type' => 'post_type',
  2123 				'type'      => 'post_type',
  2010 				'object' => 'page',
  2124 				'object'    => 'page',
  2011 				'object_id' => '{{contact}}',
  2125 				'object_id' => '{{contact}}',
  2012 			),
  2126 			),
  2013 
  2127 
  2014 			'link_email' => array(
  2128 			'link_email'      => array(
  2015 				'title' => _x( 'Email', 'Theme starter content' ),
  2129 				'title' => _x( 'Email', 'Theme starter content' ),
  2016 				'url' => 'mailto:wordpress@example.com',
  2130 				'url'   => 'mailto:wordpress@example.com',
  2017 			),
  2131 			),
  2018 			'link_facebook' => array(
  2132 			'link_facebook'   => array(
  2019 				'title' => _x( 'Facebook', 'Theme starter content' ),
  2133 				'title' => _x( 'Facebook', 'Theme starter content' ),
  2020 				'url' => 'https://www.facebook.com/wordpress',
  2134 				'url'   => 'https://www.facebook.com/wordpress',
  2021 			),
  2135 			),
  2022 			'link_foursquare' => array(
  2136 			'link_foursquare' => array(
  2023 				'title' => _x( 'Foursquare', 'Theme starter content' ),
  2137 				'title' => _x( 'Foursquare', 'Theme starter content' ),
  2024 				'url' => 'https://foursquare.com/',
  2138 				'url'   => 'https://foursquare.com/',
  2025 			),
  2139 			),
  2026 			'link_github' => array(
  2140 			'link_github'     => array(
  2027 				'title' => _x( 'GitHub', 'Theme starter content' ),
  2141 				'title' => _x( 'GitHub', 'Theme starter content' ),
  2028 				'url' => 'https://github.com/wordpress/',
  2142 				'url'   => 'https://github.com/wordpress/',
  2029 			),
  2143 			),
  2030 			'link_instagram' => array(
  2144 			'link_instagram'  => array(
  2031 				'title' => _x( 'Instagram', 'Theme starter content' ),
  2145 				'title' => _x( 'Instagram', 'Theme starter content' ),
  2032 				'url' => 'https://www.instagram.com/explore/tags/wordcamp/',
  2146 				'url'   => 'https://www.instagram.com/explore/tags/wordcamp/',
  2033 			),
  2147 			),
  2034 			'link_linkedin' => array(
  2148 			'link_linkedin'   => array(
  2035 				'title' => _x( 'LinkedIn', 'Theme starter content' ),
  2149 				'title' => _x( 'LinkedIn', 'Theme starter content' ),
  2036 				'url' => 'https://www.linkedin.com/company/1089783',
  2150 				'url'   => 'https://www.linkedin.com/company/1089783',
  2037 			),
  2151 			),
  2038 			'link_pinterest' => array(
  2152 			'link_pinterest'  => array(
  2039 				'title' => _x( 'Pinterest', 'Theme starter content' ),
  2153 				'title' => _x( 'Pinterest', 'Theme starter content' ),
  2040 				'url' => 'https://www.pinterest.com/',
  2154 				'url'   => 'https://www.pinterest.com/',
  2041 			),
  2155 			),
  2042 			'link_twitter' => array(
  2156 			'link_twitter'    => array(
  2043 				'title' => _x( 'Twitter', 'Theme starter content' ),
  2157 				'title' => _x( 'Twitter', 'Theme starter content' ),
  2044 				'url' => 'https://twitter.com/wordpress',
  2158 				'url'   => 'https://twitter.com/wordpress',
  2045 			),
  2159 			),
  2046 			'link_yelp' => array(
  2160 			'link_yelp'       => array(
  2047 				'title' => _x( 'Yelp', 'Theme starter content' ),
  2161 				'title' => _x( 'Yelp', 'Theme starter content' ),
  2048 				'url' => 'https://www.yelp.com',
  2162 				'url'   => 'https://www.yelp.com',
  2049 			),
  2163 			),
  2050 			'link_youtube' => array(
  2164 			'link_youtube'    => array(
  2051 				'title' => _x( 'YouTube', 'Theme starter content' ),
  2165 				'title' => _x( 'YouTube', 'Theme starter content' ),
  2052 				'url' => 'https://www.youtube.com/channel/UCdof4Ju7amm1chz1gi1T2ZA',
  2166 				'url'   => 'https://www.youtube.com/channel/UCdof4Ju7amm1chz1gi1T2ZA',
  2053 			),
  2167 			),
  2054 		),
  2168 		),
  2055 		'posts' => array(
  2169 		'posts'     => array(
  2056 			'home' => array(
  2170 			'home'             => array(
  2057 				'post_type' => 'page',
  2171 				'post_type'    => 'page',
  2058 				'post_title' => _x( 'Home', 'Theme starter content' ),
  2172 				'post_title'   => _x( 'Home', 'Theme starter content' ),
  2059 				'post_content' => _x( 'Welcome to your site! This is your homepage, which is what most visitors will see when they come to your site for the first time.', 'Theme starter content' ),
  2173 				'post_content' => _x( 'Welcome to your site! This is your homepage, which is what most visitors will see when they come to your site for the first time.', 'Theme starter content' ),
  2060 			),
  2174 			),
  2061 			'about' => array(
  2175 			'about'            => array(
  2062 				'post_type' => 'page',
  2176 				'post_type'    => 'page',
  2063 				'post_title' => _x( 'About', 'Theme starter content' ),
  2177 				'post_title'   => _x( 'About', 'Theme starter content' ),
  2064 				'post_content' => _x( 'You might be an artist who would like to introduce yourself and your work here or maybe you&rsquo;re a business with a mission to describe.', 'Theme starter content' ),
  2178 				'post_content' => _x( 'You might be an artist who would like to introduce yourself and your work here or maybe you&rsquo;re a business with a mission to describe.', 'Theme starter content' ),
  2065 			),
  2179 			),
  2066 			'contact' => array(
  2180 			'contact'          => array(
  2067 				'post_type' => 'page',
  2181 				'post_type'    => 'page',
  2068 				'post_title' => _x( 'Contact', 'Theme starter content' ),
  2182 				'post_title'   => _x( 'Contact', 'Theme starter content' ),
  2069 				'post_content' => _x( 'This is a page with some basic contact information, such as an address and phone number. You might also try a plugin to add a contact form.', 'Theme starter content' ),
  2183 				'post_content' => _x( 'This is a page with some basic contact information, such as an address and phone number. You might also try a plugin to add a contact form.', 'Theme starter content' ),
  2070 			),
  2184 			),
  2071 			'blog' => array(
  2185 			'blog'             => array(
  2072 				'post_type' => 'page',
  2186 				'post_type'  => 'page',
  2073 				'post_title' => _x( 'Blog', 'Theme starter content' ),
  2187 				'post_title' => _x( 'Blog', 'Theme starter content' ),
  2074 			),
  2188 			),
  2075 			'news' => array(
  2189 			'news'             => array(
  2076 				'post_type' => 'page',
  2190 				'post_type'  => 'page',
  2077 				'post_title' => _x( 'News', 'Theme starter content' ),
  2191 				'post_title' => _x( 'News', 'Theme starter content' ),
  2078 			),
  2192 			),
  2079 
  2193 
  2080 			'homepage-section' => array(
  2194 			'homepage-section' => array(
  2081 				'post_type' => 'page',
  2195 				'post_type'    => 'page',
  2082 				'post_title' => _x( 'A homepage section', 'Theme starter content' ),
  2196 				'post_title'   => _x( 'A homepage section', 'Theme starter content' ),
  2083 				'post_content' => _x( 'This is an example of a homepage section. Homepage sections can be any page other than the homepage itself, including the page that shows your latest blog posts.', 'Theme starter content' ),
  2197 				'post_content' => _x( 'This is an example of a homepage section. Homepage sections can be any page other than the homepage itself, including the page that shows your latest blog posts.', 'Theme starter content' ),
  2084 			),
  2198 			),
  2085 		),
  2199 		),
  2086 	);
  2200 	);
  2087 
  2201 
  2088 	$content = array();
  2202 	$content = array();
  2089 
  2203 
  2090 	foreach ( $config as $type => $args ) {
  2204 	foreach ( $config as $type => $args ) {
  2091 		switch( $type ) {
  2205 		switch ( $type ) {
  2092 			// Use options and theme_mods as-is.
  2206 			// Use options and theme_mods as-is.
  2093 			case 'options' :
  2207 			case 'options':
  2094 			case 'theme_mods' :
  2208 			case 'theme_mods':
  2095 				$content[ $type ] = $config[ $type ];
  2209 				$content[ $type ] = $config[ $type ];
  2096 				break;
  2210 				break;
  2097 
  2211 
  2098 			// Widgets are grouped into sidebars.
  2212 			// Widgets are grouped into sidebars.
  2099 			case 'widgets' :
  2213 			case 'widgets':
  2100 				foreach ( $config[ $type ] as $sidebar_id => $widgets ) {
  2214 				foreach ( $config[ $type ] as $sidebar_id => $widgets ) {
  2101 					foreach ( $widgets as $id => $widget ) {
  2215 					foreach ( $widgets as $id => $widget ) {
  2102 						if ( is_array( $widget ) ) {
  2216 						if ( is_array( $widget ) ) {
  2103 
  2217 
  2104 							// Item extends core content.
  2218 							// Item extends core content.
  2116 					}
  2230 					}
  2117 				}
  2231 				}
  2118 				break;
  2232 				break;
  2119 
  2233 
  2120 			// And nav menu items are grouped into nav menus.
  2234 			// And nav menu items are grouped into nav menus.
  2121 			case 'nav_menus' :
  2235 			case 'nav_menus':
  2122 				foreach ( $config[ $type ] as $nav_menu_location => $nav_menu ) {
  2236 				foreach ( $config[ $type ] as $nav_menu_location => $nav_menu ) {
  2123 
  2237 
  2124 					// Ensure nav menus get a name.
  2238 					// Ensure nav menus get a name.
  2125 					if ( empty( $nav_menu['name'] ) ) {
  2239 					if ( empty( $nav_menu['name'] ) ) {
  2126 						$nav_menu['name'] = $nav_menu_location;
  2240 						$nav_menu['name'] = $nav_menu_location;
  2143 					}
  2257 					}
  2144 				}
  2258 				}
  2145 				break;
  2259 				break;
  2146 
  2260 
  2147 			// Attachments are posts but have special treatment.
  2261 			// Attachments are posts but have special treatment.
  2148 			case 'attachments' :
  2262 			case 'attachments':
  2149 				foreach ( $config[ $type ] as $id => $item ) {
  2263 				foreach ( $config[ $type ] as $id => $item ) {
  2150 					if ( ! empty( $item['file'] ) ) {
  2264 					if ( ! empty( $item['file'] ) ) {
  2151 						$content[ $type ][ $id ] = $item;
  2265 						$content[ $type ][ $id ] = $item;
  2152 					}
  2266 					}
  2153 				}
  2267 				}
  2154 				break;
  2268 				break;
  2155 
  2269 
  2156 			// All that's left now are posts (besides attachments). Not a default case for the sake of clarity and future work.
  2270 			// All that's left now are posts (besides attachments). Not a default case for the sake of clarity and future work.
  2157 			case 'posts' :
  2271 			case 'posts':
  2158 				foreach ( $config[ $type ] as $id => $item ) {
  2272 				foreach ( $config[ $type ] as $id => $item ) {
  2159 					if ( is_array( $item ) ) {
  2273 					if ( is_array( $item ) ) {
  2160 
  2274 
  2161 						// Item extends core content.
  2275 						// Item extends core content.
  2162 						if ( ! empty( $core_content[ $type ][ $id ] ) ) {
  2276 						if ( ! empty( $core_content[ $type ][ $id ] ) ) {
  2208  * @since 3.6.0 The `html5` feature was added
  2322  * @since 3.6.0 The `html5` feature was added
  2209  * @since 3.9.0 The `html5` feature now also accepts 'gallery' and 'caption'
  2323  * @since 3.9.0 The `html5` feature now also accepts 'gallery' and 'caption'
  2210  * @since 4.1.0 The `title-tag` feature was added
  2324  * @since 4.1.0 The `title-tag` feature was added
  2211  * @since 4.5.0 The `customize-selective-refresh-widgets` feature was added
  2325  * @since 4.5.0 The `customize-selective-refresh-widgets` feature was added
  2212  * @since 4.7.0 The `starter-content` feature was added
  2326  * @since 4.7.0 The `starter-content` feature was added
       
  2327  * @since 5.0.0 The `responsive-embeds`, `align-wide`, `dark-editor-style`, `disable-custom-colors`,
       
  2328  *              `disable-custom-font-sizes`, `editor-color-pallete`, `editor-font-sizes`,
       
  2329  *              `editor-styles`, and `wp-block-styles` features were added.
  2213  *
  2330  *
  2214  * @global array $_wp_theme_features
  2331  * @global array $_wp_theme_features
  2215  *
  2332  *
  2216  * @param string $feature  The feature being added. Likely core values include 'post-formats',
  2333  * @param string $feature  The feature being added. Likely core values include 'post-formats',
  2217  *                         'post-thumbnails', 'html5', 'custom-logo', 'custom-header-uploads',
  2334  *                         'post-thumbnails', 'html5', 'custom-logo', 'custom-header-uploads',
  2218  *                         'custom-header', 'custom-background', 'title-tag', 'starter-content', etc.
  2335  *                         'custom-header', 'custom-background', 'title-tag', 'starter-content',
       
  2336  *                         'responsive-embeds', etc.
  2219  * @param mixed  $args,... Optional extra arguments to pass along with certain features.
  2337  * @param mixed  $args,... Optional extra arguments to pass along with certain features.
  2220  * @return void|bool False on failure, void otherwise.
  2338  * @return void|bool False on failure, void otherwise.
  2221  */
  2339  */
  2222 function add_theme_support( $feature ) {
  2340 function add_theme_support( $feature ) {
  2223 	global $_wp_theme_features;
  2341 	global $_wp_theme_features;
  2224 
  2342 
  2225 	if ( func_num_args() == 1 )
  2343 	if ( func_num_args() == 1 ) {
  2226 		$args = true;
  2344 		$args = true;
  2227 	else
  2345 	} else {
  2228 		$args = array_slice( func_get_args(), 1 );
  2346 		$args = array_slice( func_get_args(), 1 );
       
  2347 	}
  2229 
  2348 
  2230 	switch ( $feature ) {
  2349 	switch ( $feature ) {
  2231 		case 'post-thumbnails':
  2350 		case 'post-thumbnails':
  2232 			// All post types are already supported.
  2351 			// All post types are already supported.
  2233 			if ( true === get_theme_support( 'post-thumbnails' ) ) {
  2352 			if ( true === get_theme_support( 'post-thumbnails' ) ) {
  2242 				$args[0] = array_unique( array_merge( $_wp_theme_features['post-thumbnails'][0], $args[0] ) );
  2361 				$args[0] = array_unique( array_merge( $_wp_theme_features['post-thumbnails'][0], $args[0] ) );
  2243 			}
  2362 			}
  2244 
  2363 
  2245 			break;
  2364 			break;
  2246 
  2365 
  2247 		case 'post-formats' :
  2366 		case 'post-formats':
  2248 			if ( is_array( $args[0] ) ) {
  2367 			if ( is_array( $args[0] ) ) {
  2249 				$post_formats = get_post_format_slugs();
  2368 				$post_formats = get_post_format_slugs();
  2250 				unset( $post_formats['standard'] );
  2369 				unset( $post_formats['standard'] );
  2251 
  2370 
  2252 				$args[0] = array_intersect( $args[0], array_keys( $post_formats ) );
  2371 				$args[0] = array_intersect( $args[0], array_keys( $post_formats ) );
  2253 			}
  2372 			}
  2254 			break;
  2373 			break;
  2255 
  2374 
  2256 		case 'html5' :
  2375 		case 'html5':
  2257 			// You can't just pass 'html5', you need to pass an array of types.
  2376 			// You can't just pass 'html5', you need to pass an array of types.
  2258 			if ( empty( $args[0] ) ) {
  2377 			if ( empty( $args[0] ) ) {
  2259 				// Build an array of types for back-compat.
  2378 				// Build an array of types for back-compat.
  2260 				$args = array( 0 => array( 'comment-list', 'comment-form', 'search-form' ) );
  2379 				$args = array( 0 => array( 'comment-list', 'comment-form', 'search-form' ) );
  2261 			} elseif ( ! is_array( $args[0] ) ) {
  2380 			} elseif ( ! is_array( $args[0] ) ) {
  2262 				_doing_it_wrong( "add_theme_support( 'html5' )", __( 'You need to pass an array of types.' ), '3.6.1' );
  2381 				_doing_it_wrong( "add_theme_support( 'html5' )", __( 'You need to pass an array of types.' ), '3.6.1' );
  2263 				return false;
  2382 				return false;
  2264 			}
  2383 			}
  2265 
  2384 
  2266 			// Calling 'html5' again merges, rather than overwrites.
  2385 			// Calling 'html5' again merges, rather than overwrites.
  2267 			if ( isset( $_wp_theme_features['html5'] ) )
  2386 			if ( isset( $_wp_theme_features['html5'] ) ) {
  2268 				$args[0] = array_merge( $_wp_theme_features['html5'][0], $args[0] );
  2387 				$args[0] = array_merge( $_wp_theme_features['html5'][0], $args[0] );
       
  2388 			}
  2269 			break;
  2389 			break;
  2270 
  2390 
  2271 		case 'custom-logo':
  2391 		case 'custom-logo':
  2272 			if ( ! is_array( $args ) ) {
  2392 			if ( ! is_array( $args ) ) {
  2273 				$args = array( 0 => array() );
  2393 				$args = array( 0 => array() );
  2277 				'height'      => null,
  2397 				'height'      => null,
  2278 				'flex-width'  => false,
  2398 				'flex-width'  => false,
  2279 				'flex-height' => false,
  2399 				'flex-height' => false,
  2280 				'header-text' => '',
  2400 				'header-text' => '',
  2281 			);
  2401 			);
  2282 			$args[0] = wp_parse_args( array_intersect_key( $args[0], $defaults ), $defaults );
  2402 			$args[0]  = wp_parse_args( array_intersect_key( $args[0], $defaults ), $defaults );
  2283 
  2403 
  2284 			// Allow full flexibility if no size is specified.
  2404 			// Allow full flexibility if no size is specified.
  2285 			if ( is_null( $args[0]['width'] ) && is_null( $args[0]['height'] ) ) {
  2405 			if ( is_null( $args[0]['width'] ) && is_null( $args[0]['height'] ) ) {
  2286 				$args[0]['flex-width']  = true;
  2406 				$args[0]['flex-width']  = true;
  2287 				$args[0]['flex-height'] = true;
  2407 				$args[0]['flex-height'] = true;
  2288 			}
  2408 			}
  2289 			break;
  2409 			break;
  2290 
  2410 
  2291 		case 'custom-header-uploads' :
  2411 		case 'custom-header-uploads':
  2292 			return add_theme_support( 'custom-header', array( 'uploads' => true ) );
  2412 			return add_theme_support( 'custom-header', array( 'uploads' => true ) );
  2293 
  2413 
  2294 		case 'custom-header' :
  2414 		case 'custom-header':
  2295 			if ( ! is_array( $args ) )
  2415 			if ( ! is_array( $args ) ) {
  2296 				$args = array( 0 => array() );
  2416 				$args = array( 0 => array() );
       
  2417 			}
  2297 
  2418 
  2298 			$defaults = array(
  2419 			$defaults = array(
  2299 				'default-image' => '',
  2420 				'default-image'          => '',
  2300 				'random-default' => false,
  2421 				'random-default'         => false,
  2301 				'width' => 0,
  2422 				'width'                  => 0,
  2302 				'height' => 0,
  2423 				'height'                 => 0,
  2303 				'flex-height' => false,
  2424 				'flex-height'            => false,
  2304 				'flex-width' => false,
  2425 				'flex-width'             => false,
  2305 				'default-text-color' => '',
  2426 				'default-text-color'     => '',
  2306 				'header-text' => true,
  2427 				'header-text'            => true,
  2307 				'uploads' => true,
  2428 				'uploads'                => true,
  2308 				'wp-head-callback' => '',
  2429 				'wp-head-callback'       => '',
  2309 				'admin-head-callback' => '',
  2430 				'admin-head-callback'    => '',
  2310 				'admin-preview-callback' => '',
  2431 				'admin-preview-callback' => '',
  2311 				'video' => false,
  2432 				'video'                  => false,
  2312 				'video-active-callback' => 'is_front_page',
  2433 				'video-active-callback'  => 'is_front_page',
  2313 			);
  2434 			);
  2314 
  2435 
  2315 			$jit = isset( $args[0]['__jit'] );
  2436 			$jit = isset( $args[0]['__jit'] );
  2316 			unset( $args[0]['__jit'] );
  2437 			unset( $args[0]['__jit'] );
  2317 
  2438 
  2318 			// Merge in data from previous add_theme_support() calls.
  2439 			// Merge in data from previous add_theme_support() calls.
  2319 			// The first value registered wins. (A child theme is set up first.)
  2440 			// The first value registered wins. (A child theme is set up first.)
  2320 			if ( isset( $_wp_theme_features['custom-header'] ) )
  2441 			if ( isset( $_wp_theme_features['custom-header'] ) ) {
  2321 				$args[0] = wp_parse_args( $_wp_theme_features['custom-header'][0], $args[0] );
  2442 				$args[0] = wp_parse_args( $_wp_theme_features['custom-header'][0], $args[0] );
       
  2443 			}
  2322 
  2444 
  2323 			// Load in the defaults at the end, as we need to insure first one wins.
  2445 			// Load in the defaults at the end, as we need to insure first one wins.
  2324 			// This will cause all constants to be defined, as each arg will then be set to the default.
  2446 			// This will cause all constants to be defined, as each arg will then be set to the default.
  2325 			if ( $jit )
  2447 			if ( $jit ) {
  2326 				$args[0] = wp_parse_args( $args[0], $defaults );
  2448 				$args[0] = wp_parse_args( $args[0], $defaults );
       
  2449 			}
  2327 
  2450 
  2328 			// If a constant was defined, use that value. Otherwise, define the constant to ensure
  2451 			// If a constant was defined, use that value. Otherwise, define the constant to ensure
  2329 			// the constant is always accurate (and is not defined later,  overriding our value).
  2452 			// the constant is always accurate (and is not defined later,  overriding our value).
  2330 			// As stated above, the first value wins.
  2453 			// As stated above, the first value wins.
  2331 			// Once we get to wp_loaded (just-in-time), define any constants we haven't already.
  2454 			// Once we get to wp_loaded (just-in-time), define any constants we haven't already.
  2332 			// Constants are lame. Don't reference them. This is just for backward compatibility.
  2455 			// Constants are lame. Don't reference them. This is just for backward compatibility.
  2333 
  2456 
  2334 			if ( defined( 'NO_HEADER_TEXT' ) )
  2457 			if ( defined( 'NO_HEADER_TEXT' ) ) {
  2335 				$args[0]['header-text'] = ! NO_HEADER_TEXT;
  2458 				$args[0]['header-text'] = ! NO_HEADER_TEXT;
  2336 			elseif ( isset( $args[0]['header-text'] ) )
  2459 			} elseif ( isset( $args[0]['header-text'] ) ) {
  2337 				define( 'NO_HEADER_TEXT', empty( $args[0]['header-text'] ) );
  2460 				define( 'NO_HEADER_TEXT', empty( $args[0]['header-text'] ) );
  2338 
  2461 			}
  2339 			if ( defined( 'HEADER_IMAGE_WIDTH' ) )
  2462 
       
  2463 			if ( defined( 'HEADER_IMAGE_WIDTH' ) ) {
  2340 				$args[0]['width'] = (int) HEADER_IMAGE_WIDTH;
  2464 				$args[0]['width'] = (int) HEADER_IMAGE_WIDTH;
  2341 			elseif ( isset( $args[0]['width'] ) )
  2465 			} elseif ( isset( $args[0]['width'] ) ) {
  2342 				define( 'HEADER_IMAGE_WIDTH', (int) $args[0]['width'] );
  2466 				define( 'HEADER_IMAGE_WIDTH', (int) $args[0]['width'] );
  2343 
  2467 			}
  2344 			if ( defined( 'HEADER_IMAGE_HEIGHT' ) )
  2468 
       
  2469 			if ( defined( 'HEADER_IMAGE_HEIGHT' ) ) {
  2345 				$args[0]['height'] = (int) HEADER_IMAGE_HEIGHT;
  2470 				$args[0]['height'] = (int) HEADER_IMAGE_HEIGHT;
  2346 			elseif ( isset( $args[0]['height'] ) )
  2471 			} elseif ( isset( $args[0]['height'] ) ) {
  2347 				define( 'HEADER_IMAGE_HEIGHT', (int) $args[0]['height'] );
  2472 				define( 'HEADER_IMAGE_HEIGHT', (int) $args[0]['height'] );
  2348 
  2473 			}
  2349 			if ( defined( 'HEADER_TEXTCOLOR' ) )
  2474 
       
  2475 			if ( defined( 'HEADER_TEXTCOLOR' ) ) {
  2350 				$args[0]['default-text-color'] = HEADER_TEXTCOLOR;
  2476 				$args[0]['default-text-color'] = HEADER_TEXTCOLOR;
  2351 			elseif ( isset( $args[0]['default-text-color'] ) )
  2477 			} elseif ( isset( $args[0]['default-text-color'] ) ) {
  2352 				define( 'HEADER_TEXTCOLOR', $args[0]['default-text-color'] );
  2478 				define( 'HEADER_TEXTCOLOR', $args[0]['default-text-color'] );
  2353 
  2479 			}
  2354 			if ( defined( 'HEADER_IMAGE' ) )
  2480 
       
  2481 			if ( defined( 'HEADER_IMAGE' ) ) {
  2355 				$args[0]['default-image'] = HEADER_IMAGE;
  2482 				$args[0]['default-image'] = HEADER_IMAGE;
  2356 			elseif ( isset( $args[0]['default-image'] ) )
  2483 			} elseif ( isset( $args[0]['default-image'] ) ) {
  2357 				define( 'HEADER_IMAGE', $args[0]['default-image'] );
  2484 				define( 'HEADER_IMAGE', $args[0]['default-image'] );
  2358 
  2485 			}
  2359 			if ( $jit && ! empty( $args[0]['default-image'] ) )
  2486 
       
  2487 			if ( $jit && ! empty( $args[0]['default-image'] ) ) {
  2360 				$args[0]['random-default'] = false;
  2488 				$args[0]['random-default'] = false;
       
  2489 			}
  2361 
  2490 
  2362 			// If headers are supported, and we still don't have a defined width or height,
  2491 			// If headers are supported, and we still don't have a defined width or height,
  2363 			// we have implicit flex sizes.
  2492 			// we have implicit flex sizes.
  2364 			if ( $jit ) {
  2493 			if ( $jit ) {
  2365 				if ( empty( $args[0]['width'] ) && empty( $args[0]['flex-width'] ) )
  2494 				if ( empty( $args[0]['width'] ) && empty( $args[0]['flex-width'] ) ) {
  2366 					$args[0]['flex-width'] = true;
  2495 					$args[0]['flex-width'] = true;
  2367 				if ( empty( $args[0]['height'] ) && empty( $args[0]['flex-height'] ) )
  2496 				}
       
  2497 				if ( empty( $args[0]['height'] ) && empty( $args[0]['flex-height'] ) ) {
  2368 					$args[0]['flex-height'] = true;
  2498 					$args[0]['flex-height'] = true;
       
  2499 				}
  2369 			}
  2500 			}
  2370 
  2501 
  2371 			break;
  2502 			break;
  2372 
  2503 
  2373 		case 'custom-background' :
  2504 		case 'custom-background':
  2374 			if ( ! is_array( $args ) )
  2505 			if ( ! is_array( $args ) ) {
  2375 				$args = array( 0 => array() );
  2506 				$args = array( 0 => array() );
       
  2507 			}
  2376 
  2508 
  2377 			$defaults = array(
  2509 			$defaults = array(
  2378 				'default-image'          => '',
  2510 				'default-image'          => '',
  2379 				'default-preset'         => 'default',
  2511 				'default-preset'         => 'default',
  2380 				'default-position-x'     => 'left',
  2512 				'default-position-x'     => 'left',
  2390 
  2522 
  2391 			$jit = isset( $args[0]['__jit'] );
  2523 			$jit = isset( $args[0]['__jit'] );
  2392 			unset( $args[0]['__jit'] );
  2524 			unset( $args[0]['__jit'] );
  2393 
  2525 
  2394 			// Merge in data from previous add_theme_support() calls. The first value registered wins.
  2526 			// Merge in data from previous add_theme_support() calls. The first value registered wins.
  2395 			if ( isset( $_wp_theme_features['custom-background'] ) )
  2527 			if ( isset( $_wp_theme_features['custom-background'] ) ) {
  2396 				$args[0] = wp_parse_args( $_wp_theme_features['custom-background'][0], $args[0] );
  2528 				$args[0] = wp_parse_args( $_wp_theme_features['custom-background'][0], $args[0] );
  2397 
  2529 			}
  2398 			if ( $jit )
  2530 
       
  2531 			if ( $jit ) {
  2399 				$args[0] = wp_parse_args( $args[0], $defaults );
  2532 				$args[0] = wp_parse_args( $args[0], $defaults );
  2400 
  2533 			}
  2401 			if ( defined( 'BACKGROUND_COLOR' ) )
  2534 
       
  2535 			if ( defined( 'BACKGROUND_COLOR' ) ) {
  2402 				$args[0]['default-color'] = BACKGROUND_COLOR;
  2536 				$args[0]['default-color'] = BACKGROUND_COLOR;
  2403 			elseif ( isset( $args[0]['default-color'] ) || $jit )
  2537 			} elseif ( isset( $args[0]['default-color'] ) || $jit ) {
  2404 				define( 'BACKGROUND_COLOR', $args[0]['default-color'] );
  2538 				define( 'BACKGROUND_COLOR', $args[0]['default-color'] );
  2405 
  2539 			}
  2406 			if ( defined( 'BACKGROUND_IMAGE' ) )
  2540 
       
  2541 			if ( defined( 'BACKGROUND_IMAGE' ) ) {
  2407 				$args[0]['default-image'] = BACKGROUND_IMAGE;
  2542 				$args[0]['default-image'] = BACKGROUND_IMAGE;
  2408 			elseif ( isset( $args[0]['default-image'] ) || $jit )
  2543 			} elseif ( isset( $args[0]['default-image'] ) || $jit ) {
  2409 				define( 'BACKGROUND_IMAGE', $args[0]['default-image'] );
  2544 				define( 'BACKGROUND_IMAGE', $args[0]['default-image'] );
       
  2545 			}
  2410 
  2546 
  2411 			break;
  2547 			break;
  2412 
  2548 
  2413 		// Ensure that 'title-tag' is accessible in the admin.
  2549 		// Ensure that 'title-tag' is accessible in the admin.
  2414 		case 'title-tag' :
  2550 		case 'title-tag':
  2415 			// Can be called in functions.php but must happen before wp_loaded, i.e. not in header.php.
  2551 			// Can be called in functions.php but must happen before wp_loaded, i.e. not in header.php.
  2416 			if ( did_action( 'wp_loaded' ) ) {
  2552 			if ( did_action( 'wp_loaded' ) ) {
  2417 				/* translators: 1: Theme support 2: hook name */
  2553 				/* translators: 1: title-tag, 2: wp_loaded */
  2418 				_doing_it_wrong( "add_theme_support( 'title-tag' )", sprintf( __( 'Theme support for %1$s should be registered before the %2$s hook.' ),
  2554 				_doing_it_wrong(
  2419 					'<code>title-tag</code>', '<code>wp_loaded</code>' ), '4.1.0' );
  2555 					"add_theme_support( 'title-tag' )",
       
  2556 					sprintf(
       
  2557 						__( 'Theme support for %1$s should be registered before the %2$s hook.' ),
       
  2558 						'<code>title-tag</code>',
       
  2559 						'<code>wp_loaded</code>'
       
  2560 					),
       
  2561 					'4.1.0'
       
  2562 				);
  2420 
  2563 
  2421 				return false;
  2564 				return false;
  2422 			}
  2565 			}
  2423 	}
  2566 	}
  2424 
  2567 
  2440 	if ( current_theme_supports( 'custom-header' ) ) {
  2583 	if ( current_theme_supports( 'custom-header' ) ) {
  2441 		// In case any constants were defined after an add_custom_image_header() call, re-run.
  2584 		// In case any constants were defined after an add_custom_image_header() call, re-run.
  2442 		add_theme_support( 'custom-header', array( '__jit' => true ) );
  2585 		add_theme_support( 'custom-header', array( '__jit' => true ) );
  2443 
  2586 
  2444 		$args = get_theme_support( 'custom-header' );
  2587 		$args = get_theme_support( 'custom-header' );
  2445 		if ( $args[0]['wp-head-callback'] )
  2588 		if ( $args[0]['wp-head-callback'] ) {
  2446 			add_action( 'wp_head', $args[0]['wp-head-callback'] );
  2589 			add_action( 'wp_head', $args[0]['wp-head-callback'] );
       
  2590 		}
  2447 
  2591 
  2448 		if ( is_admin() ) {
  2592 		if ( is_admin() ) {
  2449 			require_once( ABSPATH . 'wp-admin/custom-header.php' );
  2593 			require_once( ABSPATH . 'wp-admin/custom-header.php' );
  2450 			$custom_image_header = new Custom_Image_Header( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
  2594 			$custom_image_header = new Custom_Image_Header( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
  2451 		}
  2595 		}
  2483 			<?php echo $classes; ?> {
  2627 			<?php echo $classes; ?> {
  2484 				position: absolute;
  2628 				position: absolute;
  2485 				clip: rect(1px, 1px, 1px, 1px);
  2629 				clip: rect(1px, 1px, 1px, 1px);
  2486 			}
  2630 			}
  2487 		</style>
  2631 		</style>
  2488 	<?php
  2632 		<?php
  2489 	}
  2633 	}
  2490 }
  2634 }
  2491 
  2635 
  2492 /**
  2636 /**
  2493  * Gets the theme support arguments passed when registering that support
  2637  * Gets the theme support arguments passed when registering that support
  2494  *
  2638  *
  2495  * @since 3.1.0
  2639  * @since 3.1.0
  2496  *
  2640  *
  2497  * @global array $_wp_theme_features
  2641  * @global array $_wp_theme_features
  2498  *
  2642  *
  2499  * @param string $feature the feature to check
  2643  * @param string $feature The feature to check.
  2500  * @return mixed The array of extra arguments or the value for the registered feature.
  2644  * @return mixed The array of extra arguments or the value for the registered feature.
  2501  */
  2645  */
  2502 function get_theme_support( $feature ) {
  2646 function get_theme_support( $feature ) {
  2503 	global $_wp_theme_features;
  2647 	global $_wp_theme_features;
  2504 	if ( ! isset( $_wp_theme_features[ $feature ] ) )
  2648 	if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
  2505 		return false;
  2649 		return false;
  2506 
  2650 	}
  2507 	if ( func_num_args() <= 1 )
  2651 
       
  2652 	if ( func_num_args() <= 1 ) {
  2508 		return $_wp_theme_features[ $feature ];
  2653 		return $_wp_theme_features[ $feature ];
       
  2654 	}
  2509 
  2655 
  2510 	$args = array_slice( func_get_args(), 1 );
  2656 	$args = array_slice( func_get_args(), 1 );
  2511 	switch ( $feature ) {
  2657 	switch ( $feature ) {
  2512 		case 'custom-logo' :
  2658 		case 'custom-logo':
  2513 		case 'custom-header' :
  2659 		case 'custom-header':
  2514 		case 'custom-background' :
  2660 		case 'custom-background':
  2515 			if ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) )
  2661 			if ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) ) {
  2516 				return $_wp_theme_features[ $feature ][0][ $args[0] ];
  2662 				return $_wp_theme_features[ $feature ][0][ $args[0] ];
       
  2663 			}
  2517 			return false;
  2664 			return false;
  2518 
  2665 
  2519 		default :
  2666 		default:
  2520 			return $_wp_theme_features[ $feature ];
  2667 			return $_wp_theme_features[ $feature ];
  2521 	}
  2668 	}
  2522 }
  2669 }
  2523 
  2670 
  2524 /**
  2671 /**
  2527  * Should be called in the theme's functions.php file. Generally would
  2674  * Should be called in the theme's functions.php file. Generally would
  2528  * be used for child themes to override support from the parent theme.
  2675  * be used for child themes to override support from the parent theme.
  2529  *
  2676  *
  2530  * @since 3.0.0
  2677  * @since 3.0.0
  2531  * @see add_theme_support()
  2678  * @see add_theme_support()
  2532  * @param string $feature the feature being added
  2679  * @param string $feature The feature being removed.
  2533  * @return bool|void Whether feature was removed.
  2680  * @return bool|void Whether feature was removed.
  2534  */
  2681  */
  2535 function remove_theme_support( $feature ) {
  2682 function remove_theme_support( $feature ) {
  2536 	// Blacklist: for internal registrations not used directly by themes.
  2683 	// Blacklist: for internal registrations not used directly by themes.
  2537 	if ( in_array( $feature, array( 'editor-style', 'widgets', 'menus' ) ) )
  2684 	if ( in_array( $feature, array( 'editor-style', 'widgets', 'menus' ) ) ) {
  2538 		return false;
  2685 		return false;
       
  2686 	}
  2539 
  2687 
  2540 	return _remove_theme_support( $feature );
  2688 	return _remove_theme_support( $feature );
  2541 }
  2689 }
  2542 
  2690 
  2543 /**
  2691 /**
  2554  */
  2702  */
  2555 function _remove_theme_support( $feature ) {
  2703 function _remove_theme_support( $feature ) {
  2556 	global $_wp_theme_features;
  2704 	global $_wp_theme_features;
  2557 
  2705 
  2558 	switch ( $feature ) {
  2706 	switch ( $feature ) {
  2559 		case 'custom-header-uploads' :
  2707 		case 'custom-header-uploads':
  2560 			if ( ! isset( $_wp_theme_features['custom-header'] ) )
  2708 			if ( ! isset( $_wp_theme_features['custom-header'] ) ) {
  2561 				return false;
  2709 				return false;
       
  2710 			}
  2562 			add_theme_support( 'custom-header', array( 'uploads' => false ) );
  2711 			add_theme_support( 'custom-header', array( 'uploads' => false ) );
  2563 			return; // Do not continue - custom-header-uploads no longer exists.
  2712 			return; // Do not continue - custom-header-uploads no longer exists.
  2564 	}
  2713 	}
  2565 
  2714 
  2566 	if ( ! isset( $_wp_theme_features[ $feature ] ) )
  2715 	if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
  2567 		return false;
  2716 		return false;
       
  2717 	}
  2568 
  2718 
  2569 	switch ( $feature ) {
  2719 	switch ( $feature ) {
  2570 		case 'custom-header' :
  2720 		case 'custom-header':
  2571 			if ( ! did_action( 'wp_loaded' ) )
  2721 			if ( ! did_action( 'wp_loaded' ) ) {
  2572 				break;
  2722 				break;
       
  2723 			}
  2573 			$support = get_theme_support( 'custom-header' );
  2724 			$support = get_theme_support( 'custom-header' );
  2574 			if ( isset( $support[0]['wp-head-callback'] ) ) {
  2725 			if ( isset( $support[0]['wp-head-callback'] ) ) {
  2575 				remove_action( 'wp_head', $support[0]['wp-head-callback'] );
  2726 				remove_action( 'wp_head', $support[0]['wp-head-callback'] );
  2576 			}
  2727 			}
  2577 			if ( isset( $GLOBALS['custom_image_header'] ) ) {
  2728 			if ( isset( $GLOBALS['custom_image_header'] ) ) {
  2578 				remove_action( 'admin_menu', array( $GLOBALS['custom_image_header'], 'init' ) );
  2729 				remove_action( 'admin_menu', array( $GLOBALS['custom_image_header'], 'init' ) );
  2579 				unset( $GLOBALS['custom_image_header'] );
  2730 				unset( $GLOBALS['custom_image_header'] );
  2580 			}
  2731 			}
  2581 			break;
  2732 			break;
  2582 
  2733 
  2583 		case 'custom-background' :
  2734 		case 'custom-background':
  2584 			if ( ! did_action( 'wp_loaded' ) )
  2735 			if ( ! did_action( 'wp_loaded' ) ) {
  2585 				break;
  2736 				break;
       
  2737 			}
  2586 			$support = get_theme_support( 'custom-background' );
  2738 			$support = get_theme_support( 'custom-background' );
  2587 			remove_action( 'wp_head', $support[0]['wp-head-callback'] );
  2739 			if ( isset( $support[0]['wp-head-callback'] ) ) {
       
  2740 				remove_action( 'wp_head', $support[0]['wp-head-callback'] );
       
  2741 			}
  2588 			remove_action( 'admin_menu', array( $GLOBALS['custom_background'], 'init' ) );
  2742 			remove_action( 'admin_menu', array( $GLOBALS['custom_background'], 'init' ) );
  2589 			unset( $GLOBALS['custom_background'] );
  2743 			unset( $GLOBALS['custom_background'] );
  2590 			break;
  2744 			break;
  2591 	}
  2745 	}
  2592 
  2746 
  2593 	unset( $_wp_theme_features[ $feature ] );
  2747 	unset( $_wp_theme_features[ $feature ] );
  2594 	return true;
  2748 	return true;
  2595 }
  2749 }
  2596 
  2750 
  2597 /**
  2751 /**
  2598  * Checks a theme's support for a given feature
  2752  * Checks a theme's support for a given feature.
  2599  *
  2753  *
  2600  * @since 2.9.0
  2754  * @since 2.9.0
  2601  *
  2755  *
  2602  * @global array $_wp_theme_features
  2756  * @global array $_wp_theme_features
  2603  *
  2757  *
  2604  * @param string $feature the feature being checked
  2758  * @param string $feature The feature being checked.
  2605  * @return bool
  2759  * @return bool True if the current theme supports the feature, false otherwise.
  2606  */
  2760  */
  2607 function current_theme_supports( $feature ) {
  2761 function current_theme_supports( $feature ) {
  2608 	global $_wp_theme_features;
  2762 	global $_wp_theme_features;
  2609 
  2763 
  2610 	if ( 'custom-header-uploads' == $feature )
  2764 	if ( 'custom-header-uploads' == $feature ) {
  2611 		return current_theme_supports( 'custom-header', 'uploads' );
  2765 		return current_theme_supports( 'custom-header', 'uploads' );
  2612 
  2766 	}
  2613 	if ( !isset( $_wp_theme_features[$feature] ) )
  2767 
       
  2768 	if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
  2614 		return false;
  2769 		return false;
       
  2770 	}
  2615 
  2771 
  2616 	// If no args passed then no extra checks need be performed
  2772 	// If no args passed then no extra checks need be performed
  2617 	if ( func_num_args() <= 1 )
  2773 	if ( func_num_args() <= 1 ) {
  2618 		return true;
  2774 		return true;
       
  2775 	}
  2619 
  2776 
  2620 	$args = array_slice( func_get_args(), 1 );
  2777 	$args = array_slice( func_get_args(), 1 );
  2621 
  2778 
  2622 	switch ( $feature ) {
  2779 	switch ( $feature ) {
  2623 		case 'post-thumbnails':
  2780 		case 'post-thumbnails':
  2624 			// post-thumbnails can be registered for only certain content/post types by passing
  2781 			// post-thumbnails can be registered for only certain content/post types by passing
  2625 			// an array of types to add_theme_support(). If no array was passed, then
  2782 			// an array of types to add_theme_support(). If no array was passed, then
  2626 			// any type is accepted
  2783 			// any type is accepted
  2627 			if ( true === $_wp_theme_features[$feature] )  // Registered for all types
  2784 			if ( true === $_wp_theme_features[ $feature ] ) {  // Registered for all types
  2628 				return true;
  2785 				return true;
       
  2786 			}
  2629 			$content_type = $args[0];
  2787 			$content_type = $args[0];
  2630 			return in_array( $content_type, $_wp_theme_features[$feature][0] );
  2788 			return in_array( $content_type, $_wp_theme_features[ $feature ][0] );
  2631 
  2789 
  2632 		case 'html5':
  2790 		case 'html5':
  2633 		case 'post-formats':
  2791 		case 'post-formats':
  2634 			// specific post formats can be registered by passing an array of types to
  2792 			// specific post formats can be registered by passing an array of types to
  2635 			// add_theme_support()
  2793 			// add_theme_support()
  2636 
  2794 
  2637 			// Specific areas of HTML5 support *must* be passed via an array to add_theme_support()
  2795 			// Specific areas of HTML5 support *must* be passed via an array to add_theme_support()
  2638 
  2796 
  2639 			$type = $args[0];
  2797 			$type = $args[0];
  2640 			return in_array( $type, $_wp_theme_features[$feature][0] );
  2798 			return in_array( $type, $_wp_theme_features[ $feature ][0] );
  2641 
  2799 
  2642 		case 'custom-logo':
  2800 		case 'custom-logo':
  2643 		case 'custom-header':
  2801 		case 'custom-header':
  2644 		case 'custom-background':
  2802 		case 'custom-background':
  2645 			// Specific capabilities can be registered by passing an array to add_theme_support().
  2803 			// Specific capabilities can be registered by passing an array to add_theme_support().
  2658 	 *
  2816 	 *
  2659 	 * @param bool   true     Whether the current theme supports the given feature. Default true.
  2817 	 * @param bool   true     Whether the current theme supports the given feature. Default true.
  2660 	 * @param array  $args    Array of arguments for the feature.
  2818 	 * @param array  $args    Array of arguments for the feature.
  2661 	 * @param string $feature The theme feature.
  2819 	 * @param string $feature The theme feature.
  2662 	 */
  2820 	 */
  2663 	return apply_filters( "current_theme_supports-{$feature}", true, $args, $_wp_theme_features[$feature] );
  2821 	return apply_filters( "current_theme_supports-{$feature}", true, $args, $_wp_theme_features[ $feature ] );
  2664 }
  2822 }
  2665 
  2823 
  2666 /**
  2824 /**
  2667  * Checks a theme's support for a given feature before loading the functions which implement it.
  2825  * Checks a theme's support for a given feature before loading the functions which implement it.
  2668  *
  2826  *
  2672  * @param string $include Path to the file.
  2830  * @param string $include Path to the file.
  2673  * @return bool True if the current theme supports the supplied feature, false otherwise.
  2831  * @return bool True if the current theme supports the supplied feature, false otherwise.
  2674  */
  2832  */
  2675 function require_if_theme_supports( $feature, $include ) {
  2833 function require_if_theme_supports( $feature, $include ) {
  2676 	if ( current_theme_supports( $feature ) ) {
  2834 	if ( current_theme_supports( $feature ) ) {
  2677 		require ( $include );
  2835 		require( $include );
  2678 		return true;
  2836 		return true;
  2679 	}
  2837 	}
  2680 	return false;
  2838 	return false;
  2681 }
  2839 }
  2682 
  2840 
  2771  * @global WP_Customize_Manager $wp_customize
  2929  * @global WP_Customize_Manager $wp_customize
  2772  */
  2930  */
  2773 function _wp_customize_include() {
  2931 function _wp_customize_include() {
  2774 
  2932 
  2775 	$is_customize_admin_page = ( is_admin() && 'customize.php' == basename( $_SERVER['PHP_SELF'] ) );
  2933 	$is_customize_admin_page = ( is_admin() && 'customize.php' == basename( $_SERVER['PHP_SELF'] ) );
  2776 	$should_include = (
  2934 	$should_include          = (
  2777 		$is_customize_admin_page
  2935 		$is_customize_admin_page
  2778 		||
  2936 		||
  2779 		( isset( $_REQUEST['wp_customize'] ) && 'on' == $_REQUEST['wp_customize'] )
  2937 		( isset( $_REQUEST['wp_customize'] ) && 'on' == $_REQUEST['wp_customize'] )
  2780 		||
  2938 		||
  2781 		( ! empty( $_GET['customize_changeset_uuid'] ) || ! empty( $_POST['customize_changeset_uuid'] ) )
  2939 		( ! empty( $_GET['customize_changeset_uuid'] ) || ! empty( $_POST['customize_changeset_uuid'] ) )
  2788 	/*
  2946 	/*
  2789 	 * Note that wp_unslash() is not being used on the input vars because it is
  2947 	 * Note that wp_unslash() is not being used on the input vars because it is
  2790 	 * called before wp_magic_quotes() gets called. Besides this fact, none of
  2948 	 * called before wp_magic_quotes() gets called. Besides this fact, none of
  2791 	 * the values should contain any characters needing slashes anyway.
  2949 	 * the values should contain any characters needing slashes anyway.
  2792 	 */
  2950 	 */
  2793 	$keys = array( 'changeset_uuid', 'customize_changeset_uuid', 'customize_theme', 'theme', 'customize_messenger_channel', 'customize_autosaved' );
  2951 	$keys       = array( 'changeset_uuid', 'customize_changeset_uuid', 'customize_theme', 'theme', 'customize_messenger_channel', 'customize_autosaved' );
  2794 	$input_vars = array_merge(
  2952 	$input_vars = array_merge(
  2795 		wp_array_slice_assoc( $_GET, $keys ),
  2953 		wp_array_slice_assoc( $_GET, $keys ),
  2796 		wp_array_slice_assoc( $_POST, $keys )
  2954 		wp_array_slice_assoc( $_POST, $keys )
  2797 	);
  2955 	);
  2798 
  2956 
  2799 	$theme = null;
  2957 	$theme             = null;
  2800 	$changeset_uuid = false; // Value false indicates UUID should be determined after_setup_theme to either re-use existing saved changeset or else generate a new UUID if none exists.
  2958 	$changeset_uuid    = false; // Value false indicates UUID should be determined after_setup_theme to either re-use existing saved changeset or else generate a new UUID if none exists.
  2801 	$messenger_channel = null;
  2959 	$messenger_channel = null;
  2802 	$autosaved = null;
  2960 	$autosaved         = null;
  2803 	$branching = false; // Set initially fo false since defaults to true for back-compat; can be overridden via the customize_changeset_branching filter.
  2961 	$branching         = false; // Set initially fo false since defaults to true for back-compat; can be overridden via the customize_changeset_branching filter.
  2804 
  2962 
  2805 	if ( $is_customize_admin_page && isset( $input_vars['changeset_uuid'] ) ) {
  2963 	if ( $is_customize_admin_page && isset( $input_vars['changeset_uuid'] ) ) {
  2806 		$changeset_uuid = sanitize_key( $input_vars['changeset_uuid'] );
  2964 		$changeset_uuid = sanitize_key( $input_vars['changeset_uuid'] );
  2807 	} elseif ( ! empty( $input_vars['customize_changeset_uuid'] ) ) {
  2965 	} elseif ( ! empty( $input_vars['customize_changeset_uuid'] ) ) {
  2808 		$changeset_uuid = sanitize_key( $input_vars['customize_changeset_uuid'] );
  2966 		$changeset_uuid = sanitize_key( $input_vars['customize_changeset_uuid'] );
  2835 		&&
  2993 		&&
  2836 		isset( $_REQUEST['action'] )
  2994 		isset( $_REQUEST['action'] )
  2837 		&&
  2995 		&&
  2838 		'customize_save' === wp_unslash( $_REQUEST['action'] )
  2996 		'customize_save' === wp_unslash( $_REQUEST['action'] )
  2839 	);
  2997 	);
  2840 	$settings_previewed = ! $is_customize_save_action;
  2998 	$settings_previewed       = ! $is_customize_save_action;
  2841 
  2999 
  2842 	require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
  3000 	require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
  2843 	$GLOBALS['wp_customize'] = new WP_Customize_Manager( compact( 'changeset_uuid', 'theme', 'messenger_channel', 'settings_previewed', 'autosaved', 'branching' ) );
  3001 	$GLOBALS['wp_customize'] = new WP_Customize_Manager( compact( 'changeset_uuid', 'theme', 'messenger_channel', 'settings_previewed', 'autosaved', 'branching' ) );
  2844 }
  3002 }
  2845 
  3003 
  2870 		return;
  3028 		return;
  2871 	}
  3029 	}
  2872 
  3030 
  2873 	if ( empty( $wp_customize ) ) {
  3031 	if ( empty( $wp_customize ) ) {
  2874 		require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
  3032 		require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
  2875 		$wp_customize = new WP_Customize_Manager( array(
  3033 		$wp_customize = new WP_Customize_Manager(
  2876 			'changeset_uuid' => $changeset_post->post_name,
  3034 			array(
  2877 			'settings_previewed' => false,
  3035 				'changeset_uuid'     => $changeset_post->post_name,
  2878 		) );
  3036 				'settings_previewed' => false,
       
  3037 			)
       
  3038 		);
  2879 	}
  3039 	}
  2880 
  3040 
  2881 	if ( ! did_action( 'customize_register' ) ) {
  3041 	if ( ! did_action( 'customize_register' ) ) {
  2882 		/*
  3042 		/*
  2883 		 * When running from CLI or Cron, the customize_register action will need
  3043 		 * When running from CLI or Cron, the customize_register action will need
  2897 		$wp_customize->register_controls();
  3057 		$wp_customize->register_controls();
  2898 
  3058 
  2899 		/** This filter is documented in /wp-includes/class-wp-customize-manager.php */
  3059 		/** This filter is documented in /wp-includes/class-wp-customize-manager.php */
  2900 		do_action( 'customize_register', $wp_customize );
  3060 		do_action( 'customize_register', $wp_customize );
  2901 	}
  3061 	}
  2902 	$wp_customize->_publish_changeset_values( $changeset_post->ID ) ;
  3062 	$wp_customize->_publish_changeset_values( $changeset_post->ID );
  2903 
  3063 
  2904 	/*
  3064 	/*
  2905 	 * Trash the changeset post if revisions are not enabled. Unpublished
  3065 	 * Trash the changeset post if revisions are not enabled. Unpublished
  2906 	 * changesets by default get garbage collected due to the auto-draft status.
  3066 	 * changesets by default get garbage collected due to the auto-draft status.
  2907 	 * When a changeset post is published, however, it would no longer get cleaned
  3067 	 * When a changeset post is published, however, it would no longer get cleaned
  2908 	 * out. Ths is a problem when the changeset posts are never displayed anywhere,
  3068 	 * out. This is a problem when the changeset posts are never displayed anywhere,
  2909 	 * since they would just be endlessly piling up. So here we use the revisions
  3069 	 * since they would just be endlessly piling up. So here we use the revisions
  2910 	 * feature to indicate whether or not a published changeset should get trashed
  3070 	 * feature to indicate whether or not a published changeset should get trashed
  2911 	 * and thus garbage collected.
  3071 	 * and thus garbage collected.
  2912 	 */
  3072 	 */
  2913 	if ( ! wp_revisions_enabled( $changeset_post ) ) {
  3073 	if ( ! wp_revisions_enabled( $changeset_post ) ) {
  2945  * @since 3.4.0
  3105  * @since 3.4.0
  2946  */
  3106  */
  2947 function _wp_customize_loader_settings() {
  3107 function _wp_customize_loader_settings() {
  2948 	$admin_origin = parse_url( admin_url() );
  3108 	$admin_origin = parse_url( admin_url() );
  2949 	$home_origin  = parse_url( home_url() );
  3109 	$home_origin  = parse_url( home_url() );
  2950 	$cross_domain = ( strtolower( $admin_origin[ 'host' ] ) != strtolower( $home_origin[ 'host' ] ) );
  3110 	$cross_domain = ( strtolower( $admin_origin['host'] ) != strtolower( $home_origin['host'] ) );
  2951 
  3111 
  2952 	$browser = array(
  3112 	$browser = array(
  2953 		'mobile' => wp_is_mobile(),
  3113 		'mobile' => wp_is_mobile(),
  2954 		'ios'    => wp_is_mobile() && preg_match( '/iPad|iPod|iPhone/', $_SERVER['HTTP_USER_AGENT'] ),
  3114 		'ios'    => wp_is_mobile() && preg_match( '/iPad|iPod|iPhone/', $_SERVER['HTTP_USER_AGENT'] ),
  2955 	);
  3115 	);
  2965 	);
  3125 	);
  2966 
  3126 
  2967 	$script = 'var _wpCustomizeLoaderSettings = ' . wp_json_encode( $settings ) . ';';
  3127 	$script = 'var _wpCustomizeLoaderSettings = ' . wp_json_encode( $settings ) . ';';
  2968 
  3128 
  2969 	$wp_scripts = wp_scripts();
  3129 	$wp_scripts = wp_scripts();
  2970 	$data = $wp_scripts->get_data( 'customize-loader', 'data' );
  3130 	$data       = $wp_scripts->get_data( 'customize-loader', 'data' );
  2971 	if ( $data )
  3131 	if ( $data ) {
  2972 		$script = "$data\n$script";
  3132 		$script = "$data\n$script";
       
  3133 	}
  2973 
  3134 
  2974 	$wp_scripts->add_data( 'customize-loader', 'data', $script );
  3135 	$wp_scripts->add_data( 'customize-loader', 'data', $script );
  2975 }
  3136 }
  2976 
  3137 
  2977 /**
  3138 /**
  2978  * Returns a URL to load the Customizer.
  3139  * Returns a URL to load the Customizer.
  2979  *
  3140  *
  2980  * @since 3.4.0
  3141  * @since 3.4.0
  2981  *
  3142  *
  2982  * @param string $stylesheet Optional. Theme to customize. Defaults to current theme.
  3143  * @param string $stylesheet Optional. Theme to customize. Defaults to current theme.
  2983  * 	                         The theme's stylesheet will be urlencoded if necessary.
  3144  *                           The theme's stylesheet will be urlencoded if necessary.
  2984  * @return string
  3145  * @return string
  2985  */
  3146  */
  2986 function wp_customize_url( $stylesheet = null ) {
  3147 function wp_customize_url( $stylesheet = null ) {
  2987 	$url = admin_url( 'customize.php' );
  3148 	$url = admin_url( 'customize.php' );
  2988 	if ( $stylesheet )
  3149 	if ( $stylesheet ) {
  2989 		$url .= '?theme=' . urlencode( $stylesheet );
  3150 		$url .= '?theme=' . urlencode( $stylesheet );
       
  3151 	}
  2990 	return esc_url( $url );
  3152 	return esc_url( $url );
  2991 }
  3153 }
  2992 
  3154 
  2993 /**
  3155 /**
  2994  * Prints a script to check whether or not the Customizer is supported,
  3156  * Prints a script to check whether or not the Customizer is supported,
  3007  * @since 4.7.0 Support for IE8 and below is explicitly removed via conditional comments.
  3169  * @since 4.7.0 Support for IE8 and below is explicitly removed via conditional comments.
  3008  */
  3170  */
  3009 function wp_customize_support_script() {
  3171 function wp_customize_support_script() {
  3010 	$admin_origin = parse_url( admin_url() );
  3172 	$admin_origin = parse_url( admin_url() );
  3011 	$home_origin  = parse_url( home_url() );
  3173 	$home_origin  = parse_url( home_url() );
  3012 	$cross_domain = ( strtolower( $admin_origin[ 'host' ] ) != strtolower( $home_origin[ 'host' ] ) );
  3174 	$cross_domain = ( strtolower( $admin_origin['host'] ) != strtolower( $home_origin['host'] ) );
  3013 
  3175 
  3014 	?>
  3176 	?>
  3015 	<!--[if lte IE 8]>
  3177 	<!--[if lte IE 8]>
  3016 		<script type="text/javascript">
  3178 		<script type="text/javascript">
  3017 			document.body.className = document.body.className.replace( /(^|\s)(no-)?customize-support(?=\s|$)/, '' ) + ' no-customize-support';
  3179 			document.body.className = document.body.className.replace( /(^|\s)(no-)?customize-support(?=\s|$)/, '' ) + ' no-customize-support';
  3121 		/*
  3283 		/*
  3122 		 * Since the changeset no longer has an auto-draft (and it is not published)
  3284 		 * Since the changeset no longer has an auto-draft (and it is not published)
  3123 		 * it is now a persistent changeset, a long-lived draft, and so any
  3285 		 * it is now a persistent changeset, a long-lived draft, and so any
  3124 		 * associated auto-draft posts should likewise transition into having a draft
  3286 		 * associated auto-draft posts should likewise transition into having a draft
  3125 		 * status. These drafts will be treated differently than regular drafts in
  3287 		 * status. These drafts will be treated differently than regular drafts in
  3126 		 * that they will be tied to the given changeset. The publish metabox is
  3288 		 * that they will be tied to the given changeset. The publish meta box is
  3127 		 * replaced with a notice about how the post is part of a set of customized changes
  3289 		 * replaced with a notice about how the post is part of a set of customized changes
  3128 		 * which will be published when the changeset is published.
  3290 		 * which will be published when the changeset is published.
  3129 		 */
  3291 		 */
  3130 		$post_args['post_status'] = 'draft';
  3292 		$post_args['post_status'] = 'draft';
  3131 	}
  3293 	}