diff -r 3d4e9c994f10 -r a86126ab1dd4 wp/wp-includes/theme.php --- a/wp/wp-includes/theme.php Tue Oct 22 16:11:46 2019 +0200 +++ b/wp/wp-includes/theme.php Tue Dec 15 13:49:49 2020 +0100 @@ -15,18 +15,20 @@ * @since 3.4.0 * * @global array $wp_theme_directories - * @staticvar array $_themes * * @param array $args { * Optional. The search arguments. * - * @type mixed $errors True to return themes with errors, false to return themes without errors, null to return all themes. - * Defaults to false. - * @type mixed $allowed (Multisite) True to return only allowed themes for a site. False to return only disallowed themes for a site. - * 'site' to return only site-allowed themes. 'network' to return only network-allowed themes. - * Null to return all themes. Defaults to null. - * @type int $blog_id (Multisite) The blog ID used to calculate which themes are allowed. - * Defaults to 0, synonymous for the current blog. + * @type mixed $errors True to return themes with errors, false to return + * themes without errors, null to return all themes. + * Default false. + * @type mixed $allowed (Multisite) True to return only allowed themes for a site. + * False to return only disallowed themes for a site. + * 'site' to return only site-allowed themes. + * 'network' to return only network-allowed themes. + * Null to return all themes. Default null. + * @type int $blog_id (Multisite) The blog ID used to calculate which themes + * are allowed. Default 0, synonymous for the current blog. * } * @return WP_Theme[] Array of WP_Theme objects. */ @@ -48,7 +50,7 @@ $current_theme = get_stylesheet(); if ( isset( $theme_directories[ $current_theme ] ) ) { $root_of_current_theme = get_raw_theme_root( $current_theme ); - if ( ! in_array( $root_of_current_theme, $wp_theme_directories ) ) { + if ( ! in_array( $root_of_current_theme, $wp_theme_directories, true ) ) { $root_of_current_theme = WP_CONTENT_DIR . $root_of_current_theme; } $theme_directories[ $current_theme ]['theme_root'] = $root_of_current_theme; @@ -79,7 +81,9 @@ if ( isset( $_themes[ $theme_root['theme_root'] . '/' . $theme ] ) ) { $themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ]; } else { - $themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ] = new WP_Theme( $theme, $theme_root['theme_root'] ); + $themes[ $theme ] = new WP_Theme( $theme, $theme_root['theme_root'] ); + + $_themes[ $theme_root['theme_root'] . '/' . $theme ] = $themes[ $theme ]; } } @@ -101,12 +105,14 @@ * * @global array $wp_theme_directories * - * @param string $stylesheet Directory name for the theme. Optional. Defaults to current theme. - * @param string $theme_root Absolute path of the theme root to look in. Optional. If not specified, get_raw_theme_root() - * is used to calculate the theme root for the $stylesheet provided (or current theme). - * @return WP_Theme Theme object. Be sure to check the object's exists() method if you need to confirm the theme's existence. + * @param string $stylesheet Optional. Directory name for the theme. Defaults to current theme. + * @param string $theme_root Optional. Absolute path of the theme root to look in. + * If not specified, get_raw_theme_root() is used to calculate + * the theme root for the $stylesheet provided (or current theme). + * @return WP_Theme Theme object. Be sure to check the object's exists() method + * if you need to confirm the theme's existence. */ -function wp_get_theme( $stylesheet = null, $theme_root = null ) { +function wp_get_theme( $stylesheet = '', $theme_root = '' ) { global $wp_theme_directories; if ( empty( $stylesheet ) ) { @@ -117,7 +123,7 @@ $theme_root = get_raw_theme_root( $stylesheet ); if ( false === $theme_root ) { $theme_root = WP_CONTENT_DIR . '/themes'; - } elseif ( ! in_array( $theme_root, (array) $wp_theme_directories ) ) { + } elseif ( ! in_array( $theme_root, (array) $wp_theme_directories, true ) ) { $theme_root = WP_CONTENT_DIR . $theme_root; } } @@ -129,7 +135,7 @@ * Clears the cache held by get_theme_roots() and WP_Theme. * * @since 3.5.0 - * @param bool $clear_update_cache Whether to clear the Theme updates cache + * @param bool $clear_update_cache Whether to clear the theme updates cache. */ function wp_clean_themes_cache( $clear_update_cache = true ) { if ( $clear_update_cache ) { @@ -146,20 +152,19 @@ * * @since 3.0.0 * - * @return bool true if a child theme is in use, false otherwise. + * @return bool True if a child theme is in use, false otherwise. */ function is_child_theme() { return ( TEMPLATEPATH !== STYLESHEETPATH ); } /** - * Retrieve name of the current stylesheet. + * Retrieves name of the current stylesheet. * - * The theme name that the administrator has currently set the front end theme - * as. + * The theme name that is currently set as the front end theme. * - * For all intents and purposes, the template name and the stylesheet name are - * going to be the same for most cases. + * For all intents and purposes, the template name and the stylesheet name + * are going to be the same for most cases. * * @since 1.5.0 * @@ -177,11 +182,11 @@ } /** - * Retrieve stylesheet directory path for current theme. + * Retrieves stylesheet directory path for current theme. * * @since 1.5.0 * - * @return string Path to current theme directory. + * @return string Path to current theme's stylesheet directory. */ function get_stylesheet_directory() { $stylesheet = get_stylesheet(); @@ -201,11 +206,11 @@ } /** - * Retrieve stylesheet directory URI. + * Retrieves stylesheet directory URI for current theme. * * @since 1.5.0 * - * @return string + * @return string URI to current theme's stylesheet directory. */ function get_stylesheet_directory_uri() { $stylesheet = str_replace( '%2F', '/', rawurlencode( get_stylesheet() ) ); @@ -225,14 +230,14 @@ } /** - * Retrieves the URI of current theme stylesheet. + * Retrieves stylesheet URI for current theme. * * The stylesheet file name is 'style.css' which is appended to the stylesheet directory URI path. * See get_stylesheet_directory_uri(). * * @since 1.5.0 * - * @return string + * @return string URI to current theme's stylesheet. */ function get_stylesheet_uri() { $stylesheet_dir_uri = get_stylesheet_directory_uri(); @@ -265,9 +270,9 @@ * * @since 2.1.0 * - * @global WP_Locale $wp_locale + * @global WP_Locale $wp_locale WordPress date and time locale object. * - * @return string + * @return string URI to current theme's localized stylesheet. */ function get_locale_stylesheet_uri() { global $wp_locale; @@ -293,7 +298,7 @@ } /** - * Retrieve name of the current theme. + * Retrieves name of the current theme. * * @since 1.5.0 * @@ -311,11 +316,11 @@ } /** - * Retrieve current theme directory. + * Retrieves template directory path for current theme. * * @since 1.5.0 * - * @return string Template directory path. + * @return string Path to current theme's template directory. */ function get_template_directory() { $template = get_template(); @@ -327,7 +332,7 @@ * * @since 1.5.0 * - * @param string $template_dir The URI of the current theme directory. + * @param string $template_dir The path of the current theme directory. * @param string $template Directory name of the current theme. * @param string $theme_root Absolute path to the themes directory. */ @@ -335,11 +340,11 @@ } /** - * Retrieve theme directory URI. + * Retrieves template directory URI for current theme. * * @since 1.5.0 * - * @return string Template directory URI. + * @return string URI to current theme's template directory. */ function get_template_directory_uri() { $template = str_replace( '%2F', '/', rawurlencode( get_template() ) ); @@ -359,13 +364,14 @@ } /** - * Retrieve theme roots. + * Retrieves theme roots. * * @since 2.9.0 * * @global array $wp_theme_directories * - * @return array|string An array of theme roots keyed by template/stylesheet or a single theme root if all themes have the same root. + * @return array|string An array of theme roots keyed by template/stylesheet + * or a single theme root if all themes have the same root. */ function get_theme_roots() { global $wp_theme_directories; @@ -383,22 +389,24 @@ } /** - * Register a directory that contains themes. + * Registers a directory that contains themes. * * @since 2.9.0 * * @global array $wp_theme_directories * - * @param string $directory Either the full filesystem path to a theme folder or a folder within WP_CONTENT_DIR - * @return bool + * @param string $directory Either the full filesystem path to a theme folder + * or a folder within WP_CONTENT_DIR. + * @return bool True if successfully registered a directory that contains themes, + * false if the directory does not exist. */ function register_theme_directory( $directory ) { global $wp_theme_directories; if ( ! file_exists( $directory ) ) { - // Try prepending as the theme directory could be relative to the content directory + // Try prepending as the theme directory could be relative to the content directory. $directory = WP_CONTENT_DIR . '/' . $directory; - // If this directory does not exist, return and do not register + // If this directory does not exist, return and do not register. if ( ! file_exists( $directory ) ) { return false; } @@ -409,7 +417,7 @@ } $untrailed = untrailingslashit( $directory ); - if ( ! empty( $untrailed ) && ! in_array( $untrailed, $wp_theme_directories ) ) { + if ( ! empty( $untrailed ) && ! in_array( $untrailed, $wp_theme_directories, true ) ) { $wp_theme_directories[] = $untrailed; } @@ -417,15 +425,14 @@ } /** - * Search all registered theme directories for complete and valid themes. + * Searches all registered theme directories for complete and valid themes. * * @since 2.9.0 * * @global array $wp_theme_directories - * @staticvar array $found_themes * - * @param bool $force Optional. Whether to force a new directory scan. Defaults to false. - * @return array|false Valid themes found + * @param bool $force Optional. Whether to force a new directory scan. Default false. + * @return array|false Valid themes found on success, false on failure. */ function search_theme_directories( $force = false ) { global $wp_theme_directories; @@ -444,9 +451,11 @@ $wp_theme_directories = (array) $wp_theme_directories; $relative_theme_roots = array(); - // Set up maybe-relative, maybe-absolute array of theme directories. - // We always want to return absolute, but we need to cache relative - // to use in get_theme_root(). + /* + * Set up maybe-relative, maybe-absolute array of theme directories. + * We always want to return absolute, but we need to cache relative + * to use in get_theme_root(). + */ foreach ( $wp_theme_directories as $theme_root ) { if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) { $relative_theme_roots[ str_replace( WP_CONTENT_DIR, '', $theme_root ) ] = $theme_root; @@ -461,9 +470,11 @@ * @since 3.4.0 * * @param bool $cache_expiration Whether to get the cache of the theme directories. Default false. - * @param string $cache_directory Directory to be searched for the cache. + * @param string $context The class or function name calling the filter. */ - if ( $cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' ) ) { + $cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' ); + + if ( $cache_expiration ) { $cached_roots = get_site_transient( 'theme_roots' ); if ( is_array( $cached_roots ) ) { foreach ( $cached_roots as $theme_dir => $theme_root ) { @@ -479,10 +490,10 @@ return $found_themes; } if ( ! is_int( $cache_expiration ) ) { - $cache_expiration = 1800; // half hour + $cache_expiration = 30 * MINUTE_IN_SECONDS; } } else { - $cache_expiration = 1800; // half hour + $cache_expiration = 30 * MINUTE_IN_SECONDS; } /* Loop the registered theme directories and extract all themes */ @@ -495,12 +506,12 @@ continue; } foreach ( $dirs as $dir ) { - if ( ! is_dir( $theme_root . '/' . $dir ) || $dir[0] == '.' || $dir == 'CVS' ) { + if ( ! is_dir( $theme_root . '/' . $dir ) || '.' === $dir[0] || 'CVS' === $dir ) { continue; } if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) { // wp-content/themes/a-single-theme - // wp-content/themes is $theme_root, a-single-theme is $dir + // wp-content/themes is $theme_root, a-single-theme is $dir. $found_themes[ $dir ] = array( 'theme_file' => $dir . '/style.css', 'theme_root' => $theme_root, @@ -508,14 +519,14 @@ } else { $found_theme = false; // wp-content/themes/a-folder-of-themes/* - // wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs + // wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs. $sub_dirs = @ scandir( $theme_root . '/' . $dir ); if ( ! $sub_dirs ) { trigger_error( "$theme_root/$dir is not readable", E_USER_NOTICE ); continue; } foreach ( $sub_dirs as $sub_dir ) { - if ( ! is_dir( $theme_root . '/' . $dir . '/' . $sub_dir ) || $dir[0] == '.' || $dir == 'CVS' ) { + if ( ! is_dir( $theme_root . '/' . $dir . '/' . $sub_dir ) || '.' === $dir[0] || 'CVS' === $dir ) { continue; } if ( ! file_exists( $theme_root . '/' . $dir . '/' . $sub_dir . '/style.css' ) ) { @@ -548,7 +559,7 @@ $theme_roots[ $theme_dir ] = $relative_theme_roots[ $theme_data['theme_root'] ]; // Convert absolute to relative. } - if ( $theme_roots != get_site_transient( 'theme_roots' ) ) { + if ( get_site_transient( 'theme_roots' ) != $theme_roots ) { set_site_transient( 'theme_roots', $theme_roots, $cache_expiration ); } @@ -556,7 +567,7 @@ } /** - * Retrieve path to themes directory. + * Retrieves path to themes directory. * * Does not have trailing slash. * @@ -564,19 +575,27 @@ * * @global array $wp_theme_directories * - * @param string $stylesheet_or_template The stylesheet or template name of the theme - * @return string Theme path. + * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme. + * Default is to leverage the main theme root. + * @return string Themes directory path. */ -function get_theme_root( $stylesheet_or_template = false ) { +function get_theme_root( $stylesheet_or_template = '' ) { global $wp_theme_directories; - if ( $stylesheet_or_template && $theme_root = get_raw_theme_root( $stylesheet_or_template ) ) { - // Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory. - // This gives relative theme roots the benefit of the doubt when things go haywire. - if ( ! in_array( $theme_root, (array) $wp_theme_directories ) ) { - $theme_root = WP_CONTENT_DIR . $theme_root; + $theme_root = ''; + + if ( $stylesheet_or_template ) { + $theme_root = get_raw_theme_root( $stylesheet_or_template ); + if ( $theme_root ) { + // Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory. + // This gives relative theme roots the benefit of the doubt when things go haywire. + if ( ! in_array( $theme_root, (array) $wp_theme_directories, true ) ) { + $theme_root = WP_CONTENT_DIR . $theme_root; + } } - } else { + } + + if ( ! $theme_root ) { $theme_root = WP_CONTENT_DIR . '/themes'; } @@ -591,7 +610,7 @@ } /** - * Retrieve URI for themes directory. + * Retrieves URI for themes directory. * * Does not have trailing slash. * @@ -601,11 +620,11 @@ * * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme. * Default is to leverage the main theme root. - * @param string $theme_root Optional. The theme root for which calculations will be based, preventing - * the need for a get_raw_theme_root() call. - * @return string Themes URI. + * @param string $theme_root Optional. The theme root for which calculations will be based, + * preventing the need for a get_raw_theme_root() call. Default empty. + * @return string Themes directory URI. */ -function get_theme_root_uri( $stylesheet_or_template = false, $theme_root = false ) { +function get_theme_root_uri( $stylesheet_or_template = '', $theme_root = '' ) { global $wp_theme_directories; if ( $stylesheet_or_template && ! $theme_root ) { @@ -613,7 +632,7 @@ } if ( $stylesheet_or_template && $theme_root ) { - if ( in_array( $theme_root, (array) $wp_theme_directories ) ) { + if ( in_array( $theme_root, (array) $wp_theme_directories, true ) ) { // Absolute path. Make an educated guess. YMMV -- but note the filter below. if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) { $theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) ); @@ -638,22 +657,22 @@ * * @param string $theme_root_uri The URI for themes directory. * @param string $siteurl WordPress web address which is set in General Options. - * @param string $stylesheet_or_template Stylesheet or template name of the theme. + * @param string $stylesheet_or_template The stylesheet or template name of the theme. */ return apply_filters( 'theme_root_uri', $theme_root_uri, get_option( 'siteurl' ), $stylesheet_or_template ); } /** - * Get the raw theme root relative to the content directory with no filters applied. + * Gets the raw theme root relative to the content directory with no filters applied. * * @since 3.1.0 * * @global array $wp_theme_directories * - * @param string $stylesheet_or_template The stylesheet or template name of the theme + * @param string $stylesheet_or_template The stylesheet or template name of the theme. * @param bool $skip_cache Optional. Whether to skip the cache. * Defaults to false, meaning the cache is used. - * @return string Theme root + * @return string Theme root. */ function get_raw_theme_root( $stylesheet_or_template, $skip_cache = false ) { global $wp_theme_directories; @@ -664,7 +683,7 @@ $theme_root = false; - // If requesting the root for the current theme, consult options to avoid calling get_theme_roots() + // If requesting the root for the current theme, consult options to avoid calling get_theme_roots(). if ( ! $skip_cache ) { if ( get_option( 'stylesheet' ) == $stylesheet_or_template ) { $theme_root = get_option( 'stylesheet_root' ); @@ -684,7 +703,7 @@ } /** - * Display localized stylesheet link element. + * Displays localized stylesheet link element. * * @since 2.1.0 */ @@ -693,7 +712,14 @@ if ( empty( $stylesheet ) ) { return; } - echo ''; + + $type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"'; + + printf( + '', + $stylesheet, + $type_attr + ); } /** @@ -708,11 +734,16 @@ * @global WP_Customize_Manager $wp_customize * @global array $sidebars_widgets * - * @param string $stylesheet Stylesheet name + * @param string $stylesheet Stylesheet name. */ function switch_theme( $stylesheet ) { global $wp_theme_directories, $wp_customize, $sidebars_widgets; + $requirements = validate_theme_requirements( $stylesheet ); + if ( is_wp_error( $requirements ) ) { + wp_die( $requirements ); + } + $_sidebars_widgets = null; if ( 'wp_ajax_customize_save' === current_action() ) { $old_sidebars_widgets_data_setting = $wp_customize->get_setting( 'old_sidebars_widgets_data' ); @@ -799,16 +830,17 @@ } /** - * Checks that current theme files 'index.php' and 'style.css' exists. + * Checks that the current theme has 'index.php' and 'style.css' files. * * Does not initially check the default theme, which is the fallback and should always exist. * But if it doesn't exist, it'll fall back to the latest core default theme that does exist. * Will switch theme to the fallback theme if current theme does not validate. * - * You can use the {@see 'validate_current_theme'} filter to return false to - * disable this functionality. + * You can use the {@see 'validate_current_theme'} filter to return false to disable + * this functionality. * * @since 1.5.0 + * * @see WP_DEFAULT_THEME * * @return bool @@ -845,6 +877,7 @@ /** * If we're in an invalid state but WP_DEFAULT_THEME doesn't exist, * switch to the latest core default theme that's installed. + * * If it turns out that this latest core default theme is our current * theme, then there's nothing we can do about that, so we have to bail, * rather than going into an infinite loop. (This is why there are @@ -861,7 +894,79 @@ } /** - * Retrieve all theme modifications. + * Validates the theme requirements for WordPress version and PHP version. + * + * Uses the information from `Requires at least` and `Requires PHP` headers + * defined in the theme's `style.css` file. + * + * If the headers are not present in the theme's stylesheet file, + * `readme.txt` is also checked as a fallback. + * + * @since 5.5.0 + * + * @param string $stylesheet Directory name for the theme. + * @return true|WP_Error True if requirements are met, WP_Error on failure. + */ +function validate_theme_requirements( $stylesheet ) { + $theme = wp_get_theme( $stylesheet ); + + $requirements = array( + 'requires' => ! empty( $theme->get( 'RequiresWP' ) ) ? $theme->get( 'RequiresWP' ) : '', + 'requires_php' => ! empty( $theme->get( 'RequiresPHP' ) ) ? $theme->get( 'RequiresPHP' ) : '', + ); + + $readme_file = $theme->theme_root . '/' . $stylesheet . '/readme.txt'; + + if ( file_exists( $readme_file ) ) { + $readme_headers = get_file_data( + $readme_file, + array( + 'requires' => 'Requires at least', + 'requires_php' => 'Requires PHP', + ), + 'theme' + ); + + $requirements = array_merge( $readme_headers, $requirements ); + } + + $compatible_wp = is_wp_version_compatible( $requirements['requires'] ); + $compatible_php = is_php_version_compatible( $requirements['requires_php'] ); + + if ( ! $compatible_wp && ! $compatible_php ) { + return new WP_Error( + 'theme_wp_php_incompatible', + sprintf( + /* translators: %s: Theme name. */ + _x( 'Error: Current WordPress and PHP versions do not meet minimum requirements for %s.', 'theme' ), + $theme->display( 'Name' ) + ) + ); + } elseif ( ! $compatible_php ) { + return new WP_Error( + 'theme_php_incompatible', + sprintf( + /* translators: %s: Theme name. */ + _x( 'Error: Current PHP version does not meet minimum requirements for %s.', 'theme' ), + $theme->display( 'Name' ) + ) + ); + } elseif ( ! $compatible_wp ) { + return new WP_Error( + 'theme_wp_incompatible', + sprintf( + /* translators: %s: Theme name. */ + _x( 'Error: Current WordPress version does not meet minimum requirements for %s.', 'theme' ), + $theme->display( 'Name' ) + ) + ); + } + + return true; +} + +/** + * Retrieves all theme modifications. * * @since 3.1.0 * @@ -885,18 +990,18 @@ } /** - * Retrieve theme modification value for the current theme. + * Retrieves theme modification value for the current theme. * * If the modification name does not exist, then the $default will be passed - * through {@link https://secure.php.net/sprintf sprintf()} PHP function with the first - * string the template directory URI and the second string the stylesheet - * directory URI. + * through {@link https://www.php.net/sprintf sprintf()} PHP function with + * the template directory URI as the first string and the stylesheet directory URI + * as the second string. * * @since 2.1.0 * - * @param string $name Theme modification name. - * @param bool|string $default - * @return mixed + * @param string $name Theme modification name. + * @param string|false $default Optional. Theme modification default value. Default false. + * @return mixed Theme modification value. */ function get_theme_mod( $name, $default = false ) { $mods = get_theme_mods(); @@ -905,10 +1010,9 @@ /** * Filters the theme modification, or 'theme_mod', value. * - * The dynamic portion of the hook name, `$name`, refers to - * the key name of the modification array. For example, - * 'header_textcolor', 'header_image', and so on depending - * on the theme options. + * The dynamic portion of the hook name, `$name`, refers to the key name + * of the modification array. For example, 'header_textcolor', 'header_image', + * and so on depending on the theme options. * * @since 2.2.0 * @@ -918,7 +1022,10 @@ } if ( is_string( $default ) ) { - $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() ); + // Only run the replacement if an sprintf() string format pattern was found. + if ( preg_match( '#(?url = sprintf( $_wp_random_header->url, get_template_directory_uri(), get_stylesheet_directory_uri() ); $_wp_random_header->thumbnail_url = sprintf( $_wp_random_header->thumbnail_url, get_template_directory_uri(), get_stylesheet_directory_uri() ); } + return $_wp_random_header; } /** - * Get random header image url from registered images in theme. + * Gets random header image URL from registered images in theme. * * @since 3.2.0 * - * @return string Path to header image + * @return string Path to header image. */ function get_random_header_image() { $random_image = _get_random_header_data(); + if ( empty( $random_image->url ) ) { return ''; } + return $random_image->url; } /** - * Check if random header image is in use. + * Checks if random header image is in use. * * Always true if user expressly chooses the option in Appearance > Header. * Also true if theme has multiple header images registered, no specific header image @@ -1214,20 +1323,24 @@ * * @since 3.2.0 * - * @param string $type The random pool to use. any|default|uploaded + * @param string $type The random pool to use. Possible values include 'any', + * 'default', 'uploaded'. Default 'any'. * @return bool */ function is_random_header_image( $type = 'any' ) { $header_image_mod = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) ); - if ( 'any' == $type ) { - if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) ) { + if ( 'any' === $type ) { + if ( 'random-default-image' === $header_image_mod + || 'random-uploaded-image' === $header_image_mod + || ( '' !== get_random_header_image() && empty( $header_image_mod ) ) + ) { return true; } } else { - if ( "random-$type-image" == $header_image_mod ) { + if ( "random-$type-image" === $header_image_mod ) { return true; - } elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image() ) { + } elseif ( 'default' === $type && empty( $header_image_mod ) && '' !== get_random_header_image() ) { return true; } } @@ -1236,19 +1349,20 @@ } /** - * Display header image URL. + * Displays header image URL. * * @since 2.1.0 */ function header_image() { $image = get_header_image(); + if ( $image ) { echo esc_url( $image ); } } /** - * Get the header images uploaded for the current theme. + * Gets the header images uploaded for the current theme. * * @since 3.2.0 * @@ -1257,7 +1371,7 @@ function get_uploaded_header_images() { $header_images = array(); - // @todo caching + // @todo Caching. $headers = get_posts( array( 'post_type' => 'attachment', @@ -1296,7 +1410,7 @@ } /** - * Get the header image data. + * Gets the header image data. * * @since 3.4.0 * @@ -1312,9 +1426,10 @@ } else { $data = get_theme_mod( 'header_image_data' ); if ( ! $data && current_theme_supports( 'custom-header', 'default-image' ) ) { - $directory_args = array( get_template_directory_uri(), get_stylesheet_directory_uri() ); - $data = array(); - $data['url'] = $data['thumbnail_url'] = vsprintf( get_theme_support( 'custom-header', 'default-image' ), $directory_args ); + $directory_args = array( get_template_directory_uri(), get_stylesheet_directory_uri() ); + $data = array(); + $data['url'] = vsprintf( get_theme_support( 'custom-header', 'default-image' ), $directory_args ); + $data['thumbnail_url'] = $data['url']; if ( ! empty( $_wp_default_headers ) ) { foreach ( (array) $_wp_default_headers as $default_header ) { $url = vsprintf( $default_header['url'], $directory_args ); @@ -1340,13 +1455,14 @@ } /** - * Register a selection of default headers to be displayed by the custom header admin UI. + * Registers a selection of default headers to be displayed by the custom header admin UI. * * @since 3.0.0 * * @global array $_wp_default_headers * - * @param array $headers Array of headers keyed by a string id. The ids point to arrays containing 'url', 'thumbnail_url', and 'description' keys. + * @param array $headers Array of headers keyed by a string ID. The IDs point to arrays + * containing 'url', 'thumbnail_url', and 'description' keys. */ function register_default_headers( $headers ) { global $_wp_default_headers; @@ -1355,7 +1471,7 @@ } /** - * Unregister default headers. + * Unregisters default headers. * * This function must be called after register_default_headers() has already added the * header you want to remove. @@ -1382,7 +1498,7 @@ } /** - * Check whether a header video is set or not. + * Checks whether a header video is set or not. * * @since 4.7.0 * @@ -1395,7 +1511,7 @@ } /** - * Retrieve header video URL for custom header. + * Retrieves header video URL for custom header. * * Uses a local video if present, or falls back to an external video. * @@ -1404,12 +1520,13 @@ * @return string|false Header video URL or false if there is no video. */ function get_header_video_url() { - $id = absint( get_theme_mod( 'header_video' ) ); - $url = esc_url( get_theme_mod( 'external_header_video' ) ); + $id = absint( get_theme_mod( 'header_video' ) ); if ( $id ) { // Get the file URL from the attachment ID. $url = wp_get_attachment_url( $id ); + } else { + $url = get_theme_mod( 'external_header_video' ); } /** @@ -1429,19 +1546,20 @@ } /** - * Display header video URL. + * Displays header video URL. * * @since 4.7.0 */ function the_header_video_url() { $video = get_header_video_url(); + if ( $video ) { echo esc_url( $video ); } } /** - * Retrieve header video settings. + * Retrieves header video settings. * * @since 4.7.0 * @@ -1485,7 +1603,7 @@ } /** - * Check whether a custom header is set or not. + * Checks whether a custom header is set or not. * * @since 4.7.0 * @@ -1520,7 +1638,7 @@ } /** - * Modify whether the custom header video is eligible to show on the current page. + * Filters whether the custom header video is eligible to show on the current page. * * @since 4.7.0 * @@ -1532,7 +1650,7 @@ } /** - * Retrieve the markup for a custom header. + * Retrieves the markup for a custom header. * * The container div will always be returned in the Customizer preview. * @@ -1552,7 +1670,7 @@ } /** - * Print the markup for a custom header. + * Prints the markup for a custom header. * * A container div will always be printed in the Customizer preview. * @@ -1573,7 +1691,7 @@ } /** - * Retrieve background image for custom background. + * Retrieves background image for custom background. * * @since 3.0.0 * @@ -1584,7 +1702,7 @@ } /** - * Display background image path. + * Displays background image path. * * @since 3.0.0 */ @@ -1593,7 +1711,7 @@ } /** - * Retrieve value for custom background color. + * Retrieves value for custom background color. * * @since 3.0.0 * @@ -1604,7 +1722,7 @@ } /** - * Display background color value. + * Displays background color value. * * @since 3.0.0 */ @@ -1625,13 +1743,15 @@ // A default has to be specified in style.css. It will not be printed here. $color = get_background_color(); - if ( $color === get_theme_support( 'custom-background', 'default-color' ) ) { + if ( get_theme_support( 'custom-background', 'default-color' ) === $color ) { $color = false; } + $type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"'; + if ( ! $background && ! $color ) { if ( is_customize_preview() ) { - echo ''; + printf( '', $type_attr ); } return; } @@ -1685,22 +1805,23 @@ $style .= $image . $position . $size . $repeat . $attachment; } ?> - - ' . _x( 'Address', 'Theme starter content' ) . "\n", _x( '123 Main Street', 'Theme starter content' ) . "\n" . _x( 'New York, NY 10001', 'Theme starter content' ) . "\n\n", '' . _x( 'Hours', 'Theme starter content' ) . "\n", - _x( 'Monday—Friday: 9:00AM–5:00PM', 'Theme starter content' ) . "\n" . _x( 'Saturday & Sunday: 11:00AM–3:00PM', 'Theme starter content' ), + _x( 'Monday–Friday: 9:00AM–5:00PM', 'Theme starter content' ) . "\n" . _x( 'Saturday & Sunday: 11:00AM–3:00PM', 'Theme starter content' ), ) ), 'filter' => true, @@ -2099,7 +2218,7 @@ 'title' => _x( 'Home', 'Theme starter content' ), 'url' => home_url( '/' ), ), - 'page_home' => array( // Deprecated in favor of link_home. + 'page_home' => array( // Deprecated in favor of 'link_home'. 'type' => 'post_type', 'object' => 'page', 'object_id' => '{{home}}', @@ -2170,17 +2289,26 @@ 'home' => array( 'post_type' => 'page', 'post_title' => _x( 'Home', 'Theme starter content' ), - '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' ), + 'post_content' => sprintf( + "\n

%s

\n", + _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' ) + ), ), 'about' => array( 'post_type' => 'page', 'post_title' => _x( 'About', 'Theme starter content' ), - 'post_content' => _x( 'You might be an artist who would like to introduce yourself and your work here or maybe you’re a business with a mission to describe.', 'Theme starter content' ), + 'post_content' => sprintf( + "\n

%s

\n", + _x( 'You might be an artist who would like to introduce yourself and your work here or maybe you’re a business with a mission to describe.', 'Theme starter content' ) + ), ), 'contact' => array( 'post_type' => 'page', 'post_title' => _x( 'Contact', 'Theme starter content' ), - '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' ), + 'post_content' => sprintf( + "\n

%s

\n", + _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' ) + ), ), 'blog' => array( 'post_type' => 'page', @@ -2194,7 +2322,10 @@ 'homepage-section' => array( 'post_type' => 'page', 'post_title' => _x( 'A homepage section', 'Theme starter content' ), - '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' ), + 'post_content' => sprintf( + "\n

%s

\n", + _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' ) + ), ), ), ); @@ -2267,7 +2398,8 @@ } break; - // All that's left now are posts (besides attachments). Not a default case for the sake of clarity and future work. + // All that's left now are posts (besides attachments). + // Not a default case for the sake of clarity and future work. case 'posts': foreach ( $config[ $type ] as $id => $item ) { if ( is_array( $item ) ) { @@ -2318,32 +2450,46 @@ * If attached to a hook, it must be {@see 'after_setup_theme'}. * The {@see 'init'} hook may be too late for some features. * + * Example usage: + * + * add_theme_support( 'title-tag' ); + * add_theme_support( 'custom-logo', array( + * 'height' => 480, + * 'width' => 720, + * ) ); + * * @since 2.9.0 - * @since 3.6.0 The `html5` feature was added - * @since 3.9.0 The `html5` feature now also accepts 'gallery' and 'caption' - * @since 4.1.0 The `title-tag` feature was added - * @since 4.5.0 The `customize-selective-refresh-widgets` feature was added - * @since 4.7.0 The `starter-content` feature was added + * @since 3.4.0 The `custom-header-uploads` feature was deprecated. + * @since 3.6.0 The `html5` feature was added. + * @since 3.9.0 The `html5` feature now also accepts 'gallery' and 'caption'. + * @since 4.1.0 The `title-tag` feature was added. + * @since 4.5.0 The `customize-selective-refresh-widgets` feature was added. + * @since 4.7.0 The `starter-content` feature was added. * @since 5.0.0 The `responsive-embeds`, `align-wide`, `dark-editor-style`, `disable-custom-colors`, - * `disable-custom-font-sizes`, `editor-color-pallete`, `editor-font-sizes`, + * `disable-custom-font-sizes`, `editor-color-palette`, `editor-font-sizes`, * `editor-styles`, and `wp-block-styles` features were added. + * @since 5.3.0 The `html5` feature now also accepts 'script' and 'style'. + * @since 5.3.0 Formalized the existing and already documented `...$args` parameter + * by adding it to the function signature. + * @since 5.5.0 The `core-block-patterns` feature was added and is enabled by default. + * @since 5.5.0 The `custom-logo` feature now also accepts 'unlink-homepage-logo'. * * @global array $_wp_theme_features * - * @param string $feature The feature being added. Likely core values include 'post-formats', - * 'post-thumbnails', 'html5', 'custom-logo', 'custom-header-uploads', - * 'custom-header', 'custom-background', 'title-tag', 'starter-content', - * 'responsive-embeds', etc. - * @param mixed $args,... Optional extra arguments to pass along with certain features. + * @param string $feature The feature being added. Likely core values include 'post-formats', 'post-thumbnails', + * 'custom-header', 'custom-background', 'custom-logo', 'menus', 'automatic-feed-links', + * 'html5', 'title-tag', 'customize-selective-refresh-widgets', 'starter-content', + * 'responsive-embeds', 'align-wide', 'dark-editor-style', 'disable-custom-colors', + * 'disable-custom-font-sizes', 'editor-color-palette', 'editor-font-sizes', + * 'editor-styles', 'wp-block-styles', and 'core-block-patterns'. + * @param mixed ...$args Optional extra arguments to pass along with certain features. * @return void|bool False on failure, void otherwise. */ -function add_theme_support( $feature ) { +function add_theme_support( $feature, ...$args ) { global $_wp_theme_features; - if ( func_num_args() == 1 ) { + if ( ! $args ) { $args = true; - } else { - $args = array_slice( func_get_args(), 1 ); } switch ( $feature ) { @@ -2357,14 +2503,14 @@ * Merge post types with any that already declared their support * for post thumbnails. */ - if ( is_array( $args[0] ) && isset( $_wp_theme_features['post-thumbnails'] ) ) { + if ( isset( $args[0] ) && is_array( $args[0] ) && isset( $_wp_theme_features['post-thumbnails'] ) ) { $args[0] = array_unique( array_merge( $_wp_theme_features['post-thumbnails'][0], $args[0] ) ); } break; case 'post-formats': - if ( is_array( $args[0] ) ) { + if ( isset( $args[0] ) && is_array( $args[0] ) ) { $post_formats = get_post_format_slugs(); unset( $post_formats['standard'] ); @@ -2377,7 +2523,7 @@ if ( empty( $args[0] ) ) { // Build an array of types for back-compat. $args = array( 0 => array( 'comment-list', 'comment-form', 'search-form' ) ); - } elseif ( ! is_array( $args[0] ) ) { + } elseif ( ! isset( $args[0] ) || ! is_array( $args[0] ) ) { _doing_it_wrong( "add_theme_support( 'html5' )", __( 'You need to pass an array of types.' ), '3.6.1' ); return false; } @@ -2389,15 +2535,16 @@ break; case 'custom-logo': - if ( ! is_array( $args ) ) { + if ( true === $args ) { $args = array( 0 => array() ); } $defaults = array( - 'width' => null, - 'height' => null, - 'flex-width' => false, - 'flex-height' => false, - 'header-text' => '', + 'width' => null, + 'height' => null, + 'flex-width' => false, + 'flex-height' => false, + 'header-text' => '', + 'unlink-homepage-logo' => false, ); $args[0] = wp_parse_args( array_intersect_key( $args[0], $defaults ), $defaults ); @@ -2412,7 +2559,7 @@ return add_theme_support( 'custom-header', array( 'uploads' => true ) ); case 'custom-header': - if ( ! is_array( $args ) ) { + if ( true === $args ) { $args = array( 0 => array() ); } @@ -2448,11 +2595,13 @@ $args[0] = wp_parse_args( $args[0], $defaults ); } - // If a constant was defined, use that value. Otherwise, define the constant to ensure - // the constant is always accurate (and is not defined later, overriding our value). - // As stated above, the first value wins. - // Once we get to wp_loaded (just-in-time), define any constants we haven't already. - // Constants are lame. Don't reference them. This is just for backward compatibility. + /* + * If a constant was defined, use that value. Otherwise, define the constant to ensure + * the constant is always accurate (and is not defined later, overriding our value). + * As stated above, the first value wins. + * Once we get to wp_loaded (just-in-time), define any constants we haven't already. + * Constants are lame. Don't reference them. This is just for backward compatibility. + */ if ( defined( 'NO_HEADER_TEXT' ) ) { $args[0]['header-text'] = ! NO_HEADER_TEXT; @@ -2502,7 +2651,7 @@ break; case 'custom-background': - if ( ! is_array( $args ) ) { + if ( true === $args ) { $args = array( 0 => array() ); } @@ -2550,10 +2699,10 @@ case 'title-tag': // Can be called in functions.php but must happen before wp_loaded, i.e. not in header.php. if ( did_action( 'wp_loaded' ) ) { - /* translators: 1: title-tag, 2: wp_loaded */ _doing_it_wrong( "add_theme_support( 'title-tag' )", sprintf( + /* translators: 1: title-tag, 2: wp_loaded */ __( 'Theme support for %1$s should be registered before the %2$s hook.' ), 'title-tag', 'wp_loaded' @@ -2590,7 +2739,7 @@ } if ( is_admin() ) { - require_once( ABSPATH . 'wp-admin/custom-header.php' ); + require_once ABSPATH . 'wp-admin/includes/class-custom-image-header.php'; $custom_image_header = new Custom_Image_Header( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] ); } } @@ -2603,7 +2752,7 @@ add_action( 'wp_head', $args[0]['wp-head-callback'] ); if ( is_admin() ) { - require_once( ABSPATH . 'wp-admin/custom-background.php' ); + require_once ABSPATH . 'wp-admin/includes/class-custom-background.php'; $custom_background = new Custom_Background( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] ); } } @@ -2621,9 +2770,10 @@ $classes = array_map( 'sanitize_html_class', $classes ); $classes = '.' . implode( ', .', $classes ); + $type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"'; ?> -