From 65ac5c57b7af622c9e965d5ea0b072b64fce83b1 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 3 Apr 2023 10:50:36 -0700 Subject: [PATCH 1/4] Utilize preg_replace_callback() in _wp_normalize_relative_css_links() --- src/wp-includes/script-loader.php | 37 +++++++++++++------------------ 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index e0e01299a097d..dd2583e263bfa 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2941,41 +2941,36 @@ 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 ) { - $has_src_results = preg_match_all( '#url\s*\(\s*[\'"]?\s*([^\'"\)]+)#', $css, $src_results ); - if ( $has_src_results ) { - // Loop through the URLs to find relative ones. - foreach ( $src_results[1] as $src_index => $src_result ) { + return preg_replace_callback( + '#(url\s*\(\s*[\'"]?\s*)([^\'"\)]+)#', + static function ( $matches ) use ( $stylesheet_url ) { + list( $original, $prefix, $url ) = $matches; + // Skip if this is an absolute URL. - if ( 0 === strpos( $src_result, 'http' ) || 0 === strpos( $src_result, '//' ) ) { - continue; + if ( 0 === strpos( $url, 'http' ) || 0 === strpos( $url, '//' ) ) { + return $original; } // Skip if the URL is an HTML ID. - if ( str_starts_with( $src_result, '#' ) ) { - continue; + if ( str_starts_with( $url, '#' ) ) { + return $original; } // Skip if the URL is a data URI. - if ( str_starts_with( $src_result, 'data:' ) ) { - continue; + if ( str_starts_with( $url, 'data:' ) ) { + return $original; } // Build the absolute URL. - $absolute_url = dirname( $stylesheet_url ) . '/' . $src_result; + $absolute_url = dirname( $stylesheet_url ) . '/' . $url; $absolute_url = str_replace( '/./', '/', $absolute_url ); // Convert to URL related to the site root. $relative_url = wp_make_link_relative( $absolute_url ); - // Replace the URL in the CSS. - $css = str_replace( - $src_results[0][ $src_index ], - str_replace( $src_result, $relative_url, $src_results[0][ $src_index ] ), - $css - ); - } - } - - return $css; + return $prefix . $relative_url; + }, + $css + ); } /** From 786c4b6dfa683873f920eb74e0a9b3ac941403bd Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 3 Apr 2023 10:53:50 -0700 Subject: [PATCH 2/4] Utilize str_starts_with() instead of strpos() --- src/wp-includes/script-loader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index dd2583e263bfa..9849e7e0ea992 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2947,7 +2947,7 @@ static function ( $matches ) use ( $stylesheet_url ) { list( $original, $prefix, $url ) = $matches; // Skip if this is an absolute URL. - if ( 0 === strpos( $url, 'http' ) || 0 === strpos( $url, '//' ) ) { + if ( str_starts_with( $url, 'http' ) || str_starts_with( $url, '//' ) ) { return $original; } From 1aa6ff5205c44a1dda415e4645c56b19a841986a Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 3 Apr 2023 10:57:09 -0700 Subject: [PATCH 3/4] Fix case where relative URL path begins with http or https --- src/wp-includes/script-loader.php | 2 +- tests/phpunit/tests/dependencies/styles.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 9849e7e0ea992..9bd65278839c6 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2947,7 +2947,7 @@ static function ( $matches ) use ( $stylesheet_url ) { list( $original, $prefix, $url ) = $matches; // Skip if this is an absolute URL. - if ( str_starts_with( $url, 'http' ) || str_starts_with( $url, '//' ) ) { + if ( str_starts_with( $url, 'http:' ) || str_starts_with( $url, 'https:' ) || str_starts_with( $url, '//' ) ) { return $original; } diff --git a/tests/phpunit/tests/dependencies/styles.php b/tests/phpunit/tests/dependencies/styles.php index 0d2f8e664bf33..e0a13af5e3a19 100644 --- a/tests/phpunit/tests/dependencies/styles.php +++ b/tests/phpunit/tests/dependencies/styles.php @@ -240,6 +240,14 @@ public function data_normalize_relative_css_links() { 'css' => 'img {mask-image: url(\'data:image/svg+xml;utf8,\');}', 'expected' => 'img {mask-image: url(\'data:image/svg+xml;utf8,\');}', ), + 'URLs with path beginning with http' => array( + 'css' => 'p {background:url( "http-is-awesome.png" );}', + 'expected' => 'p {background:url( "/wp-content/themes/test/http-is-awesome.png" );}', + ), + 'URLs with path beginning with https' => array( + 'css' => 'p {background:url( "https-is-more-awesome.png" );}', + 'expected' => 'p {background:url( "/wp-content/themes/test/https-is-more-awesome.png" );}', + ), ); } From 2cf15506d2d6aaf8b4877313560a27d9ed40b9b4 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 3 Apr 2023 11:02:47 -0700 Subject: [PATCH 4/4] Refactor callback to return once --- src/wp-includes/script-loader.php | 42 +++++++++++++++---------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 9bd65278839c6..c18628bc58c6a 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2944,30 +2944,28 @@ function _wp_normalize_relative_css_links( $css, $stylesheet_url ) { return preg_replace_callback( '#(url\s*\(\s*[\'"]?\s*)([^\'"\)]+)#', static function ( $matches ) use ( $stylesheet_url ) { - list( $original, $prefix, $url ) = $matches; - - // Skip if this is an absolute URL. - if ( str_starts_with( $url, 'http:' ) || str_starts_with( $url, 'https:' ) || str_starts_with( $url, '//' ) ) { - return $original; - } - - // Skip if the URL is an HTML ID. - if ( str_starts_with( $url, '#' ) ) { - return $original; + list( , $prefix, $url ) = $matches; + + if ( ! ( + str_starts_with( $url, 'http:' ) + || + str_starts_with( $url, 'https:' ) + || + str_starts_with( $url, '//' ) + || + str_starts_with( $url, '#' ) + || + str_starts_with( $url, 'data:' ) + ) ) { + // Build the absolute URL. + $absolute_url = dirname( $stylesheet_url ) . '/' . $url; + $absolute_url = str_replace( '/./', '/', $absolute_url ); + + // Convert to URL related to the site root. + $url = wp_make_link_relative( $absolute_url ); } - // Skip if the URL is a data URI. - if ( str_starts_with( $url, 'data:' ) ) { - return $original; - } - - // Build the absolute URL. - $absolute_url = dirname( $stylesheet_url ) . '/' . $url; - $absolute_url = str_replace( '/./', '/', $absolute_url ); - // Convert to URL related to the site root. - $relative_url = wp_make_link_relative( $absolute_url ); - - return $prefix . $relative_url; + return $prefix . $url; }, $css );