diff --git a/src/wp-includes/class-wp-dependencies.php b/src/wp-includes/class-wp-dependencies.php index c3dc40bc88141..ae5c37eed9bca 100644 --- a/src/wp-includes/class-wp-dependencies.php +++ b/src/wp-includes/class-wp-dependencies.php @@ -264,9 +264,10 @@ public function all_deps( $handles, $recursion = false, $group = false ) { * @since 2.6.0 Moved from `WP_Scripts`. * * @param string $handle Name of the item. Should be unique. - * @param string|false $src Full URL of the item, or path of the item relative + * @param string|bool $src Full URL of the item, or path of the item relative * to the WordPress root directory. If source is set to false, - * the item is an alias of other items it depends on. + * the item is an alias of other items it depends on. If the source is set to true, + * then filters will apply on the src (which is not the case when it is an alias). * @param string[] $deps Optional. An array of registered item handles this item depends on. * Default empty array. * @param string|bool|null $ver Optional. String specifying item version number, if it has one, diff --git a/src/wp-includes/class-wp-dependency.php b/src/wp-includes/class-wp-dependency.php index 4900bf737ddeb..4819d47c56201 100644 --- a/src/wp-includes/class-wp-dependency.php +++ b/src/wp-includes/class-wp-dependency.php @@ -30,9 +30,10 @@ class _WP_Dependency { * The handle source. * * If source is set to false, the item is an alias of other items it depends on. + * If source is set to true, the item is a provisional alias since filters may provide an actual URL. * * @since 2.6.0 - * @var string|false + * @var string|bool */ public $src; diff --git a/src/wp-includes/class-wp-scripts.php b/src/wp-includes/class-wp-scripts.php index 7628db0a875b7..d42792ac2a8ae 100644 --- a/src/wp-includes/class-wp-scripts.php +++ b/src/wp-includes/class-wp-scripts.php @@ -372,8 +372,8 @@ public function do_item( $handle, $group = false ) { * * @since 2.2.0 * - * @param string $src Script loader source path. - * @param string $handle Script handle. + * @param string|true $src Script loader source path. + * @param string $handle Script handle. */ $filtered_src = apply_filters( 'script_loader_src', $src, $handle ); @@ -413,7 +413,7 @@ public function do_item( $handle, $group = false ) { return true; } - if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $this->content_url && str_starts_with( $src, $this->content_url ) ) ) { + if ( is_string( $src ) && ! preg_match( '|^(https?:)?//|', $src ) && ! ( $this->content_url && str_starts_with( $src, $this->content_url ) ) ) { $src = $this->base_url . $src; } @@ -429,12 +429,17 @@ public function do_item( $handle, $group = false ) { $query_args = array_merge( $query_args, $parsed_args ); } } - $src = add_query_arg( rawurlencode_deep( $query_args ), $src ); + if ( count( $query_args ) > 0 ) { + $src = add_query_arg( rawurlencode_deep( $query_args ), $src ); + } /** This filter is documented in wp-includes/class-wp-scripts.php */ - $src = esc_url_raw( apply_filters( 'script_loader_src', $src, $handle ) ); - - if ( ! $src ) { + $src = apply_filters( 'script_loader_src', $src, $handle ); + if ( ! is_string( $src ) ) { + return true; + } + $src = esc_url_raw( $src ); + if ( ! is_string( $src ) || ! $src ) { return true; } diff --git a/src/wp-includes/class-wp-styles.php b/src/wp-includes/class-wp-styles.php index 72af6c29b0171..e34f0d3ce7f57 100644 --- a/src/wp-includes/class-wp-styles.php +++ b/src/wp-includes/class-wp-styles.php @@ -401,13 +401,13 @@ public function all_deps( $handles, $recursion = false, $group = false ) { * * @since 2.6.0 * - * @param string $src The source of the enqueued style. + * @param string|true $src The source of the enqueued style. * @param string|false|null $ver The version of the enqueued style. * @param string $handle The style's registered handle. * @return string Style's fully-qualified URL. */ public function _css_href( $src, $ver, $handle ) { - if ( ! is_bool( $src ) && ! preg_match( '|^(https?:)?//|', $src ) && ! ( $this->content_url && str_starts_with( $src, $this->content_url ) ) ) { + if ( is_string( $src ) && ! preg_match( '|^(https?:)?//|', $src ) && ! ( $this->content_url && str_starts_with( $src, $this->content_url ) ) ) { $src = $this->base_url . $src; } @@ -423,15 +423,17 @@ public function _css_href( $src, $ver, $handle ) { $query_args = array_merge( $query_args, $parsed_args ); } } - $src = add_query_arg( rawurlencode_deep( $query_args ), $src ); + if ( count( $query_args ) > 0 ) { + $src = add_query_arg( rawurlencode_deep( $query_args ), $src ); + } /** * Filters an enqueued style's fully-qualified URL. * * @since 2.6.0 * - * @param string $src The source URL of the enqueued style. - * @param string $handle The style's registered handle. + * @param string|true $src The source URL of the enqueued style. + * @param string $handle The style's registered handle. */ $src = apply_filters( 'style_loader_src', $src, $handle ); return esc_url( $src ); diff --git a/src/wp-includes/functions.wp-scripts.php b/src/wp-includes/functions.wp-scripts.php index f1a9b2afd6b7c..979c9f0498985 100644 --- a/src/wp-includes/functions.wp-scripts.php +++ b/src/wp-includes/functions.wp-scripts.php @@ -161,8 +161,10 @@ function wp_add_inline_script( $handle, $data, $position = 'after' ) { * @since 6.9.0 The $fetchpriority parameter of type string was added to the $args parameter of type array. * * @param string $handle Name of the script. Should be unique. - * @param string|false $src Full URL of the script, or path of the script relative to the WordPress root directory. + * @param string|bool $src Full URL of the script, or path of the script relative to the WordPress root directory. * If source is set to false, script is an alias of other scripts it depends on. + * If source is set to true, it is a provisional alias where {@see 'script_loader_src'} filters + * may also provide an actual URL. * @param string[] $deps Optional. An array of registered script handles this script depends on. Default empty array. * @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL * as a query string for cache busting purposes. If version is set to false, a version diff --git a/src/wp-includes/functions.wp-styles.php b/src/wp-includes/functions.wp-styles.php index 903097c313a4a..6a4d676e27b07 100644 --- a/src/wp-includes/functions.wp-styles.php +++ b/src/wp-includes/functions.wp-styles.php @@ -114,8 +114,10 @@ function wp_add_inline_style( $handle, $data ) { * @since 4.3.0 A return value was added. * * @param string $handle Name of the stylesheet. Should be unique. - * @param string|false $src Full URL of the stylesheet, or path of the stylesheet relative to the WordPress root directory. + * @param string|bool $src Full URL of the stylesheet, or path of the stylesheet relative to the WordPress root directory. * If source is set to false, stylesheet is an alias of other stylesheets it depends on. + * If source is set to true, it is a provisional alias where {@see 'style_loader_src'} filters + * may also provide an actual URL. * @param string[] $deps Optional. An array of registered stylesheet handles this stylesheet depends on. Default empty array. * @param string|bool|null $ver Optional. String specifying stylesheet version number, if it has one, which is added to the URL * as a query string for cache busting purposes. If version is set to false, a version diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 9d2df0dac687f..02846babe844b 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -186,7 +186,7 @@ function wp_get_script_polyfill( $scripts, $tests ) { $src = $scripts->registered[ $handle ]->src; $ver = $scripts->registered[ $handle ]->ver; - if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $scripts->content_url && str_starts_with( $src, $scripts->content_url ) ) ) { + if ( is_string( $src ) && ! preg_match( '|^(https?:)?//|', $src ) && ! ( $scripts->content_url && str_starts_with( $src, $scripts->content_url ) ) ) { $src = $scripts->base_url . $src; } @@ -688,14 +688,14 @@ function wp_scripts_get_suffix( $type = '' ) { * via wp-admin/load-scripts.php or wp-admin/load-styles.php, in which case * wp-includes/functions.php is not loaded. */ - require ABSPATH . WPINC . '/version.php'; + $versions = require ABSPATH . WPINC . '/version.php'; /* * Note: str_contains() is not used here, as this file can be included * via wp-admin/load-scripts.php or wp-admin/load-styles.php, in which case * the polyfills from wp-includes/compat.php are not loaded. */ - $develop_src = false !== strpos( $wp_version, '-src' ); + $develop_src = false !== strpos( $versions['wp_version'] ?? '', '-src' ); if ( ! defined( 'SCRIPT_DEBUG' ) ) { define( 'SCRIPT_DEBUG', $develop_src ); @@ -1084,7 +1084,7 @@ function wp_default_scripts( $scripts ) { 'var mejsL10n = %s;', wp_json_encode( array( - 'language' => strtolower( strtok( determine_locale(), '_-' ) ), + 'language' => strtolower( (string) strtok( determine_locale(), '_-' ) ), 'strings' => array( 'mejs.download-file' => __( 'Download File' ), 'mejs.install-flash' => __( 'You are using a browser that does not have Flash player enabled or installed. Please turn on your Flash player plugin or download the latest version from https://get.adobe.com/flashplayer/' ), @@ -1551,7 +1551,7 @@ function wp_default_styles( $styles ) { * via wp-admin/load-scripts.php or wp-admin/load-styles.php, in which case * wp-includes/functions.php is not loaded. */ - require ABSPATH . WPINC . '/version.php'; + $versions = require ABSPATH . WPINC . '/version.php'; if ( ! defined( 'SCRIPT_DEBUG' ) ) { /* @@ -1559,7 +1559,7 @@ function wp_default_styles( $styles ) { * via wp-admin/load-scripts.php or wp-admin/load-styles.php, in which case * the polyfills from wp-includes/compat.php are not loaded. */ - define( 'SCRIPT_DEBUG', false !== strpos( $wp_version, '-src' ) ); + define( 'SCRIPT_DEBUG', false !== strpos( $versions['wp_version'] ?? '', '-src' ) ); } $guessurl = site_url(); @@ -1602,7 +1602,13 @@ function wp_default_styles( $styles ) { $open_sans_font_url = "https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,300,400,600&subset=$subsets&display=fallback"; } - // Register a stylesheet for the selected admin color scheme. + /* + * Register a stylesheet for the selected admin color scheme. + * The src here is uniquely `true` to ensure that the dependency is not treated as an alias and so that the + * `wp_style_loader_src` filters will apply. This results in the wp_style_loader_src() function applying on the + * value so that it can dynamically apply the user-selected color. If no user-defined color is supplied, then + * the function returns `false` so that it ultimately does behave as an alias. + */ $styles->add( 'colors', true, array( 'wp-admin', 'buttons' ) ); $suffix = SCRIPT_DEBUG ? '' : '.min'; @@ -1902,7 +1908,7 @@ function wp_prototype_before_jquery( $js_array ) { unset( $js_array[ $prototype ] ); - array_splice( $js_array, $jquery, 0, 'prototype' ); + array_splice( $js_array, (int) $jquery, 0, 'prototype' ); return $js_array; } @@ -2070,15 +2076,15 @@ function wp_localize_community_events() { * * @global array $_wp_admin_css_colors * - * @param string $src Source URL. - * @param string $handle Either 'colors' or 'colors-rtl'. - * @return string|false URL path to CSS stylesheet for Administration Screens. + * @param string|bool $src Source URL. + * @param string $handle Either 'colors' or 'colors-rtl'. + * @return string|bool URL path to CSS stylesheet for Administration Screens. */ function wp_style_loader_src( $src, $handle ) { global $_wp_admin_css_colors; if ( wp_installing() ) { - return preg_replace( '#^wp-admin/#', './', $src ); + return (string) preg_replace( '#^wp-admin/#', './', $src ); // TODO: Parameter #3 $subject of function preg_replace expects array|string, bool|string given. } if ( 'colors' === $handle ) { @@ -2095,7 +2101,7 @@ function wp_style_loader_src( $src, $handle ) { return false; } - $parsed = parse_url( $src ); + $parsed = parse_url( $src ); // TODO: Parameter #1 $url of function parse_url expects string, bool|string given. if ( isset( $parsed['query'] ) && $parsed['query'] ) { wp_parse_str( $parsed['query'], $qv ); $url = add_query_arg( $qv, $url ); @@ -2986,7 +2992,7 @@ function wp_print_inline_script_tag( $data, $attributes = array() ) { * @global WP_Styles $wp_styles */ function wp_maybe_inline_styles() { - global $wp_styles; + $wp_styles = wp_styles(); $total_inline_limit = 40000; /** @@ -3008,7 +3014,7 @@ function wp_maybe_inline_styles() { } $src = $wp_styles->registered[ $handle ]->src; $path = $wp_styles->get_data( $handle, 'path' ); - if ( $path && $src ) { + if ( is_string( $path ) && '' !== $path && is_string( $src ) && '' !== $src ) { $size = wp_filesize( $path ); if ( 0 === $size && ! file_exists( $path ) ) { _doing_it_wrong( @@ -3073,7 +3079,7 @@ static function ( $a, $b ) { ); continue; } - $style['css'] = file_get_contents( $style['path'] ); + $style['css'] = (string) file_get_contents( $style['path'] ); /* * Check if the style contains relative URLs that need to be modified. @@ -3109,7 +3115,7 @@ static function ( $a, $b ) { * @return string The CSS with URLs made relative to the WordPress installation. */ function _wp_normalize_relative_css_links( $css, $stylesheet_url ) { - return preg_replace_callback( + return (string) preg_replace_callback( '#(url\s*\(\s*[\'"]?\s*)([^\'"\)]+)#', static function ( $matches ) use ( $stylesheet_url ) { list( , $prefix, $url ) = $matches; @@ -3683,7 +3689,7 @@ static function () use ( $placeholder ) { if ( count( $enqueued_block_styles ) > 0 ) { ob_start(); wp_styles()->do_items( $enqueued_block_styles ); - $printed_block_styles = ob_get_clean(); + $printed_block_styles = (string) ob_get_clean(); } /* @@ -3693,7 +3699,7 @@ static function () use ( $placeholder ) { */ ob_start(); wp_styles()->do_footer_items(); - $printed_late_styles = ob_get_clean(); + $printed_late_styles = (string) ob_get_clean(); }; /* @@ -3710,14 +3716,14 @@ static function () use ( $placeholder ) { // The normal priority for wp_print_footer_scripts() is to run at 20. add_action( 'wp_footer', $capture_late_styles, 20 ); } else { - remove_action( 'wp_print_footer_scripts', '_wp_footer_scripts', $wp_print_footer_scripts_priority ); + remove_action( 'wp_print_footer_scripts', '_wp_footer_scripts', (int) $wp_print_footer_scripts_priority ); add_action( 'wp_print_footer_scripts', static function () use ( $capture_late_styles ) { $capture_late_styles(); print_footer_scripts(); }, - $wp_print_footer_scripts_priority + (int) $wp_print_footer_scripts_priority ); } diff --git a/src/wp-includes/version.php b/src/wp-includes/version.php index fb46afd6789c5..9ab3eca45bc65 100644 --- a/src/wp-includes/version.php +++ b/src/wp-includes/version.php @@ -55,3 +55,12 @@ * @global string $required_mysql_version */ $required_mysql_version = '5.5.5'; + +return compact( + 'wp_version', + 'wp_db_version', + 'tinymce_version', + 'required_php_version', + 'required_php_extensions', + 'required_mysql_version' +); diff --git a/tests/phpunit/tests/functions/wpGetWpVersion.php b/tests/phpunit/tests/functions/wpGetWpVersion.php index d10d946e3baea..680bded20870d 100644 --- a/tests/phpunit/tests/functions/wpGetWpVersion.php +++ b/tests/phpunit/tests/functions/wpGetWpVersion.php @@ -31,4 +31,33 @@ public function test_should_ignore_changes_to_wp_version_global() { $this->assertSame( $original_wp_version, $actual ); } + + /** + * Tests the `$wp_version` global matches the return value of requiring version.php. + */ + public function test_versions_returned_by_version_php() { + $versions = require ABSPATH . WPINC . '/version.php'; + $this->assertIsArray( $versions, 'Expected requiring version.php to return an array.' ); + + $this->assertEqualSets( + array( + 'wp_version', + 'wp_db_version', + 'tinymce_version', + 'required_php_version', + 'required_php_extensions', + 'required_mysql_version', + ), + array_keys( $versions ), + 'Expected the same keys to be returned in the array when requiring version.php.' + ); + + $this->assertSame( wp_get_wp_version(), $versions['wp_version'], 'Expected global $wp_version to match the "wp_version" key.' ); + $this->assertIsString( $versions['wp_version'], 'Expected type for wp_version.' ); + $this->assertIsInt( $versions['wp_db_version'], 'Expected type for wp_db_version.' ); + $this->assertIsString( $versions['tinymce_version'], 'Expected type for tinymce_version.' ); + $this->assertIsString( $versions['required_php_version'], 'Expected type for required_php_version.' ); + $this->assertIsArray( $versions['required_php_extensions'], 'Expected type for required_php_extensions.' ); + $this->assertIsString( $versions['required_mysql_version'], 'Expected type for required_mysql_version.' ); + } }