Make WordPress Core

Changeset 61947


Ignore:
Timestamp:
03/11/2026 11:38:35 PM (2 months ago)
Author:
adamsilverstein
Message:

Editor: Skip cross-origin isolation for third-party page builders.

Document-Isolation-Policy (DIP) isolates the document and blocks same-origin iframe access that page builders rely on. Skip DIP setup when a third-party page builder overrides the block editor via a custom action query parameter.

Also gates wp_is_client_side_media_processing_enabled() on a secure context check, since SharedArrayBuffer requires a secure context (HTTPS or localhost).

Props adamsilverstein, westonruter, mukesh27, louiswol94, manhar, illuminea.
Fixes #64803.

Location:
trunk
Files:
4 edited

Legend:

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

    r61934 r61947  
    64126412 */
    64136413function wp_is_client_side_media_processing_enabled(): bool {
     6414    // This is due to SharedArrayBuffer requiring a secure context.
     6415    $host    = strtolower( (string) strtok( $_SERVER['HTTP_HOST'] ?? '', ':' ) );
     6416    $enabled = ( is_ssl() || 'localhost' === $host || str_ends_with( $host, '.localhost' ) );
     6417
    64146418    /**
    64156419     * Filters whether client-side media processing is enabled.
     
    64176421     * @since 7.0.0
    64186422     *
    6419      * @param bool $enabled Whether client-side media processing is enabled. Default true.
    6420      */
    6421     return (bool) apply_filters( 'wp_client_side_media_processing_enabled', true );
     6423     * @param bool $enabled Whether client-side media processing is enabled. Default true if the page is served in a secure context.
     6424     */
     6425    return (bool) apply_filters( 'wp_client_side_media_processing_enabled', $enabled );
    64226426}
    64236427
     
    64326436    }
    64336437
    6434     wp_add_inline_script( 'wp-block-editor', 'window.__clientSideMediaProcessing = true', 'before' );
     6438    wp_add_inline_script( 'wp-block-editor', 'window.__clientSideMediaProcessing = true;', 'before' );
    64356439
    64366440    $chromium_version = wp_get_chromium_major_version();
     
    64786482 * on supported browsers (Chromium 137+).
    64796483 *
     6484 * Skips setup when a third-party page builder overrides the block
     6485 * editor via a custom `action` query parameter, as DIP would block
     6486 * same-origin iframe access that these editors rely on.
     6487 *
    64806488 * @since 7.0.0
    64816489 */
     
    64926500
    64936501    if ( ! $screen->is_block_editor() && 'site-editor' !== $screen->id && ! ( 'widgets' === $screen->id && wp_use_widgets_block_editor() ) ) {
     6502        return;
     6503    }
     6504
     6505    /*
     6506     * Skip when a third-party page builder overrides the block editor.
     6507     * DIP isolates the document into its own agent cluster,
     6508     * which blocks same-origin iframe access that these editors rely on.
     6509     */
     6510    if ( isset( $_GET['action'] ) && 'edit' !== $_GET['action'] ) {
    64946511        return;
    64956512    }
  • trunk/tests/phpunit/tests/media/wpCrossOriginIsolation.php

    r61844 r61947  
    77 * @covers ::wp_set_up_cross_origin_isolation
    88 * @covers ::wp_start_cross_origin_isolation_output_buffer
     9 * @covers ::wp_is_client_side_media_processing_enabled
    910 */
    1011class Tests_Media_wpCrossOriginIsolation extends WP_UnitTestCase {
     
    1213    /**
    1314     * Original HTTP_USER_AGENT value.
    14      *
    15      * @var string|null
    16      */
    17     private $original_user_agent;
     15     */
     16    private ?string $original_user_agent;
     17
     18    /**
     19     * Original HTTP_HOST value.
     20     */
     21    private ?string $original_http_host;
     22
     23    /**
     24     * Original HTTPS value.
     25     */
     26    private ?string $original_https;
     27
     28    /**
     29     * Original $_GET['action'] value.
     30     */
     31    private ?string $original_get_action;
    1832
    1933    public function set_up() {
    2034        parent::set_up();
    21         $this->original_user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : null;
     35        $this->original_user_agent = $_SERVER['HTTP_USER_AGENT'] ?? null;
     36        $this->original_http_host  = $_SERVER['HTTP_HOST'] ?? null;
     37        $this->original_https      = $_SERVER['HTTPS'] ?? null;
     38        $this->original_get_action = $_GET['action'] ?? null;
    2239    }
    2340
     
    2946        }
    3047
     48        if ( null === $this->original_http_host ) {
     49            unset( $_SERVER['HTTP_HOST'] );
     50        } else {
     51            $_SERVER['HTTP_HOST'] = $this->original_http_host;
     52        }
     53
     54        if ( null === $this->original_https ) {
     55            unset( $_SERVER['HTTPS'] );
     56        } else {
     57            $_SERVER['HTTPS'] = $this->original_https;
     58        }
     59
     60        if ( null === $this->original_get_action ) {
     61            unset( $_GET['action'] );
     62        } else {
     63            $_GET['action'] = $this->original_get_action;
     64        }
     65
    3166        // Clean up any output buffers started during tests.
    3267        while ( ob_get_level() > 1 ) {
     
    126161
    127162    /**
     163     * @ticket 64803
     164     */
     165    public function test_client_side_processing_disabled_on_non_secure_origin() {
     166        $_SERVER['HTTP_HOST'] = 'example.com';
     167        $_SERVER['HTTPS']     = '';
     168
     169        $this->assertFalse(
     170            wp_is_client_side_media_processing_enabled(),
     171            'Client-side media processing should be disabled on non-secure, non-localhost origins.'
     172        );
     173    }
     174
     175    /**
     176     * @ticket 64803
     177     */
     178    public function test_client_side_processing_enabled_on_localhost() {
     179        $_SERVER['HTTP_HOST'] = 'localhost';
     180        $_SERVER['HTTPS']     = '';
     181
     182        $this->assertTrue(
     183            wp_is_client_side_media_processing_enabled(),
     184            'Client-side media processing should be enabled on localhost.'
     185        );
     186    }
     187
     188    /**
    128189     * This test must run in a separate process because the output buffer
    129190     * callback sends HTTP headers via header(), which would fail in the
  • trunk/tests/phpunit/tests/rest-api/rest-attachments-controller.php

    r61809 r61947  
    31633163     */
    31643164    public function test_sideload_scaled_image() {
     3165        add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
     3166        // Reinitialize REST server so the sideload route is registered.
     3167        global $wp_rest_server;
     3168        $wp_rest_server = new Spy_REST_Server();
     3169        do_action( 'rest_api_init', $wp_rest_server );
     3170
    31653171        wp_set_current_user( self::$author_id );
    31663172
     
    32163222     */
    32173223    public function test_sideload_scaled_image_requires_auth() {
     3224        add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
     3225        // Reinitialize REST server so the sideload route is registered.
     3226        global $wp_rest_server;
     3227        $wp_rest_server = new Spy_REST_Server();
     3228        do_action( 'rest_api_init', $wp_rest_server );
     3229
    32183230        wp_set_current_user( self::$author_id );
    32193231
     
    32453257     */
    32463258    public function test_sideload_route_includes_scaled_enum() {
     3259        add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
     3260        // Reinitialize REST server so the sideload route is registered.
     3261        global $wp_rest_server;
     3262        $wp_rest_server = new Spy_REST_Server();
     3263        do_action( 'rest_api_init', $wp_rest_server );
     3264
    32473265        $server = rest_get_server();
    32483266        $routes = $server->get_routes();
     
    32673285     */
    32683286    public function test_sideload_scaled_unique_filename() {
     3287        add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
     3288        // Reinitialize REST server so the sideload route is registered.
     3289        global $wp_rest_server;
     3290        $wp_rest_server = new Spy_REST_Server();
     3291        do_action( 'rest_api_init', $wp_rest_server );
     3292
    32693293        wp_set_current_user( self::$author_id );
    32703294
     
    33013325     */
    33023326    public function test_sideload_scaled_unique_filename_conflict() {
     3327        add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
     3328        // Reinitialize REST server so the sideload route is registered.
     3329        global $wp_rest_server;
     3330        $wp_rest_server = new Spy_REST_Server();
     3331        do_action( 'rest_api_init', $wp_rest_server );
     3332
    33033333        wp_set_current_user( self::$author_id );
    33043334
  • trunk/tests/phpunit/tests/rest-api/rest-schema-setup.php

    r61703 r61947  
    1616    public function set_up() {
    1717        parent::set_up();
     18
     19        // Ensure client-side media processing is enabled so the sideload route is registered.
     20        add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
    1821
    1922        /** @var WP_REST_Server $wp_rest_server */
Note: See TracChangeset for help on using the changeset viewer.