Make WordPress Core

Changeset 52036


Ignore:
Timestamp:
11/08/2021 01:23:44 PM (3 years ago)
Author:
gziolo
Message:

Fix relative URLs in inlined block styles that involve external assets

When styles got inlined, relative URLs break. The problem was that URLs inside CSS files are relative to the stylesheet's path, and when styles get inlined that relation is lost. This patch fixes the issue by finding relative URLs which then get modified to be relative to the site's root.

Fixes #54243.
Props aristath, cdyerkes, hellofromtonya.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/script-loader.php

    r52032 r52036  
    27022702            $styles[] = array(
    27032703                'handle' => $handle,
     2704                'src'    => $wp_styles->registered[ $handle ]->src,
    27042705                'path'   => $wp_styles->registered[ $handle ]->extra['path'],
    27052706                'size'   => filesize( $wp_styles->registered[ $handle ]->extra['path'] ),
     
    27362737            $style['css'] = file_get_contents( $style['path'] );
    27372738
     2739            // Check if the style contains relative URLs that need to be modified.
     2740            // URLs relative to the stylesheet's path should be converted to relative to the site's root.
     2741            $style['css'] = _wp_normalize_relative_css_links( $style['css'], $style['src'] );
     2742
    27382743            // Set `src` to `false` and add styles inline.
    27392744            $wp_styles->registered[ $style['handle'] ]->src = false;
     
    27502755
    27512756/**
     2757 * Make URLs relative to the WordPress installation.
     2758 *
     2759 * @since 5.9.0
     2760 * @access private
     2761 *
     2762 * @param string $css            The CSS to make URLs relative to the WordPress installation.
     2763 * @param string $stylesheet_url The URL to the stylesheet.
     2764 *
     2765 * @return string The CSS with URLs made relative to the WordPress installation.
     2766 */
     2767function _wp_normalize_relative_css_links( $css, $stylesheet_url ) {
     2768    $has_src_results = preg_match_all( '#url\s*\(\s*[\'"]?\s*([^\'"\)]+)#', $css, $src_results );
     2769    if ( $has_src_results ) {
     2770        // Loop through the URLs to find relative ones.
     2771        foreach ( $src_results[1] as $src_index => $src_result ) {
     2772            // Skip if this is an absolute URL.
     2773            if ( 0 === strpos( $src_result, 'http' ) || 0 === strpos( $src_result, '//' ) ) {
     2774                continue;
     2775            }
     2776
     2777            // Build the absolute URL.
     2778            $absolute_url = dirname( $stylesheet_url ) . '/' . $src_result;
     2779            $absolute_url = str_replace( '/./', '/', $absolute_url );
     2780            // Convert to URL related to the site root.
     2781            $relative_url = wp_make_link_relative( $absolute_url );
     2782
     2783            // Replace the URL in the CSS.
     2784            $css = str_replace(
     2785                $src_results[0][ $src_index ],
     2786                str_replace( $src_result, $relative_url, $src_results[0][ $src_index ] ),
     2787                $css
     2788            );
     2789        }
     2790    }
     2791
     2792    return $css;
     2793}
     2794
     2795/**
    27522796 * Inject the block editor assets that need to be loaded into the editor's iframe as an inline script.
    27532797 *
  • trunk/tests/phpunit/tests/dependencies/styles.php

    r52010 r52036  
    191191
    192192    /**
     193     * Test normalizing relative links in CSS.
     194     *
     195     * @dataProvider data_normalize_relative_css_links
     196     *
     197     * @ticket 54243
     198     *
     199     * @covers ::_wp_normalize_relative_css_links
     200     *
     201     * @param string $css      Given CSS to test.
     202     * @param string $expected Expected result.
     203     */
     204    public function test_normalize_relative_css_links( $css, $expected ) {
     205        $this->assertSame(
     206            $expected,
     207            _wp_normalize_relative_css_links( $css, site_url( 'wp-content/themes/test/style.css' ) )
     208        );
     209    }
     210
     211    /**
     212     * Data provider.
     213     *
     214     * @return array
     215     */
     216    public function data_normalize_relative_css_links() {
     217        return array(
     218            'Double quotes, same path'                     => array(
     219                'css'      => 'p {background:url( "image0.svg" );}',
     220                'expected' => 'p {background:url( "/wp-content/themes/test/image0.svg" );}',
     221            ),
     222            'Single quotes, same path, prefixed with "./"' => array(
     223                'css'      => 'p {background-image: url(\'./image2.png\');}',
     224                'expected' => 'p {background-image: url(\'/wp-content/themes/test/image2.png\');}',
     225            ),
     226            'Single quotes, one level up, prefixed with "../"' => array(
     227                'css'      => 'p {background-image: url(\'../image1.jpg\');}',
     228                'expected' => 'p {background-image: url(\'/wp-content/themes/test/../image1.jpg\');}',
     229            ),
     230            'External URLs, shouldn\'t change'             => array(
     231                'css'      => 'p {background-image: url(\'http://foo.com/image2.png\');}',
     232                'expected' => 'p {background-image: url(\'http://foo.com/image2.png\');}',
     233            ),
     234        );
     235    }
     236
     237    /**
    193238     * Test if multiple inline styles work
    194239     *
Note: See TracChangeset for help on using the changeset viewer.