Make WordPress Core

Changeset 60648


Ignore:
Timestamp:
08/19/2025 06:50:05 PM (3 months ago)
Author:
jonsurrell
Message:

Editor: Ensure preloading middleware JSON is correctly encoded.

Adds the appropriate JSON flags to wp_json_encode() to safely encode data for use in script tags.

Developed in https://github.com/WordPress/wordpress-develop/pull/8145.

Props jonsurrell, bernhard-reiter, dmsnell, artpi, ankitkumarshah, abcd95, dilipbheda, sainathpoojary, shanemuir.
Fixes #62797.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/block-editor.php

    r60003 r60648  
    767767        sprintf(
    768768            'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );',
    769             wp_json_encode( $preload_data )
     769            wp_json_encode( $preload_data, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES )
    770770        ),
    771771        'after'
  • trunk/tests/phpunit/tests/blocks/editor.php

    r59775 r60648  
    1010 */
    1111class Tests_Blocks_Editor extends WP_UnitTestCase {
    12 
    1312    /**
    1413     * Sets up each test method.
     
    632631        $after = implode( '', wp_scripts()->registered['wp-api-fetch']->extra['after'] );
    633632        $this->assertStringContainsString( 'wp.apiFetch.createPreloadingMiddleware', $after );
    634         $this->assertStringContainsString( '"\/wp\/v2\/blocks"', $after );
    635         $this->assertStringContainsString( '"\/wp\/v2\/types"', $after );
     633        $this->assertStringContainsString( '"/wp/v2/blocks"', $after );
     634        $this->assertStringContainsString( '"/wp/v2/types"', $after );
    636635    }
    637636
     
    698697            'a string without a slash'               => array(
    699698                'preload_paths' => array( 'wp/v2/blocks' ),
    700                 'expected'      => '\/wp\/v2\/blocks',
     699                'expected'      => '/wp/v2/blocks',
    701700            ),
    702701            'a string with a slash'                  => array(
    703702                'preload_paths' => array( '/wp/v2/blocks' ),
    704                 'expected'      => '\/wp\/v2\/blocks',
     703                'expected'      => '/wp/v2/blocks',
    705704            ),
    706705            'a string starting with a question mark' => array(
     
    710709            'an array with a string without a slash' => array(
    711710                'preload_paths' => array( array( 'wp/v2/blocks', 'OPTIONS' ) ),
    712                 'expected'      => '\/wp\/v2\/blocks',
     711                'expected'      => '/wp/v2/blocks',
    713712            ),
    714713            'an array with a string with a slash'    => array(
    715714                'preload_paths' => array( array( '/wp/v2/blocks', 'OPTIONS' ) ),
    716                 'expected'      => '\/wp\/v2\/blocks',
     715                'expected'      => '/wp/v2/blocks',
    717716            ),
    718717            'an array with a string starting with a question mark' => array(
    719718                'preload_paths' => array( array( '?context=edit', 'OPTIONS' ) ),
    720                 'expected'      => '\/?context=edit',
    721             ),
    722         );
     719                'expected'      => '/?context=edit',
     720            ),
     721        );
     722    }
     723
     724    /**
     725     * @ticket 62797
     726     *
     727     * @covers ::block_editor_rest_api_preload
     728     *
     729     * Some valid JSON-encoded data is dangerous to embed in HTML without appropriate
     730     * escaping. This test includes an example of data that would prevent the enclosing
     731     * `<script></script>` tag from closing on its apparent closer and remain open.
     732     */
     733    public function test_ensure_preload_data_script_tag_closes() {
     734        add_theme_support( 'html5', array( 'script' ) );
     735        register_rest_route(
     736            'test/v0',
     737            'test-62797',
     738            array(
     739                'methods'             => 'GET',
     740                'callback'            => function () {
     741                    return 'Unclosed comment and a script open tag <!--<script>';
     742                },
     743                'permission_callback' => '__return_true',
     744            )
     745        );
     746
     747        // Prevent a bunch of noisy or unstable data from being included in the test output.
     748        wp_scripts()->registered['wp-api-fetch']->ver            = 'test';
     749        wp_scripts()->registered['wp-api-fetch']->extra['after'] = array();
     750
     751        block_editor_rest_api_preload(
     752            array( '/test/v0/test-62797' ),
     753            new WP_Block_Editor_Context()
     754        );
     755
     756        ob_start();
     757        wp_scripts()->do_item( 'wp-api-fetch' );
     758        $output = ob_get_clean();
     759
     760        $baseurl  = site_url();
     761        $expected = <<<HTML
     762<script src="{$baseurl}/wp-includes/js/dist/api-fetch.min.js?ver=test" id="wp-api-fetch-js"></script>
     763<script id="wp-api-fetch-js-after">
     764wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( {"/test/v0/test-62797":{"body":["Unclosed comment and a script open tag \\u003C!--\\u003Cscript\\u003E"],"headers":{"Allow":"GET"}}} ) );
     765</script>
     766
     767HTML;
     768        $this->assertEqualHTML( $expected, $output );
    723769    }
    724770}
Note: See TracChangeset for help on using the changeset viewer.