wp/wp-includes/theme.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    13  * linearly with additional themes. Stick to wp_get_theme() if possible.
    13  * linearly with additional themes. Stick to wp_get_theme() if possible.
    14  *
    14  *
    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
       
    19  *
    18  *
    20  * @param array $args {
    19  * @param array $args {
    21  *     Optional. The search arguments.
    20  *     Optional. The search arguments.
    22  *
    21  *
    23  *     @type mixed $errors  True to return themes with errors, false to return themes without errors, null to return all themes.
    22  *     @type mixed $errors  True to return themes with errors, false to return
    24  *                          Defaults to false.
    23  *                          themes without errors, null to return all themes.
    25  *     @type mixed $allowed (Multisite) True to return only allowed themes for a site. False to return only disallowed themes for a site.
    24  *                          Default false.
    26  *                          'site' to return only site-allowed themes. 'network' to return only network-allowed themes.
    25  *     @type mixed $allowed (Multisite) True to return only allowed themes for a site.
    27  *                          Null to return all themes. Defaults to null.
    26  *                          False to return only disallowed themes for a site.
    28  *     @type int   $blog_id (Multisite) The blog ID used to calculate which themes are allowed.
    27  *                          'site' to return only site-allowed themes.
    29  *                          Defaults to 0, synonymous for the current blog.
    28  *                          'network' to return only network-allowed themes.
       
    29  *                          Null to return all themes. Default null.
       
    30  *     @type int   $blog_id (Multisite) The blog ID used to calculate which themes
       
    31  *                          are allowed. Default 0, synonymous for the current blog.
    30  * }
    32  * }
    31  * @return WP_Theme[] Array of WP_Theme objects.
    33  * @return WP_Theme[] Array of WP_Theme objects.
    32  */
    34  */
    33 function wp_get_themes( $args = array() ) {
    35 function wp_get_themes( $args = array() ) {
    34 	global $wp_theme_directories;
    36 	global $wp_theme_directories;
    46 		// Make sure the current theme wins out, in case search_theme_directories() picks the wrong
    48 		// Make sure the current theme wins out, in case search_theme_directories() picks the wrong
    47 		// one in the case of a conflict. (Normally, last registered theme root wins.)
    49 		// one in the case of a conflict. (Normally, last registered theme root wins.)
    48 		$current_theme = get_stylesheet();
    50 		$current_theme = get_stylesheet();
    49 		if ( isset( $theme_directories[ $current_theme ] ) ) {
    51 		if ( isset( $theme_directories[ $current_theme ] ) ) {
    50 			$root_of_current_theme = get_raw_theme_root( $current_theme );
    52 			$root_of_current_theme = get_raw_theme_root( $current_theme );
    51 			if ( ! in_array( $root_of_current_theme, $wp_theme_directories ) ) {
    53 			if ( ! in_array( $root_of_current_theme, $wp_theme_directories, true ) ) {
    52 				$root_of_current_theme = WP_CONTENT_DIR . $root_of_current_theme;
    54 				$root_of_current_theme = WP_CONTENT_DIR . $root_of_current_theme;
    53 			}
    55 			}
    54 			$theme_directories[ $current_theme ]['theme_root'] = $root_of_current_theme;
    56 			$theme_directories[ $current_theme ]['theme_root'] = $root_of_current_theme;
    55 		}
    57 		}
    56 	}
    58 	}
    77 
    79 
    78 	foreach ( $theme_directories as $theme => $theme_root ) {
    80 	foreach ( $theme_directories as $theme => $theme_root ) {
    79 		if ( isset( $_themes[ $theme_root['theme_root'] . '/' . $theme ] ) ) {
    81 		if ( isset( $_themes[ $theme_root['theme_root'] . '/' . $theme ] ) ) {
    80 			$themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ];
    82 			$themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ];
    81 		} else {
    83 		} else {
    82 			$themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ] = new WP_Theme( $theme, $theme_root['theme_root'] );
    84 			$themes[ $theme ] = new WP_Theme( $theme, $theme_root['theme_root'] );
       
    85 
       
    86 			$_themes[ $theme_root['theme_root'] . '/' . $theme ] = $themes[ $theme ];
    83 		}
    87 		}
    84 	}
    88 	}
    85 
    89 
    86 	if ( null !== $args['errors'] ) {
    90 	if ( null !== $args['errors'] ) {
    87 		foreach ( $themes as $theme => $wp_theme ) {
    91 		foreach ( $themes as $theme => $wp_theme ) {
    99  *
   103  *
   100  * @since 3.4.0
   104  * @since 3.4.0
   101  *
   105  *
   102  * @global array $wp_theme_directories
   106  * @global array $wp_theme_directories
   103  *
   107  *
   104  * @param string $stylesheet Directory name for the theme. Optional. Defaults to current theme.
   108  * @param string $stylesheet Optional. Directory name for the theme. Defaults to current theme.
   105  * @param string $theme_root Absolute path of the theme root to look in. Optional. If not specified, get_raw_theme_root()
   109  * @param string $theme_root Optional. Absolute path of the theme root to look in.
   106  *                           is used to calculate the theme root for the $stylesheet provided (or current theme).
   110  *                           If not specified, get_raw_theme_root() is used to calculate
   107  * @return WP_Theme Theme object. Be sure to check the object's exists() method if you need to confirm the theme's existence.
   111  *                           the theme root for the $stylesheet provided (or current theme).
   108  */
   112  * @return WP_Theme Theme object. Be sure to check the object's exists() method
   109 function wp_get_theme( $stylesheet = null, $theme_root = null ) {
   113  *                  if you need to confirm the theme's existence.
       
   114  */
       
   115 function wp_get_theme( $stylesheet = '', $theme_root = '' ) {
   110 	global $wp_theme_directories;
   116 	global $wp_theme_directories;
   111 
   117 
   112 	if ( empty( $stylesheet ) ) {
   118 	if ( empty( $stylesheet ) ) {
   113 		$stylesheet = get_stylesheet();
   119 		$stylesheet = get_stylesheet();
   114 	}
   120 	}
   115 
   121 
   116 	if ( empty( $theme_root ) ) {
   122 	if ( empty( $theme_root ) ) {
   117 		$theme_root = get_raw_theme_root( $stylesheet );
   123 		$theme_root = get_raw_theme_root( $stylesheet );
   118 		if ( false === $theme_root ) {
   124 		if ( false === $theme_root ) {
   119 			$theme_root = WP_CONTENT_DIR . '/themes';
   125 			$theme_root = WP_CONTENT_DIR . '/themes';
   120 		} elseif ( ! in_array( $theme_root, (array) $wp_theme_directories ) ) {
   126 		} elseif ( ! in_array( $theme_root, (array) $wp_theme_directories, true ) ) {
   121 			$theme_root = WP_CONTENT_DIR . $theme_root;
   127 			$theme_root = WP_CONTENT_DIR . $theme_root;
   122 		}
   128 		}
   123 	}
   129 	}
   124 
   130 
   125 	return new WP_Theme( $stylesheet, $theme_root );
   131 	return new WP_Theme( $stylesheet, $theme_root );
   127 
   133 
   128 /**
   134 /**
   129  * Clears the cache held by get_theme_roots() and WP_Theme.
   135  * Clears the cache held by get_theme_roots() and WP_Theme.
   130  *
   136  *
   131  * @since 3.5.0
   137  * @since 3.5.0
   132  * @param bool $clear_update_cache Whether to clear the Theme updates cache
   138  * @param bool $clear_update_cache Whether to clear the theme updates cache.
   133  */
   139  */
   134 function wp_clean_themes_cache( $clear_update_cache = true ) {
   140 function wp_clean_themes_cache( $clear_update_cache = true ) {
   135 	if ( $clear_update_cache ) {
   141 	if ( $clear_update_cache ) {
   136 		delete_site_transient( 'update_themes' );
   142 		delete_site_transient( 'update_themes' );
   137 	}
   143 	}
   144 /**
   150 /**
   145  * Whether a child theme is in use.
   151  * Whether a child theme is in use.
   146  *
   152  *
   147  * @since 3.0.0
   153  * @since 3.0.0
   148  *
   154  *
   149  * @return bool true if a child theme is in use, false otherwise.
   155  * @return bool True if a child theme is in use, false otherwise.
   150  */
   156  */
   151 function is_child_theme() {
   157 function is_child_theme() {
   152 	return ( TEMPLATEPATH !== STYLESHEETPATH );
   158 	return ( TEMPLATEPATH !== STYLESHEETPATH );
   153 }
   159 }
   154 
   160 
   155 /**
   161 /**
   156  * Retrieve name of the current stylesheet.
   162  * Retrieves name of the current stylesheet.
   157  *
   163  *
   158  * The theme name that the administrator has currently set the front end theme
   164  * The theme name that is currently set as the front end theme.
   159  * as.
   165  *
   160  *
   166  * For all intents and purposes, the template name and the stylesheet name
   161  * For all intents and purposes, the template name and the stylesheet name are
   167  * are going to be the same for most cases.
   162  * going to be the same for most cases.
       
   163  *
   168  *
   164  * @since 1.5.0
   169  * @since 1.5.0
   165  *
   170  *
   166  * @return string Stylesheet name.
   171  * @return string Stylesheet name.
   167  */
   172  */
   175 	 */
   180 	 */
   176 	return apply_filters( 'stylesheet', get_option( 'stylesheet' ) );
   181 	return apply_filters( 'stylesheet', get_option( 'stylesheet' ) );
   177 }
   182 }
   178 
   183 
   179 /**
   184 /**
   180  * Retrieve stylesheet directory path for current theme.
   185  * Retrieves stylesheet directory path for current theme.
   181  *
   186  *
   182  * @since 1.5.0
   187  * @since 1.5.0
   183  *
   188  *
   184  * @return string Path to current theme directory.
   189  * @return string Path to current theme's stylesheet directory.
   185  */
   190  */
   186 function get_stylesheet_directory() {
   191 function get_stylesheet_directory() {
   187 	$stylesheet     = get_stylesheet();
   192 	$stylesheet     = get_stylesheet();
   188 	$theme_root     = get_theme_root( $stylesheet );
   193 	$theme_root     = get_theme_root( $stylesheet );
   189 	$stylesheet_dir = "$theme_root/$stylesheet";
   194 	$stylesheet_dir = "$theme_root/$stylesheet";
   199 	 */
   204 	 */
   200 	return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
   205 	return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
   201 }
   206 }
   202 
   207 
   203 /**
   208 /**
   204  * Retrieve stylesheet directory URI.
   209  * Retrieves stylesheet directory URI for current theme.
   205  *
   210  *
   206  * @since 1.5.0
   211  * @since 1.5.0
   207  *
   212  *
   208  * @return string
   213  * @return string URI to current theme's stylesheet directory.
   209  */
   214  */
   210 function get_stylesheet_directory_uri() {
   215 function get_stylesheet_directory_uri() {
   211 	$stylesheet         = str_replace( '%2F', '/', rawurlencode( get_stylesheet() ) );
   216 	$stylesheet         = str_replace( '%2F', '/', rawurlencode( get_stylesheet() ) );
   212 	$theme_root_uri     = get_theme_root_uri( $stylesheet );
   217 	$theme_root_uri     = get_theme_root_uri( $stylesheet );
   213 	$stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
   218 	$stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
   223 	 */
   228 	 */
   224 	return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
   229 	return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
   225 }
   230 }
   226 
   231 
   227 /**
   232 /**
   228  * Retrieves the URI of current theme stylesheet.
   233  * Retrieves stylesheet URI for current theme.
   229  *
   234  *
   230  * The stylesheet file name is 'style.css' which is appended to the stylesheet directory URI path.
   235  * The stylesheet file name is 'style.css' which is appended to the stylesheet directory URI path.
   231  * See get_stylesheet_directory_uri().
   236  * See get_stylesheet_directory_uri().
   232  *
   237  *
   233  * @since 1.5.0
   238  * @since 1.5.0
   234  *
   239  *
   235  * @return string
   240  * @return string URI to current theme's stylesheet.
   236  */
   241  */
   237 function get_stylesheet_uri() {
   242 function get_stylesheet_uri() {
   238 	$stylesheet_dir_uri = get_stylesheet_directory_uri();
   243 	$stylesheet_dir_uri = get_stylesheet_directory_uri();
   239 	$stylesheet_uri     = $stylesheet_dir_uri . '/style.css';
   244 	$stylesheet_uri     = $stylesheet_dir_uri . '/style.css';
   240 	/**
   245 	/**
   263  * WordPress workflow, then change the former. If you just have the locale in a
   268  * WordPress workflow, then change the former. If you just have the locale in a
   264  * separate folder, then change the latter.
   269  * separate folder, then change the latter.
   265  *
   270  *
   266  * @since 2.1.0
   271  * @since 2.1.0
   267  *
   272  *
   268  * @global WP_Locale $wp_locale
   273  * @global WP_Locale $wp_locale WordPress date and time locale object.
   269  *
   274  *
   270  * @return string
   275  * @return string URI to current theme's localized stylesheet.
   271  */
   276  */
   272 function get_locale_stylesheet_uri() {
   277 function get_locale_stylesheet_uri() {
   273 	global $wp_locale;
   278 	global $wp_locale;
   274 	$stylesheet_dir_uri = get_stylesheet_directory_uri();
   279 	$stylesheet_dir_uri = get_stylesheet_directory_uri();
   275 	$dir                = get_stylesheet_directory();
   280 	$dir                = get_stylesheet_directory();
   291 	 */
   296 	 */
   292 	return apply_filters( 'locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri );
   297 	return apply_filters( 'locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri );
   293 }
   298 }
   294 
   299 
   295 /**
   300 /**
   296  * Retrieve name of the current theme.
   301  * Retrieves name of the current theme.
   297  *
   302  *
   298  * @since 1.5.0
   303  * @since 1.5.0
   299  *
   304  *
   300  * @return string Template name.
   305  * @return string Template name.
   301  */
   306  */
   309 	 */
   314 	 */
   310 	return apply_filters( 'template', get_option( 'template' ) );
   315 	return apply_filters( 'template', get_option( 'template' ) );
   311 }
   316 }
   312 
   317 
   313 /**
   318 /**
   314  * Retrieve current theme directory.
   319  * Retrieves template directory path for current theme.
   315  *
   320  *
   316  * @since 1.5.0
   321  * @since 1.5.0
   317  *
   322  *
   318  * @return string Template directory path.
   323  * @return string Path to current theme's template directory.
   319  */
   324  */
   320 function get_template_directory() {
   325 function get_template_directory() {
   321 	$template     = get_template();
   326 	$template     = get_template();
   322 	$theme_root   = get_theme_root( $template );
   327 	$theme_root   = get_theme_root( $template );
   323 	$template_dir = "$theme_root/$template";
   328 	$template_dir = "$theme_root/$template";
   325 	/**
   330 	/**
   326 	 * Filters the current theme directory path.
   331 	 * Filters the current theme directory path.
   327 	 *
   332 	 *
   328 	 * @since 1.5.0
   333 	 * @since 1.5.0
   329 	 *
   334 	 *
   330 	 * @param string $template_dir The URI of the current theme directory.
   335 	 * @param string $template_dir The path of the current theme directory.
   331 	 * @param string $template     Directory name of the current theme.
   336 	 * @param string $template     Directory name of the current theme.
   332 	 * @param string $theme_root   Absolute path to the themes directory.
   337 	 * @param string $theme_root   Absolute path to the themes directory.
   333 	 */
   338 	 */
   334 	return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
   339 	return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
   335 }
   340 }
   336 
   341 
   337 /**
   342 /**
   338  * Retrieve theme directory URI.
   343  * Retrieves template directory URI for current theme.
   339  *
   344  *
   340  * @since 1.5.0
   345  * @since 1.5.0
   341  *
   346  *
   342  * @return string Template directory URI.
   347  * @return string URI to current theme's template directory.
   343  */
   348  */
   344 function get_template_directory_uri() {
   349 function get_template_directory_uri() {
   345 	$template         = str_replace( '%2F', '/', rawurlencode( get_template() ) );
   350 	$template         = str_replace( '%2F', '/', rawurlencode( get_template() ) );
   346 	$theme_root_uri   = get_theme_root_uri( $template );
   351 	$theme_root_uri   = get_theme_root_uri( $template );
   347 	$template_dir_uri = "$theme_root_uri/$template";
   352 	$template_dir_uri = "$theme_root_uri/$template";
   357 	 */
   362 	 */
   358 	return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
   363 	return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
   359 }
   364 }
   360 
   365 
   361 /**
   366 /**
   362  * Retrieve theme roots.
   367  * Retrieves theme roots.
   363  *
   368  *
   364  * @since 2.9.0
   369  * @since 2.9.0
   365  *
   370  *
   366  * @global array $wp_theme_directories
   371  * @global array $wp_theme_directories
   367  *
   372  *
   368  * @return array|string An array of theme roots keyed by template/stylesheet or a single theme root if all themes have the same root.
   373  * @return array|string An array of theme roots keyed by template/stylesheet
       
   374  *                      or a single theme root if all themes have the same root.
   369  */
   375  */
   370 function get_theme_roots() {
   376 function get_theme_roots() {
   371 	global $wp_theme_directories;
   377 	global $wp_theme_directories;
   372 
   378 
   373 	if ( ! is_array( $wp_theme_directories ) || count( $wp_theme_directories ) <= 1 ) {
   379 	if ( ! is_array( $wp_theme_directories ) || count( $wp_theme_directories ) <= 1 ) {
   381 	}
   387 	}
   382 	return $theme_roots;
   388 	return $theme_roots;
   383 }
   389 }
   384 
   390 
   385 /**
   391 /**
   386  * Register a directory that contains themes.
   392  * Registers a directory that contains themes.
   387  *
   393  *
   388  * @since 2.9.0
   394  * @since 2.9.0
   389  *
   395  *
   390  * @global array $wp_theme_directories
   396  * @global array $wp_theme_directories
   391  *
   397  *
   392  * @param string $directory Either the full filesystem path to a theme folder or a folder within WP_CONTENT_DIR
   398  * @param string $directory Either the full filesystem path to a theme folder
   393  * @return bool
   399  *                          or a folder within WP_CONTENT_DIR.
       
   400  * @return bool True if successfully registered a directory that contains themes,
       
   401  *              false if the directory does not exist.
   394  */
   402  */
   395 function register_theme_directory( $directory ) {
   403 function register_theme_directory( $directory ) {
   396 	global $wp_theme_directories;
   404 	global $wp_theme_directories;
   397 
   405 
   398 	if ( ! file_exists( $directory ) ) {
   406 	if ( ! file_exists( $directory ) ) {
   399 		// Try prepending as the theme directory could be relative to the content directory
   407 		// Try prepending as the theme directory could be relative to the content directory.
   400 		$directory = WP_CONTENT_DIR . '/' . $directory;
   408 		$directory = WP_CONTENT_DIR . '/' . $directory;
   401 		// If this directory does not exist, return and do not register
   409 		// If this directory does not exist, return and do not register.
   402 		if ( ! file_exists( $directory ) ) {
   410 		if ( ! file_exists( $directory ) ) {
   403 			return false;
   411 			return false;
   404 		}
   412 		}
   405 	}
   413 	}
   406 
   414 
   407 	if ( ! is_array( $wp_theme_directories ) ) {
   415 	if ( ! is_array( $wp_theme_directories ) ) {
   408 		$wp_theme_directories = array();
   416 		$wp_theme_directories = array();
   409 	}
   417 	}
   410 
   418 
   411 	$untrailed = untrailingslashit( $directory );
   419 	$untrailed = untrailingslashit( $directory );
   412 	if ( ! empty( $untrailed ) && ! in_array( $untrailed, $wp_theme_directories ) ) {
   420 	if ( ! empty( $untrailed ) && ! in_array( $untrailed, $wp_theme_directories, true ) ) {
   413 		$wp_theme_directories[] = $untrailed;
   421 		$wp_theme_directories[] = $untrailed;
   414 	}
   422 	}
   415 
   423 
   416 	return true;
   424 	return true;
   417 }
   425 }
   418 
   426 
   419 /**
   427 /**
   420  * Search all registered theme directories for complete and valid themes.
   428  * Searches all registered theme directories for complete and valid themes.
   421  *
   429  *
   422  * @since 2.9.0
   430  * @since 2.9.0
   423  *
   431  *
   424  * @global array $wp_theme_directories
   432  * @global array $wp_theme_directories
   425  * @staticvar array $found_themes
   433  *
   426  *
   434  * @param bool $force Optional. Whether to force a new directory scan. Default false.
   427  * @param bool $force Optional. Whether to force a new directory scan. Defaults to false.
   435  * @return array|false Valid themes found on success, false on failure.
   428  * @return array|false Valid themes found
       
   429  */
   436  */
   430 function search_theme_directories( $force = false ) {
   437 function search_theme_directories( $force = false ) {
   431 	global $wp_theme_directories;
   438 	global $wp_theme_directories;
   432 	static $found_themes = null;
   439 	static $found_themes = null;
   433 
   440 
   442 	$found_themes = array();
   449 	$found_themes = array();
   443 
   450 
   444 	$wp_theme_directories = (array) $wp_theme_directories;
   451 	$wp_theme_directories = (array) $wp_theme_directories;
   445 	$relative_theme_roots = array();
   452 	$relative_theme_roots = array();
   446 
   453 
   447 	// Set up maybe-relative, maybe-absolute array of theme directories.
   454 	/*
   448 	// We always want to return absolute, but we need to cache relative
   455 	 * Set up maybe-relative, maybe-absolute array of theme directories.
   449 	// to use in get_theme_root().
   456 	 * We always want to return absolute, but we need to cache relative
       
   457 	 * to use in get_theme_root().
       
   458 	 */
   450 	foreach ( $wp_theme_directories as $theme_root ) {
   459 	foreach ( $wp_theme_directories as $theme_root ) {
   451 		if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) {
   460 		if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) {
   452 			$relative_theme_roots[ str_replace( WP_CONTENT_DIR, '', $theme_root ) ] = $theme_root;
   461 			$relative_theme_roots[ str_replace( WP_CONTENT_DIR, '', $theme_root ) ] = $theme_root;
   453 		} else {
   462 		} else {
   454 			$relative_theme_roots[ $theme_root ] = $theme_root;
   463 			$relative_theme_roots[ $theme_root ] = $theme_root;
   459 	 * Filters whether to get the cache of the registered theme directories.
   468 	 * Filters whether to get the cache of the registered theme directories.
   460 	 *
   469 	 *
   461 	 * @since 3.4.0
   470 	 * @since 3.4.0
   462 	 *
   471 	 *
   463 	 * @param bool   $cache_expiration Whether to get the cache of the theme directories. Default false.
   472 	 * @param bool   $cache_expiration Whether to get the cache of the theme directories. Default false.
   464 	 * @param string $cache_directory  Directory to be searched for the cache.
   473 	 * @param string $context          The class or function name calling the filter.
   465 	 */
   474 	 */
   466 	if ( $cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' ) ) {
   475 	$cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' );
       
   476 
       
   477 	if ( $cache_expiration ) {
   467 		$cached_roots = get_site_transient( 'theme_roots' );
   478 		$cached_roots = get_site_transient( 'theme_roots' );
   468 		if ( is_array( $cached_roots ) ) {
   479 		if ( is_array( $cached_roots ) ) {
   469 			foreach ( $cached_roots as $theme_dir => $theme_root ) {
   480 			foreach ( $cached_roots as $theme_dir => $theme_root ) {
   470 				// A cached theme root is no longer around, so skip it.
   481 				// A cached theme root is no longer around, so skip it.
   471 				if ( ! isset( $relative_theme_roots[ $theme_root ] ) ) {
   482 				if ( ! isset( $relative_theme_roots[ $theme_root ] ) ) {
   477 				);
   488 				);
   478 			}
   489 			}
   479 			return $found_themes;
   490 			return $found_themes;
   480 		}
   491 		}
   481 		if ( ! is_int( $cache_expiration ) ) {
   492 		if ( ! is_int( $cache_expiration ) ) {
   482 			$cache_expiration = 1800; // half hour
   493 			$cache_expiration = 30 * MINUTE_IN_SECONDS;
   483 		}
   494 		}
   484 	} else {
   495 	} else {
   485 		$cache_expiration = 1800; // half hour
   496 		$cache_expiration = 30 * MINUTE_IN_SECONDS;
   486 	}
   497 	}
   487 
   498 
   488 	/* Loop the registered theme directories and extract all themes */
   499 	/* Loop the registered theme directories and extract all themes */
   489 	foreach ( $wp_theme_directories as $theme_root ) {
   500 	foreach ( $wp_theme_directories as $theme_root ) {
   490 
   501 
   493 		if ( ! $dirs ) {
   504 		if ( ! $dirs ) {
   494 			trigger_error( "$theme_root is not readable", E_USER_NOTICE );
   505 			trigger_error( "$theme_root is not readable", E_USER_NOTICE );
   495 			continue;
   506 			continue;
   496 		}
   507 		}
   497 		foreach ( $dirs as $dir ) {
   508 		foreach ( $dirs as $dir ) {
   498 			if ( ! is_dir( $theme_root . '/' . $dir ) || $dir[0] == '.' || $dir == 'CVS' ) {
   509 			if ( ! is_dir( $theme_root . '/' . $dir ) || '.' === $dir[0] || 'CVS' === $dir ) {
   499 				continue;
   510 				continue;
   500 			}
   511 			}
   501 			if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) {
   512 			if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) {
   502 				// wp-content/themes/a-single-theme
   513 				// wp-content/themes/a-single-theme
   503 				// wp-content/themes is $theme_root, a-single-theme is $dir
   514 				// wp-content/themes is $theme_root, a-single-theme is $dir.
   504 				$found_themes[ $dir ] = array(
   515 				$found_themes[ $dir ] = array(
   505 					'theme_file' => $dir . '/style.css',
   516 					'theme_file' => $dir . '/style.css',
   506 					'theme_root' => $theme_root,
   517 					'theme_root' => $theme_root,
   507 				);
   518 				);
   508 			} else {
   519 			} else {
   509 				$found_theme = false;
   520 				$found_theme = false;
   510 				// wp-content/themes/a-folder-of-themes/*
   521 				// wp-content/themes/a-folder-of-themes/*
   511 				// wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs
   522 				// wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs.
   512 				$sub_dirs = @ scandir( $theme_root . '/' . $dir );
   523 				$sub_dirs = @ scandir( $theme_root . '/' . $dir );
   513 				if ( ! $sub_dirs ) {
   524 				if ( ! $sub_dirs ) {
   514 					trigger_error( "$theme_root/$dir is not readable", E_USER_NOTICE );
   525 					trigger_error( "$theme_root/$dir is not readable", E_USER_NOTICE );
   515 					continue;
   526 					continue;
   516 				}
   527 				}
   517 				foreach ( $sub_dirs as $sub_dir ) {
   528 				foreach ( $sub_dirs as $sub_dir ) {
   518 					if ( ! is_dir( $theme_root . '/' . $dir . '/' . $sub_dir ) || $dir[0] == '.' || $dir == 'CVS' ) {
   529 					if ( ! is_dir( $theme_root . '/' . $dir . '/' . $sub_dir ) || '.' === $dir[0] || 'CVS' === $dir ) {
   519 						continue;
   530 						continue;
   520 					}
   531 					}
   521 					if ( ! file_exists( $theme_root . '/' . $dir . '/' . $sub_dir . '/style.css' ) ) {
   532 					if ( ! file_exists( $theme_root . '/' . $dir . '/' . $sub_dir . '/style.css' ) ) {
   522 						continue;
   533 						continue;
   523 					}
   534 					}
   546 
   557 
   547 	foreach ( $found_themes as $theme_dir => $theme_data ) {
   558 	foreach ( $found_themes as $theme_dir => $theme_data ) {
   548 		$theme_roots[ $theme_dir ] = $relative_theme_roots[ $theme_data['theme_root'] ]; // Convert absolute to relative.
   559 		$theme_roots[ $theme_dir ] = $relative_theme_roots[ $theme_data['theme_root'] ]; // Convert absolute to relative.
   549 	}
   560 	}
   550 
   561 
   551 	if ( $theme_roots != get_site_transient( 'theme_roots' ) ) {
   562 	if ( get_site_transient( 'theme_roots' ) != $theme_roots ) {
   552 		set_site_transient( 'theme_roots', $theme_roots, $cache_expiration );
   563 		set_site_transient( 'theme_roots', $theme_roots, $cache_expiration );
   553 	}
   564 	}
   554 
   565 
   555 	return $found_themes;
   566 	return $found_themes;
   556 }
   567 }
   557 
   568 
   558 /**
   569 /**
   559  * Retrieve path to themes directory.
   570  * Retrieves path to themes directory.
   560  *
   571  *
   561  * Does not have trailing slash.
   572  * Does not have trailing slash.
   562  *
   573  *
   563  * @since 1.5.0
   574  * @since 1.5.0
   564  *
   575  *
   565  * @global array $wp_theme_directories
   576  * @global array $wp_theme_directories
   566  *
   577  *
   567  * @param string $stylesheet_or_template The stylesheet or template name of the theme
   578  * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
   568  * @return string Theme path.
   579  *                                       Default is to leverage the main theme root.
   569  */
   580  * @return string Themes directory path.
   570 function get_theme_root( $stylesheet_or_template = false ) {
   581  */
       
   582 function get_theme_root( $stylesheet_or_template = '' ) {
   571 	global $wp_theme_directories;
   583 	global $wp_theme_directories;
   572 
   584 
   573 	if ( $stylesheet_or_template && $theme_root = get_raw_theme_root( $stylesheet_or_template ) ) {
   585 	$theme_root = '';
   574 		// Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory.
   586 
   575 		// This gives relative theme roots the benefit of the doubt when things go haywire.
   587 	if ( $stylesheet_or_template ) {
   576 		if ( ! in_array( $theme_root, (array) $wp_theme_directories ) ) {
   588 		$theme_root = get_raw_theme_root( $stylesheet_or_template );
   577 			$theme_root = WP_CONTENT_DIR . $theme_root;
   589 		if ( $theme_root ) {
   578 		}
   590 			// Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory.
   579 	} else {
   591 			// This gives relative theme roots the benefit of the doubt when things go haywire.
       
   592 			if ( ! in_array( $theme_root, (array) $wp_theme_directories, true ) ) {
       
   593 				$theme_root = WP_CONTENT_DIR . $theme_root;
       
   594 			}
       
   595 		}
       
   596 	}
       
   597 
       
   598 	if ( ! $theme_root ) {
   580 		$theme_root = WP_CONTENT_DIR . '/themes';
   599 		$theme_root = WP_CONTENT_DIR . '/themes';
   581 	}
   600 	}
   582 
   601 
   583 	/**
   602 	/**
   584 	 * Filters the absolute path to the themes directory.
   603 	 * Filters the absolute path to the themes directory.
   589 	 */
   608 	 */
   590 	return apply_filters( 'theme_root', $theme_root );
   609 	return apply_filters( 'theme_root', $theme_root );
   591 }
   610 }
   592 
   611 
   593 /**
   612 /**
   594  * Retrieve URI for themes directory.
   613  * Retrieves URI for themes directory.
   595  *
   614  *
   596  * Does not have trailing slash.
   615  * Does not have trailing slash.
   597  *
   616  *
   598  * @since 1.5.0
   617  * @since 1.5.0
   599  *
   618  *
   600  * @global array $wp_theme_directories
   619  * @global array $wp_theme_directories
   601  *
   620  *
   602  * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
   621  * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
   603  *                                       Default is to leverage the main theme root.
   622  *                                       Default is to leverage the main theme root.
   604  * @param string $theme_root             Optional. The theme root for which calculations will be based, preventing
   623  * @param string $theme_root             Optional. The theme root for which calculations will be based,
   605  *                                       the need for a get_raw_theme_root() call.
   624  *                                       preventing the need for a get_raw_theme_root() call. Default empty.
   606  * @return string Themes URI.
   625  * @return string Themes directory URI.
   607  */
   626  */
   608 function get_theme_root_uri( $stylesheet_or_template = false, $theme_root = false ) {
   627 function get_theme_root_uri( $stylesheet_or_template = '', $theme_root = '' ) {
   609 	global $wp_theme_directories;
   628 	global $wp_theme_directories;
   610 
   629 
   611 	if ( $stylesheet_or_template && ! $theme_root ) {
   630 	if ( $stylesheet_or_template && ! $theme_root ) {
   612 		$theme_root = get_raw_theme_root( $stylesheet_or_template );
   631 		$theme_root = get_raw_theme_root( $stylesheet_or_template );
   613 	}
   632 	}
   614 
   633 
   615 	if ( $stylesheet_or_template && $theme_root ) {
   634 	if ( $stylesheet_or_template && $theme_root ) {
   616 		if ( in_array( $theme_root, (array) $wp_theme_directories ) ) {
   635 		if ( in_array( $theme_root, (array) $wp_theme_directories, true ) ) {
   617 			// Absolute path. Make an educated guess. YMMV -- but note the filter below.
   636 			// Absolute path. Make an educated guess. YMMV -- but note the filter below.
   618 			if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) {
   637 			if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) {
   619 				$theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) );
   638 				$theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) );
   620 			} elseif ( 0 === strpos( $theme_root, ABSPATH ) ) {
   639 			} elseif ( 0 === strpos( $theme_root, ABSPATH ) ) {
   621 				$theme_root_uri = site_url( str_replace( ABSPATH, '', $theme_root ) );
   640 				$theme_root_uri = site_url( str_replace( ABSPATH, '', $theme_root ) );
   636 	 *
   655 	 *
   637 	 * @since 1.5.0
   656 	 * @since 1.5.0
   638 	 *
   657 	 *
   639 	 * @param string $theme_root_uri         The URI for themes directory.
   658 	 * @param string $theme_root_uri         The URI for themes directory.
   640 	 * @param string $siteurl                WordPress web address which is set in General Options.
   659 	 * @param string $siteurl                WordPress web address which is set in General Options.
   641 	 * @param string $stylesheet_or_template Stylesheet or template name of the theme.
   660 	 * @param string $stylesheet_or_template The stylesheet or template name of the theme.
   642 	 */
   661 	 */
   643 	return apply_filters( 'theme_root_uri', $theme_root_uri, get_option( 'siteurl' ), $stylesheet_or_template );
   662 	return apply_filters( 'theme_root_uri', $theme_root_uri, get_option( 'siteurl' ), $stylesheet_or_template );
   644 }
   663 }
   645 
   664 
   646 /**
   665 /**
   647  * Get the raw theme root relative to the content directory with no filters applied.
   666  * Gets the raw theme root relative to the content directory with no filters applied.
   648  *
   667  *
   649  * @since 3.1.0
   668  * @since 3.1.0
   650  *
   669  *
   651  * @global array $wp_theme_directories
   670  * @global array $wp_theme_directories
   652  *
   671  *
   653  * @param string $stylesheet_or_template The stylesheet or template name of the theme
   672  * @param string $stylesheet_or_template The stylesheet or template name of the theme.
   654  * @param bool   $skip_cache             Optional. Whether to skip the cache.
   673  * @param bool   $skip_cache             Optional. Whether to skip the cache.
   655  *                                       Defaults to false, meaning the cache is used.
   674  *                                       Defaults to false, meaning the cache is used.
   656  * @return string Theme root
   675  * @return string Theme root.
   657  */
   676  */
   658 function get_raw_theme_root( $stylesheet_or_template, $skip_cache = false ) {
   677 function get_raw_theme_root( $stylesheet_or_template, $skip_cache = false ) {
   659 	global $wp_theme_directories;
   678 	global $wp_theme_directories;
   660 
   679 
   661 	if ( ! is_array( $wp_theme_directories ) || count( $wp_theme_directories ) <= 1 ) {
   680 	if ( ! is_array( $wp_theme_directories ) || count( $wp_theme_directories ) <= 1 ) {
   662 		return '/themes';
   681 		return '/themes';
   663 	}
   682 	}
   664 
   683 
   665 	$theme_root = false;
   684 	$theme_root = false;
   666 
   685 
   667 	// If requesting the root for the current theme, consult options to avoid calling get_theme_roots()
   686 	// If requesting the root for the current theme, consult options to avoid calling get_theme_roots().
   668 	if ( ! $skip_cache ) {
   687 	if ( ! $skip_cache ) {
   669 		if ( get_option( 'stylesheet' ) == $stylesheet_or_template ) {
   688 		if ( get_option( 'stylesheet' ) == $stylesheet_or_template ) {
   670 			$theme_root = get_option( 'stylesheet_root' );
   689 			$theme_root = get_option( 'stylesheet_root' );
   671 		} elseif ( get_option( 'template' ) == $stylesheet_or_template ) {
   690 		} elseif ( get_option( 'template' ) == $stylesheet_or_template ) {
   672 			$theme_root = get_option( 'template_root' );
   691 			$theme_root = get_option( 'template_root' );
   682 
   701 
   683 	return $theme_root;
   702 	return $theme_root;
   684 }
   703 }
   685 
   704 
   686 /**
   705 /**
   687  * Display localized stylesheet link element.
   706  * Displays localized stylesheet link element.
   688  *
   707  *
   689  * @since 2.1.0
   708  * @since 2.1.0
   690  */
   709  */
   691 function locale_stylesheet() {
   710 function locale_stylesheet() {
   692 	$stylesheet = get_locale_stylesheet_uri();
   711 	$stylesheet = get_locale_stylesheet_uri();
   693 	if ( empty( $stylesheet ) ) {
   712 	if ( empty( $stylesheet ) ) {
   694 		return;
   713 		return;
   695 	}
   714 	}
   696 	echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
   715 
       
   716 	$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
       
   717 
       
   718 	printf(
       
   719 		'<link rel="stylesheet" href="%s"%s media="screen" />',
       
   720 		$stylesheet,
       
   721 		$type_attr
       
   722 	);
   697 }
   723 }
   698 
   724 
   699 /**
   725 /**
   700  * Switches the theme.
   726  * Switches the theme.
   701  *
   727  *
   706  *
   732  *
   707  * @global array                $wp_theme_directories
   733  * @global array                $wp_theme_directories
   708  * @global WP_Customize_Manager $wp_customize
   734  * @global WP_Customize_Manager $wp_customize
   709  * @global array                $sidebars_widgets
   735  * @global array                $sidebars_widgets
   710  *
   736  *
   711  * @param string $stylesheet Stylesheet name
   737  * @param string $stylesheet Stylesheet name.
   712  */
   738  */
   713 function switch_theme( $stylesheet ) {
   739 function switch_theme( $stylesheet ) {
   714 	global $wp_theme_directories, $wp_customize, $sidebars_widgets;
   740 	global $wp_theme_directories, $wp_customize, $sidebars_widgets;
       
   741 
       
   742 	$requirements = validate_theme_requirements( $stylesheet );
       
   743 	if ( is_wp_error( $requirements ) ) {
       
   744 		wp_die( $requirements );
       
   745 	}
   715 
   746 
   716 	$_sidebars_widgets = null;
   747 	$_sidebars_widgets = null;
   717 	if ( 'wp_ajax_customize_save' === current_action() ) {
   748 	if ( 'wp_ajax_customize_save' === current_action() ) {
   718 		$old_sidebars_widgets_data_setting = $wp_customize->get_setting( 'old_sidebars_widgets_data' );
   749 		$old_sidebars_widgets_data_setting = $wp_customize->get_setting( 'old_sidebars_widgets_data' );
   719 		if ( $old_sidebars_widgets_data_setting ) {
   750 		if ( $old_sidebars_widgets_data_setting ) {
   797 	 */
   828 	 */
   798 	do_action( 'switch_theme', $new_name, $new_theme, $old_theme );
   829 	do_action( 'switch_theme', $new_name, $new_theme, $old_theme );
   799 }
   830 }
   800 
   831 
   801 /**
   832 /**
   802  * Checks that current theme files 'index.php' and 'style.css' exists.
   833  * Checks that the current theme has 'index.php' and 'style.css' files.
   803  *
   834  *
   804  * Does not initially check the default theme, which is the fallback and should always exist.
   835  * Does not initially check the default theme, which is the fallback and should always exist.
   805  * But if it doesn't exist, it'll fall back to the latest core default theme that does exist.
   836  * But if it doesn't exist, it'll fall back to the latest core default theme that does exist.
   806  * Will switch theme to the fallback theme if current theme does not validate.
   837  * Will switch theme to the fallback theme if current theme does not validate.
   807  *
   838  *
   808  * You can use the {@see 'validate_current_theme'} filter to return false to
   839  * You can use the {@see 'validate_current_theme'} filter to return false to disable
   809  * disable this functionality.
   840  * this functionality.
   810  *
   841  *
   811  * @since 1.5.0
   842  * @since 1.5.0
       
   843  *
   812  * @see WP_DEFAULT_THEME
   844  * @see WP_DEFAULT_THEME
   813  *
   845  *
   814  * @return bool
   846  * @return bool
   815  */
   847  */
   816 function validate_current_theme() {
   848 function validate_current_theme() {
   843 	}
   875 	}
   844 
   876 
   845 	/**
   877 	/**
   846 	 * If we're in an invalid state but WP_DEFAULT_THEME doesn't exist,
   878 	 * If we're in an invalid state but WP_DEFAULT_THEME doesn't exist,
   847 	 * switch to the latest core default theme that's installed.
   879 	 * switch to the latest core default theme that's installed.
       
   880 	 *
   848 	 * If it turns out that this latest core default theme is our current
   881 	 * If it turns out that this latest core default theme is our current
   849 	 * theme, then there's nothing we can do about that, so we have to bail,
   882 	 * theme, then there's nothing we can do about that, so we have to bail,
   850 	 * rather than going into an infinite loop. (This is why there are
   883 	 * rather than going into an infinite loop. (This is why there are
   851 	 * checks against WP_DEFAULT_THEME above, also.) We also can't do anything
   884 	 * checks against WP_DEFAULT_THEME above, also.) We also can't do anything
   852 	 * if it turns out there is no default theme installed. (That's `false`.)
   885 	 * if it turns out there is no default theme installed. (That's `false`.)
   859 	switch_theme( $default->get_stylesheet() );
   892 	switch_theme( $default->get_stylesheet() );
   860 	return false;
   893 	return false;
   861 }
   894 }
   862 
   895 
   863 /**
   896 /**
   864  * Retrieve all theme modifications.
   897  * Validates the theme requirements for WordPress version and PHP version.
       
   898  *
       
   899  * Uses the information from `Requires at least` and `Requires PHP` headers
       
   900  * defined in the theme's `style.css` file.
       
   901  *
       
   902  * If the headers are not present in the theme's stylesheet file,
       
   903  * `readme.txt` is also checked as a fallback.
       
   904  *
       
   905  * @since 5.5.0
       
   906  *
       
   907  * @param string $stylesheet Directory name for the theme.
       
   908  * @return true|WP_Error True if requirements are met, WP_Error on failure.
       
   909  */
       
   910 function validate_theme_requirements( $stylesheet ) {
       
   911 	$theme = wp_get_theme( $stylesheet );
       
   912 
       
   913 	$requirements = array(
       
   914 		'requires'     => ! empty( $theme->get( 'RequiresWP' ) ) ? $theme->get( 'RequiresWP' ) : '',
       
   915 		'requires_php' => ! empty( $theme->get( 'RequiresPHP' ) ) ? $theme->get( 'RequiresPHP' ) : '',
       
   916 	);
       
   917 
       
   918 	$readme_file = $theme->theme_root . '/' . $stylesheet . '/readme.txt';
       
   919 
       
   920 	if ( file_exists( $readme_file ) ) {
       
   921 		$readme_headers = get_file_data(
       
   922 			$readme_file,
       
   923 			array(
       
   924 				'requires'     => 'Requires at least',
       
   925 				'requires_php' => 'Requires PHP',
       
   926 			),
       
   927 			'theme'
       
   928 		);
       
   929 
       
   930 		$requirements = array_merge( $readme_headers, $requirements );
       
   931 	}
       
   932 
       
   933 	$compatible_wp  = is_wp_version_compatible( $requirements['requires'] );
       
   934 	$compatible_php = is_php_version_compatible( $requirements['requires_php'] );
       
   935 
       
   936 	if ( ! $compatible_wp && ! $compatible_php ) {
       
   937 		return new WP_Error(
       
   938 			'theme_wp_php_incompatible',
       
   939 			sprintf(
       
   940 				/* translators: %s: Theme name. */
       
   941 				_x( '<strong>Error:</strong> Current WordPress and PHP versions do not meet minimum requirements for %s.', 'theme' ),
       
   942 				$theme->display( 'Name' )
       
   943 			)
       
   944 		);
       
   945 	} elseif ( ! $compatible_php ) {
       
   946 		return new WP_Error(
       
   947 			'theme_php_incompatible',
       
   948 			sprintf(
       
   949 				/* translators: %s: Theme name. */
       
   950 				_x( '<strong>Error:</strong> Current PHP version does not meet minimum requirements for %s.', 'theme' ),
       
   951 				$theme->display( 'Name' )
       
   952 			)
       
   953 		);
       
   954 	} elseif ( ! $compatible_wp ) {
       
   955 		return new WP_Error(
       
   956 			'theme_wp_incompatible',
       
   957 			sprintf(
       
   958 				/* translators: %s: Theme name. */
       
   959 				_x( '<strong>Error:</strong> Current WordPress version does not meet minimum requirements for %s.', 'theme' ),
       
   960 				$theme->display( 'Name' )
       
   961 			)
       
   962 		);
       
   963 	}
       
   964 
       
   965 	return true;
       
   966 }
       
   967 
       
   968 /**
       
   969  * Retrieves all theme modifications.
   865  *
   970  *
   866  * @since 3.1.0
   971  * @since 3.1.0
   867  *
   972  *
   868  * @return array|void Theme modifications.
   973  * @return array|void Theme modifications.
   869  */
   974  */
   883 	}
   988 	}
   884 	return $mods;
   989 	return $mods;
   885 }
   990 }
   886 
   991 
   887 /**
   992 /**
   888  * Retrieve theme modification value for the current theme.
   993  * Retrieves theme modification value for the current theme.
   889  *
   994  *
   890  * If the modification name does not exist, then the $default will be passed
   995  * If the modification name does not exist, then the $default will be passed
   891  * through {@link https://secure.php.net/sprintf sprintf()} PHP function with the first
   996  * through {@link https://www.php.net/sprintf sprintf()} PHP function with
   892  * string the template directory URI and the second string the stylesheet
   997  * the template directory URI as the first string and the stylesheet directory URI
   893  * directory URI.
   998  * as the second string.
   894  *
   999  *
   895  * @since 2.1.0
  1000  * @since 2.1.0
   896  *
  1001  *
   897  * @param string      $name    Theme modification name.
  1002  * @param string       $name    Theme modification name.
   898  * @param bool|string $default
  1003  * @param string|false $default Optional. Theme modification default value. Default false.
   899  * @return mixed
  1004  * @return mixed Theme modification value.
   900  */
  1005  */
   901 function get_theme_mod( $name, $default = false ) {
  1006 function get_theme_mod( $name, $default = false ) {
   902 	$mods = get_theme_mods();
  1007 	$mods = get_theme_mods();
   903 
  1008 
   904 	if ( isset( $mods[ $name ] ) ) {
  1009 	if ( isset( $mods[ $name ] ) ) {
   905 		/**
  1010 		/**
   906 		 * Filters the theme modification, or 'theme_mod', value.
  1011 		 * Filters the theme modification, or 'theme_mod', value.
   907 		 *
  1012 		 *
   908 		 * The dynamic portion of the hook name, `$name`, refers to
  1013 		 * The dynamic portion of the hook name, `$name`, refers to the key name
   909 		 * the key name of the modification array. For example,
  1014 		 * of the modification array. For example, 'header_textcolor', 'header_image',
   910 		 * 'header_textcolor', 'header_image', and so on depending
  1015 		 * and so on depending on the theme options.
   911 		 * on the theme options.
       
   912 		 *
  1016 		 *
   913 		 * @since 2.2.0
  1017 		 * @since 2.2.0
   914 		 *
  1018 		 *
   915 		 * @param string $current_mod The value of the current theme modification.
  1019 		 * @param string $current_mod The value of the current theme modification.
   916 		 */
  1020 		 */
   917 		return apply_filters( "theme_mod_{$name}", $mods[ $name ] );
  1021 		return apply_filters( "theme_mod_{$name}", $mods[ $name ] );
   918 	}
  1022 	}
   919 
  1023 
   920 	if ( is_string( $default ) ) {
  1024 	if ( is_string( $default ) ) {
   921 		$default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
  1025 		// Only run the replacement if an sprintf() string format pattern was found.
       
  1026 		if ( preg_match( '#(?<!%)%(?:\d+\$?)?s#', $default ) ) {
       
  1027 			$default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
       
  1028 		}
   922 	}
  1029 	}
   923 
  1030 
   924 	/** This filter is documented in wp-includes/theme.php */
  1031 	/** This filter is documented in wp-includes/theme.php */
   925 	return apply_filters( "theme_mod_{$name}", $default );
  1032 	return apply_filters( "theme_mod_{$name}", $default );
   926 }
  1033 }
   927 
  1034 
   928 /**
  1035 /**
   929  * Update theme modification value for the current theme.
  1036  * Updates theme modification value for the current theme.
   930  *
  1037  *
   931  * @since 2.1.0
  1038  * @since 2.1.0
   932  *
  1039  *
   933  * @param string $name  Theme modification name.
  1040  * @param string $name  Theme modification name.
   934  * @param mixed  $value Theme modification value.
  1041  * @param mixed  $value Theme modification value.
   936 function set_theme_mod( $name, $value ) {
  1043 function set_theme_mod( $name, $value ) {
   937 	$mods      = get_theme_mods();
  1044 	$mods      = get_theme_mods();
   938 	$old_value = isset( $mods[ $name ] ) ? $mods[ $name ] : false;
  1045 	$old_value = isset( $mods[ $name ] ) ? $mods[ $name ] : false;
   939 
  1046 
   940 	/**
  1047 	/**
   941 	 * Filters the theme mod value on save.
  1048 	 * Filters the theme modification, or 'theme_mod', value on save.
   942 	 *
  1049 	 *
   943 	 * The dynamic portion of the hook name, `$name`, refers to the key name of
  1050 	 * The dynamic portion of the hook name, `$name`, refers to the key name
   944 	 * the modification array. For example, 'header_textcolor', 'header_image',
  1051 	 * of the modification array. For example, 'header_textcolor', 'header_image',
   945 	 * and so on depending on the theme options.
  1052 	 * and so on depending on the theme options.
   946 	 *
  1053 	 *
   947 	 * @since 3.9.0
  1054 	 * @since 3.9.0
   948 	 *
  1055 	 *
   949 	 * @param string $value     The new value of the theme mod.
  1056 	 * @param string $value     The new value of the theme modification.
   950 	 * @param string $old_value The current value of the theme mod.
  1057 	 * @param string $old_value The current value of the theme modification.
   951 	 */
  1058 	 */
   952 	$mods[ $name ] = apply_filters( "pre_set_theme_mod_{$name}", $value, $old_value );
  1059 	$mods[ $name ] = apply_filters( "pre_set_theme_mod_{$name}", $value, $old_value );
   953 
  1060 
   954 	$theme = get_option( 'stylesheet' );
  1061 	$theme = get_option( 'stylesheet' );
   955 	update_option( "theme_mods_$theme", $mods );
  1062 	update_option( "theme_mods_$theme", $mods );
   956 }
  1063 }
   957 
  1064 
   958 /**
  1065 /**
   959  * Remove theme modification name from current theme list.
  1066  * Removes theme modification name from current theme list.
   960  *
  1067  *
   961  * If removing the name also removes all elements, then the entire option will
  1068  * If removing the name also removes all elements, then the entire option
   962  * be removed.
  1069  * will be removed.
   963  *
  1070  *
   964  * @since 2.1.0
  1071  * @since 2.1.0
   965  *
  1072  *
   966  * @param string $name Theme modification name.
  1073  * @param string $name Theme modification name.
   967  */
  1074  */
   981 	$theme = get_option( 'stylesheet' );
  1088 	$theme = get_option( 'stylesheet' );
   982 	update_option( "theme_mods_$theme", $mods );
  1089 	update_option( "theme_mods_$theme", $mods );
   983 }
  1090 }
   984 
  1091 
   985 /**
  1092 /**
   986  * Remove theme modifications option for current theme.
  1093  * Removes theme modifications option for current theme.
   987  *
  1094  *
   988  * @since 2.1.0
  1095  * @since 2.1.0
   989  */
  1096  */
   990 function remove_theme_mods() {
  1097 function remove_theme_mods() {
   991 	delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
  1098 	delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
  1033 	$text_color = get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
  1140 	$text_color = get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
  1034 	return 'blank' !== $text_color;
  1141 	return 'blank' !== $text_color;
  1035 }
  1142 }
  1036 
  1143 
  1037 /**
  1144 /**
  1038  * Check whether a header image is set or not.
  1145  * Checks whether a header image is set or not.
  1039  *
  1146  *
  1040  * @since 4.2.0
  1147  * @since 4.2.0
  1041  *
  1148  *
  1042  * @see get_header_image()
  1149  * @see get_header_image()
  1043  *
  1150  *
  1046 function has_header_image() {
  1153 function has_header_image() {
  1047 	return (bool) get_header_image();
  1154 	return (bool) get_header_image();
  1048 }
  1155 }
  1049 
  1156 
  1050 /**
  1157 /**
  1051  * Retrieve header image for custom header.
  1158  * Retrieves header image for custom header.
  1052  *
  1159  *
  1053  * @since 2.1.0
  1160  * @since 2.1.0
  1054  *
  1161  *
  1055  * @return string|false
  1162  * @return string|false
  1056  */
  1163  */
  1057 function get_header_image() {
  1164 function get_header_image() {
  1058 	$url = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
  1165 	$url = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
  1059 
  1166 
  1060 	if ( 'remove-header' == $url ) {
  1167 	if ( 'remove-header' === $url ) {
  1061 		return false;
  1168 		return false;
  1062 	}
  1169 	}
  1063 
  1170 
  1064 	if ( is_random_header_image() ) {
  1171 	if ( is_random_header_image() ) {
  1065 		$url = get_random_header_image();
  1172 		$url = get_random_header_image();
  1067 
  1174 
  1068 	return esc_url_raw( set_url_scheme( $url ) );
  1175 	return esc_url_raw( set_url_scheme( $url ) );
  1069 }
  1176 }
  1070 
  1177 
  1071 /**
  1178 /**
  1072  * Create image tag markup for a custom header image.
  1179  * Creates image tag markup for a custom header image.
  1073  *
  1180  *
  1074  * @since 4.4.0
  1181  * @since 4.4.0
  1075  *
  1182  *
  1076  * @param array $attr Optional. Additional attributes for the image tag. Can be used
  1183  * @param array $attr Optional. Additional attributes for the image tag. Can be used
  1077  *                              to override the default attributes. Default empty.
  1184  *                              to override the default attributes. Default empty.
  1134 	 */
  1241 	 */
  1135 	return apply_filters( 'get_header_image_tag', $html, $header, $attr );
  1242 	return apply_filters( 'get_header_image_tag', $html, $header, $attr );
  1136 }
  1243 }
  1137 
  1244 
  1138 /**
  1245 /**
  1139  * Display the image markup for a custom header image.
  1246  * Displays the image markup for a custom header image.
  1140  *
  1247  *
  1141  * @since 4.4.0
  1248  * @since 4.4.0
  1142  *
  1249  *
  1143  * @param array $attr Optional. Attributes for the image markup. Default empty.
  1250  * @param array $attr Optional. Attributes for the image markup. Default empty.
  1144  */
  1251  */
  1145 function the_header_image_tag( $attr = array() ) {
  1252 function the_header_image_tag( $attr = array() ) {
  1146 	echo get_header_image_tag( $attr );
  1253 	echo get_header_image_tag( $attr );
  1147 }
  1254 }
  1148 
  1255 
  1149 /**
  1256 /**
  1150  * Get random header image data from registered images in theme.
  1257  * Gets random header image data from registered images in theme.
  1151  *
  1258  *
  1152  * @since 3.4.0
  1259  * @since 3.4.0
  1153  *
  1260  *
  1154  * @access private
  1261  * @access private
  1155  *
  1262  *
  1156  * @global array  $_wp_default_headers
  1263  * @global array $_wp_default_headers
  1157  * @staticvar object $_wp_random_header
       
  1158  *
  1264  *
  1159  * @return object
  1265  * @return object
  1160  */
  1266  */
  1161 function _get_random_header_data() {
  1267 function _get_random_header_data() {
  1162 	static $_wp_random_header = null;
  1268 	static $_wp_random_header = null;
  1164 	if ( empty( $_wp_random_header ) ) {
  1270 	if ( empty( $_wp_random_header ) ) {
  1165 		global $_wp_default_headers;
  1271 		global $_wp_default_headers;
  1166 		$header_image_mod = get_theme_mod( 'header_image', '' );
  1272 		$header_image_mod = get_theme_mod( 'header_image', '' );
  1167 		$headers          = array();
  1273 		$headers          = array();
  1168 
  1274 
  1169 		if ( 'random-uploaded-image' == $header_image_mod ) {
  1275 		if ( 'random-uploaded-image' === $header_image_mod ) {
  1170 			$headers = get_uploaded_header_images();
  1276 			$headers = get_uploaded_header_images();
  1171 		} elseif ( ! empty( $_wp_default_headers ) ) {
  1277 		} elseif ( ! empty( $_wp_default_headers ) ) {
  1172 			if ( 'random-default-image' == $header_image_mod ) {
  1278 			if ( 'random-default-image' === $header_image_mod ) {
  1173 				$headers = $_wp_default_headers;
  1279 				$headers = $_wp_default_headers;
  1174 			} else {
  1280 			} else {
  1175 				if ( current_theme_supports( 'custom-header', 'random-default' ) ) {
  1281 				if ( current_theme_supports( 'custom-header', 'random-default' ) ) {
  1176 					$headers = $_wp_default_headers;
  1282 					$headers = $_wp_default_headers;
  1177 				}
  1283 				}
  1185 		$_wp_random_header = (object) $headers[ array_rand( $headers ) ];
  1291 		$_wp_random_header = (object) $headers[ array_rand( $headers ) ];
  1186 
  1292 
  1187 		$_wp_random_header->url           = sprintf( $_wp_random_header->url, get_template_directory_uri(), get_stylesheet_directory_uri() );
  1293 		$_wp_random_header->url           = sprintf( $_wp_random_header->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() );
  1294 		$_wp_random_header->thumbnail_url = sprintf( $_wp_random_header->thumbnail_url, get_template_directory_uri(), get_stylesheet_directory_uri() );
  1189 	}
  1295 	}
       
  1296 
  1190 	return $_wp_random_header;
  1297 	return $_wp_random_header;
  1191 }
  1298 }
  1192 
  1299 
  1193 /**
  1300 /**
  1194  * Get random header image url from registered images in theme.
  1301  * Gets random header image URL from registered images in theme.
  1195  *
  1302  *
  1196  * @since 3.2.0
  1303  * @since 3.2.0
  1197  *
  1304  *
  1198  * @return string Path to header image
  1305  * @return string Path to header image.
  1199  */
  1306  */
  1200 function get_random_header_image() {
  1307 function get_random_header_image() {
  1201 	$random_image = _get_random_header_data();
  1308 	$random_image = _get_random_header_data();
       
  1309 
  1202 	if ( empty( $random_image->url ) ) {
  1310 	if ( empty( $random_image->url ) ) {
  1203 		return '';
  1311 		return '';
  1204 	}
  1312 	}
       
  1313 
  1205 	return $random_image->url;
  1314 	return $random_image->url;
  1206 }
  1315 }
  1207 
  1316 
  1208 /**
  1317 /**
  1209  * Check if random header image is in use.
  1318  * Checks if random header image is in use.
  1210  *
  1319  *
  1211  * Always true if user expressly chooses the option in Appearance > Header.
  1320  * Always true if user expressly chooses the option in Appearance > Header.
  1212  * Also true if theme has multiple header images registered, no specific header image
  1321  * Also true if theme has multiple header images registered, no specific header image
  1213  * is chosen, and theme turns on random headers with add_theme_support().
  1322  * is chosen, and theme turns on random headers with add_theme_support().
  1214  *
  1323  *
  1215  * @since 3.2.0
  1324  * @since 3.2.0
  1216  *
  1325  *
  1217  * @param string $type The random pool to use. any|default|uploaded
  1326  * @param string $type The random pool to use. Possible values include 'any',
       
  1327  *                     'default', 'uploaded'. Default 'any'.
  1218  * @return bool
  1328  * @return bool
  1219  */
  1329  */
  1220 function is_random_header_image( $type = 'any' ) {
  1330 function is_random_header_image( $type = 'any' ) {
  1221 	$header_image_mod = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
  1331 	$header_image_mod = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
  1222 
  1332 
  1223 	if ( 'any' == $type ) {
  1333 	if ( 'any' === $type ) {
  1224 		if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) ) {
  1334 		if ( 'random-default-image' === $header_image_mod
       
  1335 			|| 'random-uploaded-image' === $header_image_mod
       
  1336 			|| ( '' !== get_random_header_image() && empty( $header_image_mod ) )
       
  1337 		) {
  1225 			return true;
  1338 			return true;
  1226 		}
  1339 		}
  1227 	} else {
  1340 	} else {
  1228 		if ( "random-$type-image" == $header_image_mod ) {
  1341 		if ( "random-$type-image" === $header_image_mod ) {
  1229 			return true;
  1342 			return true;
  1230 		} elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image() ) {
  1343 		} elseif ( 'default' === $type && empty( $header_image_mod ) && '' !== get_random_header_image() ) {
  1231 			return true;
  1344 			return true;
  1232 		}
  1345 		}
  1233 	}
  1346 	}
  1234 
  1347 
  1235 	return false;
  1348 	return false;
  1236 }
  1349 }
  1237 
  1350 
  1238 /**
  1351 /**
  1239  * Display header image URL.
  1352  * Displays header image URL.
  1240  *
  1353  *
  1241  * @since 2.1.0
  1354  * @since 2.1.0
  1242  */
  1355  */
  1243 function header_image() {
  1356 function header_image() {
  1244 	$image = get_header_image();
  1357 	$image = get_header_image();
       
  1358 
  1245 	if ( $image ) {
  1359 	if ( $image ) {
  1246 		echo esc_url( $image );
  1360 		echo esc_url( $image );
  1247 	}
  1361 	}
  1248 }
  1362 }
  1249 
  1363 
  1250 /**
  1364 /**
  1251  * Get the header images uploaded for the current theme.
  1365  * Gets the header images uploaded for the current theme.
  1252  *
  1366  *
  1253  * @since 3.2.0
  1367  * @since 3.2.0
  1254  *
  1368  *
  1255  * @return array
  1369  * @return array
  1256  */
  1370  */
  1257 function get_uploaded_header_images() {
  1371 function get_uploaded_header_images() {
  1258 	$header_images = array();
  1372 	$header_images = array();
  1259 
  1373 
  1260 	// @todo caching
  1374 	// @todo Caching.
  1261 	$headers = get_posts(
  1375 	$headers = get_posts(
  1262 		array(
  1376 		array(
  1263 			'post_type'  => 'attachment',
  1377 			'post_type'  => 'attachment',
  1264 			'meta_key'   => '_wp_attachment_is_custom_header',
  1378 			'meta_key'   => '_wp_attachment_is_custom_header',
  1265 			'meta_value' => get_option( 'stylesheet' ),
  1379 			'meta_value' => get_option( 'stylesheet' ),
  1294 
  1408 
  1295 	return $header_images;
  1409 	return $header_images;
  1296 }
  1410 }
  1297 
  1411 
  1298 /**
  1412 /**
  1299  * Get the header image data.
  1413  * Gets the header image data.
  1300  *
  1414  *
  1301  * @since 3.4.0
  1415  * @since 3.4.0
  1302  *
  1416  *
  1303  * @global array $_wp_default_headers
  1417  * @global array $_wp_default_headers
  1304  *
  1418  *
  1310 	if ( is_random_header_image() ) {
  1424 	if ( is_random_header_image() ) {
  1311 		$data = _get_random_header_data();
  1425 		$data = _get_random_header_data();
  1312 	} else {
  1426 	} else {
  1313 		$data = get_theme_mod( 'header_image_data' );
  1427 		$data = get_theme_mod( 'header_image_data' );
  1314 		if ( ! $data && current_theme_supports( 'custom-header', 'default-image' ) ) {
  1428 		if ( ! $data && current_theme_supports( 'custom-header', 'default-image' ) ) {
  1315 			$directory_args = array( get_template_directory_uri(), get_stylesheet_directory_uri() );
  1429 			$directory_args        = array( get_template_directory_uri(), get_stylesheet_directory_uri() );
  1316 			$data           = array();
  1430 			$data                  = array();
  1317 			$data['url']    = $data['thumbnail_url'] = vsprintf( get_theme_support( 'custom-header', 'default-image' ), $directory_args );
  1431 			$data['url']           = vsprintf( get_theme_support( 'custom-header', 'default-image' ), $directory_args );
       
  1432 			$data['thumbnail_url'] = $data['url'];
  1318 			if ( ! empty( $_wp_default_headers ) ) {
  1433 			if ( ! empty( $_wp_default_headers ) ) {
  1319 				foreach ( (array) $_wp_default_headers as $default_header ) {
  1434 				foreach ( (array) $_wp_default_headers as $default_header ) {
  1320 					$url = vsprintf( $default_header['url'], $directory_args );
  1435 					$url = vsprintf( $default_header['url'], $directory_args );
  1321 					if ( $data['url'] == $url ) {
  1436 					if ( $data['url'] == $url ) {
  1322 						$data                  = $default_header;
  1437 						$data                  = $default_header;
  1338 	);
  1453 	);
  1339 	return (object) wp_parse_args( $data, $default );
  1454 	return (object) wp_parse_args( $data, $default );
  1340 }
  1455 }
  1341 
  1456 
  1342 /**
  1457 /**
  1343  * Register a selection of default headers to be displayed by the custom header admin UI.
  1458  * Registers a selection of default headers to be displayed by the custom header admin UI.
  1344  *
  1459  *
  1345  * @since 3.0.0
  1460  * @since 3.0.0
  1346  *
  1461  *
  1347  * @global array $_wp_default_headers
  1462  * @global array $_wp_default_headers
  1348  *
  1463  *
  1349  * @param array $headers Array of headers keyed by a string id. The ids point to arrays containing 'url', 'thumbnail_url', and 'description' keys.
  1464  * @param array $headers Array of headers keyed by a string ID. The IDs point to arrays
       
  1465  *                       containing 'url', 'thumbnail_url', and 'description' keys.
  1350  */
  1466  */
  1351 function register_default_headers( $headers ) {
  1467 function register_default_headers( $headers ) {
  1352 	global $_wp_default_headers;
  1468 	global $_wp_default_headers;
  1353 
  1469 
  1354 	$_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
  1470 	$_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
  1355 }
  1471 }
  1356 
  1472 
  1357 /**
  1473 /**
  1358  * Unregister default headers.
  1474  * Unregisters default headers.
  1359  *
  1475  *
  1360  * This function must be called after register_default_headers() has already added the
  1476  * This function must be called after register_default_headers() has already added the
  1361  * header you want to remove.
  1477  * header you want to remove.
  1362  *
  1478  *
  1363  * @see register_default_headers()
  1479  * @see register_default_headers()
  1380 		return false;
  1496 		return false;
  1381 	}
  1497 	}
  1382 }
  1498 }
  1383 
  1499 
  1384 /**
  1500 /**
  1385  * Check whether a header video is set or not.
  1501  * Checks whether a header video is set or not.
  1386  *
  1502  *
  1387  * @since 4.7.0
  1503  * @since 4.7.0
  1388  *
  1504  *
  1389  * @see get_header_video_url()
  1505  * @see get_header_video_url()
  1390  *
  1506  *
  1393 function has_header_video() {
  1509 function has_header_video() {
  1394 	return (bool) get_header_video_url();
  1510 	return (bool) get_header_video_url();
  1395 }
  1511 }
  1396 
  1512 
  1397 /**
  1513 /**
  1398  * Retrieve header video URL for custom header.
  1514  * Retrieves header video URL for custom header.
  1399  *
  1515  *
  1400  * Uses a local video if present, or falls back to an external video.
  1516  * Uses a local video if present, or falls back to an external video.
  1401  *
  1517  *
  1402  * @since 4.7.0
  1518  * @since 4.7.0
  1403  *
  1519  *
  1404  * @return string|false Header video URL or false if there is no video.
  1520  * @return string|false Header video URL or false if there is no video.
  1405  */
  1521  */
  1406 function get_header_video_url() {
  1522 function get_header_video_url() {
  1407 	$id  = absint( get_theme_mod( 'header_video' ) );
  1523 	$id = absint( get_theme_mod( 'header_video' ) );
  1408 	$url = esc_url( get_theme_mod( 'external_header_video' ) );
       
  1409 
  1524 
  1410 	if ( $id ) {
  1525 	if ( $id ) {
  1411 		// Get the file URL from the attachment ID.
  1526 		// Get the file URL from the attachment ID.
  1412 		$url = wp_get_attachment_url( $id );
  1527 		$url = wp_get_attachment_url( $id );
       
  1528 	} else {
       
  1529 		$url = get_theme_mod( 'external_header_video' );
  1413 	}
  1530 	}
  1414 
  1531 
  1415 	/**
  1532 	/**
  1416 	 * Filters the header video URL.
  1533 	 * Filters the header video URL.
  1417 	 *
  1534 	 *
  1427 
  1544 
  1428 	return esc_url_raw( set_url_scheme( $url ) );
  1545 	return esc_url_raw( set_url_scheme( $url ) );
  1429 }
  1546 }
  1430 
  1547 
  1431 /**
  1548 /**
  1432  * Display header video URL.
  1549  * Displays header video URL.
  1433  *
  1550  *
  1434  * @since 4.7.0
  1551  * @since 4.7.0
  1435  */
  1552  */
  1436 function the_header_video_url() {
  1553 function the_header_video_url() {
  1437 	$video = get_header_video_url();
  1554 	$video = get_header_video_url();
       
  1555 
  1438 	if ( $video ) {
  1556 	if ( $video ) {
  1439 		echo esc_url( $video );
  1557 		echo esc_url( $video );
  1440 	}
  1558 	}
  1441 }
  1559 }
  1442 
  1560 
  1443 /**
  1561 /**
  1444  * Retrieve header video settings.
  1562  * Retrieves header video settings.
  1445  *
  1563  *
  1446  * @since 4.7.0
  1564  * @since 4.7.0
  1447  *
  1565  *
  1448  * @return array
  1566  * @return array
  1449  */
  1567  */
  1483 	 */
  1601 	 */
  1484 	return apply_filters( 'header_video_settings', $settings );
  1602 	return apply_filters( 'header_video_settings', $settings );
  1485 }
  1603 }
  1486 
  1604 
  1487 /**
  1605 /**
  1488  * Check whether a custom header is set or not.
  1606  * Checks whether a custom header is set or not.
  1489  *
  1607  *
  1490  * @since 4.7.0
  1608  * @since 4.7.0
  1491  *
  1609  *
  1492  * @return bool True if a custom header is set. False if not.
  1610  * @return bool True if a custom header is set. False if not.
  1493  */
  1611  */
  1518 	} else {
  1636 	} else {
  1519 		$show_video = call_user_func( $video_active_cb );
  1637 		$show_video = call_user_func( $video_active_cb );
  1520 	}
  1638 	}
  1521 
  1639 
  1522 	/**
  1640 	/**
  1523 	 * Modify whether the custom header video is eligible to show on the current page.
  1641 	 * Filters whether the custom header video is eligible to show on the current page.
  1524 	 *
  1642 	 *
  1525 	 * @since 4.7.0
  1643 	 * @since 4.7.0
  1526 	 *
  1644 	 *
  1527 	 * @param bool $show_video Whether the custom header video should be shown. Returns the value
  1645 	 * @param bool $show_video Whether the custom header video should be shown. Returns the value
  1528 	 *                         of the theme setting for the `custom-header`'s `video-active-callback`.
  1646 	 *                         of the theme setting for the `custom-header`'s `video-active-callback`.
  1530 	 */
  1648 	 */
  1531 	return apply_filters( 'is_header_video_active', $show_video );
  1649 	return apply_filters( 'is_header_video_active', $show_video );
  1532 }
  1650 }
  1533 
  1651 
  1534 /**
  1652 /**
  1535  * Retrieve the markup for a custom header.
  1653  * Retrieves the markup for a custom header.
  1536  *
  1654  *
  1537  * The container div will always be returned in the Customizer preview.
  1655  * The container div will always be returned in the Customizer preview.
  1538  *
  1656  *
  1539  * @since 4.7.0
  1657  * @since 4.7.0
  1540  *
  1658  *
  1550 		get_header_image_tag()
  1668 		get_header_image_tag()
  1551 	);
  1669 	);
  1552 }
  1670 }
  1553 
  1671 
  1554 /**
  1672 /**
  1555  * Print the markup for a custom header.
  1673  * Prints the markup for a custom header.
  1556  *
  1674  *
  1557  * A container div will always be printed in the Customizer preview.
  1675  * A container div will always be printed in the Customizer preview.
  1558  *
  1676  *
  1559  * @since 4.7.0
  1677  * @since 4.7.0
  1560  */
  1678  */
  1571 		wp_localize_script( 'wp-custom-header', '_wpCustomHeaderSettings', get_header_video_settings() );
  1689 		wp_localize_script( 'wp-custom-header', '_wpCustomHeaderSettings', get_header_video_settings() );
  1572 	}
  1690 	}
  1573 }
  1691 }
  1574 
  1692 
  1575 /**
  1693 /**
  1576  * Retrieve background image for custom background.
  1694  * Retrieves background image for custom background.
  1577  *
  1695  *
  1578  * @since 3.0.0
  1696  * @since 3.0.0
  1579  *
  1697  *
  1580  * @return string
  1698  * @return string
  1581  */
  1699  */
  1582 function get_background_image() {
  1700 function get_background_image() {
  1583 	return get_theme_mod( 'background_image', get_theme_support( 'custom-background', 'default-image' ) );
  1701 	return get_theme_mod( 'background_image', get_theme_support( 'custom-background', 'default-image' ) );
  1584 }
  1702 }
  1585 
  1703 
  1586 /**
  1704 /**
  1587  * Display background image path.
  1705  * Displays background image path.
  1588  *
  1706  *
  1589  * @since 3.0.0
  1707  * @since 3.0.0
  1590  */
  1708  */
  1591 function background_image() {
  1709 function background_image() {
  1592 	echo get_background_image();
  1710 	echo get_background_image();
  1593 }
  1711 }
  1594 
  1712 
  1595 /**
  1713 /**
  1596  * Retrieve value for custom background color.
  1714  * Retrieves value for custom background color.
  1597  *
  1715  *
  1598  * @since 3.0.0
  1716  * @since 3.0.0
  1599  *
  1717  *
  1600  * @return string
  1718  * @return string
  1601  */
  1719  */
  1602 function get_background_color() {
  1720 function get_background_color() {
  1603 	return get_theme_mod( 'background_color', get_theme_support( 'custom-background', 'default-color' ) );
  1721 	return get_theme_mod( 'background_color', get_theme_support( 'custom-background', 'default-color' ) );
  1604 }
  1722 }
  1605 
  1723 
  1606 /**
  1724 /**
  1607  * Display background color value.
  1725  * Displays background color value.
  1608  *
  1726  *
  1609  * @since 3.0.0
  1727  * @since 3.0.0
  1610  */
  1728  */
  1611 function background_color() {
  1729 function background_color() {
  1612 	echo get_background_color();
  1730 	echo get_background_color();
  1623 
  1741 
  1624 	// $color is the saved custom color.
  1742 	// $color is the saved custom color.
  1625 	// A default has to be specified in style.css. It will not be printed here.
  1743 	// A default has to be specified in style.css. It will not be printed here.
  1626 	$color = get_background_color();
  1744 	$color = get_background_color();
  1627 
  1745 
  1628 	if ( $color === get_theme_support( 'custom-background', 'default-color' ) ) {
  1746 	if ( get_theme_support( 'custom-background', 'default-color' ) === $color ) {
  1629 		$color = false;
  1747 		$color = false;
  1630 	}
  1748 	}
       
  1749 
       
  1750 	$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
  1631 
  1751 
  1632 	if ( ! $background && ! $color ) {
  1752 	if ( ! $background && ! $color ) {
  1633 		if ( is_customize_preview() ) {
  1753 		if ( is_customize_preview() ) {
  1634 			echo '<style type="text/css" id="custom-background-css"></style>';
  1754 			printf( '<style%s id="custom-background-css"></style>', $type_attr );
  1635 		}
  1755 		}
  1636 		return;
  1756 		return;
  1637 	}
  1757 	}
  1638 
  1758 
  1639 	$style = $color ? "background-color: #$color;" : '';
  1759 	$style = $color ? "background-color: #$color;" : '';
  1683 		$attachment = " background-attachment: $attachment;";
  1803 		$attachment = " background-attachment: $attachment;";
  1684 
  1804 
  1685 		$style .= $image . $position . $size . $repeat . $attachment;
  1805 		$style .= $image . $position . $size . $repeat . $attachment;
  1686 	}
  1806 	}
  1687 	?>
  1807 	?>
  1688 <style type="text/css" id="custom-background-css">
  1808 <style<?php echo $type_attr; ?> id="custom-background-css">
  1689 body.custom-background { <?php echo trim( $style ); ?> }
  1809 body.custom-background { <?php echo trim( $style ); ?> }
  1690 </style>
  1810 </style>
  1691 	<?php
  1811 	<?php
  1692 }
  1812 }
  1693 
  1813 
  1694 /**
  1814 /**
  1695  * Render the Custom CSS style element.
  1815  * Renders the Custom CSS style element.
  1696  *
  1816  *
  1697  * @since 4.7.0
  1817  * @since 4.7.0
  1698  */
  1818  */
  1699 function wp_custom_css_cb() {
  1819 function wp_custom_css_cb() {
  1700 	$styles = wp_get_custom_css();
  1820 	$styles = wp_get_custom_css();
  1701 	if ( $styles || is_customize_preview() ) :
  1821 	if ( $styles || is_customize_preview() ) :
       
  1822 		$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
  1702 		?>
  1823 		?>
  1703 		<style type="text/css" id="wp-custom-css">
  1824 		<style<?php echo $type_attr; ?> id="wp-custom-css">
  1704 			<?php echo strip_tags( $styles ); // Note that esc_html() cannot be used because `div &gt; span` is not interpreted properly. ?>
  1825 			<?php echo strip_tags( $styles ); // Note that esc_html() cannot be used because `div &gt; span` is not interpreted properly. ?>
  1705 		</style>
  1826 		</style>
  1706 		<?php
  1827 		<?php
  1707 	endif;
  1828 	endif;
  1708 }
  1829 }
  1709 
  1830 
  1710 /**
  1831 /**
  1711  * Fetch the `custom_css` post for a given theme.
  1832  * Fetches the `custom_css` post for a given theme.
  1712  *
  1833  *
  1713  * @since 4.7.0
  1834  * @since 4.7.0
  1714  *
  1835  *
  1715  * @param string $stylesheet Optional. A theme object stylesheet name. Defaults to the current theme.
  1836  * @param string $stylesheet Optional. A theme object stylesheet name. Defaults to the current theme.
  1716  * @return WP_Post|null The custom_css post or null if none exists.
  1837  * @return WP_Post|null The custom_css post or null if none exists.
  1757 
  1878 
  1758 	return $post;
  1879 	return $post;
  1759 }
  1880 }
  1760 
  1881 
  1761 /**
  1882 /**
  1762  * Fetch the saved Custom CSS content for rendering.
  1883  * Fetches the saved Custom CSS content for rendering.
  1763  *
  1884  *
  1764  * @since 4.7.0
  1885  * @since 4.7.0
  1765  *
  1886  *
  1766  * @param string $stylesheet Optional. A theme object stylesheet name. Defaults to the current theme.
  1887  * @param string $stylesheet Optional. A theme object stylesheet name. Defaults to the current theme.
  1767  * @return string The Custom CSS Post content.
  1888  * @return string The Custom CSS Post content.
  1790 
  1911 
  1791 	return $css;
  1912 	return $css;
  1792 }
  1913 }
  1793 
  1914 
  1794 /**
  1915 /**
  1795  * Update the `custom_css` post for a given theme.
  1916  * Updates the `custom_css` post for a given theme.
  1796  *
  1917  *
  1797  * Inserts a `custom_css` post when one doesn't yet exist.
  1918  * Inserts a `custom_css` post when one doesn't yet exist.
  1798  *
  1919  *
  1799  * @since 4.7.0
  1920  * @since 4.7.0
  1800  *
  1921  *
  1890 	}
  2011 	}
  1891 	return get_post( $r );
  2012 	return get_post( $r );
  1892 }
  2013 }
  1893 
  2014 
  1894 /**
  2015 /**
  1895  * Add callback for custom TinyMCE editor stylesheets.
  2016  * Adds callback for custom TinyMCE editor stylesheets.
  1896  *
  2017  *
  1897  * The parameter $stylesheet is the name of the stylesheet, relative to
  2018  * The parameter $stylesheet is the name of the stylesheet, relative to
  1898  * the theme root. It also accepts an array of stylesheets.
  2019  * the theme root. It also accepts an array of stylesheets.
  1899  * It is optional and defaults to 'editor-style.css'.
  2020  * It is optional and defaults to 'editor-style.css'.
  1900  *
  2021  *
  1912  *
  2033  *
  1913  * @param array|string $stylesheet Optional. Stylesheet name or array thereof, relative to theme root.
  2034  * @param array|string $stylesheet Optional. Stylesheet name or array thereof, relative to theme root.
  1914  *                                 Defaults to 'editor-style.css'
  2035  *                                 Defaults to 'editor-style.css'
  1915  */
  2036  */
  1916 function add_editor_style( $stylesheet = 'editor-style.css' ) {
  2037 function add_editor_style( $stylesheet = 'editor-style.css' ) {
       
  2038 	global $editor_styles;
       
  2039 
  1917 	add_theme_support( 'editor-style' );
  2040 	add_theme_support( 'editor-style' );
  1918 
  2041 
  1919 	if ( ! is_admin() ) {
       
  1920 		return;
       
  1921 	}
       
  1922 
       
  1923 	global $editor_styles;
       
  1924 	$editor_styles = (array) $editor_styles;
  2042 	$editor_styles = (array) $editor_styles;
  1925 	$stylesheet    = (array) $stylesheet;
  2043 	$stylesheet    = (array) $stylesheet;
       
  2044 
  1926 	if ( is_rtl() ) {
  2045 	if ( is_rtl() ) {
  1927 		$rtl_stylesheet = str_replace( '.css', '-rtl.css', $stylesheet[0] );
  2046 		$rtl_stylesheet = str_replace( '.css', '-rtl.css', $stylesheet[0] );
  1928 		$stylesheet[]   = $rtl_stylesheet;
  2047 		$stylesheet[]   = $rtl_stylesheet;
  1929 	}
  2048 	}
  1930 
  2049 
  1950 	}
  2069 	}
  1951 	return true;
  2070 	return true;
  1952 }
  2071 }
  1953 
  2072 
  1954 /**
  2073 /**
  1955  * Retrieve any registered editor stylesheets
  2074  * Retrieves any registered editor stylesheet URLs.
  1956  *
  2075  *
  1957  * @since 4.0.0
  2076  * @since 4.0.0
  1958  *
  2077  *
  1959  * @global array $editor_styles Registered editor stylesheets
  2078  * @global array $editor_styles Registered editor stylesheets
  1960  *
  2079  *
  1961  * @return array If registered, a list of editor stylesheet URLs.
  2080  * @return string[] If registered, a list of editor stylesheet URLs.
  1962  */
  2081  */
  1963 function get_editor_stylesheets() {
  2082 function get_editor_stylesheets() {
  1964 	$stylesheets = array();
  2083 	$stylesheets = array();
  1965 	// load editor_style.css if the current theme supports it
  2084 	// Load editor_style.css if the current theme supports it.
  1966 	if ( ! empty( $GLOBALS['editor_styles'] ) && is_array( $GLOBALS['editor_styles'] ) ) {
  2085 	if ( ! empty( $GLOBALS['editor_styles'] ) && is_array( $GLOBALS['editor_styles'] ) ) {
  1967 		$editor_styles = $GLOBALS['editor_styles'];
  2086 		$editor_styles = $GLOBALS['editor_styles'];
  1968 
  2087 
  1969 		$editor_styles = array_unique( array_filter( $editor_styles ) );
  2088 		$editor_styles = array_unique( array_filter( $editor_styles ) );
  1970 		$style_uri     = get_stylesheet_directory_uri();
  2089 		$style_uri     = get_stylesheet_directory_uri();
  1996 			}
  2115 			}
  1997 		}
  2116 		}
  1998 	}
  2117 	}
  1999 
  2118 
  2000 	/**
  2119 	/**
  2001 	 * Filters the array of stylesheets applied to the editor.
  2120 	 * Filters the array of URLs of stylesheets applied to the editor.
  2002 	 *
  2121 	 *
  2003 	 * @since 4.3.0
  2122 	 * @since 4.3.0
  2004 	 *
  2123 	 *
  2005 	 * @param array $stylesheets Array of stylesheets to be applied to the editor.
  2124 	 * @param string[] $stylesheets Array of URLs of stylesheets to be applied to the editor.
  2006 	 */
  2125 	 */
  2007 	return apply_filters( 'editor_stylesheets', $stylesheets );
  2126 	return apply_filters( 'editor_stylesheets', $stylesheets );
  2008 }
  2127 }
  2009 
  2128 
  2010 /**
  2129 /**
  2011  * Expand a theme's starter content configuration using core-provided data.
  2130  * Expands a theme's starter content configuration using core-provided data.
  2012  *
  2131  *
  2013  * @since 4.7.0
  2132  * @since 4.7.0
  2014  *
  2133  *
  2015  * @return array Array of starter content.
  2134  * @return array Array of starter content.
  2016  */
  2135  */
  2032 						'',
  2151 						'',
  2033 						array(
  2152 						array(
  2034 							'<strong>' . _x( 'Address', 'Theme starter content' ) . "</strong>\n",
  2153 							'<strong>' . _x( 'Address', 'Theme starter content' ) . "</strong>\n",
  2035 							_x( '123 Main Street', 'Theme starter content' ) . "\n" . _x( 'New York, NY 10001', 'Theme starter content' ) . "\n\n",
  2154 							_x( '123 Main Street', 'Theme starter content' ) . "\n" . _x( 'New York, NY 10001', 'Theme starter content' ) . "\n\n",
  2036 							'<strong>' . _x( 'Hours', 'Theme starter content' ) . "</strong>\n",
  2155 							'<strong>' . _x( 'Hours', 'Theme starter content' ) . "</strong>\n",
  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' ),
  2156 							_x( 'Monday&ndash;Friday: 9:00AM&ndash;5:00PM', 'Theme starter content' ) . "\n" . _x( 'Saturday &amp; Sunday: 11:00AM&ndash;3:00PM', 'Theme starter content' ),
  2038 						)
  2157 						)
  2039 					),
  2158 					),
  2040 					'filter' => true,
  2159 					'filter' => true,
  2041 					'visual' => true,
  2160 					'visual' => true,
  2042 				),
  2161 				),
  2097 			'link_home'       => array(
  2216 			'link_home'       => array(
  2098 				'type'  => 'custom',
  2217 				'type'  => 'custom',
  2099 				'title' => _x( 'Home', 'Theme starter content' ),
  2218 				'title' => _x( 'Home', 'Theme starter content' ),
  2100 				'url'   => home_url( '/' ),
  2219 				'url'   => home_url( '/' ),
  2101 			),
  2220 			),
  2102 			'page_home'       => array( // Deprecated in favor of link_home.
  2221 			'page_home'       => array( // Deprecated in favor of 'link_home'.
  2103 				'type'      => 'post_type',
  2222 				'type'      => 'post_type',
  2104 				'object'    => 'page',
  2223 				'object'    => 'page',
  2105 				'object_id' => '{{home}}',
  2224 				'object_id' => '{{home}}',
  2106 			),
  2225 			),
  2107 			'page_about'      => array(
  2226 			'page_about'      => array(
  2168 		),
  2287 		),
  2169 		'posts'     => array(
  2288 		'posts'     => array(
  2170 			'home'             => array(
  2289 			'home'             => array(
  2171 				'post_type'    => 'page',
  2290 				'post_type'    => 'page',
  2172 				'post_title'   => _x( 'Home', 'Theme starter content' ),
  2291 				'post_title'   => _x( 'Home', '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' ),
  2292 				'post_content' => sprintf(
       
  2293 					"<!-- wp:paragraph -->\n<p>%s</p>\n<!-- /wp:paragraph -->",
       
  2294 					_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' )
       
  2295 				),
  2174 			),
  2296 			),
  2175 			'about'            => array(
  2297 			'about'            => array(
  2176 				'post_type'    => 'page',
  2298 				'post_type'    => 'page',
  2177 				'post_title'   => _x( 'About', 'Theme starter content' ),
  2299 				'post_title'   => _x( 'About', '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' ),
  2300 				'post_content' => sprintf(
       
  2301 					"<!-- wp:paragraph -->\n<p>%s</p>\n<!-- /wp:paragraph -->",
       
  2302 					_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' )
       
  2303 				),
  2179 			),
  2304 			),
  2180 			'contact'          => array(
  2305 			'contact'          => array(
  2181 				'post_type'    => 'page',
  2306 				'post_type'    => 'page',
  2182 				'post_title'   => _x( 'Contact', 'Theme starter content' ),
  2307 				'post_title'   => _x( 'Contact', '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' ),
  2308 				'post_content' => sprintf(
       
  2309 					"<!-- wp:paragraph -->\n<p>%s</p>\n<!-- /wp:paragraph -->",
       
  2310 					_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' )
       
  2311 				),
  2184 			),
  2312 			),
  2185 			'blog'             => array(
  2313 			'blog'             => array(
  2186 				'post_type'  => 'page',
  2314 				'post_type'  => 'page',
  2187 				'post_title' => _x( 'Blog', 'Theme starter content' ),
  2315 				'post_title' => _x( 'Blog', 'Theme starter content' ),
  2188 			),
  2316 			),
  2192 			),
  2320 			),
  2193 
  2321 
  2194 			'homepage-section' => array(
  2322 			'homepage-section' => array(
  2195 				'post_type'    => 'page',
  2323 				'post_type'    => 'page',
  2196 				'post_title'   => _x( 'A homepage section', 'Theme starter content' ),
  2324 				'post_title'   => _x( 'A homepage section', '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' ),
  2325 				'post_content' => sprintf(
       
  2326 					"<!-- wp:paragraph -->\n<p>%s</p>\n<!-- /wp:paragraph -->",
       
  2327 					_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' )
       
  2328 				),
  2198 			),
  2329 			),
  2199 		),
  2330 		),
  2200 	);
  2331 	);
  2201 
  2332 
  2202 	$content = array();
  2333 	$content = array();
  2265 						$content[ $type ][ $id ] = $item;
  2396 						$content[ $type ][ $id ] = $item;
  2266 					}
  2397 					}
  2267 				}
  2398 				}
  2268 				break;
  2399 				break;
  2269 
  2400 
  2270 			// All that's left now are posts (besides attachments). Not a default case for the sake of clarity and future work.
  2401 			// All that's left now are posts (besides attachments).
       
  2402 			// Not a default case for the sake of clarity and future work.
  2271 			case 'posts':
  2403 			case 'posts':
  2272 				foreach ( $config[ $type ] as $id => $item ) {
  2404 				foreach ( $config[ $type ] as $id => $item ) {
  2273 					if ( is_array( $item ) ) {
  2405 					if ( is_array( $item ) ) {
  2274 
  2406 
  2275 						// Item extends core content.
  2407 						// Item extends core content.
  2316  *
  2448  *
  2317  * Must be called in the theme's functions.php file to work.
  2449  * Must be called in the theme's functions.php file to work.
  2318  * If attached to a hook, it must be {@see 'after_setup_theme'}.
  2450  * If attached to a hook, it must be {@see 'after_setup_theme'}.
  2319  * The {@see 'init'} hook may be too late for some features.
  2451  * The {@see 'init'} hook may be too late for some features.
  2320  *
  2452  *
       
  2453  * Example usage:
       
  2454  *
       
  2455  *     add_theme_support( 'title-tag' );
       
  2456  *     add_theme_support( 'custom-logo', array(
       
  2457  *         'height' => 480,
       
  2458  *         'width'  => 720,
       
  2459  *     ) );
       
  2460  *
  2321  * @since 2.9.0
  2461  * @since 2.9.0
  2322  * @since 3.6.0 The `html5` feature was added
  2462  * @since 3.4.0 The `custom-header-uploads` feature was deprecated.
  2323  * @since 3.9.0 The `html5` feature now also accepts 'gallery' and 'caption'
  2463  * @since 3.6.0 The `html5` feature was added.
  2324  * @since 4.1.0 The `title-tag` feature was added
  2464  * @since 3.9.0 The `html5` feature now also accepts 'gallery' and 'caption'.
  2325  * @since 4.5.0 The `customize-selective-refresh-widgets` feature was added
  2465  * @since 4.1.0 The `title-tag` feature was added.
  2326  * @since 4.7.0 The `starter-content` feature was added
  2466  * @since 4.5.0 The `customize-selective-refresh-widgets` feature was added.
       
  2467  * @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`,
  2468  * @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`,
  2469  *              `disable-custom-font-sizes`, `editor-color-palette`, `editor-font-sizes`,
  2329  *              `editor-styles`, and `wp-block-styles` features were added.
  2470  *              `editor-styles`, and `wp-block-styles` features were added.
       
  2471  * @since 5.3.0 The `html5` feature now also accepts 'script' and 'style'.
       
  2472  * @since 5.3.0 Formalized the existing and already documented `...$args` parameter
       
  2473  *              by adding it to the function signature.
       
  2474  * @since 5.5.0 The `core-block-patterns` feature was added and is enabled by default.
       
  2475  * @since 5.5.0 The `custom-logo` feature now also accepts 'unlink-homepage-logo'.
  2330  *
  2476  *
  2331  * @global array $_wp_theme_features
  2477  * @global array $_wp_theme_features
  2332  *
  2478  *
  2333  * @param string $feature  The feature being added. Likely core values include 'post-formats',
  2479  * @param string $feature The feature being added. Likely core values include 'post-formats', 'post-thumbnails',
  2334  *                         'post-thumbnails', 'html5', 'custom-logo', 'custom-header-uploads',
  2480  *                        'custom-header', 'custom-background', 'custom-logo', 'menus', 'automatic-feed-links',
  2335  *                         'custom-header', 'custom-background', 'title-tag', 'starter-content',
  2481  *                        'html5', 'title-tag', 'customize-selective-refresh-widgets', 'starter-content',
  2336  *                         'responsive-embeds', etc.
  2482  *                        'responsive-embeds', 'align-wide', 'dark-editor-style', 'disable-custom-colors',
  2337  * @param mixed  $args,... Optional extra arguments to pass along with certain features.
  2483  *                        'disable-custom-font-sizes', 'editor-color-palette', 'editor-font-sizes',
       
  2484  *                        'editor-styles', 'wp-block-styles', and 'core-block-patterns'.
       
  2485  * @param mixed  ...$args Optional extra arguments to pass along with certain features.
  2338  * @return void|bool False on failure, void otherwise.
  2486  * @return void|bool False on failure, void otherwise.
  2339  */
  2487  */
  2340 function add_theme_support( $feature ) {
  2488 function add_theme_support( $feature, ...$args ) {
  2341 	global $_wp_theme_features;
  2489 	global $_wp_theme_features;
  2342 
  2490 
  2343 	if ( func_num_args() == 1 ) {
  2491 	if ( ! $args ) {
  2344 		$args = true;
  2492 		$args = true;
  2345 	} else {
       
  2346 		$args = array_slice( func_get_args(), 1 );
       
  2347 	}
  2493 	}
  2348 
  2494 
  2349 	switch ( $feature ) {
  2495 	switch ( $feature ) {
  2350 		case 'post-thumbnails':
  2496 		case 'post-thumbnails':
  2351 			// All post types are already supported.
  2497 			// All post types are already supported.
  2355 
  2501 
  2356 			/*
  2502 			/*
  2357 			 * Merge post types with any that already declared their support
  2503 			 * Merge post types with any that already declared their support
  2358 			 * for post thumbnails.
  2504 			 * for post thumbnails.
  2359 			 */
  2505 			 */
  2360 			if ( is_array( $args[0] ) && isset( $_wp_theme_features['post-thumbnails'] ) ) {
  2506 			if ( isset( $args[0] ) && is_array( $args[0] ) && isset( $_wp_theme_features['post-thumbnails'] ) ) {
  2361 				$args[0] = array_unique( array_merge( $_wp_theme_features['post-thumbnails'][0], $args[0] ) );
  2507 				$args[0] = array_unique( array_merge( $_wp_theme_features['post-thumbnails'][0], $args[0] ) );
  2362 			}
  2508 			}
  2363 
  2509 
  2364 			break;
  2510 			break;
  2365 
  2511 
  2366 		case 'post-formats':
  2512 		case 'post-formats':
  2367 			if ( is_array( $args[0] ) ) {
  2513 			if ( isset( $args[0] ) && is_array( $args[0] ) ) {
  2368 				$post_formats = get_post_format_slugs();
  2514 				$post_formats = get_post_format_slugs();
  2369 				unset( $post_formats['standard'] );
  2515 				unset( $post_formats['standard'] );
  2370 
  2516 
  2371 				$args[0] = array_intersect( $args[0], array_keys( $post_formats ) );
  2517 				$args[0] = array_intersect( $args[0], array_keys( $post_formats ) );
  2372 			}
  2518 			}
  2375 		case 'html5':
  2521 		case 'html5':
  2376 			// You can't just pass 'html5', you need to pass an array of types.
  2522 			// You can't just pass 'html5', you need to pass an array of types.
  2377 			if ( empty( $args[0] ) ) {
  2523 			if ( empty( $args[0] ) ) {
  2378 				// Build an array of types for back-compat.
  2524 				// Build an array of types for back-compat.
  2379 				$args = array( 0 => array( 'comment-list', 'comment-form', 'search-form' ) );
  2525 				$args = array( 0 => array( 'comment-list', 'comment-form', 'search-form' ) );
  2380 			} elseif ( ! is_array( $args[0] ) ) {
  2526 			} elseif ( ! isset( $args[0] ) || ! is_array( $args[0] ) ) {
  2381 				_doing_it_wrong( "add_theme_support( 'html5' )", __( 'You need to pass an array of types.' ), '3.6.1' );
  2527 				_doing_it_wrong( "add_theme_support( 'html5' )", __( 'You need to pass an array of types.' ), '3.6.1' );
  2382 				return false;
  2528 				return false;
  2383 			}
  2529 			}
  2384 
  2530 
  2385 			// Calling 'html5' again merges, rather than overwrites.
  2531 			// Calling 'html5' again merges, rather than overwrites.
  2387 				$args[0] = array_merge( $_wp_theme_features['html5'][0], $args[0] );
  2533 				$args[0] = array_merge( $_wp_theme_features['html5'][0], $args[0] );
  2388 			}
  2534 			}
  2389 			break;
  2535 			break;
  2390 
  2536 
  2391 		case 'custom-logo':
  2537 		case 'custom-logo':
  2392 			if ( ! is_array( $args ) ) {
  2538 			if ( true === $args ) {
  2393 				$args = array( 0 => array() );
  2539 				$args = array( 0 => array() );
  2394 			}
  2540 			}
  2395 			$defaults = array(
  2541 			$defaults = array(
  2396 				'width'       => null,
  2542 				'width'                => null,
  2397 				'height'      => null,
  2543 				'height'               => null,
  2398 				'flex-width'  => false,
  2544 				'flex-width'           => false,
  2399 				'flex-height' => false,
  2545 				'flex-height'          => false,
  2400 				'header-text' => '',
  2546 				'header-text'          => '',
       
  2547 				'unlink-homepage-logo' => false,
  2401 			);
  2548 			);
  2402 			$args[0]  = wp_parse_args( array_intersect_key( $args[0], $defaults ), $defaults );
  2549 			$args[0]  = wp_parse_args( array_intersect_key( $args[0], $defaults ), $defaults );
  2403 
  2550 
  2404 			// Allow full flexibility if no size is specified.
  2551 			// Allow full flexibility if no size is specified.
  2405 			if ( is_null( $args[0]['width'] ) && is_null( $args[0]['height'] ) ) {
  2552 			if ( is_null( $args[0]['width'] ) && is_null( $args[0]['height'] ) ) {
  2410 
  2557 
  2411 		case 'custom-header-uploads':
  2558 		case 'custom-header-uploads':
  2412 			return add_theme_support( 'custom-header', array( 'uploads' => true ) );
  2559 			return add_theme_support( 'custom-header', array( 'uploads' => true ) );
  2413 
  2560 
  2414 		case 'custom-header':
  2561 		case 'custom-header':
  2415 			if ( ! is_array( $args ) ) {
  2562 			if ( true === $args ) {
  2416 				$args = array( 0 => array() );
  2563 				$args = array( 0 => array() );
  2417 			}
  2564 			}
  2418 
  2565 
  2419 			$defaults = array(
  2566 			$defaults = array(
  2420 				'default-image'          => '',
  2567 				'default-image'          => '',
  2446 			// This will cause all constants to be defined, as each arg will then be set to the default.
  2593 			// This will cause all constants to be defined, as each arg will then be set to the default.
  2447 			if ( $jit ) {
  2594 			if ( $jit ) {
  2448 				$args[0] = wp_parse_args( $args[0], $defaults );
  2595 				$args[0] = wp_parse_args( $args[0], $defaults );
  2449 			}
  2596 			}
  2450 
  2597 
  2451 			// If a constant was defined, use that value. Otherwise, define the constant to ensure
  2598 			/*
  2452 			// the constant is always accurate (and is not defined later,  overriding our value).
  2599 			 * If a constant was defined, use that value. Otherwise, define the constant to ensure
  2453 			// As stated above, the first value wins.
  2600 			 * the constant is always accurate (and is not defined later,  overriding our value).
  2454 			// Once we get to wp_loaded (just-in-time), define any constants we haven't already.
  2601 			 * As stated above, the first value wins.
  2455 			// Constants are lame. Don't reference them. This is just for backward compatibility.
  2602 			 * Once we get to wp_loaded (just-in-time), define any constants we haven't already.
       
  2603 			 * Constants are lame. Don't reference them. This is just for backward compatibility.
       
  2604 			 */
  2456 
  2605 
  2457 			if ( defined( 'NO_HEADER_TEXT' ) ) {
  2606 			if ( defined( 'NO_HEADER_TEXT' ) ) {
  2458 				$args[0]['header-text'] = ! NO_HEADER_TEXT;
  2607 				$args[0]['header-text'] = ! NO_HEADER_TEXT;
  2459 			} elseif ( isset( $args[0]['header-text'] ) ) {
  2608 			} elseif ( isset( $args[0]['header-text'] ) ) {
  2460 				define( 'NO_HEADER_TEXT', empty( $args[0]['header-text'] ) );
  2609 				define( 'NO_HEADER_TEXT', empty( $args[0]['header-text'] ) );
  2500 			}
  2649 			}
  2501 
  2650 
  2502 			break;
  2651 			break;
  2503 
  2652 
  2504 		case 'custom-background':
  2653 		case 'custom-background':
  2505 			if ( ! is_array( $args ) ) {
  2654 			if ( true === $args ) {
  2506 				$args = array( 0 => array() );
  2655 				$args = array( 0 => array() );
  2507 			}
  2656 			}
  2508 
  2657 
  2509 			$defaults = array(
  2658 			$defaults = array(
  2510 				'default-image'          => '',
  2659 				'default-image'          => '',
  2548 
  2697 
  2549 		// Ensure that 'title-tag' is accessible in the admin.
  2698 		// Ensure that 'title-tag' is accessible in the admin.
  2550 		case 'title-tag':
  2699 		case 'title-tag':
  2551 			// Can be called in functions.php but must happen before wp_loaded, i.e. not in header.php.
  2700 			// Can be called in functions.php but must happen before wp_loaded, i.e. not in header.php.
  2552 			if ( did_action( 'wp_loaded' ) ) {
  2701 			if ( did_action( 'wp_loaded' ) ) {
  2553 				/* translators: 1: title-tag, 2: wp_loaded */
       
  2554 				_doing_it_wrong(
  2702 				_doing_it_wrong(
  2555 					"add_theme_support( 'title-tag' )",
  2703 					"add_theme_support( 'title-tag' )",
  2556 					sprintf(
  2704 					sprintf(
       
  2705 						/* translators: 1: title-tag, 2: wp_loaded */
  2557 						__( 'Theme support for %1$s should be registered before the %2$s hook.' ),
  2706 						__( 'Theme support for %1$s should be registered before the %2$s hook.' ),
  2558 						'<code>title-tag</code>',
  2707 						'<code>title-tag</code>',
  2559 						'<code>wp_loaded</code>'
  2708 						'<code>wp_loaded</code>'
  2560 					),
  2709 					),
  2561 					'4.1.0'
  2710 					'4.1.0'
  2588 		if ( $args[0]['wp-head-callback'] ) {
  2737 		if ( $args[0]['wp-head-callback'] ) {
  2589 			add_action( 'wp_head', $args[0]['wp-head-callback'] );
  2738 			add_action( 'wp_head', $args[0]['wp-head-callback'] );
  2590 		}
  2739 		}
  2591 
  2740 
  2592 		if ( is_admin() ) {
  2741 		if ( is_admin() ) {
  2593 			require_once( ABSPATH . 'wp-admin/custom-header.php' );
  2742 			require_once ABSPATH . 'wp-admin/includes/class-custom-image-header.php';
  2594 			$custom_image_header = new Custom_Image_Header( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
  2743 			$custom_image_header = new Custom_Image_Header( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
  2595 		}
  2744 		}
  2596 	}
  2745 	}
  2597 
  2746 
  2598 	if ( current_theme_supports( 'custom-background' ) ) {
  2747 	if ( current_theme_supports( 'custom-background' ) ) {
  2601 
  2750 
  2602 		$args = get_theme_support( 'custom-background' );
  2751 		$args = get_theme_support( 'custom-background' );
  2603 		add_action( 'wp_head', $args[0]['wp-head-callback'] );
  2752 		add_action( 'wp_head', $args[0]['wp-head-callback'] );
  2604 
  2753 
  2605 		if ( is_admin() ) {
  2754 		if ( is_admin() ) {
  2606 			require_once( ABSPATH . 'wp-admin/custom-background.php' );
  2755 			require_once ABSPATH . 'wp-admin/includes/class-custom-background.php';
  2607 			$custom_background = new Custom_Background( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
  2756 			$custom_background = new Custom_Background( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
  2608 		}
  2757 		}
  2609 	}
  2758 	}
  2610 }
  2759 }
  2611 
  2760 
  2619 	if ( ! current_theme_supports( 'custom-header', 'header-text' ) && get_theme_support( 'custom-logo', 'header-text' ) && ! get_theme_mod( 'header_text', true ) ) {
  2768 	if ( ! current_theme_supports( 'custom-header', 'header-text' ) && get_theme_support( 'custom-logo', 'header-text' ) && ! get_theme_mod( 'header_text', true ) ) {
  2620 		$classes = (array) get_theme_support( 'custom-logo', 'header-text' );
  2769 		$classes = (array) get_theme_support( 'custom-logo', 'header-text' );
  2621 		$classes = array_map( 'sanitize_html_class', $classes );
  2770 		$classes = array_map( 'sanitize_html_class', $classes );
  2622 		$classes = '.' . implode( ', .', $classes );
  2771 		$classes = '.' . implode( ', .', $classes );
  2623 
  2772 
       
  2773 		$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
  2624 		?>
  2774 		?>
  2625 		<!-- Custom Logo: hide header text -->
  2775 		<!-- Custom Logo: hide header text -->
  2626 		<style id="custom-logo-css" type="text/css">
  2776 		<style id="custom-logo-css"<?php echo $type_attr; ?>>
  2627 			<?php echo $classes; ?> {
  2777 			<?php echo $classes; ?> {
  2628 				position: absolute;
  2778 				position: absolute;
  2629 				clip: rect(1px, 1px, 1px, 1px);
  2779 				clip: rect(1px, 1px, 1px, 1px);
  2630 			}
  2780 			}
  2631 		</style>
  2781 		</style>
  2632 		<?php
  2782 		<?php
  2633 	}
  2783 	}
  2634 }
  2784 }
  2635 
  2785 
  2636 /**
  2786 /**
  2637  * Gets the theme support arguments passed when registering that support
  2787  * Gets the theme support arguments passed when registering that support.
       
  2788  *
       
  2789  * Example usage:
       
  2790  *
       
  2791  *     get_theme_support( 'custom-logo' );
       
  2792  *     get_theme_support( 'custom-header', 'width' );
  2638  *
  2793  *
  2639  * @since 3.1.0
  2794  * @since 3.1.0
       
  2795  * @since 5.3.0 Formalized the existing and already documented `...$args` parameter
       
  2796  *              by adding it to the function signature.
  2640  *
  2797  *
  2641  * @global array $_wp_theme_features
  2798  * @global array $_wp_theme_features
  2642  *
  2799  *
  2643  * @param string $feature The feature to check.
  2800  * @param string $feature The feature to check. See add_theme_support() for the list
       
  2801  *                        of possible values.
       
  2802  * @param mixed  ...$args Optional extra arguments to be checked against certain features.
  2644  * @return mixed The array of extra arguments or the value for the registered feature.
  2803  * @return mixed The array of extra arguments or the value for the registered feature.
  2645  */
  2804  */
  2646 function get_theme_support( $feature ) {
  2805 function get_theme_support( $feature, ...$args ) {
  2647 	global $_wp_theme_features;
  2806 	global $_wp_theme_features;
  2648 	if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
  2807 	if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
  2649 		return false;
  2808 		return false;
  2650 	}
  2809 	}
  2651 
  2810 
  2652 	if ( func_num_args() <= 1 ) {
  2811 	if ( ! $args ) {
  2653 		return $_wp_theme_features[ $feature ];
  2812 		return $_wp_theme_features[ $feature ];
  2654 	}
  2813 	}
  2655 
  2814 
  2656 	$args = array_slice( func_get_args(), 1 );
       
  2657 	switch ( $feature ) {
  2815 	switch ( $feature ) {
  2658 		case 'custom-logo':
  2816 		case 'custom-logo':
  2659 		case 'custom-header':
  2817 		case 'custom-header':
  2660 		case 'custom-background':
  2818 		case 'custom-background':
  2661 			if ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) ) {
  2819 			if ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) ) {
  2673  *
  2831  *
  2674  * Should be called in the theme's functions.php file. Generally would
  2832  * Should be called in the theme's functions.php file. Generally would
  2675  * be used for child themes to override support from the parent theme.
  2833  * be used for child themes to override support from the parent theme.
  2676  *
  2834  *
  2677  * @since 3.0.0
  2835  * @since 3.0.0
       
  2836  *
  2678  * @see add_theme_support()
  2837  * @see add_theme_support()
  2679  * @param string $feature The feature being removed.
  2838  *
       
  2839  * @param string $feature The feature being removed. See add_theme_support() for the list
       
  2840  *                        of possible values.
  2680  * @return bool|void Whether feature was removed.
  2841  * @return bool|void Whether feature was removed.
  2681  */
  2842  */
  2682 function remove_theme_support( $feature ) {
  2843 function remove_theme_support( $feature ) {
  2683 	// Blacklist: for internal registrations not used directly by themes.
  2844 	// Do not remove internal registrations that are not used directly by themes.
  2684 	if ( in_array( $feature, array( 'editor-style', 'widgets', 'menus' ) ) ) {
  2845 	if ( in_array( $feature, array( 'editor-style', 'widgets', 'menus' ), true ) ) {
  2685 		return false;
  2846 		return false;
  2686 	}
  2847 	}
  2687 
  2848 
  2688 	return _remove_theme_support( $feature );
  2849 	return _remove_theme_support( $feature );
  2689 }
  2850 }
  2690 
  2851 
  2691 /**
  2852 /**
  2692  * Do not use. Removes theme support internally, ignorant of the blacklist.
  2853  * Do not use. Removes theme support internally without knowledge of those not used
       
  2854  * by themes directly.
  2693  *
  2855  *
  2694  * @access private
  2856  * @access private
  2695  * @since 3.1.0
  2857  * @since 3.1.0
  2696  *
       
  2697  * @global array               $_wp_theme_features
  2858  * @global array               $_wp_theme_features
  2698  * @global Custom_Image_Header $custom_image_header
  2859  * @global Custom_Image_Header $custom_image_header
  2699  * @global Custom_Background   $custom_background
  2860  * @global Custom_Background   $custom_background
  2700  *
  2861  *
  2701  * @param string $feature
  2862  * @param string $feature The feature being removed. See add_theme_support() for the list
       
  2863  *                        of possible values.
       
  2864  * @return bool True if support was removed, false if the feature was not registered.
  2702  */
  2865  */
  2703 function _remove_theme_support( $feature ) {
  2866 function _remove_theme_support( $feature ) {
  2704 	global $_wp_theme_features;
  2867 	global $_wp_theme_features;
  2705 
  2868 
  2706 	switch ( $feature ) {
  2869 	switch ( $feature ) {
  2743 			unset( $GLOBALS['custom_background'] );
  2906 			unset( $GLOBALS['custom_background'] );
  2744 			break;
  2907 			break;
  2745 	}
  2908 	}
  2746 
  2909 
  2747 	unset( $_wp_theme_features[ $feature ] );
  2910 	unset( $_wp_theme_features[ $feature ] );
       
  2911 
  2748 	return true;
  2912 	return true;
  2749 }
  2913 }
  2750 
  2914 
  2751 /**
  2915 /**
  2752  * Checks a theme's support for a given feature.
  2916  * Checks a theme's support for a given feature.
  2753  *
  2917  *
       
  2918  * Example usage:
       
  2919  *
       
  2920  *     current_theme_supports( 'custom-logo' );
       
  2921  *     current_theme_supports( 'html5', 'comment-form' );
       
  2922  *
  2754  * @since 2.9.0
  2923  * @since 2.9.0
       
  2924  * @since 5.3.0 Formalized the existing and already documented `...$args` parameter
       
  2925  *              by adding it to the function signature.
  2755  *
  2926  *
  2756  * @global array $_wp_theme_features
  2927  * @global array $_wp_theme_features
  2757  *
  2928  *
  2758  * @param string $feature The feature being checked.
  2929  * @param string $feature The feature being checked. See add_theme_support() for the list
       
  2930  *                        of possible values.
       
  2931  * @param mixed  ...$args Optional extra arguments to be checked against certain features.
  2759  * @return bool True if the current theme supports the feature, false otherwise.
  2932  * @return bool True if the current theme supports the feature, false otherwise.
  2760  */
  2933  */
  2761 function current_theme_supports( $feature ) {
  2934 function current_theme_supports( $feature, ...$args ) {
  2762 	global $_wp_theme_features;
  2935 	global $_wp_theme_features;
  2763 
  2936 
  2764 	if ( 'custom-header-uploads' == $feature ) {
  2937 	if ( 'custom-header-uploads' === $feature ) {
  2765 		return current_theme_supports( 'custom-header', 'uploads' );
  2938 		return current_theme_supports( 'custom-header', 'uploads' );
  2766 	}
  2939 	}
  2767 
  2940 
  2768 	if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
  2941 	if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
  2769 		return false;
  2942 		return false;
  2770 	}
  2943 	}
  2771 
  2944 
  2772 	// If no args passed then no extra checks need be performed
  2945 	// If no args passed then no extra checks need be performed.
  2773 	if ( func_num_args() <= 1 ) {
  2946 	if ( ! $args ) {
  2774 		return true;
  2947 		return true;
  2775 	}
  2948 	}
  2776 
       
  2777 	$args = array_slice( func_get_args(), 1 );
       
  2778 
  2949 
  2779 	switch ( $feature ) {
  2950 	switch ( $feature ) {
  2780 		case 'post-thumbnails':
  2951 		case 'post-thumbnails':
  2781 			// post-thumbnails can be registered for only certain content/post types by passing
  2952 			/*
  2782 			// an array of types to add_theme_support(). If no array was passed, then
  2953 			 * post-thumbnails can be registered for only certain content/post types
  2783 			// any type is accepted
  2954 			 * by passing an array of types to add_theme_support().
  2784 			if ( true === $_wp_theme_features[ $feature ] ) {  // Registered for all types
  2955 			 * If no array was passed, then any type is accepted.
       
  2956 			 */
       
  2957 			if ( true === $_wp_theme_features[ $feature ] ) {  // Registered for all types.
  2785 				return true;
  2958 				return true;
  2786 			}
  2959 			}
  2787 			$content_type = $args[0];
  2960 			$content_type = $args[0];
  2788 			return in_array( $content_type, $_wp_theme_features[ $feature ][0] );
  2961 			return in_array( $content_type, $_wp_theme_features[ $feature ][0], true );
  2789 
  2962 
  2790 		case 'html5':
  2963 		case 'html5':
  2791 		case 'post-formats':
  2964 		case 'post-formats':
  2792 			// specific post formats can be registered by passing an array of types to
  2965 			/*
  2793 			// add_theme_support()
  2966 			 * Specific post formats can be registered by passing an array of types
  2794 
  2967 			 * to add_theme_support().
  2795 			// Specific areas of HTML5 support *must* be passed via an array to add_theme_support()
  2968 			 *
  2796 
  2969 			 * Specific areas of HTML5 support *must* be passed via an array to add_theme_support().
       
  2970 			 */
  2797 			$type = $args[0];
  2971 			$type = $args[0];
  2798 			return in_array( $type, $_wp_theme_features[ $feature ][0] );
  2972 			return in_array( $type, $_wp_theme_features[ $feature ][0], true );
  2799 
  2973 
  2800 		case 'custom-logo':
  2974 		case 'custom-logo':
  2801 		case 'custom-header':
  2975 		case 'custom-header':
  2802 		case 'custom-background':
  2976 		case 'custom-background':
  2803 			// Specific capabilities can be registered by passing an array to add_theme_support().
  2977 			// Specific capabilities can be registered by passing an array to add_theme_support().
  2805 	}
  2979 	}
  2806 
  2980 
  2807 	/**
  2981 	/**
  2808 	 * Filters whether the current theme supports a specific feature.
  2982 	 * Filters whether the current theme supports a specific feature.
  2809 	 *
  2983 	 *
  2810 	 * The dynamic portion of the hook name, `$feature`, refers to the specific theme
  2984 	 * The dynamic portion of the hook name, `$feature`, refers to the specific
  2811 	 * feature. Possible values include 'post-formats', 'post-thumbnails', 'custom-background',
  2985 	 * theme feature. See add_theme_support() for the list of possible values.
  2812 	 * 'custom-header', 'menus', 'automatic-feed-links', 'html5',
       
  2813 	 * 'starter-content', and 'customize-selective-refresh-widgets'.
       
  2814 	 *
  2986 	 *
  2815 	 * @since 3.4.0
  2987 	 * @since 3.4.0
  2816 	 *
  2988 	 *
  2817 	 * @param bool   true     Whether the current theme supports the given feature. Default true.
  2989 	 * @param bool   $supports Whether the current theme supports the given feature. Default true.
  2818 	 * @param array  $args    Array of arguments for the feature.
  2990 	 * @param array  $args     Array of arguments for the feature.
  2819 	 * @param string $feature The theme feature.
  2991 	 * @param string $feature  The theme feature.
  2820 	 */
  2992 	 */
  2821 	return apply_filters( "current_theme_supports-{$feature}", true, $args, $_wp_theme_features[ $feature ] );
  2993 	return apply_filters( "current_theme_supports-{$feature}", true, $args, $_wp_theme_features[ $feature ] ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
  2822 }
  2994 }
  2823 
  2995 
  2824 /**
  2996 /**
  2825  * Checks a theme's support for a given feature before loading the functions which implement it.
  2997  * Checks a theme's support for a given feature before loading the functions which implement it.
  2826  *
  2998  *
  2827  * @since 2.9.0
  2999  * @since 2.9.0
  2828  *
  3000  *
  2829  * @param string $feature The feature being checked.
  3001  * @param string $feature The feature being checked. See add_theme_support() for the list
       
  3002  *                        of possible values.
  2830  * @param string $include Path to the file.
  3003  * @param string $include Path to the file.
  2831  * @return bool True if the current theme supports the supplied feature, false otherwise.
  3004  * @return bool True if the current theme supports the supplied feature, false otherwise.
  2832  */
  3005  */
  2833 function require_if_theme_supports( $feature, $include ) {
  3006 function require_if_theme_supports( $feature, $include ) {
  2834 	if ( current_theme_supports( $feature ) ) {
  3007 	if ( current_theme_supports( $feature ) ) {
  2835 		require( $include );
  3008 		require $include;
  2836 		return true;
  3009 		return true;
  2837 	}
  3010 	}
  2838 	return false;
  3011 	return false;
       
  3012 }
       
  3013 
       
  3014 /**
       
  3015  * Registers a theme feature for use in add_theme_support().
       
  3016  *
       
  3017  * This does not indicate that the current theme supports the feature, it only describes
       
  3018  * the feature's supported options.
       
  3019  *
       
  3020  * @since 5.5.0
       
  3021  *
       
  3022  * @see add_theme_support()
       
  3023  *
       
  3024  * @global array $_wp_registered_theme_features
       
  3025  *
       
  3026  * @param string $feature The name uniquely identifying the feature. See add_theme_support()
       
  3027  *                        for the list of possible values.
       
  3028  * @param array  $args {
       
  3029  *     Data used to describe the theme.
       
  3030  *
       
  3031  *     @type string     $type         The type of data associated with this feature.
       
  3032  *                                    Valid values are 'string', 'boolean', 'integer',
       
  3033  *                                    'number', 'array', and 'object'. Defaults to 'boolean'.
       
  3034  *     @type boolean    $variadic     Does this feature utilize the variadic support
       
  3035  *                                    of add_theme_support(), or are all arguments specified
       
  3036  *                                    as the second parameter. Must be used with the "array" type.
       
  3037  *     @type string     $description  A short description of the feature. Included in
       
  3038  *                                    the Themes REST API schema. Intended for developers.
       
  3039  *     @type bool|array $show_in_rest {
       
  3040  *         Whether this feature should be included in the Themes REST API endpoint.
       
  3041  *         Defaults to not being included. When registering an 'array' or 'object' type,
       
  3042  *         this argument must be an array with the 'schema' key.
       
  3043  *
       
  3044  *         @type array    $schema           Specifies the JSON Schema definition describing
       
  3045  *                                          the feature. If any objects in the schema do not include
       
  3046  *                                          the 'additionalProperties' keyword, it is set to false.
       
  3047  *         @type string   $name             An alternate name to be used as the property name
       
  3048  *                                          in the REST API.
       
  3049  *         @type callable $prepare_callback A function used to format the theme support in the REST API.
       
  3050  *                                          Receives the raw theme support value.
       
  3051  *      }
       
  3052  * }
       
  3053  * @return true|WP_Error True if the theme feature was successfully registered, a WP_Error object if not.
       
  3054  */
       
  3055 function register_theme_feature( $feature, $args = array() ) {
       
  3056 	global $_wp_registered_theme_features;
       
  3057 
       
  3058 	if ( ! is_array( $_wp_registered_theme_features ) ) {
       
  3059 		$_wp_registered_theme_features = array();
       
  3060 	}
       
  3061 
       
  3062 	$defaults = array(
       
  3063 		'type'         => 'boolean',
       
  3064 		'variadic'     => false,
       
  3065 		'description'  => '',
       
  3066 		'show_in_rest' => false,
       
  3067 	);
       
  3068 
       
  3069 	$args = wp_parse_args( $args, $defaults );
       
  3070 
       
  3071 	if ( true === $args['show_in_rest'] ) {
       
  3072 		$args['show_in_rest'] = array();
       
  3073 	}
       
  3074 
       
  3075 	if ( is_array( $args['show_in_rest'] ) ) {
       
  3076 		$args['show_in_rest'] = wp_parse_args(
       
  3077 			$args['show_in_rest'],
       
  3078 			array(
       
  3079 				'schema'           => array(),
       
  3080 				'name'             => $feature,
       
  3081 				'prepare_callback' => null,
       
  3082 			)
       
  3083 		);
       
  3084 	}
       
  3085 
       
  3086 	if ( ! in_array( $args['type'], array( 'string', 'boolean', 'integer', 'number', 'array', 'object' ), true ) ) {
       
  3087 		return new WP_Error(
       
  3088 			'invalid_type',
       
  3089 			__( 'The feature "type" is not valid JSON Schema type.' )
       
  3090 		);
       
  3091 	}
       
  3092 
       
  3093 	if ( true === $args['variadic'] && 'array' !== $args['type'] ) {
       
  3094 		return new WP_Error(
       
  3095 			'variadic_must_be_array',
       
  3096 			__( 'When registering a "variadic" theme feature, the "type" must be an "array".' )
       
  3097 		);
       
  3098 	}
       
  3099 
       
  3100 	if ( false !== $args['show_in_rest'] && in_array( $args['type'], array( 'array', 'object' ), true ) ) {
       
  3101 		if ( ! is_array( $args['show_in_rest'] ) || empty( $args['show_in_rest']['schema'] ) ) {
       
  3102 			return new WP_Error(
       
  3103 				'missing_schema',
       
  3104 				__( 'When registering an "array" or "object" feature to show in the REST API, the feature\'s schema must also be defined.' )
       
  3105 			);
       
  3106 		}
       
  3107 
       
  3108 		if ( 'array' === $args['type'] && ! isset( $args['show_in_rest']['schema']['items'] ) ) {
       
  3109 			return new WP_Error(
       
  3110 				'missing_schema_items',
       
  3111 				__( 'When registering an "array" feature, the feature\'s schema must include the "items" keyword.' )
       
  3112 			);
       
  3113 		}
       
  3114 
       
  3115 		if ( 'object' === $args['type'] && ! isset( $args['show_in_rest']['schema']['properties'] ) ) {
       
  3116 			return new WP_Error(
       
  3117 				'missing_schema_properties',
       
  3118 				__( 'When registering an "object" feature, the feature\'s schema must include the "properties" keyword.' )
       
  3119 			);
       
  3120 		}
       
  3121 	}
       
  3122 
       
  3123 	if ( is_array( $args['show_in_rest'] ) ) {
       
  3124 		if ( isset( $args['show_in_rest']['prepare_callback'] ) && ! is_callable( $args['show_in_rest']['prepare_callback'] ) ) {
       
  3125 			return new WP_Error(
       
  3126 				'invalid_rest_prepare_callback',
       
  3127 				sprintf(
       
  3128 					/* translators: %s: prepare_callback */
       
  3129 					__( 'The "%s" must be a callable function.' ),
       
  3130 					'prepare_callback'
       
  3131 				)
       
  3132 			);
       
  3133 		}
       
  3134 
       
  3135 		$args['show_in_rest']['schema'] = wp_parse_args(
       
  3136 			$args['show_in_rest']['schema'],
       
  3137 			array(
       
  3138 				'description' => $args['description'],
       
  3139 				'type'        => $args['type'],
       
  3140 				'default'     => false,
       
  3141 			)
       
  3142 		);
       
  3143 
       
  3144 		if ( is_bool( $args['show_in_rest']['schema']['default'] )
       
  3145 			&& ! in_array( 'boolean', (array) $args['show_in_rest']['schema']['type'], true )
       
  3146 		) {
       
  3147 			// Automatically include the "boolean" type when the default value is a boolean.
       
  3148 			$args['show_in_rest']['schema']['type'] = (array) $args['show_in_rest']['schema']['type'];
       
  3149 			array_unshift( $args['show_in_rest']['schema']['type'], 'boolean' );
       
  3150 		}
       
  3151 
       
  3152 		$args['show_in_rest']['schema'] = rest_default_additional_properties_to_false( $args['show_in_rest']['schema'] );
       
  3153 	}
       
  3154 
       
  3155 	$_wp_registered_theme_features[ $feature ] = $args;
       
  3156 
       
  3157 	return true;
       
  3158 }
       
  3159 
       
  3160 /**
       
  3161  * Gets the list of registered theme features.
       
  3162  *
       
  3163  * @since 5.5.0
       
  3164  *
       
  3165  * @global array $_wp_registered_theme_features
       
  3166  *
       
  3167  * @return array[] List of theme features, keyed by their name.
       
  3168  */
       
  3169 function get_registered_theme_features() {
       
  3170 	global $_wp_registered_theme_features;
       
  3171 
       
  3172 	if ( ! is_array( $_wp_registered_theme_features ) ) {
       
  3173 		return array();
       
  3174 	}
       
  3175 
       
  3176 	return $_wp_registered_theme_features;
       
  3177 }
       
  3178 
       
  3179 /**
       
  3180  * Gets the registration config for a theme feature.
       
  3181  *
       
  3182  * @since 5.5.0
       
  3183  *
       
  3184  * @global array $_wp_registered_theme_features
       
  3185  *
       
  3186  * @param string $feature The feature name. See add_theme_support() for the list
       
  3187  *                        of possible values.
       
  3188  * @return array|null The registration args, or null if the feature was not registered.
       
  3189  */
       
  3190 function get_registered_theme_feature( $feature ) {
       
  3191 	global $_wp_registered_theme_features;
       
  3192 
       
  3193 	if ( ! is_array( $_wp_registered_theme_features ) ) {
       
  3194 		return null;
       
  3195 	}
       
  3196 
       
  3197 	return isset( $_wp_registered_theme_features[ $feature ] ) ? $_wp_registered_theme_features[ $feature ] : null;
  2839 }
  3198 }
  2840 
  3199 
  2841 /**
  3200 /**
  2842  * Checks an attachment being deleted to see if it's a header or background image.
  3201  * Checks an attachment being deleted to see if it's a header or background image.
  2843  *
  3202  *
  2847  * @access private
  3206  * @access private
  2848  * @since 3.0.0
  3207  * @since 3.0.0
  2849  * @since 4.3.0 Also removes `header_image_data`.
  3208  * @since 4.3.0 Also removes `header_image_data`.
  2850  * @since 4.5.0 Also removes custom logo theme mods.
  3209  * @since 4.5.0 Also removes custom logo theme mods.
  2851  *
  3210  *
  2852  * @param int $id The attachment id.
  3211  * @param int $id The attachment ID.
  2853  */
  3212  */
  2854 function _delete_attachment_theme_mod( $id ) {
  3213 function _delete_attachment_theme_mod( $id ) {
  2855 	$attachment_image = wp_get_attachment_url( $id );
  3214 	$attachment_image = wp_get_attachment_url( $id );
  2856 	$header_image     = get_header_image();
  3215 	$header_image     = get_header_image();
  2857 	$background_image = get_background_image();
  3216 	$background_image = get_background_image();
  2878  * See {@see 'after_switch_theme'}.
  3237  * See {@see 'after_switch_theme'}.
  2879  *
  3238  *
  2880  * @since 3.3.0
  3239  * @since 3.3.0
  2881  */
  3240  */
  2882 function check_theme_switched() {
  3241 function check_theme_switched() {
  2883 	if ( $stylesheet = get_option( 'theme_switched' ) ) {
  3242 	$stylesheet = get_option( 'theme_switched' );
       
  3243 	if ( $stylesheet ) {
  2884 		$old_theme = wp_get_theme( $stylesheet );
  3244 		$old_theme = wp_get_theme( $stylesheet );
  2885 
  3245 
  2886 		// Prevent widget & menu mapping from running since Customizer already called it up front
  3246 		// Prevent widget & menu mapping from running since Customizer already called it up front.
  2887 		if ( get_option( 'theme_switched_via_customizer' ) ) {
  3247 		if ( get_option( 'theme_switched_via_customizer' ) ) {
  2888 			remove_action( 'after_switch_theme', '_wp_menus_changed' );
  3248 			remove_action( 'after_switch_theme', '_wp_menus_changed' );
  2889 			remove_action( 'after_switch_theme', '_wp_sidebars_changed' );
  3249 			remove_action( 'after_switch_theme', '_wp_sidebars_changed' );
  2890 			update_option( 'theme_switched_via_customizer', false );
  3250 			update_option( 'theme_switched_via_customizer', false );
  2891 		}
  3251 		}
  2928  *
  3288  *
  2929  * @global WP_Customize_Manager $wp_customize
  3289  * @global WP_Customize_Manager $wp_customize
  2930  */
  3290  */
  2931 function _wp_customize_include() {
  3291 function _wp_customize_include() {
  2932 
  3292 
  2933 	$is_customize_admin_page = ( is_admin() && 'customize.php' == basename( $_SERVER['PHP_SELF'] ) );
  3293 	$is_customize_admin_page = ( is_admin() && 'customize.php' === basename( $_SERVER['PHP_SELF'] ) );
  2934 	$should_include          = (
  3294 	$should_include          = (
  2935 		$is_customize_admin_page
  3295 		$is_customize_admin_page
  2936 		||
  3296 		||
  2937 		( isset( $_REQUEST['wp_customize'] ) && 'on' == $_REQUEST['wp_customize'] )
  3297 		( isset( $_REQUEST['wp_customize'] ) && 'on' === $_REQUEST['wp_customize'] )
  2938 		||
  3298 		||
  2939 		( ! empty( $_GET['customize_changeset_uuid'] ) || ! empty( $_POST['customize_changeset_uuid'] ) )
  3299 		( ! empty( $_GET['customize_changeset_uuid'] ) || ! empty( $_POST['customize_changeset_uuid'] ) )
  2940 	);
  3300 	);
  2941 
  3301 
  2942 	if ( ! $should_include ) {
  3302 	if ( ! $should_include ) {
  2953 		wp_array_slice_assoc( $_GET, $keys ),
  3313 		wp_array_slice_assoc( $_GET, $keys ),
  2954 		wp_array_slice_assoc( $_POST, $keys )
  3314 		wp_array_slice_assoc( $_POST, $keys )
  2955 	);
  3315 	);
  2956 
  3316 
  2957 	$theme             = null;
  3317 	$theme             = null;
  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.
  3318 	$autosaved         = null;
  2959 	$messenger_channel = null;
  3319 	$messenger_channel = null;
  2960 	$autosaved         = null;
  3320 
  2961 	$branching         = false; // Set initially fo false since defaults to true for back-compat; can be overridden via the customize_changeset_branching filter.
  3321 	// Value false indicates UUID should be determined after_setup_theme
       
  3322 	// to either re-use existing saved changeset or else generate a new UUID if none exists.
       
  3323 	$changeset_uuid = false;
       
  3324 
       
  3325 	// Set initially fo false since defaults to true for back-compat;
       
  3326 	// can be overridden via the customize_changeset_branching filter.
       
  3327 	$branching = false;
  2962 
  3328 
  2963 	if ( $is_customize_admin_page && isset( $input_vars['changeset_uuid'] ) ) {
  3329 	if ( $is_customize_admin_page && isset( $input_vars['changeset_uuid'] ) ) {
  2964 		$changeset_uuid = sanitize_key( $input_vars['changeset_uuid'] );
  3330 		$changeset_uuid = sanitize_key( $input_vars['changeset_uuid'] );
  2965 	} elseif ( ! empty( $input_vars['customize_changeset_uuid'] ) ) {
  3331 	} elseif ( ! empty( $input_vars['customize_changeset_uuid'] ) ) {
  2966 		$changeset_uuid = sanitize_key( $input_vars['customize_changeset_uuid'] );
  3332 		$changeset_uuid = sanitize_key( $input_vars['customize_changeset_uuid'] );
  3080  *
  3446  *
  3081  * This is needed to prevent the post_name from being dropped when the post is
  3447  * This is needed to prevent the post_name from being dropped when the post is
  3082  * transitioned into pending status by a contributor.
  3448  * transitioned into pending status by a contributor.
  3083  *
  3449  *
  3084  * @since 4.7.0
  3450  * @since 4.7.0
       
  3451  *
  3085  * @see wp_insert_post()
  3452  * @see wp_insert_post()
  3086  *
  3453  *
  3087  * @param array $post_data          An array of slashed post data.
  3454  * @param array $post_data          An array of slashed post data.
  3088  * @param array $supplied_post_data An array of sanitized, but otherwise unmodified post data.
  3455  * @param array $supplied_post_data An array of sanitized, but otherwise unmodified post data.
  3089  * @returns array Filtered data.
  3456  * @return array Filtered data.
  3090  */
  3457  */
  3091 function _wp_customize_changeset_filter_insert_post_data( $post_data, $supplied_post_data ) {
  3458 function _wp_customize_changeset_filter_insert_post_data( $post_data, $supplied_post_data ) {
  3092 	if ( isset( $post_data['post_type'] ) && 'customize_changeset' === $post_data['post_type'] ) {
  3459 	if ( isset( $post_data['post_type'] ) && 'customize_changeset' === $post_data['post_type'] ) {
  3093 
  3460 
  3094 		// Prevent post_name from being dropped, such as when contributor saves a changeset post as pending.
  3461 		// Prevent post_name from being dropped, such as when contributor saves a changeset post as pending.
  3142  *
  3509  *
  3143  * @param string $stylesheet Optional. Theme to customize. Defaults to current theme.
  3510  * @param string $stylesheet Optional. Theme to customize. Defaults to current theme.
  3144  *                           The theme's stylesheet will be urlencoded if necessary.
  3511  *                           The theme's stylesheet will be urlencoded if necessary.
  3145  * @return string
  3512  * @return string
  3146  */
  3513  */
  3147 function wp_customize_url( $stylesheet = null ) {
  3514 function wp_customize_url( $stylesheet = '' ) {
  3148 	$url = admin_url( 'customize.php' );
  3515 	$url = admin_url( 'customize.php' );
  3149 	if ( $stylesheet ) {
  3516 	if ( $stylesheet ) {
  3150 		$url .= '?theme=' . urlencode( $stylesheet );
  3517 		$url .= '?theme=' . urlencode( $stylesheet );
  3151 	}
  3518 	}
  3152 	return esc_url( $url );
  3519 	return esc_url( $url );
  3165  * It is also recommended that you add the "no-customize-support" class
  3532  * It is also recommended that you add the "no-customize-support" class
  3166  * to the body tag by default.
  3533  * to the body tag by default.
  3167  *
  3534  *
  3168  * @since 3.4.0
  3535  * @since 3.4.0
  3169  * @since 4.7.0 Support for IE8 and below is explicitly removed via conditional comments.
  3536  * @since 4.7.0 Support for IE8 and below is explicitly removed via conditional comments.
       
  3537  * @since 5.5.0 IE8 and older are no longer supported.
  3170  */
  3538  */
  3171 function wp_customize_support_script() {
  3539 function wp_customize_support_script() {
  3172 	$admin_origin = parse_url( admin_url() );
  3540 	$admin_origin = parse_url( admin_url() );
  3173 	$home_origin  = parse_url( home_url() );
  3541 	$home_origin  = parse_url( home_url() );
  3174 	$cross_domain = ( strtolower( $admin_origin['host'] ) != strtolower( $home_origin['host'] ) );
  3542 	$cross_domain = ( strtolower( $admin_origin['host'] ) != strtolower( $home_origin['host'] ) );
  3175 
  3543 	$type_attr    = current_theme_supports( 'html5', 'script' ) ? '' : ' type="text/javascript"';
  3176 	?>
  3544 	?>
  3177 	<!--[if lte IE 8]>
  3545 	<script<?php echo $type_attr; ?>>
  3178 		<script type="text/javascript">
  3546 		(function() {
  3179 			document.body.className = document.body.className.replace( /(^|\s)(no-)?customize-support(?=\s|$)/, '' ) + ' no-customize-support';
  3547 			var request, b = document.body, c = 'className', cs = 'customize-support', rcs = new RegExp('(^|\\s+)(no-)?'+cs+'(\\s+|$)');
  3180 		</script>
  3548 
  3181 	<![endif]-->
  3549 	<?php	if ( $cross_domain ) : ?>
  3182 	<!--[if gte IE 9]><!-->
  3550 			request = (function(){ var xhr = new XMLHttpRequest(); return ('withCredentials' in xhr); })();
  3183 		<script type="text/javascript">
  3551 	<?php	else : ?>
  3184 			(function() {
  3552 			request = true;
  3185 				var request, b = document.body, c = 'className', cs = 'customize-support', rcs = new RegExp('(^|\\s+)(no-)?'+cs+'(\\s+|$)');
  3553 	<?php	endif; ?>
  3186 
  3554 
  3187 		<?php	if ( $cross_domain ) : ?>
  3555 			b[c] = b[c].replace( rcs, ' ' );
  3188 				request = (function(){ var xhr = new XMLHttpRequest(); return ('withCredentials' in xhr); })();
  3556 			// The customizer requires postMessage and CORS (if the site is cross domain).
  3189 		<?php	else : ?>
  3557 			b[c] += ( window.postMessage && request ? ' ' : ' no-' ) + cs;
  3190 				request = true;
  3558 		}());
  3191 		<?php	endif; ?>
  3559 	</script>
  3192 
       
  3193 				b[c] = b[c].replace( rcs, ' ' );
       
  3194 				// The customizer requires postMessage and CORS (if the site is cross domain)
       
  3195 				b[c] += ( window.postMessage && request ? ' ' : ' no-' ) + cs;
       
  3196 			}());
       
  3197 		</script>
       
  3198 	<!--<![endif]-->
       
  3199 	<?php
  3560 	<?php
  3200 }
  3561 }
  3201 
  3562 
  3202 /**
  3563 /**
  3203  * Whether the site is being previewed in the Customizer.
  3564  * Whether the site is being previewed in the Customizer.
  3213 
  3574 
  3214 	return ( $wp_customize instanceof WP_Customize_Manager ) && $wp_customize->is_preview();
  3575 	return ( $wp_customize instanceof WP_Customize_Manager ) && $wp_customize->is_preview();
  3215 }
  3576 }
  3216 
  3577 
  3217 /**
  3578 /**
  3218  * Make sure that auto-draft posts get their post_date bumped or status changed to draft to prevent premature garbage-collection.
  3579  * Makes sure that auto-draft posts get their post_date bumped or status changed to draft to prevent premature garbage-collection.
  3219  *
  3580  *
  3220  * When a changeset is updated but remains an auto-draft, ensure the post_date
  3581  * When a changeset is updated but remains an auto-draft, ensure the post_date
  3221  * for the auto-draft posts remains the same so that it will be
  3582  * for the auto-draft posts remains the same so that it will be
  3222  * garbage-collected at the same time by `wp_delete_auto_drafts()`. Otherwise,
  3583  * garbage-collected at the same time by `wp_delete_auto_drafts()`. Otherwise,
  3223  * if the changeset is updated to be a draft then update the posts
  3584  * if the changeset is updated to be a draft then update the posts
  3234  *
  3595  *
  3235  * @since 4.8.0
  3596  * @since 4.8.0
  3236  * @access private
  3597  * @access private
  3237  * @see wp_delete_auto_drafts()
  3598  * @see wp_delete_auto_drafts()
  3238  *
  3599  *
       
  3600  * @global wpdb $wpdb WordPress database abstraction object.
       
  3601  *
  3239  * @param string   $new_status Transition to this post status.
  3602  * @param string   $new_status Transition to this post status.
  3240  * @param string   $old_status Previous post status.
  3603  * @param string   $old_status Previous post status.
  3241  * @param \WP_Post $post       Post data.
  3604  * @param \WP_Post $post       Post data.
  3242  * @global wpdb $wpdb
       
  3243  */
  3605  */
  3244 function _wp_keep_alive_customize_changeset_dependent_auto_drafts( $new_status, $old_status, $post ) {
  3606 function _wp_keep_alive_customize_changeset_dependent_auto_drafts( $new_status, $old_status, $post ) {
  3245 	global $wpdb;
  3607 	global $wpdb;
  3246 	unset( $old_status );
  3608 	unset( $old_status );
  3247 
  3609 
  3302 			array( 'ID' => $post_id )
  3664 			array( 'ID' => $post_id )
  3303 		);
  3665 		);
  3304 		clean_post_cache( $post_id );
  3666 		clean_post_cache( $post_id );
  3305 	}
  3667 	}
  3306 }
  3668 }
       
  3669 
       
  3670 /**
       
  3671  * Creates the initial theme features when the 'setup_theme' action is fired.
       
  3672  *
       
  3673  * See {@see 'setup_theme'}.
       
  3674  *
       
  3675  * @since 5.5.0
       
  3676  */
       
  3677 function create_initial_theme_features() {
       
  3678 	register_theme_feature(
       
  3679 		'align-wide',
       
  3680 		array(
       
  3681 			'description'  => __( 'Whether theme opts in to wide alignment CSS class.' ),
       
  3682 			'show_in_rest' => true,
       
  3683 		)
       
  3684 	);
       
  3685 	register_theme_feature(
       
  3686 		'automatic-feed-links',
       
  3687 		array(
       
  3688 			'description'  => __( 'Whether posts and comments RSS feed links are added to head.' ),
       
  3689 			'show_in_rest' => true,
       
  3690 		)
       
  3691 	);
       
  3692 	register_theme_feature(
       
  3693 		'custom-background',
       
  3694 		array(
       
  3695 			'description'  => __( 'Custom background if defined by the theme.' ),
       
  3696 			'type'         => 'object',
       
  3697 			'show_in_rest' => array(
       
  3698 				'schema' => array(
       
  3699 					'properties' => array(
       
  3700 						'default-image'      => array(
       
  3701 							'type'   => 'string',
       
  3702 							'format' => 'uri',
       
  3703 						),
       
  3704 						'default-preset'     => array(
       
  3705 							'type' => 'string',
       
  3706 							'enum' => array(
       
  3707 								'default',
       
  3708 								'fill',
       
  3709 								'fit',
       
  3710 								'repeat',
       
  3711 								'custom',
       
  3712 							),
       
  3713 						),
       
  3714 						'default-position-x' => array(
       
  3715 							'type' => 'string',
       
  3716 							'enum' => array(
       
  3717 								'left',
       
  3718 								'center',
       
  3719 								'right',
       
  3720 							),
       
  3721 						),
       
  3722 						'default-position-y' => array(
       
  3723 							'type' => 'string',
       
  3724 							'enum' => array(
       
  3725 								'left',
       
  3726 								'center',
       
  3727 								'right',
       
  3728 							),
       
  3729 						),
       
  3730 						'default-size'       => array(
       
  3731 							'type' => 'string',
       
  3732 							'enum' => array(
       
  3733 								'auto',
       
  3734 								'contain',
       
  3735 								'cover',
       
  3736 							),
       
  3737 						),
       
  3738 						'default-repeat'     => array(
       
  3739 							'type' => 'string',
       
  3740 							'enum' => array(
       
  3741 								'repeat-x',
       
  3742 								'repeat-y',
       
  3743 								'repeat',
       
  3744 								'no-repeat',
       
  3745 							),
       
  3746 						),
       
  3747 						'default-attachment' => array(
       
  3748 							'type' => 'string',
       
  3749 							'enum' => array(
       
  3750 								'scroll',
       
  3751 								'fixed',
       
  3752 							),
       
  3753 						),
       
  3754 						'default-color'      => array(
       
  3755 							'type' => 'string',
       
  3756 						),
       
  3757 					),
       
  3758 				),
       
  3759 			),
       
  3760 		)
       
  3761 	);
       
  3762 	register_theme_feature(
       
  3763 		'custom-header',
       
  3764 		array(
       
  3765 			'description'  => __( 'Custom header if defined by the theme.' ),
       
  3766 			'type'         => 'object',
       
  3767 			'show_in_rest' => array(
       
  3768 				'schema' => array(
       
  3769 					'properties' => array(
       
  3770 						'default-image'      => array(
       
  3771 							'type'   => 'string',
       
  3772 							'format' => 'uri',
       
  3773 						),
       
  3774 						'random-default'     => array(
       
  3775 							'type' => 'boolean',
       
  3776 						),
       
  3777 						'width'              => array(
       
  3778 							'type' => 'integer',
       
  3779 						),
       
  3780 						'height'             => array(
       
  3781 							'type' => 'integer',
       
  3782 						),
       
  3783 						'flex-height'        => array(
       
  3784 							'type' => 'boolean',
       
  3785 						),
       
  3786 						'flex-width'         => array(
       
  3787 							'type' => 'boolean',
       
  3788 						),
       
  3789 						'default-text-color' => array(
       
  3790 							'type' => 'string',
       
  3791 						),
       
  3792 						'header-text'        => array(
       
  3793 							'type' => 'boolean',
       
  3794 						),
       
  3795 						'uploads'            => array(
       
  3796 							'type' => 'boolean',
       
  3797 						),
       
  3798 						'video'              => array(
       
  3799 							'type' => 'boolean',
       
  3800 						),
       
  3801 					),
       
  3802 				),
       
  3803 			),
       
  3804 		)
       
  3805 	);
       
  3806 	register_theme_feature(
       
  3807 		'custom-logo',
       
  3808 		array(
       
  3809 			'type'         => 'object',
       
  3810 			'description'  => __( 'Custom logo if defined by the theme.' ),
       
  3811 			'show_in_rest' => array(
       
  3812 				'schema' => array(
       
  3813 					'properties' => array(
       
  3814 						'width'                => array(
       
  3815 							'type' => 'integer',
       
  3816 						),
       
  3817 						'height'               => array(
       
  3818 							'type' => 'integer',
       
  3819 						),
       
  3820 						'flex-width'           => array(
       
  3821 							'type' => 'boolean',
       
  3822 						),
       
  3823 						'flex-height'          => array(
       
  3824 							'type' => 'boolean',
       
  3825 						),
       
  3826 						'header-text'          => array(
       
  3827 							'type'  => 'array',
       
  3828 							'items' => array(
       
  3829 								'type' => 'string',
       
  3830 							),
       
  3831 						),
       
  3832 						'unlink-homepage-logo' => array(
       
  3833 							'type' => 'boolean',
       
  3834 						),
       
  3835 					),
       
  3836 				),
       
  3837 			),
       
  3838 		)
       
  3839 	);
       
  3840 	register_theme_feature(
       
  3841 		'customize-selective-refresh-widgets',
       
  3842 		array(
       
  3843 			'description'  => __( 'Whether the theme enables Selective Refresh for Widgets being managed with the Customizer.' ),
       
  3844 			'show_in_rest' => true,
       
  3845 		)
       
  3846 	);
       
  3847 	register_theme_feature(
       
  3848 		'dark-editor-style',
       
  3849 		array(
       
  3850 			'description'  => __( 'Whether theme opts in to the dark editor style UI.' ),
       
  3851 			'show_in_rest' => true,
       
  3852 		)
       
  3853 	);
       
  3854 	register_theme_feature(
       
  3855 		'disable-custom-colors',
       
  3856 		array(
       
  3857 			'description'  => __( 'Whether the theme disables custom colors.' ),
       
  3858 			'show_in_rest' => true,
       
  3859 		)
       
  3860 	);
       
  3861 	register_theme_feature(
       
  3862 		'disable-custom-font-sizes',
       
  3863 		array(
       
  3864 			'description'  => __( 'Whether the theme disables custom font sizes.' ),
       
  3865 			'show_in_rest' => true,
       
  3866 		)
       
  3867 	);
       
  3868 	register_theme_feature(
       
  3869 		'disable-custom-gradients',
       
  3870 		array(
       
  3871 			'description'  => __( 'Whether the theme disables custom gradients.' ),
       
  3872 			'show_in_rest' => true,
       
  3873 		)
       
  3874 	);
       
  3875 	register_theme_feature(
       
  3876 		'editor-color-palette',
       
  3877 		array(
       
  3878 			'type'         => 'array',
       
  3879 			'description'  => __( 'Custom color palette if defined by the theme.' ),
       
  3880 			'show_in_rest' => array(
       
  3881 				'schema' => array(
       
  3882 					'items' => array(
       
  3883 						'type'       => 'object',
       
  3884 						'properties' => array(
       
  3885 							'name'  => array(
       
  3886 								'type' => 'string',
       
  3887 							),
       
  3888 							'slug'  => array(
       
  3889 								'type' => 'string',
       
  3890 							),
       
  3891 							'color' => array(
       
  3892 								'type' => 'string',
       
  3893 							),
       
  3894 						),
       
  3895 					),
       
  3896 				),
       
  3897 			),
       
  3898 		)
       
  3899 	);
       
  3900 	register_theme_feature(
       
  3901 		'editor-font-sizes',
       
  3902 		array(
       
  3903 			'type'         => 'array',
       
  3904 			'description'  => __( 'Custom font sizes if defined by the theme.' ),
       
  3905 			'show_in_rest' => array(
       
  3906 				'schema' => array(
       
  3907 					'items' => array(
       
  3908 						'type'       => 'object',
       
  3909 						'properties' => array(
       
  3910 							'name' => array(
       
  3911 								'type' => 'string',
       
  3912 							),
       
  3913 							'size' => array(
       
  3914 								'type' => 'number',
       
  3915 							),
       
  3916 							'slug' => array(
       
  3917 								'type' => 'string',
       
  3918 							),
       
  3919 						),
       
  3920 					),
       
  3921 				),
       
  3922 			),
       
  3923 		)
       
  3924 	);
       
  3925 	register_theme_feature(
       
  3926 		'editor-gradient-presets',
       
  3927 		array(
       
  3928 			'type'         => 'array',
       
  3929 			'description'  => __( 'Custom gradient presets if defined by the theme.' ),
       
  3930 			'show_in_rest' => array(
       
  3931 				'schema' => array(
       
  3932 					'items' => array(
       
  3933 						'type'       => 'object',
       
  3934 						'properties' => array(
       
  3935 							'name'     => array(
       
  3936 								'type' => 'string',
       
  3937 							),
       
  3938 							'gradient' => array(
       
  3939 								'type' => 'string',
       
  3940 							),
       
  3941 							'slug'     => array(
       
  3942 								'type' => 'string',
       
  3943 							),
       
  3944 						),
       
  3945 					),
       
  3946 				),
       
  3947 			),
       
  3948 		)
       
  3949 	);
       
  3950 	register_theme_feature(
       
  3951 		'editor-styles',
       
  3952 		array(
       
  3953 			'description'  => __( 'Whether theme opts in to the editor styles CSS wrapper.' ),
       
  3954 			'show_in_rest' => true,
       
  3955 		)
       
  3956 	);
       
  3957 	register_theme_feature(
       
  3958 		'html5',
       
  3959 		array(
       
  3960 			'type'         => 'array',
       
  3961 			'description'  => __( 'Allows use of HTML5 markup for search forms, comment forms, comment lists, gallery, and caption.' ),
       
  3962 			'show_in_rest' => array(
       
  3963 				'schema' => array(
       
  3964 					'items' => array(
       
  3965 						'type' => 'string',
       
  3966 						'enum' => array(
       
  3967 							'search-form',
       
  3968 							'comment-form',
       
  3969 							'comment-list',
       
  3970 							'gallery',
       
  3971 							'caption',
       
  3972 							'script',
       
  3973 							'style',
       
  3974 						),
       
  3975 					),
       
  3976 				),
       
  3977 			),
       
  3978 		)
       
  3979 	);
       
  3980 	register_theme_feature(
       
  3981 		'post-formats',
       
  3982 		array(
       
  3983 			'type'         => 'array',
       
  3984 			'description'  => __( 'Post formats supported.' ),
       
  3985 			'show_in_rest' => array(
       
  3986 				'name'             => 'formats',
       
  3987 				'schema'           => array(
       
  3988 					'items'   => array(
       
  3989 						'type' => 'string',
       
  3990 						'enum' => get_post_format_slugs(),
       
  3991 					),
       
  3992 					'default' => array( 'standard' ),
       
  3993 				),
       
  3994 				'prepare_callback' => static function ( $formats ) {
       
  3995 					$formats = is_array( $formats ) ? array_values( $formats[0] ) : array();
       
  3996 					$formats = array_merge( array( 'standard' ), $formats );
       
  3997 
       
  3998 					return $formats;
       
  3999 				},
       
  4000 			),
       
  4001 		)
       
  4002 	);
       
  4003 	register_theme_feature(
       
  4004 		'post-thumbnails',
       
  4005 		array(
       
  4006 			'type'         => 'array',
       
  4007 			'description'  => __( 'The post types that support thumbnails or true if all post types are supported.' ),
       
  4008 			'show_in_rest' => array(
       
  4009 				'type'   => array( 'boolean', 'array' ),
       
  4010 				'schema' => array(
       
  4011 					'items' => array(
       
  4012 						'type' => 'string',
       
  4013 					),
       
  4014 				),
       
  4015 			),
       
  4016 		)
       
  4017 	);
       
  4018 	register_theme_feature(
       
  4019 		'responsive-embeds',
       
  4020 		array(
       
  4021 			'description'  => __( 'Whether the theme supports responsive embedded content.' ),
       
  4022 			'show_in_rest' => true,
       
  4023 		)
       
  4024 	);
       
  4025 	register_theme_feature(
       
  4026 		'title-tag',
       
  4027 		array(
       
  4028 			'description'  => __( 'Whether the theme can manage the document title tag.' ),
       
  4029 			'show_in_rest' => true,
       
  4030 		)
       
  4031 	);
       
  4032 	register_theme_feature(
       
  4033 		'wp-block-styles',
       
  4034 		array(
       
  4035 			'description'  => __( 'Whether theme opts in to default WordPress block styles for viewing.' ),
       
  4036 			'show_in_rest' => true,
       
  4037 		)
       
  4038 	);
       
  4039 }