Make WordPress Core

Changeset 57662


Ignore:
Timestamp:
02/20/2024 09:53:11 AM (12 months ago)
Author:
youknowriad
Message:

Tests: Synchronize Theme.JSON unit test between Core and Gutenberg.

Merges the changes from Core and Gutenberg for the following tests:

  • WP_REST_Global_Styles_Controller_Test
  • Tests_Theme_wpThemeJsonResolver
  • Tests_Theme_wpThemeJsonSchema
  • Tests_Theme_wpThemeJson

This will help ensure the stability of the theme.json style generation.

Props ajlende, scruffian, aaronrobertshaw, get_dave, youknowriad.
Fixes #60387.

Location:
trunk/tests/phpunit
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/data/themedir1/block-theme-child/theme.json

    r57336 r57662  
    11{
    22    "$schema": "https://schemas.wp.org/trunk/theme.json",
    3     "version": 1,
     3    "version": 2,
    44    "settings": {
    55        "color": {
  • trunk/tests/phpunit/data/themedir1/block-theme/theme.json

    r57336 r57662  
    11{
    22    "$schema": "https://schemas.wp.org/trunk/theme.json",
    3     "version": 1,
     3    "version": 2,
    44    "title": "Block theme",
    55    "settings": {
     
    4343            ],
    4444            "customFontSize": false,
    45             "customLineHeight": true
     45            "lineHeight": true
    4646        },
    4747        "spacing": {
    48             "units": ["rem"],
    49             "customPadding": true,
     48            "units": [ "rem" ],
     49            "padding": true,
    5050            "blockGap": true
    5151        },
     
    6464        }
    6565    },
    66     "styles" : {
    67         "blocks" :{
     66    "styles": {
     67        "blocks": {
    6868            "core/post-featured-image": {
    6969                "shadow": "10px 10px 5px 0px rgba(0,0,0,0.66)",
     
    123123            "name": "custom-single-post-template",
    124124            "title": "Custom Single Post template",
    125             "postTypes": ["post"]
     125            "postTypes": [ "post" ]
    126126        }
    127127    ],
  • trunk/tests/phpunit/tests/rest-api/rest-global-styles-controller.php

    r55457 r57662  
    3232    protected static $post_id;
    3333
    34     private function find_and_normalize_global_styles_by_id( $global_styles, $id ) {
    35         foreach ( $global_styles as $style ) {
    36             if ( $style['id'] === $id ) {
    37                 unset( $style['_links'] );
    38                 return $style;
    39             }
    40         }
    41 
    42         return null;
    43     }
    44 
    4534    public function set_up() {
    4635        parent::set_up();
     
    131120    }
    132121
    133     /**
    134      * @doesNotPerformAssertions
    135      */
    136     public function test_get_items() {
    137         // Controller does not implement get_items().
    138     }
    139 
    140     /**
    141      * @covers WP_REST_Global_Styles_Controller::get_theme_item
    142      * @ticket 54516
    143      */
    144     public function test_get_theme_item_no_user() {
    145         wp_set_current_user( 0 );
    146         $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/tt1-blocks' );
    147         $response = rest_get_server()->dispatch( $request );
    148         $this->assertErrorResponse( 'rest_cannot_manage_global_styles', $response, 401 );
    149     }
    150 
    151     /**
    152      * @covers WP_REST_Global_Styles_Controller::get_theme_item
    153      * @ticket 54516
    154      */
    155     public function test_get_theme_item_permission_check() {
    156         wp_set_current_user( self::$subscriber_id );
    157         $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/tt1-blocks' );
    158         $response = rest_get_server()->dispatch( $request );
    159         $this->assertErrorResponse( 'rest_cannot_manage_global_styles', $response, 403 );
    160     }
    161 
    162     /**
    163      * @covers WP_REST_Global_Styles_Controller::get_theme_item
    164      * @ticket 54516
    165      */
    166     public function test_get_theme_item_invalid() {
    167         wp_set_current_user( self::$admin_id );
    168         $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/invalid' );
    169         $response = rest_get_server()->dispatch( $request );
    170         $this->assertErrorResponse( 'rest_theme_not_found', $response, 404 );
    171     }
    172 
    173     /**
    174      * @dataProvider data_get_theme_item_invalid_theme_dirname
    175      * @covers WP_REST_Global_Styles_Controller::get_theme_item
    176      * @ticket 54596
    177      *
    178      * @param string $theme_dirname Theme directory to test.
    179      * @param string $expected      Expected error code.
    180      */
    181     public function test_get_theme_item_invalid_theme_dirname( $theme_dirname, $expected ) {
    182         wp_set_current_user( self::$admin_id );
    183         switch_theme( $theme_dirname );
    184 
    185         $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/' . $theme_dirname );
    186         $response = rest_get_server()->dispatch( $request );
    187         $this->assertErrorResponse( $expected, $response, 404 );
    188     }
    189 
    190     /**
    191      * Data provider.
    192      *
    193      * @return array
    194      */
    195     public function data_get_theme_item_invalid_theme_dirname() {
    196         return array(
    197             '+'                      => array(
    198                 'theme_dirname' => 'my+theme+',
    199                 'expected'      => 'rest_theme_not_found',
    200             ),
    201             ':'                      => array(
    202                 'theme_dirname' => 'my:theme:',
    203                 'expected'      => 'rest_no_route',
    204             ),
    205             '<>'                     => array(
    206                 'theme_dirname' => 'my<theme>',
    207                 'expected'      => 'rest_no_route',
    208             ),
    209             '*'                      => array(
    210                 'theme_dirname' => 'my*theme*',
    211                 'expected'      => 'rest_no_route',
    212             ),
    213             '?'                      => array(
    214                 'theme_dirname' => 'my?theme?',
    215                 'expected'      => 'rest_no_route',
    216             ),
    217             '"'                      => array(
    218                 'theme_dirname' => 'my"theme?"',
    219                 'expected'      => 'rest_no_route',
    220             ),
    221             '| (invalid on Windows)' => array(
    222                 'theme_dirname' => 'my|theme|',
    223                 'expected'      => 'rest_no_route',
    224             ),
    225             // Themes deep in subdirectories.
    226             '2 subdirectories deep'  => array(
    227                 'theme_dirname' => 'subdir/subsubdir/mytheme',
    228                 'expected'      => 'rest_global_styles_not_found',
    229             ),
    230         );
    231     }
    232 
    233     /**
    234      * @dataProvider data_get_theme_item
    235      * @covers WP_REST_Global_Styles_Controller::get_theme_item
    236      * @ticket 54596
    237      *
    238      * @param string $theme Theme directory to test.
    239      */
    240     public function test_get_theme_item( $theme ) {
    241         wp_set_current_user( self::$admin_id );
    242         switch_theme( $theme );
    243 
    244         $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/' . $theme );
    245         $response = rest_get_server()->dispatch( $request );
    246         $data     = $response->get_data();
    247         $links    = $response->get_links();
    248         $this->assertArrayHasKey( 'settings', $data, 'Data does not have "settings" key' );
    249         $this->assertArrayHasKey( 'styles', $data, 'Data does not have "styles" key' );
    250         $this->assertArrayHasKey( 'self', $links, 'Links do not have a "self" key' );
    251         $this->assertStringContainsString( '/wp/v2/global-styles/themes/' . $theme, $links['self'][0]['href'] );
    252     }
    253 
    254     /**
    255      * Data provider.
    256      *
    257      * @return array
    258      */
    259     public function data_get_theme_item() {
    260         return array(
    261             'alphabetic'                     => array( 'mytheme' ),
    262             'alphanumeric'                   => array( 'mythemev1' ),
    263             'àáâãäåæç'                       => array( 'àáâãäåæç' ),
    264             'space'                          => array( 'my theme' ),
    265             '-_.'                            => array( 'my_theme-0.1' ),
    266             '[]'                             => array( 'my[theme]' ),
    267             '()'                             => array( 'my(theme)' ),
    268             '{}'                             => array( 'my{theme}' ),
    269             '&=#@!$,^~%'                     => array( 'theme &=#@!$,^~%' ),
    270             'all combined'                   => array( 'thémé {}&=@!$,^~%[0.1](-_-)' ),
    271 
    272             // Themes in a subdirectory.
    273             'subdir: alphabetic'             => array( 'subdir/mytheme' ),
    274             'subdir: alphanumeric in theme'  => array( 'subdir/mythemev1' ),
    275             'subdir: alphanumeric in subdir' => array( 'subdirv1/mytheme' ),
    276             'subdir: alphanumeric in both'   => array( 'subdirv1/mythemev1' ),
    277             'subdir: àáâãäåæç in theme'      => array( 'subdir/àáâãäåæç' ),
    278             'subdir: àáâãäåæç in subdir'     => array( 'àáâãäåæç/mythemev1' ),
    279             'subdir: àáâãäåæç in both'       => array( 'àáâãäåæç/àáâãäåæç' ),
    280             'subdir: space in theme'         => array( 'subdir/my theme' ),
    281             'subdir: space in subdir'        => array( 'sub dir/mytheme' ),
    282             'subdir: space in both'          => array( 'sub dir/my theme' ),
    283             'subdir: -_. in theme'           => array( 'subdir/my_theme-0.1' ),
    284             'subdir: -_. in subdir'          => array( 'sub_dir-0.1/mytheme' ),
    285             'subdir: -_. in both'            => array( 'sub_dir-0.1/my_theme-0.1' ),
    286             'subdir: all combined in theme'  => array( 'subdir/thémé {}&=@!$,^~%[0.1](-_-)' ),
    287             'subdir: all combined in subdir' => array( 'sűbdīr {}&=@!$,^~%[0.1](-_-)/mytheme' ),
    288             'subdir: all combined in both'   => array( 'sűbdīr {}&=@!$,^~%[0.1](-_-)/thémé {}&=@!$,^~%[0.1](-_-)' ),
    289         );
    290     }
    291 
    292     /**
    293      * @covers WP_REST_Global_Styles_Controller::get_theme_item
    294      * @ticket 54595
    295      */
    296     public function test_get_theme_item_fields() {
    297         wp_set_current_user( self::$admin_id );
    298         $request = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/tt1-blocks' );
    299         $request->set_param( '_fields', 'settings' );
    300         $response = rest_get_server()->dispatch( $request );
    301         $data     = $response->get_data();
    302         $this->assertArrayHasKey( 'settings', $data );
    303         $this->assertArrayNotHasKey( 'styles', $data );
    304     }
    305 
    306     /**
    307      * @covers WP_REST_Global_Styles_Controller::get_item
    308      * @ticket 54516
    309      */
    310     public function test_get_item_no_user() {
    311         wp_set_current_user( 0 );
    312         $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$global_styles_id );
    313         $response = rest_get_server()->dispatch( $request );
    314         $this->assertErrorResponse( 'rest_cannot_view', $response, 401 );
    315     }
    316 
    317     /**
    318      * @covers WP_REST_Global_Styles_Controller::get_item
    319      * @ticket 54516
    320      */
    321     public function test_get_item_invalid_post() {
    322         wp_set_current_user( self::$admin_id );
    323         $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$post_id );
    324         $response = rest_get_server()->dispatch( $request );
    325         $this->assertErrorResponse( 'rest_global_styles_not_found', $response, 404 );
    326     }
    327 
    328     /**
    329      * @covers WP_REST_Global_Styles_Controller::get_item
    330      * @ticket 54516
    331      */
    332     public function test_get_item_permission_check() {
    333         wp_set_current_user( self::$subscriber_id );
    334         $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$global_styles_id );
    335         $response = rest_get_server()->dispatch( $request );
    336         $this->assertErrorResponse( 'rest_cannot_view', $response, 403 );
    337     }
    338 
    339     /**
    340      * @covers WP_REST_Global_Styles_Controller::get_item
    341      * @ticket 54516
    342      */
    343     public function test_get_item_no_user_edit() {
    344         wp_set_current_user( 0 );
    345         $request = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$global_styles_id );
    346         $request->set_param( 'context', 'edit' );
    347         $response = rest_get_server()->dispatch( $request );
    348         $this->assertErrorResponse( 'rest_forbidden_context', $response, 401 );
    349     }
    350 
    351     /**
    352      * @covers WP_REST_Global_Styles_Controller::get_item
    353      * @ticket 54516
    354      */
    355     public function test_get_item_permission_check_edit() {
    356         wp_set_current_user( self::$subscriber_id );
    357         $request = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$global_styles_id );
    358         $request->set_param( 'context', 'edit' );
    359         $response = rest_get_server()->dispatch( $request );
    360         $this->assertErrorResponse( 'rest_forbidden_context', $response, 403 );
    361     }
    362 
    363     /**
    364      * @covers WP_REST_Global_Styles_Controller::get_item
    365      */
    366     public function test_get_item() {
    367         wp_set_current_user( self::$admin_id );
    368         $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$global_styles_id );
    369         $response = rest_get_server()->dispatch( $request );
    370         $data     = $response->get_data();
    371         $links    = $response->get_links();
    372 
    373         $this->assertEqualSets(
    374             array(
    375                 'id'       => self::$global_styles_id,
    376                 'title'    => array(
    377                     'raw'      => 'Custom Styles',
    378                     'rendered' => 'Custom Styles',
    379                 ),
    380                 'settings' => new stdClass(),
    381                 'styles'   => new stdClass(),
    382             ),
    383             $data
    384         );
    385 
    386         $this->assertArrayHasKey( 'self', $links );
    387         $this->assertStringContainsString( '/wp/v2/global-styles/' . self::$global_styles_id, $links['self'][0]['href'] );
    388     }
    389 
    390     /**
    391      * @doesNotPerformAssertions
    392      */
    393     public function test_create_item() {
    394         // Controller does not implement create_item().
    395     }
    396 
    397     /**
    398      * @covers WP_REST_Global_Styles_Controller::update_item
    399      * @ticket 54516
    400      */
    401     public function test_update_item() {
    402         wp_set_current_user( self::$admin_id );
    403         $request = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
    404         $request->set_body_params(
    405             array(
    406                 'title' => 'My new global styles title',
    407             )
    408         );
    409         $response = rest_get_server()->dispatch( $request );
    410         $data     = $response->get_data();
    411         $this->assertSame( 'My new global styles title', $data['title']['raw'] );
    412     }
    413 
    414 
    415     /**
    416      * @covers WP_REST_Global_Styles_Controller::update_item
    417      * @ticket 54516
    418      */
    419     public function test_update_item_no_user() {
    420         wp_set_current_user( 0 );
    421         $request  = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
    422         $response = rest_get_server()->dispatch( $request );
    423         $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 );
    424     }
    425 
    426     /**
    427      * @covers WP_REST_Global_Styles_Controller::update_item
    428      * @ticket 54516
    429      */
    430     public function test_update_item_invalid_post() {
    431         wp_set_current_user( self::$admin_id );
    432         $request  = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$post_id );
    433         $response = rest_get_server()->dispatch( $request );
    434         $this->assertErrorResponse( 'rest_global_styles_not_found', $response, 404 );
    435     }
    436 
    437     /**
    438      * @covers WP_REST_Global_Styles_Controller::update_item
    439      * @ticket 54516
    440      */
    441     public function test_update_item_permission_check() {
    442         wp_set_current_user( self::$subscriber_id );
    443         $request  = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
    444         $response = rest_get_server()->dispatch( $request );
    445         $this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
    446     }
    447 
    448     /**
    449      * @doesNotPerformAssertions
    450      */
    451     public function test_delete_item() {
    452         // Controller does not implement delete_item().
    453     }
    454 
    455     /**
    456      * @doesNotPerformAssertions
    457      */
    458     public function test_prepare_item() {
    459         // Controller does not implement prepare_item().
    460     }
    461 
    462     /**
    463      * @covers WP_REST_Global_Styles_Controller::get_item_schema
    464      * @ticket 54516
    465      */
    466     public function test_get_item_schema() {
    467         $request    = new WP_REST_Request( 'OPTIONS', '/wp/v2/global-styles/' . self::$global_styles_id );
    468         $response   = rest_get_server()->dispatch( $request );
    469         $data       = $response->get_data();
    470         $properties = $data['schema']['properties'];
    471         $this->assertCount( 4, $properties, 'Schema properties array does not have exactly 4 elements' );
    472         $this->assertArrayHasKey( 'id', $properties, 'Schema properties array does not have "id" key' );
    473         $this->assertArrayHasKey( 'styles', $properties, 'Schema properties array does not have "styles" key' );
    474         $this->assertArrayHasKey( 'settings', $properties, 'Schema properties array does not have "settings" key' );
    475         $this->assertArrayHasKey( 'title', $properties, 'Schema properties array does not have "title" key' );
    476     }
    477 
    478 
    479122    public function test_get_theme_items() {
    480123        wp_set_current_user( self::$admin_id );
     
    484127        $data     = $response->get_data();
    485128        $expected = array(
     129            array(
     130                'version'  => 2,
     131                'title'    => 'variation-a',
     132                'settings' => array(
     133                    'blocks' => array(
     134                        'core/paragraph' => array(
     135                            'color' => array(
     136                                'palette' => array(
     137                                    'theme' => array(
     138                                        array(
     139                                            'slug'  => 'light',
     140                                            'name'  => 'Light',
     141                                            'color' => '#f2f2f2',
     142                                        ),
     143                                    ),
     144                                ),
     145                            ),
     146                        ),
     147                    ),
     148                ),
     149            ),
    486150            array(
    487151                'version'  => 2,
     
    536200        wp_recursive_ksort( $expected );
    537201
    538         $this->assertSameSets( $data, $expected );
     202        $this->assertSameSets( $expected, $data );
     203    }
     204
     205    /**
     206     * @doesNotPerformAssertions
     207     */
     208    public function test_get_items() {
     209        // Controller does not implement get_items().
     210    }
     211
     212    /**
     213     * @covers WP_REST_Global_Styles_Controller::get_theme_item
     214     * @ticket 54516
     215     */
     216    public function test_get_theme_item_no_user() {
     217        wp_set_current_user( 0 );
     218        $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/tt1-blocks' );
     219        $response = rest_get_server()->dispatch( $request );
     220        $this->assertErrorResponse( 'rest_cannot_manage_global_styles', $response, 401 );
     221    }
     222
     223    /**
     224     * @covers WP_REST_Global_Styles_Controller::get_theme_item
     225     * @ticket 54516
     226     */
     227    public function test_get_theme_item_permission_check() {
     228        wp_set_current_user( self::$subscriber_id );
     229        $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/tt1-blocks' );
     230        $response = rest_get_server()->dispatch( $request );
     231        $this->assertErrorResponse( 'rest_cannot_manage_global_styles', $response, 403 );
     232    }
     233
     234    /**
     235     * @covers WP_REST_Global_Styles_Controller::get_theme_item
     236     * @ticket 54516
     237     */
     238    public function test_get_theme_item_invalid() {
     239        wp_set_current_user( self::$admin_id );
     240        $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/invalid' );
     241        $response = rest_get_server()->dispatch( $request );
     242        $this->assertErrorResponse( 'rest_theme_not_found', $response, 404 );
     243    }
     244
     245    /**
     246     * @dataProvider data_get_theme_item_invalid_theme_dirname
     247     * @covers WP_REST_Global_Styles_Controller::get_theme_item
     248     * @ticket 54596
     249     *
     250     * @param string $theme_dirname Theme directory to test.
     251     * @param string $expected      Expected error code.
     252     */
     253    public function test_get_theme_item_invalid_theme_dirname( $theme_dirname, $expected ) {
     254        wp_set_current_user( self::$admin_id );
     255        switch_theme( $theme_dirname );
     256
     257        $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/' . $theme_dirname );
     258        $response = rest_get_server()->dispatch( $request );
     259        $this->assertErrorResponse( $expected, $response, 404 );
     260    }
     261
     262    /**
     263     * Data provider.
     264     *
     265     * @return array
     266     */
     267    public function data_get_theme_item_invalid_theme_dirname() {
     268        return array(
     269            '+'                      => array(
     270                'theme_dirname' => 'my+theme+',
     271                'expected'      => 'rest_theme_not_found',
     272            ),
     273            ':'                      => array(
     274                'theme_dirname' => 'my:theme:',
     275                'expected'      => 'rest_no_route',
     276            ),
     277            '<>'                     => array(
     278                'theme_dirname' => 'my<theme>',
     279                'expected'      => 'rest_no_route',
     280            ),
     281            '*'                      => array(
     282                'theme_dirname' => 'my*theme*',
     283                'expected'      => 'rest_no_route',
     284            ),
     285            '?'                      => array(
     286                'theme_dirname' => 'my?theme?',
     287                'expected'      => 'rest_no_route',
     288            ),
     289            '"'                      => array(
     290                'theme_dirname' => 'my"theme?"',
     291                'expected'      => 'rest_no_route',
     292            ),
     293            '| (invalid on Windows)' => array(
     294                'theme_dirname' => 'my|theme|',
     295                'expected'      => 'rest_no_route',
     296            ),
     297            // Themes deep in subdirectories.
     298            '2 subdirectories deep'  => array(
     299                'theme_dirname' => 'subdir/subsubdir/mytheme',
     300                'expected'      => 'rest_global_styles_not_found',
     301            ),
     302        );
     303    }
     304
     305    /**
     306     * @dataProvider data_get_theme_item
     307     * @covers WP_REST_Global_Styles_Controller::get_theme_item
     308     * @ticket 54596
     309     *
     310     * @param string $theme Theme directory to test.
     311     */
     312    public function test_get_theme_item( $theme ) {
     313        wp_set_current_user( self::$admin_id );
     314        switch_theme( $theme );
     315
     316        $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/' . $theme );
     317        $response = rest_get_server()->dispatch( $request );
     318        $data     = $response->get_data();
     319        $links    = $response->get_links();
     320        $this->assertArrayHasKey( 'settings', $data, 'Data does not have "settings" key' );
     321        $this->assertArrayHasKey( 'styles', $data, 'Data does not have "styles" key' );
     322        $this->assertArrayHasKey( 'self', $links, 'Links do not have a "self" key' );
     323        $this->assertStringContainsString( '/wp/v2/global-styles/themes/' . $theme, $links['self'][0]['href'] );
     324    }
     325
     326    /**
     327     * Data provider.
     328     *
     329     * @return array
     330     */
     331    public function data_get_theme_item() {
     332        return array(
     333            'alphabetic'                     => array( 'mytheme' ),
     334            'alphanumeric'                   => array( 'mythemev1' ),
     335            'àáâãäåæç'                       => array( 'àáâãäåæç' ),
     336            'space'                          => array( 'my theme' ),
     337            '-_.'                            => array( 'my_theme-0.1' ),
     338            '[]'                             => array( 'my[theme]' ),
     339            '()'                             => array( 'my(theme)' ),
     340            '{}'                             => array( 'my{theme}' ),
     341            '&=#@!$,^~%'                     => array( 'theme &=#@!$,^~%' ),
     342            'all combined'                   => array( 'thémé {}&=@!$,^~%[0.1](-_-)' ),
     343
     344            // Themes in a subdirectory.
     345            'subdir: alphabetic'             => array( 'subdir/mytheme' ),
     346            'subdir: alphanumeric in theme'  => array( 'subdir/mythemev1' ),
     347            'subdir: alphanumeric in subdir' => array( 'subdirv1/mytheme' ),
     348            'subdir: alphanumeric in both'   => array( 'subdirv1/mythemev1' ),
     349            'subdir: àáâãäåæç in theme'      => array( 'subdir/àáâãäåæç' ),
     350            'subdir: àáâãäåæç in subdir'     => array( 'àáâãäåæç/mythemev1' ),
     351            'subdir: àáâãäåæç in both'       => array( 'àáâãäåæç/àáâãäåæç' ),
     352            'subdir: space in theme'         => array( 'subdir/my theme' ),
     353            'subdir: space in subdir'        => array( 'sub dir/mytheme' ),
     354            'subdir: space in both'          => array( 'sub dir/my theme' ),
     355            'subdir: -_. in theme'           => array( 'subdir/my_theme-0.1' ),
     356            'subdir: -_. in subdir'          => array( 'sub_dir-0.1/mytheme' ),
     357            'subdir: -_. in both'            => array( 'sub_dir-0.1/my_theme-0.1' ),
     358            'subdir: all combined in theme'  => array( 'subdir/thémé {}&=@!$,^~%[0.1](-_-)' ),
     359            'subdir: all combined in subdir' => array( 'sűbdīr {}&=@!$,^~%[0.1](-_-)/mytheme' ),
     360            'subdir: all combined in both'   => array( 'sűbdīr {}&=@!$,^~%[0.1](-_-)/thémé {}&=@!$,^~%[0.1](-_-)' ),
     361        );
     362    }
     363
     364    /**
     365     * @covers WP_REST_Global_Styles_Controller::get_theme_item
     366     * @ticket 54595
     367     */
     368    public function test_get_theme_item_fields() {
     369        wp_set_current_user( self::$admin_id );
     370        $request = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/tt1-blocks' );
     371        $request->set_param( '_fields', 'settings' );
     372        $response = rest_get_server()->dispatch( $request );
     373        $data     = $response->get_data();
     374        $this->assertArrayHasKey( 'settings', $data );
     375        $this->assertArrayNotHasKey( 'styles', $data );
     376    }
     377
     378    /**
     379     * @covers WP_REST_Global_Styles_Controller::get_item
     380     * @ticket 54516
     381     */
     382    public function test_get_item_no_user() {
     383        wp_set_current_user( 0 );
     384        $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$global_styles_id );
     385        $response = rest_get_server()->dispatch( $request );
     386        $this->assertErrorResponse( 'rest_cannot_view', $response, 401 );
     387    }
     388
     389    /**
     390     * @covers WP_REST_Global_Styles_Controller::get_item
     391     * @ticket 54516
     392     */
     393    public function test_get_item_invalid_post() {
     394        wp_set_current_user( self::$admin_id );
     395        $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$post_id );
     396        $response = rest_get_server()->dispatch( $request );
     397        $this->assertErrorResponse( 'rest_global_styles_not_found', $response, 404 );
     398    }
     399
     400    /**
     401     * @covers WP_REST_Global_Styles_Controller::get_item
     402     * @ticket 54516
     403     */
     404    public function test_get_item_permission_check() {
     405        wp_set_current_user( self::$subscriber_id );
     406        $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$global_styles_id );
     407        $response = rest_get_server()->dispatch( $request );
     408        $this->assertErrorResponse( 'rest_cannot_view', $response, 403 );
     409    }
     410
     411    /**
     412     * @covers WP_REST_Global_Styles_Controller::get_item
     413     * @ticket 54516
     414     */
     415    public function test_get_item_no_user_edit() {
     416        wp_set_current_user( 0 );
     417        $request = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$global_styles_id );
     418        $request->set_param( 'context', 'edit' );
     419        $response = rest_get_server()->dispatch( $request );
     420        $this->assertErrorResponse( 'rest_forbidden_context', $response, 401 );
     421    }
     422
     423    /**
     424     * @covers WP_REST_Global_Styles_Controller::get_item
     425     * @ticket 54516
     426     */
     427    public function test_get_item_permission_check_edit() {
     428        wp_set_current_user( self::$subscriber_id );
     429        $request = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$global_styles_id );
     430        $request->set_param( 'context', 'edit' );
     431        $response = rest_get_server()->dispatch( $request );
     432        $this->assertErrorResponse( 'rest_forbidden_context', $response, 403 );
     433    }
     434
     435    /**
     436     * @covers WP_REST_Global_Styles_Controller::get_item
     437     */
     438    public function test_get_item() {
     439        wp_set_current_user( self::$admin_id );
     440        $request  = new WP_REST_Request( 'GET', '/wp/v2/global-styles/' . self::$global_styles_id );
     441        $response = rest_get_server()->dispatch( $request );
     442        $data     = $response->get_data();
     443        $links    = $response->get_links();
     444
     445        $this->assertEqualSets(
     446            array(
     447                'id'       => self::$global_styles_id,
     448                'title'    => array(
     449                    'raw'      => 'Custom Styles',
     450                    'rendered' => 'Custom Styles',
     451                ),
     452                'settings' => new stdClass(),
     453                'styles'   => new stdClass(),
     454            ),
     455            $data
     456        );
     457
     458        $this->assertArrayHasKey( 'self', $links );
     459        $this->assertStringContainsString( '/wp/v2/global-styles/' . self::$global_styles_id, $links['self'][0]['href'] );
     460    }
     461
     462    /**
     463     * @doesNotPerformAssertions
     464     */
     465    public function test_create_item() {
     466        // Controller does not implement create_item().
     467    }
     468
     469    /**
     470     * @covers WP_REST_Global_Styles_Controller::update_item
     471     * @ticket 54516
     472     */
     473    public function test_update_item() {
     474        wp_set_current_user( self::$admin_id );
     475        $request = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
     476        $request->set_body_params(
     477            array(
     478                'title' => 'My new global styles title',
     479            )
     480        );
     481        $response = rest_get_server()->dispatch( $request );
     482        $data     = $response->get_data();
     483        $this->assertSame( 'My new global styles title', $data['title']['raw'] );
     484    }
     485
     486    /**
     487     * @covers WP_REST_Global_Styles_Controller::update_item
     488     * @ticket 54516
     489     */
     490    public function test_update_item_no_user() {
     491        wp_set_current_user( 0 );
     492        $request  = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
     493        $response = rest_get_server()->dispatch( $request );
     494        $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 );
     495    }
     496
     497    /**
     498     * @covers WP_REST_Global_Styles_Controller::update_item
     499     * @ticket 54516
     500     */
     501    public function test_update_item_invalid_post() {
     502        wp_set_current_user( self::$admin_id );
     503        $request  = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$post_id );
     504        $response = rest_get_server()->dispatch( $request );
     505        $this->assertErrorResponse( 'rest_global_styles_not_found', $response, 404 );
     506    }
     507
     508    /**
     509     * @covers WP_REST_Global_Styles_Controller::update_item
     510     * @ticket 54516
     511     */
     512    public function test_update_item_permission_check() {
     513        wp_set_current_user( self::$subscriber_id );
     514        $request  = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
     515        $response = rest_get_server()->dispatch( $request );
     516        $this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
     517    }
     518
     519    /**
     520     * @covers WP_REST_Global_Styles_Controller::update_item
     521     * @ticket 57536
     522     */
     523    public function test_update_item_valid_styles_css() {
     524        wp_set_current_user( self::$admin_id );
     525        if ( is_multisite() ) {
     526            grant_super_admin( self::$admin_id );
     527        }
     528        $request = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
     529        $request->set_body_params(
     530            array(
     531                'styles' => array( 'css' => 'body { color: red; }' ),
     532            )
     533        );
     534        $response = rest_get_server()->dispatch( $request );
     535        $data     = $response->get_data();
     536        $this->assertSame( 'body { color: red; }', $data['styles']['css'] );
     537    }
     538
     539    /**
     540     * @covers WP_REST_Global_Styles_Controller::update_item
     541     * @ticket 57536
     542     */
     543    public function test_update_item_invalid_styles_css() {
     544        wp_set_current_user( self::$admin_id );
     545        if ( is_multisite() ) {
     546            grant_super_admin( self::$admin_id );
     547        }
     548        $request = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
     549        $request->set_body_params(
     550            array(
     551                'styles' => array( 'css' => '<p>test</p> body { color: red; }' ),
     552            )
     553        );
     554        $response = rest_get_server()->dispatch( $request );
     555        $this->assertErrorResponse( 'rest_custom_css_illegal_markup', $response, 400 );
     556    }
     557
     558    /**
     559     * @doesNotPerformAssertions
     560     */
     561    public function test_delete_item() {
     562        // Controller does not implement delete_item().
     563    }
     564
     565    /**
     566     * @doesNotPerformAssertions
     567     */
     568    public function test_prepare_item() {
     569        // Controller does not implement prepare_item().
     570    }
     571
     572    /**
     573     * @covers WP_REST_Global_Styles_Controller::get_item_schema
     574     * @ticket 54516
     575     */
     576    public function test_get_item_schema() {
     577        $request    = new WP_REST_Request( 'OPTIONS', '/wp/v2/global-styles/' . self::$global_styles_id );
     578        $response   = rest_get_server()->dispatch( $request );
     579        $data       = $response->get_data();
     580        $properties = $data['schema']['properties'];
     581        $this->assertCount( 4, $properties, 'Schema properties array does not have exactly 4 elements' );
     582        $this->assertArrayHasKey( 'id', $properties, 'Schema properties array does not have "id" key' );
     583        $this->assertArrayHasKey( 'styles', $properties, 'Schema properties array does not have "styles" key' );
     584        $this->assertArrayHasKey( 'settings', $properties, 'Schema properties array does not have "settings" key' );
     585        $this->assertArrayHasKey( 'title', $properties, 'Schema properties array does not have "title" key' );
    539586    }
    540587
     
    557604        }
    558605    }
    559 
    560     /**
    561      * @covers WP_REST_Global_Styles_Controller::update_item
    562      * @ticket 57536
    563      */
    564     public function test_update_item_valid_styles_css() {
    565         wp_set_current_user( self::$admin_id );
    566         if ( is_multisite() ) {
    567             grant_super_admin( self::$admin_id );
    568         }
    569         $request = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
    570         $request->set_body_params(
    571             array(
    572                 'styles' => array( 'css' => 'body { color: red; }' ),
    573             )
    574         );
    575         $response = rest_get_server()->dispatch( $request );
    576         $data     = $response->get_data();
    577         $this->assertSame( 'body { color: red; }', $data['styles']['css'] );
    578     }
    579 
    580     /**
    581      * @covers WP_REST_Global_Styles_Controller::update_item
    582      * @ticket 57536
    583      */
    584     public function test_update_item_invalid_styles_css() {
    585         wp_set_current_user( self::$admin_id );
    586         if ( is_multisite() ) {
    587             grant_super_admin( self::$admin_id );
    588         }
    589         $request = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
    590         $request->set_body_params(
    591             array(
    592                 'styles' => array( 'css' => '<p>test</p> body { color: red; }' ),
    593             )
    594         );
    595         $response = rest_get_server()->dispatch( $request );
    596         $this->assertErrorResponse( 'rest_custom_css_illegal_markup', $response, 400 );
    597     }
    598606}
  • trunk/tests/phpunit/tests/theme/wpThemeJson.php

    r57547 r57662  
    388388
    389389    /**
    390      * @ticket 54336
    391      * @ticket 58550
    392      */
    393     public function test_get_stylesheet_support_for_shorthand_and_longhand_values() {
    394         $theme_json = new WP_Theme_JSON(
    395             array(
    396                 'version' => WP_Theme_JSON::LATEST_SCHEMA,
    397                 'styles'  => array(
    398                     'blocks' => array(
    399                         'core/group' => array(
    400                             'border'  => array(
    401                                 'radius' => '10px',
    402                             ),
    403                             'spacing' => array(
    404                                 'padding' => '24px',
    405                                 'margin'  => '1em',
    406                             ),
    407                         ),
    408                         'core/image' => array(
    409                             'border'  => array(
    410                                 'radius' => array(
    411                                     'topLeft'     => '10px',
    412                                     'bottomRight' => '1em',
    413                                 ),
    414                             ),
    415                             'spacing' => array(
    416                                 'padding' => array(
    417                                     'top' => '15px',
    418                                 ),
    419                                 'margin'  => array(
    420                                     'bottom' => '30px',
    421                                 ),
    422                             ),
    423                         ),
    424                     ),
    425                 ),
    426             )
    427         );
    428 
    429         $styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-group{border-radius: 10px;margin: 1em;padding: 24px;}.wp-block-image{margin-bottom: 30px;padding-top: 15px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder{border-top-left-radius: 10px;border-bottom-right-radius: 1em;}';
    430         $this->assertSame( $styles, $theme_json->get_stylesheet() );
    431         $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
    432     }
    433 
    434     /**
    435      * @ticket 54336
    436      * @ticket 58550
    437      */
    438     public function test_get_stylesheet_skips_disabled_protected_properties() {
    439         $theme_json = new WP_Theme_JSON(
    440             array(
    441                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    442                 'settings' => array(
    443                     'spacing' => array(
    444                         'blockGap' => null,
    445                     ),
    446                 ),
    447                 'styles'   => array(
    448                     'spacing' => array(
    449                         'blockGap' => '1em',
    450                     ),
    451                     'blocks'  => array(
    452                         'core/columns' => array(
    453                             'spacing' => array(
    454                                 'blockGap' => '24px',
    455                             ),
    456                         ),
    457                     ),
    458                 ),
    459             )
    460         );
    461 
    462         $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}';
    463         $this->assertSame( $expected, $theme_json->get_stylesheet() );
    464         $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
    465     }
    466 
    467     /**
    468      * @ticket 54336
    469      * @ticket 58548
    470      * @ticket 58550
    471      */
    472     public function test_get_stylesheet_renders_enabled_protected_properties() {
    473         $theme_json = new WP_Theme_JSON(
    474             array(
    475                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    476                 'settings' => array(
    477                     'spacing' => array(
    478                         'blockGap' => true,
    479                     ),
    480                 ),
    481                 'styles'   => array(
    482                     'spacing' => array(
    483                         'blockGap' => '1em',
    484                     ),
    485                 ),
    486             )
    487         );
    488 
    489         $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: 1em; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child:first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child:last-child { margin-block-end: 0; }body { --wp--style--block-gap: 1em; }:where(body .is-layout-flow)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-flow)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-flow)  > *{margin-block-start: 1em;margin-block-end: 0;}:where(body .is-layout-constrained)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-constrained)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-constrained)  > *{margin-block-start: 1em;margin-block-end: 0;}:where(body .is-layout-flex) {gap: 1em;}:where(body .is-layout-grid) {gap: 1em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
    490         $this->assertSame( $expected, $theme_json->get_stylesheet() );
    491         $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
    492     }
    493 
    494     /**
    495390     * @ticket 53175
    496391     * @ticket 54336
     
    584479                        ),
    585480                        'core/group'        => array(
    586                             'color'    => array(
     481                            'color'      => array(
    587482                                'gradient' => 'var:preset|gradient|custom-gradient',
    588483                            ),
    589                             'border'   => array(
     484                            'border'     => array(
    590485                                'radius' => '10px',
    591486                            ),
    592                             'elements' => array(
     487                            'dimensions' => array(
     488                                'minHeight' => '50vh',
     489                            ),
     490                            'elements'   => array(
    593491                                'link' => array(
    594492                                    'color' => array(
     
    597495                                ),
    598496                            ),
    599                             'spacing'  => array(
     497                            'spacing'    => array(
    600498                                'padding' => '24px',
    601499                            ),
     
    661559
    662560        $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--gradient--custom-gradient: linear-gradient(135deg,rgba(0,0,0) 0%,rgb(0,0,0) 100%);--wp--preset--font-size--small: 14px;--wp--preset--font-size--big: 41px;--wp--preset--font-family--arial: Arial, serif;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}';
    663         $styles    = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}body{color: var(--wp--preset--color--grey);}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-element-button, .wp-block-button__link{box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.66);}.wp-block-cover{min-height: unset;aspect-ratio: 16/9;}.wp-block-group{background: var(--wp--preset--gradient--custom-gradient);border-radius: 10px;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}.wp-block-heading{color: #123456;}.wp-block-heading a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-post-excerpt{column-count: 2;}.wp-block-image{margin-bottom: 30px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder{border-top-left-radius: 10px;border-bottom-right-radius: 1em;}.wp-block-image img, .wp-block-image .components-placeholder{filter: var(--wp--preset--duotone--custom-duotone);}';
     561        $styles    = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}body{color: var(--wp--preset--color--grey);}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-element-button, .wp-block-button__link{box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.66);}.wp-block-cover{min-height: unset;aspect-ratio: 16/9;}.wp-block-group{background: var(--wp--preset--gradient--custom-gradient);border-radius: 10px;min-height: 50vh;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}.wp-block-heading{color: #123456;}.wp-block-heading a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-post-excerpt{column-count: 2;}.wp-block-image{margin-bottom: 30px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder{border-top-left-radius: 10px;border-bottom-right-radius: 1em;}.wp-block-image img, .wp-block-image .components-placeholder{filter: var(--wp--preset--duotone--custom-duotone);}';
    664562        $presets   = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-custom-gradient-gradient-background{background: var(--wp--preset--gradient--custom-gradient) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-big-font-size{font-size: var(--wp--preset--font-size--big) !important;}.has-arial-font-family{font-family: var(--wp--preset--font-family--arial) !important;}';
    665563        $all       = $variables . $styles . $presets;
    666         $this->assertSame( $all, $theme_json->get_stylesheet() );
     564
     565        $this->assertSame( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
    667566        $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
    668567        $this->assertSame( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
    669         $this->assertSame( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
     568        $this->assertSame( $all, $theme_json->get_stylesheet() );
     569    }
     570
     571    /**
     572     * @ticket 54336
     573     * @ticket 58550
     574     */
     575    public function test_get_stylesheet_support_for_shorthand_and_longhand_values() {
     576        $theme_json = new WP_Theme_JSON(
     577            array(
     578                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     579                'styles'  => array(
     580                    'blocks' => array(
     581                        'core/group' => array(
     582                            'border'  => array(
     583                                'radius' => '10px',
     584                            ),
     585                            'spacing' => array(
     586                                'padding' => '24px',
     587                                'margin'  => '1em',
     588                            ),
     589                        ),
     590                        'core/image' => array(
     591                            'border'  => array(
     592                                'radius' => array(
     593                                    'topLeft'     => '10px',
     594                                    'bottomRight' => '1em',
     595                                ),
     596                            ),
     597                            'spacing' => array(
     598                                'padding' => array(
     599                                    'top' => '15px',
     600                                ),
     601                                'margin'  => array(
     602                                    'bottom' => '30px',
     603                                ),
     604                            ),
     605                        ),
     606                    ),
     607                ),
     608            )
     609        );
     610
     611        $styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-group{border-radius: 10px;margin: 1em;padding: 24px;}.wp-block-image{margin-bottom: 30px;padding-top: 15px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder{border-top-left-radius: 10px;border-bottom-right-radius: 1em;}';
     612        $this->assertSame( $styles, $theme_json->get_stylesheet() );
     613        $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
     614    }
     615
     616    /**
     617     * @ticket 54336
     618     * @ticket 58550
     619     */
     620    public function test_get_stylesheet_skips_disabled_protected_properties() {
     621        $theme_json = new WP_Theme_JSON(
     622            array(
     623                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     624                'settings' => array(
     625                    'spacing' => array(
     626                        'blockGap' => null,
     627                    ),
     628                ),
     629                'styles'   => array(
     630                    'spacing' => array(
     631                        'blockGap' => '1em',
     632                    ),
     633                    'blocks'  => array(
     634                        'core/columns' => array(
     635                            'spacing' => array(
     636                                'blockGap' => '24px',
     637                            ),
     638                        ),
     639                    ),
     640                ),
     641            )
     642        );
     643
     644        $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}';
     645        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     646        $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
     647    }
     648
     649    /**
     650     * @ticket 54336
     651     * @ticket 58548
     652     * @ticket 58550
     653     */
     654    public function test_get_stylesheet_renders_enabled_protected_properties() {
     655        $theme_json = new WP_Theme_JSON(
     656            array(
     657                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     658                'settings' => array(
     659                    'spacing' => array(
     660                        'blockGap' => true,
     661                    ),
     662                ),
     663                'styles'   => array(
     664                    'spacing' => array(
     665                        'blockGap' => '1em',
     666                    ),
     667                ),
     668            )
     669        );
     670
     671        $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: 1em; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child:first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child:last-child { margin-block-end: 0; }body { --wp--style--block-gap: 1em; }:where(body .is-layout-flow)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-flow)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-flow)  > *{margin-block-start: 1em;margin-block-end: 0;}:where(body .is-layout-constrained)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-constrained)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-constrained)  > *{margin-block-start: 1em;margin-block-end: 0;}:where(body .is-layout-flex) {gap: 1em;}:where(body .is-layout-grid) {gap: 1em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
     672        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     673        $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
    670674    }
    671675
     
    739743        $presets   = '.wp-block-group.has-grey-color{color: var(--wp--preset--color--grey) !important;}.wp-block-group.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.wp-block-group.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}';
    740744        $variables = '.wp-block-group{--wp--preset--color--grey: grey;}';
    741         $all       = $variables . $styles . $presets;
     745
     746        $all = $variables . $styles . $presets;
     747
    742748        $this->assertSame( $all, $theme_json->get_stylesheet() );
    743749        $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
     
    11141120
    11151121    /**
     1122     * @ticket 56467
     1123     * @ticket 58548
     1124     * @ticket 58550
     1125     */
     1126    public function test_get_stylesheet_generates_layout_styles() {
     1127        $theme_json = new WP_Theme_JSON(
     1128            array(
     1129                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1130                'settings' => array(
     1131                    'spacing' => array(
     1132                        'blockGap' => true,
     1133                    ),
     1134                ),
     1135                'styles'   => array(
     1136                    'spacing' => array(
     1137                        'blockGap' => '1em',
     1138                    ),
     1139                ),
     1140            ),
     1141            'default'
     1142        );
     1143
     1144        // Results also include root site blocks styles.
     1145        $this->assertSame(
     1146            'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: 1em; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child:first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child:last-child { margin-block-end: 0; }body { --wp--style--block-gap: 1em; }:where(body .is-layout-flow)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-flow)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-flow)  > *{margin-block-start: 1em;margin-block-end: 0;}:where(body .is-layout-constrained)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-constrained)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-constrained)  > *{margin-block-start: 1em;margin-block-end: 0;}:where(body .is-layout-flex) {gap: 1em;}:where(body .is-layout-grid) {gap: 1em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}',
     1147            $theme_json->get_stylesheet( array( 'styles' ) )
     1148        );
     1149    }
     1150
     1151    /**
     1152     * @ticket 56467
     1153     * @ticket 58548
     1154     * @ticket 58550
     1155     */
     1156    public function test_get_stylesheet_generates_layout_styles_with_spacing_presets() {
     1157        $theme_json = new WP_Theme_JSON(
     1158            array(
     1159                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1160                'settings' => array(
     1161                    'spacing' => array(
     1162                        'blockGap' => true,
     1163                    ),
     1164                ),
     1165                'styles'   => array(
     1166                    'spacing' => array(
     1167                        'blockGap' => 'var:preset|spacing|60',
     1168                    ),
     1169                ),
     1170            ),
     1171            'default'
     1172        );
     1173
     1174        // Results also include root site blocks styles.
     1175        $this->assertSame(
     1176            'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: var(--wp--preset--spacing--60); margin-block-end: 0; }:where(.wp-site-blocks) > :first-child:first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child:last-child { margin-block-end: 0; }body { --wp--style--block-gap: var(--wp--preset--spacing--60); }:where(body .is-layout-flow)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-flow)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-flow)  > *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}:where(body .is-layout-constrained)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-constrained)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-constrained)  > *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}:where(body .is-layout-flex) {gap: var(--wp--preset--spacing--60);}:where(body .is-layout-grid) {gap: var(--wp--preset--spacing--60);}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}',
     1177            $theme_json->get_stylesheet( array( 'styles' ) )
     1178        );
     1179    }
     1180
     1181    /**
     1182     * @ticket 56467
     1183     * @ticket 58550
     1184     */
     1185    public function test_get_stylesheet_generates_fallback_gap_layout_styles() {
     1186        $theme_json = new WP_Theme_JSON(
     1187            array(
     1188                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1189                'settings' => array(
     1190                    'spacing' => array(
     1191                        'blockGap' => null,
     1192                    ),
     1193                ),
     1194                'styles'   => array(
     1195                    'spacing' => array(
     1196                        'blockGap' => '1em',
     1197                    ),
     1198                ),
     1199            ),
     1200            'default'
     1201        );
     1202        $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) );
     1203
     1204        // Results also include root site blocks styles.
     1205        $this->assertSame(
     1206            'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}',
     1207            $stylesheet
     1208        );
     1209    }
     1210
     1211    /**
     1212     * @ticket 56467
     1213     * @ticket 58550
     1214     */
     1215    public function test_get_stylesheet_generates_base_fallback_gap_layout_styles() {
     1216        $theme_json = new WP_Theme_JSON(
     1217            array(
     1218                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1219                'settings' => array(
     1220                    'spacing' => array(
     1221                        'blockGap' => null,
     1222                    ),
     1223                ),
     1224            ),
     1225            'default'
     1226        );
     1227        $stylesheet = $theme_json->get_stylesheet( array( 'base-layout-styles' ) );
     1228
     1229        // Note the `base-layout-styles` includes a fallback gap for the Columns block for backwards compatibility.
     1230        $this->assertSame(
     1231            ':where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}',
     1232            $stylesheet
     1233        );
     1234    }
     1235
     1236    /**
     1237     * @ticket 56467
     1238     * @ticket 58550
     1239     */
     1240    public function test_get_stylesheet_skips_layout_styles() {
     1241        add_theme_support( 'disable-layout-styles' );
     1242        $theme_json = new WP_Theme_JSON(
     1243            array(
     1244                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1245                'settings' => array(
     1246                    'spacing' => array(
     1247                        'blockGap' => null,
     1248                    ),
     1249                ),
     1250            ),
     1251            'default'
     1252        );
     1253        $stylesheet = $theme_json->get_stylesheet( array( 'base-layout-styles' ) );
     1254        remove_theme_support( 'disable-layout-styles' );
     1255
     1256        // All Layout styles should be skipped.
     1257        $this->assertSame(
     1258            '',
     1259            $stylesheet
     1260        );
     1261    }
     1262
     1263    /**
     1264     * @ticket 56467
     1265     * @ticket 58550
     1266     */
     1267    public function test_get_stylesheet_generates_valid_block_gap_values_and_skips_null_or_false_values() {
     1268        $theme_json = new WP_Theme_JSON(
     1269            array(
     1270                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1271                'settings' => array(
     1272                    'spacing' => array(
     1273                        'blockGap' => true,
     1274                    ),
     1275                ),
     1276                'styles'   => array(
     1277                    'spacing' => array(
     1278                        'blockGap' => '1rem',
     1279                    ),
     1280                    'blocks'  => array(
     1281                        'core/post-content' => array(
     1282                            'color' => array(
     1283                                'text' => 'gray', // This value should not render block layout styles.
     1284                            ),
     1285                        ),
     1286                        'core/social-links' => array(
     1287                            'spacing' => array(
     1288                                'blockGap' => '0', // This value should render block layout gap as zero.
     1289                            ),
     1290                        ),
     1291                        'core/buttons'      => array(
     1292                            'spacing' => array(
     1293                                'blockGap' => 0, // This value should render block layout gap as zero.
     1294                            ),
     1295                        ),
     1296                        'core/columns'      => array(
     1297                            'spacing' => array(
     1298                                'blockGap' => false, // This value should be ignored. The block will use the global layout value.
     1299                            ),
     1300                        ),
     1301                    ),
     1302                ),
     1303            ),
     1304            'default'
     1305        );
     1306
     1307        $this->assertSame(
     1308            'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: 1rem; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child:first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child:last-child { margin-block-end: 0; }body { --wp--style--block-gap: 1rem; }:where(body .is-layout-flow)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-flow)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-flow)  > *{margin-block-start: 1rem;margin-block-end: 0;}:where(body .is-layout-constrained)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-constrained)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-constrained)  > *{margin-block-start: 1rem;margin-block-end: 0;}:where(body .is-layout-flex) {gap: 1rem;}:where(body .is-layout-grid) {gap: 1rem;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-post-content{color: gray;}.wp-block-social-links-is-layout-flow > :first-child:first-child{margin-block-start: 0;}.wp-block-social-links-is-layout-flow > :last-child:last-child{margin-block-end: 0;}.wp-block-social-links-is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links-is-layout-constrained > :first-child:first-child{margin-block-start: 0;}.wp-block-social-links-is-layout-constrained > :last-child:last-child{margin-block-end: 0;}.wp-block-social-links-is-layout-constrained > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links-is-layout-flex{gap: 0;}.wp-block-social-links-is-layout-grid{gap: 0;}.wp-block-buttons-is-layout-flow > :first-child:first-child{margin-block-start: 0;}.wp-block-buttons-is-layout-flow > :last-child:last-child{margin-block-end: 0;}.wp-block-buttons-is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons-is-layout-constrained > :first-child:first-child{margin-block-start: 0;}.wp-block-buttons-is-layout-constrained > :last-child:last-child{margin-block-end: 0;}.wp-block-buttons-is-layout-constrained > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons-is-layout-flex{gap: 0;}.wp-block-buttons-is-layout-grid{gap: 0;}',
     1309            $theme_json->get_stylesheet()
     1310        );
     1311    }
     1312
     1313    /**
     1314     * @ticket 57354
     1315     * @ticket 58550
     1316     */
     1317    public function test_get_stylesheet_returns_outline_styles() {
     1318        $theme_json = new WP_Theme_JSON(
     1319            array(
     1320                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     1321                'styles'  => array(
     1322                    'elements' => array(
     1323                        'button' => array(
     1324                            'outline' => array(
     1325                                'offset' => '3px',
     1326                                'width'  => '3px',
     1327                                'style'  => 'dashed',
     1328                                'color'  => 'red',
     1329                            ),
     1330                            ':hover'  => array(
     1331                                'outline' => array(
     1332                                    'offset' => '3px',
     1333                                    'width'  => '3px',
     1334                                    'style'  => 'solid',
     1335                                    'color'  => 'blue',
     1336                                ),
     1337                            ),
     1338                        ),
     1339                    ),
     1340                ),
     1341            )
     1342        );
     1343
     1344        $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
     1345
     1346        $element_styles = '.wp-element-button, .wp-block-button__link{outline-color: red;outline-offset: 3px;outline-style: dashed;outline-width: 3px;}.wp-element-button:hover, .wp-block-button__link:hover{outline-color: blue;outline-offset: 3px;outline-style: solid;outline-width: 3px;}';
     1347
     1348        $expected = $base_styles . $element_styles;
     1349        $this->assertSame( $expected, $theme_json->get_stylesheet() );
     1350    }
     1351
     1352    /**
     1353     * Tests that a custom root selector is correctly applied when generating a stylesheet.
     1354     *
     1355     * @ticket 60343
     1356     */
     1357    public function test_get_stylesheet_custom_root_selector() {
     1358        $theme_json = new WP_Theme_JSON(
     1359            array(
     1360                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     1361                'styles'  => array(
     1362                    'color' => array(
     1363                        'text' => 'teal',
     1364                    ),
     1365                ),
     1366            ),
     1367            'default'
     1368        );
     1369
     1370        $options = array( 'root_selector' => '.custom' );
     1371        $actual  = $theme_json->get_stylesheet( array( 'styles' ), null, $options );
     1372
     1373        // Results also include root site blocks styles which hard code
     1374        // `body { margin: 0; }`.
     1375        $this->assertSame(
     1376            'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.custom{color: teal;}',
     1377            $actual
     1378        );
     1379    }
     1380
     1381    public function test_allow_indirect_properties() {
     1382        $actual = WP_Theme_JSON::remove_insecure_properties(
     1383            array(
     1384                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1385                'styles'   => array(
     1386                    'blocks'  => array(
     1387                        'core/social-links' => array(
     1388                            'spacing' => array(
     1389                                'blockGap' => array(
     1390                                    'top'  => '1em',
     1391                                    'left' => '2em',
     1392                                ),
     1393                            ),
     1394                        ),
     1395                    ),
     1396                    'spacing' => array(
     1397                        'blockGap' => '3em',
     1398                    ),
     1399                ),
     1400                'settings' => array(
     1401                    'layout' => array(
     1402                        'contentSize' => '800px',
     1403                        'wideSize'    => '1000px',
     1404                    ),
     1405                ),
     1406            )
     1407        );
     1408
     1409        $expected = array(
     1410            'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1411            'styles'   => array(
     1412                'blocks'  => array(
     1413                    'core/social-links' => array(
     1414                        'spacing' => array(
     1415                            'blockGap' => array(
     1416                                'top'  => '1em',
     1417                                'left' => '2em',
     1418                            ),
     1419                        ),
     1420                    ),
     1421                ),
     1422                'spacing' => array(
     1423                    'blockGap' => '3em',
     1424                ),
     1425            ),
     1426            'settings' => array(
     1427                'layout' => array(
     1428                    'contentSize' => '800px',
     1429                    'wideSize'    => '1000px',
     1430                ),
     1431            ),
     1432        );
     1433
     1434        $this->assertEqualSetsWithIndex( $expected, $actual );
     1435    }
     1436
     1437    /**
    11161438     * @ticket 52991
    11171439     * @ticket 54336
     
    25552877                                ),
    25562878                            ),
     2879                            ':seen'  => array(
     2880                                'color' => array(
     2881                                    'background' => 'ivory',
     2882                                ),
     2883                            ),
    25572884                        ),
    25582885                    ),
     
    28413168
    28423169    /**
    2843      * @ticket 54487
    2844      */
    2845     public function test_sanitization() {
    2846         $theme_json = new WP_Theme_JSON(
    2847             array(
    2848                 'version' => 2,
    2849                 'styles'  => array(
    2850                     'spacing' => array(
    2851                         'blockGap' => 'valid value',
    2852                     ),
    2853                     'blocks'  => array(
    2854                         'core/group' => array(
    2855                             'spacing' => array(
    2856                                 'margin'  => 'valid value',
    2857                                 'display' => 'none',
    2858                             ),
    2859                         ),
    2860                     ),
    2861                 ),
    2862             )
    2863         );
    2864 
    2865         $actual   = $theme_json->get_raw_data();
    2866         $expected = array(
    2867             'version' => 2,
    2868             'styles'  => array(
    2869                 'spacing' => array(
    2870                     'blockGap' => 'valid value',
    2871                 ),
    2872                 'blocks'  => array(
    2873                     'core/group' => array(
    2874                         'spacing' => array(
    2875                             'margin' => 'valid value',
    2876                         ),
    2877                     ),
    2878                 ),
    2879             ),
    2880         );
    2881 
    2882         $this->assertEqualSetsWithIndex( $expected, $actual );
    2883     }
    2884 
    2885     /**
    28863170     * @ticket 55505
    28873171     */
     
    31553439    }
    31563440
     3441    public function test_remove_invalid_font_family_settings() {
     3442        $actual = WP_Theme_JSON::remove_insecure_properties(
     3443            array(
     3444                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     3445                'settings' => array(
     3446                    'typography' => array(
     3447                        'fontFamilies' => array(
     3448                            'custom' => array(
     3449                                array(
     3450                                    'name'       => 'Open Sans',
     3451                                    'slug'       => 'open-sans',
     3452                                    'fontFamily' => '"Open Sans", sans-serif</style><script>alert("xss")</script>',
     3453                                ),
     3454                                array(
     3455                                    'name'       => 'Arial',
     3456                                    'slug'       => 'arial',
     3457                                    'fontFamily' => 'Arial, serif',
     3458                                ),
     3459                            ),
     3460                        ),
     3461                    ),
     3462                ),
     3463            ),
     3464            true
     3465        );
     3466
     3467        $expected = array(
     3468            'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     3469            'settings' => array(
     3470                'typography' => array(
     3471                    'fontFamilies' => array(
     3472                        'custom' => array(
     3473                            array(
     3474                                'name'       => 'Arial',
     3475                                'slug'       => 'arial',
     3476                                'fontFamily' => 'Arial, serif',
     3477                            ),
     3478                        ),
     3479                    ),
     3480                ),
     3481            ),
     3482        );
     3483
     3484        $this->assertEqualSetsWithIndex( $expected, $actual );
     3485    }
    31573486
    31583487    /**
     
    32043533        );
    32053534
    3206         $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}body{background-color: #ffffff;color: #000000;}.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}';
     3535        $base_styles  = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
     3536        $color_styles = 'body{background-color: #ffffff;color: #000000;}.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}';
     3537        $expected     = $base_styles . $color_styles;
    32073538        $this->assertSame( $expected, $theme_json->get_stylesheet() );
    32083539    }
     
    32563587
    32573588    /**
    3258      * Testing that dynamic properties in theme.json that refer to other dynamic properties in a loop
     3589     * Testing that dynamic properties in theme.json that
     3590     * refer to other dynamic properties in a loop
    32593591     * should be left untouched.
    32603592     *
     
    32843616        );
    32853617
    3286         $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}body{background-color: #ffffff;}.wp-element-button, .wp-block-button__link{color: #ffffff;}';
     3618        $base_styles  = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
     3619        $color_styles = 'body{background-color: #ffffff;}.wp-element-button, .wp-block-button__link{color: #ffffff;}';
     3620        $expected     = $base_styles . $color_styles;
    32873621        $this->assertSame( $expected, $theme_json->get_stylesheet() );
    32883622    }
    32893623
    32903624    /**
    3291      * Testing that dynamic properties in theme.json that refer to other dynamic properties
     3625     * Testing that dynamic properties in theme.json that
     3626     * refer to other dynamic properties
    32923627     * should be left unprocessed.
    32933628     *
     
    33173652        );
    33183653
    3319         $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}body{background-color: #ffffff;color: #ffffff;}.wp-element-button, .wp-block-button__link{color: #ffffff;}';
     3654        $base_styles  = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
     3655        $color_styles = 'body{background-color: #ffffff;color: #ffffff;}.wp-element-button, .wp-block-button__link{color: #ffffff;}';
     3656        $expected     = $base_styles . $color_styles;
    33203657        $this->assertSame( $expected, $theme_json->get_stylesheet() );
    33213658    }
    33223659
    33233660    /**
    3324      * Testing that dynamic properties in theme.json that refer to themselves
    3325      * should be left unprocessed.
     3661     * Testing that dynamic properties in theme.json that
     3662     * refer to themselves should be left unprocessed.
    33263663     *
    33273664     * @ticket 56467
     
    33423679        );
    33433680
    3344         $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}body{background-color: #ffffff;}';
     3681        $base_styles  = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
     3682        $color_styles = 'body{background-color: #ffffff;}';
     3683        $expected     = $base_styles . $color_styles;
    33453684        $this->assertSame( $expected, $theme_json->get_stylesheet() );
    3346     }
    3347 
    3348     /**
    3349      * @ticket 56467
    3350      * @ticket 58548
    3351      * @ticket 58550
    3352      */
    3353     public function test_get_stylesheet_generates_layout_styles() {
    3354         $theme_json = new WP_Theme_JSON(
    3355             array(
    3356                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    3357                 'settings' => array(
    3358                     'spacing' => array(
    3359                         'blockGap' => true,
    3360                     ),
    3361                 ),
    3362                 'styles'   => array(
    3363                     'spacing' => array(
    3364                         'blockGap' => '1em',
    3365                     ),
    3366                 ),
    3367             ),
    3368             'default'
    3369         );
    3370 
    3371         // Results also include root site blocks styles.
    3372         $this->assertSame(
    3373             'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: 1em; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child:first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child:last-child { margin-block-end: 0; }body { --wp--style--block-gap: 1em; }:where(body .is-layout-flow)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-flow)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-flow)  > *{margin-block-start: 1em;margin-block-end: 0;}:where(body .is-layout-constrained)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-constrained)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-constrained)  > *{margin-block-start: 1em;margin-block-end: 0;}:where(body .is-layout-flex) {gap: 1em;}:where(body .is-layout-grid) {gap: 1em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}',
    3374             $theme_json->get_stylesheet( array( 'styles' ) )
    3375         );
    3376     }
    3377 
    3378     /**
    3379      * @ticket 56467
    3380      * @ticket 58548
    3381      * @ticket 58550
    3382      */
    3383     public function test_get_stylesheet_generates_layout_styles_with_spacing_presets() {
    3384         $theme_json = new WP_Theme_JSON(
    3385             array(
    3386                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    3387                 'settings' => array(
    3388                     'spacing' => array(
    3389                         'blockGap' => true,
    3390                     ),
    3391                 ),
    3392                 'styles'   => array(
    3393                     'spacing' => array(
    3394                         'blockGap' => 'var:preset|spacing|60',
    3395                     ),
    3396                 ),
    3397             ),
    3398             'default'
    3399         );
    3400 
    3401         // Results also include root site blocks styles.
    3402         $this->assertSame(
    3403             'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: var(--wp--preset--spacing--60); margin-block-end: 0; }:where(.wp-site-blocks) > :first-child:first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child:last-child { margin-block-end: 0; }body { --wp--style--block-gap: var(--wp--preset--spacing--60); }:where(body .is-layout-flow)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-flow)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-flow)  > *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}:where(body .is-layout-constrained)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-constrained)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-constrained)  > *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}:where(body .is-layout-flex) {gap: var(--wp--preset--spacing--60);}:where(body .is-layout-grid) {gap: var(--wp--preset--spacing--60);}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}',
    3404             $theme_json->get_stylesheet( array( 'styles' ) )
    3405         );
    3406     }
    3407 
    3408     /**
    3409      * @ticket 56467
    3410      * @ticket 58550
    3411      */
    3412     public function test_get_stylesheet_generates_fallback_gap_layout_styles() {
    3413         $theme_json = new WP_Theme_JSON(
    3414             array(
    3415                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    3416                 'settings' => array(
    3417                     'spacing' => array(
    3418                         'blockGap' => null,
    3419                     ),
    3420                 ),
    3421                 'styles'   => array(
    3422                     'spacing' => array(
    3423                         'blockGap' => '1em',
    3424                     ),
    3425                 ),
    3426             ),
    3427             'default'
    3428         );
    3429         $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) );
    3430 
    3431         // Results also include root site blocks styles.
    3432         $this->assertSame(
    3433             'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}',
    3434             $stylesheet
    3435         );
    3436     }
    3437 
    3438     /**
    3439      * @ticket 56467
    3440      * @ticket 58550
    3441      */
    3442     public function test_get_stylesheet_generates_base_fallback_gap_layout_styles() {
    3443         $theme_json = new WP_Theme_JSON(
    3444             array(
    3445                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    3446                 'settings' => array(
    3447                     'spacing' => array(
    3448                         'blockGap' => null,
    3449                     ),
    3450                 ),
    3451             ),
    3452             'default'
    3453         );
    3454         $stylesheet = $theme_json->get_stylesheet( array( 'base-layout-styles' ) );
    3455 
    3456         // Note the `base-layout-styles` includes a fallback gap for the Columns block for backwards compatibility.
    3457         $this->assertSame(
    3458             ':where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}',
    3459             $stylesheet
    3460         );
    3461     }
    3462 
    3463     /**
    3464      * @ticket 56467
    3465      * @ticket 58550
    3466      */
    3467     public function test_get_stylesheet_skips_layout_styles() {
    3468         add_theme_support( 'disable-layout-styles' );
    3469         $theme_json = new WP_Theme_JSON(
    3470             array(
    3471                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    3472                 'settings' => array(
    3473                     'spacing' => array(
    3474                         'blockGap' => null,
    3475                     ),
    3476                 ),
    3477             ),
    3478             'default'
    3479         );
    3480         $stylesheet = $theme_json->get_stylesheet( array( 'base-layout-styles' ) );
    3481         remove_theme_support( 'disable-layout-styles' );
    3482 
    3483         // All Layout styles should be skipped.
    3484         $this->assertSame(
    3485             '',
    3486             $stylesheet
    3487         );
    3488     }
    3489 
    3490     /**
    3491      * @ticket 56467
    3492      * @ticket 58550
    3493      */
    3494     public function test_get_stylesheet_generates_valid_block_gap_values_and_skips_null_or_false_values() {
    3495         $theme_json = new WP_Theme_JSON(
    3496             array(
    3497                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    3498                 'settings' => array(
    3499                     'spacing' => array(
    3500                         'blockGap' => true,
    3501                     ),
    3502                 ),
    3503                 'styles'   => array(
    3504                     'spacing' => array(
    3505                         'blockGap' => '1rem',
    3506                     ),
    3507                     'blocks'  => array(
    3508                         'core/post-content' => array(
    3509                             'color' => array(
    3510                                 'text' => 'gray', // This value should not render block layout styles.
    3511                             ),
    3512                         ),
    3513                         'core/social-links' => array(
    3514                             'spacing' => array(
    3515                                 'blockGap' => '0', // This value should render block layout gap as zero.
    3516                             ),
    3517                         ),
    3518                         'core/buttons'      => array(
    3519                             'spacing' => array(
    3520                                 'blockGap' => 0, // This value should render block layout gap as zero.
    3521                             ),
    3522                         ),
    3523                         'core/columns'      => array(
    3524                             'spacing' => array(
    3525                                 'blockGap' => false, // This value should be ignored. The block will use the global layout value.
    3526                             ),
    3527                         ),
    3528                     ),
    3529                 ),
    3530             ),
    3531             'default'
    3532         );
    3533 
    3534         $this->assertSame(
    3535             'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: 1rem; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child:first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child:last-child { margin-block-end: 0; }body { --wp--style--block-gap: 1rem; }:where(body .is-layout-flow)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-flow)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-flow)  > *{margin-block-start: 1rem;margin-block-end: 0;}:where(body .is-layout-constrained)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-constrained)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-constrained)  > *{margin-block-start: 1rem;margin-block-end: 0;}:where(body .is-layout-flex) {gap: 1rem;}:where(body .is-layout-grid) {gap: 1rem;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-post-content{color: gray;}.wp-block-social-links-is-layout-flow > :first-child:first-child{margin-block-start: 0;}.wp-block-social-links-is-layout-flow > :last-child:last-child{margin-block-end: 0;}.wp-block-social-links-is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links-is-layout-constrained > :first-child:first-child{margin-block-start: 0;}.wp-block-social-links-is-layout-constrained > :last-child:last-child{margin-block-end: 0;}.wp-block-social-links-is-layout-constrained > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links-is-layout-flex{gap: 0;}.wp-block-social-links-is-layout-grid{gap: 0;}.wp-block-buttons-is-layout-flow > :first-child:first-child{margin-block-start: 0;}.wp-block-buttons-is-layout-flow > :last-child:last-child{margin-block-end: 0;}.wp-block-buttons-is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons-is-layout-constrained > :first-child:first-child{margin-block-start: 0;}.wp-block-buttons-is-layout-constrained > :last-child:last-child{margin-block-end: 0;}.wp-block-buttons-is-layout-constrained > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons-is-layout-flex{gap: 0;}.wp-block-buttons-is-layout-grid{gap: 0;}',
    3536             $theme_json->get_stylesheet()
    3537         );
    35383685    }
    35393686
     
    36313778        $style_rules = $theme_json->get_styles_for_block( $metadata );
    36323779        $this->assertSame( $expected, $root_rules . $style_rules );
     3780    }
     3781
     3782    /**
     3783     * @ticket 56611
     3784     * @ticket 58548
     3785     * @ticket 58550
     3786     */
     3787    public function test_get_styles_with_appearance_tools() {
     3788        $theme_json = new WP_Theme_JSON(
     3789            array(
     3790                'version'  => 2,
     3791                'settings' => array(
     3792                    'appearanceTools' => true,
     3793                ),
     3794            )
     3795        );
     3796
     3797        $metadata = array(
     3798            'path'     => array( 'settings' ),
     3799            'selector' => 'body',
     3800        );
     3801
     3802        $expected   = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: ; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child:first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child:last-child { margin-block-end: 0; }body { --wp--style--block-gap: ; }:where(body .is-layout-flow)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-flow)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-flow)  > *{margin-block-start: 1;margin-block-end: 0;}:where(body .is-layout-constrained)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-constrained)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-constrained)  > *{margin-block-start: 1;margin-block-end: 0;}:where(body .is-layout-flex) {gap: 1;}:where(body .is-layout-grid) {gap: 1;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
     3803        $root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata );
     3804        $this->assertSame( $expected, $root_rules );
     3805    }
     3806
     3807    /**
     3808     * @ticket 54487
     3809     */
     3810    public function test_sanitization() {
     3811        $theme_json = new WP_Theme_JSON(
     3812            array(
     3813                'version' => 2,
     3814                'styles'  => array(
     3815                    'spacing' => array(
     3816                        'blockGap' => 'valid value',
     3817                    ),
     3818                    'blocks'  => array(
     3819                        'core/group' => array(
     3820                            'spacing' => array(
     3821                                'margin'  => 'valid value',
     3822                                'display' => 'none',
     3823                            ),
     3824                        ),
     3825                    ),
     3826                ),
     3827            )
     3828        );
     3829
     3830        $actual   = $theme_json->get_raw_data();
     3831        $expected = array(
     3832            'version' => 2,
     3833            'styles'  => array(
     3834                'spacing' => array(
     3835                    'blockGap' => 'valid value',
     3836                ),
     3837                'blocks'  => array(
     3838                    'core/group' => array(
     3839                        'spacing' => array(
     3840                            'margin' => 'valid value',
     3841                        ),
     3842                    ),
     3843                ),
     3844            ),
     3845        );
     3846
     3847        $this->assertEqualSetsWithIndex( $expected, $actual );
    36333848    }
    36343849
     
    37653980                ),
    37663981            ),
    3767         );
    3768     }
    3769 
    3770     /**
    3771      * @ticket 57583
    3772      *
    3773      * @dataProvider data_sanitize_with_invalid_style_variation
    3774      *
    3775      * @param array $theme_json_variations The theme.json variations to test.
    3776      */
    3777     public function test_sanitize_with_invalid_style_variation( $theme_json_variations ) {
    3778         $theme_json = new WP_Theme_JSON(
    3779             array(
    3780                 'version' => 2,
    3781                 'styles'  => array(
    3782                     'blocks' => array(
    3783                         'core/quote' => $theme_json_variations,
    3784                     ),
    3785                 ),
    3786             )
    3787         );
    3788 
    3789         // Validate structure is sanitized.
    3790         $sanitized_theme_json = $theme_json->get_raw_data();
    3791         $this->assertIsArray( $sanitized_theme_json, 'Sanitized theme.json is not an array data type' );
    3792         $this->assertArrayNotHasKey( 'styles', $sanitized_theme_json, 'Sanitized theme.json should not have a "styles" key' );
    3793     }
    3794 
    3795     /**
    3796      * Data provider.
    3797      *
    3798      * @return array
    3799      */
    3800     public function data_sanitize_with_invalid_style_variation() {
    3801         return array(
    3802             'empty string variation' => array(
    3803                 array(
    3804                     'variations' => '',
    3805                 ),
    3806             ),
    3807             'boolean variation'      => array(
    3808                 array(
    3809                     'variations' => false,
    3810                 ),
    3811             ),
    3812         );
    3813     }
    3814 
    3815     /**
    3816      * @ticket 57583
    3817      *
    3818      * @dataProvider data_get_styles_for_block_with_style_variations
    3819      *
    3820      * @param array  $theme_json_variations Theme.json variations to test.
    3821      * @param string $metadata_variations   Style variations to test.
    3822      * @param string $expected              Expected results for styling.
    3823      */
    3824     public function test_get_styles_for_block_with_style_variations( $theme_json_variations, $metadata_variations, $expected ) {
    3825         $theme_json = new WP_Theme_JSON(
    3826             array(
    3827                 'version' => 2,
    3828                 'styles'  => array(
    3829                     'blocks' => array(
    3830                         'core/quote' => $theme_json_variations,
    3831                     ),
    3832                 ),
    3833             )
    3834         );
    3835 
    3836         // Validate styles are generated properly.
    3837         $metadata      = array(
    3838             'path'       => array( 'styles', 'blocks', 'core/quote' ),
    3839             'selector'   => '.wp-block-quote',
    3840             'variations' => $metadata_variations,
    3841         );
    3842         $actual_styles = $theme_json->get_styles_for_block( $metadata );
    3843         $this->assertSame( $expected, $actual_styles );
    3844     }
    3845 
    3846     /**
    3847      * Data provider.
    3848      *
    3849      * @return array
    3850      */
    3851     public function data_get_styles_for_block_with_style_variations() {
    3852         $plain = array(
    3853             'metadata' => array(
    3854                 'path'     => array( 'styles', 'blocks', 'core/quote', 'variations', 'plain' ),
    3855                 'selector' => '.is-style-plain.is-style-plain.wp-block-quote',
    3856             ),
    3857             'styles'   => '.is-style-plain.is-style-plain.wp-block-quote{background-color: hotpink;}',
    3858         );
    3859 
    3860         return array(
    3861             '1 variation with 1 invalid property'   => array(
    3862                 'theme_json_variations' => array(
    3863                     'variations' => array(
    3864                         'plain' => array(
    3865                             'color' => array(
    3866                                 'background' => 'hotpink',
    3867                             ),
    3868                         ),
    3869                     ),
    3870                 ),
    3871                 'metadata_variation'    => array( $plain['metadata'] ),
    3872                 'expected'              => $plain['styles'],
    3873             ),
    3874             '1 variation with 2 invalid properties' => array(
    3875                 'theme_json_variations' => array(
    3876                     'variations' => array(
    3877                         'plain' => array(
    3878                             'color'            => array(
    3879                                 'background' => 'hotpink',
    3880                             ),
    3881                             'invalidProperty1' => 'value1',
    3882                             'invalidProperty2' => 'value2',
    3883                         ),
    3884                     ),
    3885                 ),
    3886                 'metadata_variation'    => array( $plain['metadata'] ),
    3887                 'expected'              => $plain['styles'],
    3888             ),
    3889         );
    3890     }
    3891 
    3892     public function test_block_style_variations() {
    3893         wp_set_current_user( static::$administrator_id );
    3894 
    3895         $expected = array(
    3896             'version' => WP_Theme_JSON::LATEST_SCHEMA,
    3897             'styles'  => array(
    3898                 'blocks' => array(
    3899                     'core/button' => array(
    3900                         'color'      => array(
    3901                             'background' => 'blue',
    3902                         ),
    3903                         'variations' => array(
    3904                             'outline' => array(
    3905                                 'color' => array(
    3906                                     'background' => 'purple',
    3907                                 ),
    3908                             ),
    3909                         ),
    3910                     ),
    3911                 ),
    3912             ),
    3913         );
    3914 
    3915         $actual = WP_Theme_JSON::remove_insecure_properties( $expected );
    3916 
    3917         $this->assertSameSetsWithIndex( $expected, $actual );
    3918     }
    3919 
    3920     public function test_block_style_variations_with_invalid_properties() {
    3921         wp_set_current_user( static::$administrator_id );
    3922 
    3923         $partially_invalid_variation = array(
    3924             'version' => WP_Theme_JSON::LATEST_SCHEMA,
    3925             'styles'  => array(
    3926                 'blocks' => array(
    3927                     'core/button' => array(
    3928                         'color'      => array(
    3929                             'background' => 'blue',
    3930                         ),
    3931                         'variations' => array(
    3932                             'outline' => array(
    3933                                 'color'   => array(
    3934                                     'background' => 'purple',
    3935                                 ),
    3936                                 'invalid' => array(
    3937                                     'value' => 'should be stripped',
    3938                                 ),
    3939                             ),
    3940                         ),
    3941                     ),
    3942                 ),
    3943             ),
    3944         );
    3945 
    3946         $expected = array(
    3947             'version' => WP_Theme_JSON::LATEST_SCHEMA,
    3948             'styles'  => array(
    3949                 'blocks' => array(
    3950                     'core/button' => array(
    3951                         'color'      => array(
    3952                             'background' => 'blue',
    3953                         ),
    3954                         'variations' => array(
    3955                             'outline' => array(
    3956                                 'color' => array(
    3957                                     'background' => 'purple',
    3958                                 ),
    3959                             ),
    3960                         ),
    3961                     ),
    3962                 ),
    3963             ),
    3964         );
    3965 
    3966         $actual = WP_Theme_JSON::remove_insecure_properties( $partially_invalid_variation );
    3967 
    3968         $this->assertSameSetsWithIndex( $expected, $actual );
    3969     }
    3970 
    3971     /**
    3972      * @ticket 56611
    3973      * @ticket 58548
    3974      * @ticket 58550
    3975      */
    3976     public function test_get_styles_with_appearance_tools() {
    3977         $theme_json = new WP_Theme_JSON(
    3978             array(
    3979                 'version'  => 2,
    3980                 'settings' => array(
    3981                     'appearanceTools' => true,
    3982                 ),
    3983             )
    3984         );
    3985 
    3986         $metadata = array(
    3987             'path'     => array( 'settings' ),
    3988             'selector' => 'body',
    3989         );
    3990 
    3991         $expected   = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: ; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child:first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child:last-child { margin-block-end: 0; }body { --wp--style--block-gap: ; }:where(body .is-layout-flow)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-flow)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-flow)  > *{margin-block-start: 1;margin-block-end: 0;}:where(body .is-layout-constrained)  > :first-child:first-child{margin-block-start: 0;}:where(body .is-layout-constrained)  > :last-child:last-child{margin-block-end: 0;}:where(body .is-layout-constrained)  > *{margin-block-start: 1;margin-block-end: 0;}:where(body .is-layout-flex) {gap: 1;}:where(body .is-layout-grid) {gap: 1;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
    3992         $root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata );
    3993         $this->assertSame( $expected, $root_rules );
    3994     }
    3995 
    3996     /**
    3997      * Tests generating the spacing presets array based on the spacing scale provided.
    3998      *
    3999      * @ticket 56467
    4000      *
    4001      * @dataProvider data_generate_spacing_scale_fixtures
    4002      *
    4003      * @param array $spacing_scale   Example spacing scale definitions from the data provider.
    4004      * @param array $expected_output Expected output from data provider.
    4005      */
    4006     public function test_should_set_spacing_sizes( $spacing_scale, $expected_output ) {
    4007         $theme_json = new WP_Theme_JSON(
    4008             array(
    4009                 'version'  => 2,
    4010                 'settings' => array(
    4011                     'spacing' => array(
    4012                         'spacingScale' => $spacing_scale,
    4013                     ),
    4014                 ),
    4015             )
    4016         );
    4017 
    4018         $theme_json->set_spacing_sizes();
    4019         $this->assertSame( $expected_output, _wp_array_get( $theme_json->get_raw_data(), array( 'settings', 'spacing', 'spacingSizes', 'default' ) ) );
    4020     }
    4021 
    4022     /**
    4023      * Data provider for spacing scale tests.
    4024      *
    4025      * @ticket 56467
    4026      *
    4027      * @return array
    4028      */
    4029     public function data_generate_spacing_scale_fixtures() {
    4030         return array(
    4031             'only one value when single step in spacing scale' => array(
    4032                 'spacing_scale'   => array(
    4033                     'operator'   => '+',
    4034                     'increment'  => 1.5,
    4035                     'steps'      => 1,
    4036                     'mediumStep' => 4,
    4037                     'unit'       => 'rem',
    4038                 ),
    4039                 'expected_output' => array(
    4040                     array(
    4041                         'name' => '1',
    4042                         'slug' => '50',
    4043                         'size' => '4rem',
    4044                     ),
    4045                 ),
    4046             ),
    4047             'one step above medium when two steps in spacing scale' => array(
    4048                 'spacing_scale'   => array(
    4049                     'operator'   => '+',
    4050                     'increment'  => 1.5,
    4051                     'steps'      => 2,
    4052                     'mediumStep' => 4,
    4053                     'unit'       => 'rem',
    4054                 ),
    4055                 'expected_output' => array(
    4056                     array(
    4057                         'name' => '1',
    4058                         'slug' => '50',
    4059                         'size' => '4rem',
    4060                     ),
    4061                     array(
    4062                         'name' => '2',
    4063                         'slug' => '60',
    4064                         'size' => '5.5rem',
    4065                     ),
    4066                 ),
    4067             ),
    4068             'one step above medium and one below when three steps in spacing scale' => array(
    4069                 'spacing_scale'   => array(
    4070                     'operator'   => '+',
    4071                     'increment'  => 1.5,
    4072                     'steps'      => 3,
    4073                     'mediumStep' => 4,
    4074                     'unit'       => 'rem',
    4075                 ),
    4076                 'expected_output' => array(
    4077                     array(
    4078                         'name' => '1',
    4079                         'slug' => '40',
    4080                         'size' => '2.5rem',
    4081                     ),
    4082                     array(
    4083                         'name' => '2',
    4084                         'slug' => '50',
    4085                         'size' => '4rem',
    4086                     ),
    4087                     array(
    4088                         'name' => '3',
    4089                         'slug' => '60',
    4090                         'size' => '5.5rem',
    4091                     ),
    4092                 ),
    4093             ),
    4094             'extra step added above medium when an even number of steps > 2 specified' => array(
    4095                 'spacing_scale'   => array(
    4096                     'operator'   => '+',
    4097                     'increment'  => 1.5,
    4098                     'steps'      => 4,
    4099                     'mediumStep' => 4,
    4100                     'unit'       => 'rem',
    4101                 ),
    4102                 'expected_output' => array(
    4103                     array(
    4104                         'name' => '1',
    4105                         'slug' => '40',
    4106                         'size' => '2.5rem',
    4107                     ),
    4108                     array(
    4109                         'name' => '2',
    4110                         'slug' => '50',
    4111                         'size' => '4rem',
    4112                     ),
    4113                     array(
    4114                         'name' => '3',
    4115                         'slug' => '60',
    4116                         'size' => '5.5rem',
    4117                     ),
    4118                     array(
    4119                         'name' => '4',
    4120                         'slug' => '70',
    4121                         'size' => '7rem',
    4122                     ),
    4123                 ),
    4124             ),
    4125             'extra steps above medium if bottom end will go below zero' => array(
    4126                 'spacing_scale'   => array(
    4127                     'operator'   => '+',
    4128                     'increment'  => 2.5,
    4129                     'steps'      => 5,
    4130                     'mediumStep' => 5,
    4131                     'unit'       => 'rem',
    4132                 ),
    4133                 'expected_output' => array(
    4134                     array(
    4135                         'name' => '1',
    4136                         'slug' => '40',
    4137                         'size' => '2.5rem',
    4138                     ),
    4139                     array(
    4140                         'name' => '2',
    4141                         'slug' => '50',
    4142                         'size' => '5rem',
    4143                     ),
    4144                     array(
    4145                         'name' => '3',
    4146                         'slug' => '60',
    4147                         'size' => '7.5rem',
    4148                     ),
    4149                     array(
    4150                         'name' => '4',
    4151                         'slug' => '70',
    4152                         'size' => '10rem',
    4153                     ),
    4154                     array(
    4155                         'name' => '5',
    4156                         'slug' => '80',
    4157                         'size' => '12.5rem',
    4158                     ),
    4159                 ),
    4160             ),
    4161             'multiplier correctly calculated above and below medium' => array(
    4162                 'spacing_scale'   => array(
    4163                     'operator'   => '*',
    4164                     'increment'  => 1.5,
    4165                     'steps'      => 5,
    4166                     'mediumStep' => 1.5,
    4167                     'unit'       => 'rem',
    4168                 ),
    4169                 'expected_output' => array(
    4170                     array(
    4171                         'name' => '1',
    4172                         'slug' => '30',
    4173                         'size' => '0.67rem',
    4174                     ),
    4175                     array(
    4176                         'name' => '2',
    4177                         'slug' => '40',
    4178                         'size' => '1rem',
    4179                     ),
    4180                     array(
    4181                         'name' => '3',
    4182                         'slug' => '50',
    4183                         'size' => '1.5rem',
    4184                     ),
    4185                     array(
    4186                         'name' => '4',
    4187                         'slug' => '60',
    4188                         'size' => '2.25rem',
    4189                     ),
    4190                     array(
    4191                         'name' => '5',
    4192                         'slug' => '70',
    4193                         'size' => '3.38rem',
    4194                     ),
    4195                 ),
    4196             ),
    4197             'increment < 1 combined showing * operator acting as divisor above and below medium' => array(
    4198                 'spacing_scale'   => array(
    4199                     'operator'   => '*',
    4200                     'increment'  => 0.25,
    4201                     'steps'      => 5,
    4202                     'mediumStep' => 1.5,
    4203                     'unit'       => 'rem',
    4204                 ),
    4205                 'expected_output' => array(
    4206                     array(
    4207                         'name' => '1',
    4208                         'slug' => '30',
    4209                         'size' => '0.09rem',
    4210                     ),
    4211                     array(
    4212                         'name' => '2',
    4213                         'slug' => '40',
    4214                         'size' => '0.38rem',
    4215                     ),
    4216                     array(
    4217                         'name' => '3',
    4218                         'slug' => '50',
    4219                         'size' => '1.5rem',
    4220                     ),
    4221                     array(
    4222                         'name' => '4',
    4223                         'slug' => '60',
    4224                         'size' => '6rem',
    4225                     ),
    4226                     array(
    4227                         'name' => '5',
    4228                         'slug' => '70',
    4229                         'size' => '24rem',
    4230                     ),
    4231                 ),
    4232             ),
    4233             't-shirt sizing used if more than 7 steps in scale' => array(
    4234                 'spacing_scale'   => array(
    4235                     'operator'   => '*',
    4236                     'increment'  => 1.5,
    4237                     'steps'      => 8,
    4238                     'mediumStep' => 1.5,
    4239                     'unit'       => 'rem',
    4240                 ),
    4241                 'expected_output' => array(
    4242                     array(
    4243                         'name' => '2X-Small',
    4244                         'slug' => '20',
    4245                         'size' => '0.44rem',
    4246                     ),
    4247                     array(
    4248                         'name' => 'X-Small',
    4249                         'slug' => '30',
    4250                         'size' => '0.67rem',
    4251                     ),
    4252                     array(
    4253                         'name' => 'Small',
    4254                         'slug' => '40',
    4255                         'size' => '1rem',
    4256                     ),
    4257                     array(
    4258                         'name' => 'Medium',
    4259                         'slug' => '50',
    4260                         'size' => '1.5rem',
    4261                     ),
    4262                     array(
    4263                         'name' => 'Large',
    4264                         'slug' => '60',
    4265                         'size' => '2.25rem',
    4266                     ),
    4267                     array(
    4268                         'name' => 'X-Large',
    4269                         'slug' => '70',
    4270                         'size' => '3.38rem',
    4271                     ),
    4272                     array(
    4273                         'name' => '2X-Large',
    4274                         'slug' => '80',
    4275                         'size' => '5.06rem',
    4276                     ),
    4277                     array(
    4278                         'name' => '3X-Large',
    4279                         'slug' => '90',
    4280                         'size' => '7.59rem',
    4281                     ),
    4282                 ),
    4283             ),
    4284         );
    4285     }
    4286 
    4287     /**
    4288      * Tests generating the spacing presets array based on the spacing scale provided.
    4289      *
    4290      * @ticket 56467
    4291      *
    4292      * @dataProvider data_set_spacing_sizes_when_invalid
    4293      *
    4294      * @param array $spacing_scale   Example spacing scale definitions from the data provider.
    4295      * @param array $expected_output Expected output from data provider.
    4296      */
    4297     public function test_set_spacing_sizes_should_detect_invalid_spacing_scale( $spacing_scale, $expected_output ) {
    4298         $this->expectException( Exception::class );
    4299         $this->expectExceptionMessage( 'Some of the theme.json settings.spacing.spacingScale values are invalid' );
    4300 
    4301         $theme_json = new WP_Theme_JSON(
    4302             array(
    4303                 'version'  => 2,
    4304                 'settings' => array(
    4305                     'spacing' => array(
    4306                         'spacingScale' => $spacing_scale,
    4307                     ),
    4308                 ),
    4309             )
    4310         );
    4311 
    4312         // Ensure PHPUnit 10 compatibility.
    4313         set_error_handler(
    4314             static function ( $errno, $errstr ) {
    4315                 restore_error_handler();
    4316                 throw new Exception( $errstr, $errno );
    4317             },
    4318             E_ALL
    4319         );
    4320 
    4321         $theme_json->set_spacing_sizes();
    4322 
    4323         restore_error_handler();
    4324 
    4325         $this->assertSame( $expected_output, _wp_array_get( $theme_json->get_raw_data(), array( 'settings', 'spacing', 'spacingSizes', 'default' ) ) );
    4326     }
    4327 
    4328     /**
    4329      * Data provider for spacing scale tests.
    4330      *
    4331      * @ticket 56467
    4332      *
    4333      * @return array
    4334      */
    4335     public function data_set_spacing_sizes_when_invalid() {
    4336         return array(
    4337             'missing operator value'  => array(
    4338                 'spacing_scale'   => array(
    4339                     'operator'   => '',
    4340                     'increment'  => 1.5,
    4341                     'steps'      => 1,
    4342                     'mediumStep' => 4,
    4343                     'unit'       => 'rem',
    4344                 ),
    4345                 'expected_output' => null,
    4346             ),
    4347             'non numeric increment'   => array(
    4348                 'spacing_scale'   => array(
    4349                     'operator'   => '+',
    4350                     'increment'  => 'add two to previous value',
    4351                     'steps'      => 1,
    4352                     'mediumStep' => 4,
    4353                     'unit'       => 'rem',
    4354                 ),
    4355                 'expected_output' => null,
    4356             ),
    4357             'non numeric steps'       => array(
    4358                 'spacing_scale'   => array(
    4359                     'operator'   => '+',
    4360                     'increment'  => 1.5,
    4361                     'steps'      => 'spiral staircase preferred',
    4362                     'mediumStep' => 4,
    4363                     'unit'       => 'rem',
    4364                 ),
    4365                 'expected_output' => null,
    4366             ),
    4367             'non numeric medium step' => array(
    4368                 'spacing_scale'   => array(
    4369                     'operator'   => '+',
    4370                     'increment'  => 1.5,
    4371                     'steps'      => 5,
    4372                     'mediumStep' => 'That which is just right',
    4373                     'unit'       => 'rem',
    4374                 ),
    4375                 'expected_output' => null,
    4376             ),
    4377             'missing unit value'      => array(
    4378                 'spacing_scale'   => array(
    4379                     'operator'   => '+',
    4380                     'increment'  => 1.5,
    4381                     'steps'      => 5,
    4382                     'mediumStep' => 4,
    4383                 ),
    4384                 'expected_output' => null,
    4385             ),
    4386         );
    4387     }
    4388 
    4389     /**
    4390      * Tests the core separator block outbut based on various provided settings.
    4391      *
    4392      * @ticket 56903
    4393      * @ticket 58550
    4394      *
    4395      * @dataProvider data_update_separator_declarations
    4396      *
    4397      * @param array $separator_block_settings Example separator block settings from the data provider.
    4398      * @param array $expected_output          Expected output from data provider.
    4399      */
    4400     public function test_update_separator_declarations( $separator_block_settings, $expected_output ) {
    4401         // If only background is defined, test that includes border-color to the style so it is applied on the front end.
    4402         $theme_json = new WP_Theme_JSON(
    4403             array(
    4404                 'version' => WP_Theme_JSON::LATEST_SCHEMA,
    4405                 'styles'  => array(
    4406                     'blocks' => array(
    4407                         'core/separator' => $separator_block_settings,
    4408                     ),
    4409                 ),
    4410             ),
    4411             'default'
    4412         );
    4413 
    4414         $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) );
    4415 
    4416         $this->assertSame( $expected_output, $stylesheet );
    4417     }
    4418 
    4419     /**
    4420      * Data provider for separator declaration tests.
    4421      *
    4422      * @return array
    4423      */
    4424     public function data_update_separator_declarations() {
    4425         return array(
    4426             // If only background is defined, test that includes border-color to the style so it is applied on the front end.
    4427             'only background'                      => array(
    4428                 array(
    4429                     'color' => array(
    4430                         'background' => 'blue',
    4431                     ),
    4432                 ),
    4433                 'expected_output' => 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-separator{background-color: blue;color: blue;}',
    4434             ),
    4435             // If background and text are defined, do not include border-color, as text color is enough.
    4436             'background and text, no border-color' => array(
    4437                 array(
    4438                     'color' => array(
    4439                         'background' => 'blue',
    4440                         'text'       => 'red',
    4441                     ),
    4442                 ),
    4443                 'expected_output' => 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-separator{background-color: blue;color: red;}',
    4444             ),
    4445             // If only text is defined, do not include border-color, as by itself is enough.
    4446             'only text'                            => array(
    4447                 array(
    4448                     'color' => array(
    4449                         'text' => 'red',
    4450                     ),
    4451                 ),
    4452                 'expected_output' => 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-separator{color: red;}',
    4453             ),
    4454             // If background, text, and border-color are defined, include everything, CSS specificity will decide which to apply.
    4455             'background, text, and border-color'   => array(
    4456                 array(
    4457                     'color'  => array(
    4458                         'background' => 'blue',
    4459                         'text'       => 'red',
    4460                     ),
    4461                     'border' => array(
    4462                         'color' => 'pink',
    4463                     ),
    4464                 ),
    4465                 'expected_output' => 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-separator{background-color: blue;border-color: pink;color: red;}',
    4466             ),
    4467             // If background and border color are defined, include everything, CSS specificity will decide which to apply.
    4468             'background, and border-color'         => array(
    4469                 array(
    4470                     'color'  => array(
    4471                         'background' => 'blue',
    4472                     ),
    4473                     'border' => array(
    4474                         'color' => 'pink',
    4475                     ),
    4476                 ),
    4477                 'expected_output' => 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-separator{background-color: blue;border-color: pink;}',
    4478             ),
    4479         );
    4480     }
    4481 
    4482     /**
    4483      * @ticket 57354
    4484      * @ticket 58550
    4485      */
    4486     public function test_get_stylesheet_returns_outline_styles() {
    4487         $theme_json = new WP_Theme_JSON(
    4488             array(
    4489                 'version' => WP_Theme_JSON::LATEST_SCHEMA,
    4490                 'styles'  => array(
    4491                     'elements' => array(
    4492                         'button' => array(
    4493                             'outline' => array(
    4494                                 'offset' => '3px',
    4495                                 'width'  => '3px',
    4496                                 'style'  => 'dashed',
    4497                                 'color'  => 'red',
    4498                             ),
    4499                             ':hover'  => array(
    4500                                 'outline' => array(
    4501                                     'offset' => '3px',
    4502                                     'width'  => '3px',
    4503                                     'style'  => 'solid',
    4504                                     'color'  => 'blue',
    4505                                 ),
    4506                             ),
    4507                         ),
    4508                     ),
    4509                 ),
    4510             )
    4511         );
    4512 
    4513         $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
    4514 
    4515         $element_styles = '.wp-element-button, .wp-block-button__link{outline-color: red;outline-offset: 3px;outline-style: dashed;outline-width: 3px;}.wp-element-button:hover, .wp-block-button__link:hover{outline-color: blue;outline-offset: 3px;outline-style: solid;outline-width: 3px;}';
    4516 
    4517         $expected = $base_styles . $element_styles;
    4518         $this->assertSame( $expected, $theme_json->get_stylesheet() );
    4519     }
    4520 
    4521     /**
    4522      * @ticket 57559
    4523      */
    4524     public function test_shadow_preset_styles() {
    4525         $theme_json = new WP_Theme_JSON(
    4526             array(
    4527                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    4528                 'settings' => array(
    4529                     'shadow' => array(
    4530                         'presets' => array(
    4531                             array(
    4532                                 'slug'   => 'natural',
    4533                                 'shadow' => '5px 5px 5px 0 black',
    4534                             ),
    4535                             array(
    4536                                 'slug'   => 'sharp',
    4537                                 'shadow' => '5px 5px black',
    4538                             ),
    4539                         ),
    4540                     ),
    4541                 ),
    4542             )
    4543         );
    4544 
    4545         $expected_styles = 'body{--wp--preset--shadow--natural: 5px 5px 5px 0 black;--wp--preset--shadow--sharp: 5px 5px black;}';
    4546         $this->assertSame( $expected_styles, $theme_json->get_stylesheet(), 'Styles returned from "::get_stylesheet()" does not match expectations' );
    4547         $this->assertSame( $expected_styles, $theme_json->get_stylesheet( array( 'variables' ) ), 'Styles returned from "::get_stylesheet()" when requiring "variables" type does not match expectations' );
    4548     }
    4549 
    4550     /**
    4551      * @ticket 57559
    4552      * @ticket 58550
    4553      */
    4554     public function test_get_shadow_styles_for_blocks() {
    4555         $theme_json = new WP_Theme_JSON(
    4556             array(
    4557                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    4558                 'settings' => array(
    4559                     'shadow' => array(
    4560                         'presets' => array(
    4561                             array(
    4562                                 'slug'   => 'natural',
    4563                                 'shadow' => '5px 5px 0 0 black',
    4564                             ),
    4565                         ),
    4566                     ),
    4567                 ),
    4568                 'styles'   => array(
    4569                     'blocks'   => array(
    4570                         'core/paragraph' => array(
    4571                             'shadow' => 'var(--wp--preset--shadow--natural)',
    4572                         ),
    4573                     ),
    4574                     'elements' => array(
    4575                         'button' => array(
    4576                             'shadow' => 'var:preset|shadow|natural',
    4577                         ),
    4578                         'link'   => array(
    4579                             'shadow' => array( 'ref' => 'styles.elements.button.shadow' ),
    4580                         ),
    4581                     ),
    4582                 ),
    4583             )
    4584         );
    4585 
    4586         $global_styles   = 'body{--wp--preset--shadow--natural: 5px 5px 0 0 black;}body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
    4587         $element_styles  = 'a:where(:not(.wp-element-button)){box-shadow: var(--wp--preset--shadow--natural);}.wp-element-button, .wp-block-button__link{box-shadow: var(--wp--preset--shadow--natural);}p{box-shadow: var(--wp--preset--shadow--natural);}';
    4588         $expected_styles = $global_styles . $element_styles;
    4589 
    4590         $this->assertSame( $expected_styles, $theme_json->get_stylesheet() );
    4591     }
    4592 
    4593     /**
    4594      * @ticket 57536
    4595      */
    4596     public function test_get_custom_css_handles_global_custom_css() {
    4597         $theme_json = new WP_Theme_JSON(
    4598             array(
    4599                 'version' => WP_Theme_JSON::LATEST_SCHEMA,
    4600                 'styles'  => array(
    4601                     'css' => 'body { color:purple; }',
    4602                 ),
    4603             )
    4604         );
    4605         $custom_css = 'body { color:purple; }';
    4606         $this->assertSame( $custom_css, $theme_json->get_custom_css() );
    4607     }
    4608 
    4609     /**
    4610      * Tests that custom CSS is kept for users with correct capabilities and removed for others.
    4611      *
    4612      * @ticket 57536
    4613      *
    4614      * @dataProvider data_custom_css_for_user_caps
    4615      *
    4616      * @param string $user_property The property name for current user.
    4617      * @param array  $expected      Expected results.
    4618      */
    4619     public function test_custom_css_for_user_caps( $user_property, array $expected ) {
    4620         wp_set_current_user( static::${$user_property} );
    4621 
    4622         $actual = WP_Theme_JSON::remove_insecure_properties(
    4623             array(
    4624                 'version' => WP_Theme_JSON::LATEST_SCHEMA,
    4625                 'styles'  => array(
    4626                     'css'    => 'body { color:purple; }',
    4627                     'blocks' => array(
    4628                         'core/separator' => array(
    4629                             'color' => array(
    4630                                 'background' => 'blue',
    4631                             ),
    4632                         ),
    4633                     ),
    4634                 ),
    4635             )
    4636         );
    4637 
    4638         $this->assertSameSetsWithIndex( $expected, $actual );
    4639     }
    4640 
    4641     /**
    4642      * Data provider.
    4643      *
    4644      * @return array[]
    4645      */
    4646     public function data_custom_css_for_user_caps() {
    4647         return array(
    4648             'allows custom css for users with caps'     => array(
    4649                 'user_property' => 'administrator_id',
    4650                 'expected'      => array(
    4651                     'version' => WP_Theme_JSON::LATEST_SCHEMA,
    4652                     'styles'  => array(
    4653                         'css'    => 'body { color:purple; }',
    4654                         'blocks' => array(
    4655                             'core/separator' => array(
    4656                                 'color' => array(
    4657                                     'background' => 'blue',
    4658                                 ),
    4659                             ),
    4660                         ),
    4661                     ),
    4662                 ),
    4663             ),
    4664             'removes custom css for users without caps' => array(
    4665                 'user_property' => 'user_id',
    4666                 'expected'      => array(
    4667                     'version' => WP_Theme_JSON::LATEST_SCHEMA,
    4668                     'styles'  => array(
    4669                         'blocks' => array(
    4670                             'core/separator' => array(
    4671                                 'color' => array(
    4672                                     'background' => 'blue',
    4673                                 ),
    4674                             ),
    4675                         ),
    4676                     ),
    4677                 ),
    4678             ),
    4679         );
    4680     }
    4681 
    4682     /**
    4683      * @dataProvider data_process_blocks_custom_css
    4684      *
    4685      * @param array  $input    An array containing the selector and css to test.
    4686      * @param string $expected Expected results.
    4687      */
    4688     public function test_process_blocks_custom_css( $input, $expected ) {
    4689         $theme_json = new WP_Theme_JSON(
    4690             array(
    4691                 'version' => WP_Theme_JSON::LATEST_SCHEMA,
    4692                 'styles'  => array(),
    4693             )
    4694         );
    4695         $reflection = new ReflectionMethod( $theme_json, 'process_blocks_custom_css' );
    4696         $reflection->setAccessible( true );
    4697 
    4698         $this->assertSame( $expected, $reflection->invoke( $theme_json, $input['css'], $input['selector'] ) );
    4699     }
    4700 
    4701     /**
    4702      * Data provider.
    4703      *
    4704      * @return array[]
    4705      */
    4706     public function data_process_blocks_custom_css() {
    4707         return array(
    4708             // Simple CSS without any nested selectors.
    4709             'no nested selectors'          => array(
    4710                 'input'    => array(
    4711                     'selector' => '.foo',
    4712                     'css'      => 'color: red; margin: auto;',
    4713                 ),
    4714                 'expected' => '.foo{color: red; margin: auto;}',
    4715             ),
    4716             // CSS with nested selectors.
    4717             'with nested selector'         => array(
    4718                 'input'    => array(
    4719                     'selector' => '.foo',
    4720                     'css'      => 'color: red; margin: auto; &.one{color: blue;} & .two{color: green;}',
    4721                 ),
    4722                 'expected' => '.foo{color: red; margin: auto;}.foo.one{color: blue;}.foo .two{color: green;}',
    4723             ),
    4724             // CSS with pseudo elements.
    4725             'with pseudo elements'         => array(
    4726                 'input'    => array(
    4727                     'selector' => '.foo',
    4728                     'css'      => 'color: red; margin: auto; &::before{color: blue;} & ::before{color: green;}  &.one::before{color: yellow;} & .two::before{color: purple;}',
    4729                 ),
    4730                 'expected' => '.foo{color: red; margin: auto;}.foo::before{color: blue;}.foo ::before{color: green;}.foo.one::before{color: yellow;}.foo .two::before{color: purple;}',
    4731             ),
    4732             // CSS with multiple root selectors.
    4733             'with multiple root selectors' => array(
    4734                 'input'    => array(
    4735                     'selector' => '.foo, .bar',
    4736                     'css'      => 'color: red; margin: auto; &.one{color: blue;} & .two{color: green;} &::before{color: yellow;} & ::before{color: purple;}  &.three::before{color: orange;} & .four::before{color: skyblue;}',
    4737                 ),
    4738                 'expected' => '.foo, .bar{color: red; margin: auto;}.foo.one, .bar.one{color: blue;}.foo .two, .bar .two{color: green;}.foo::before, .bar::before{color: yellow;}.foo ::before, .bar ::before{color: purple;}.foo.three::before, .bar.three::before{color: orange;}.foo .four::before, .bar .four::before{color: skyblue;}',
    4739             ),
    4740         );
    4741     }
    4742 
    4743     public function test_internal_syntax_is_converted_to_css_variables() {
    4744         $result = new WP_Theme_JSON(
    4745             array(
    4746                 'version' => WP_Theme_JSON::LATEST_SCHEMA,
    4747                 'styles'  => array(
    4748                     'color'    => array(
    4749                         'background' => 'var:preset|color|primary',
    4750                         'text'       => 'var(--wp--preset--color--secondary)',
    4751                     ),
    4752                     'elements' => array(
    4753                         'link' => array(
    4754                             'color' => array(
    4755                                 'background' => 'var:preset|color|pri',
    4756                                 'text'       => 'var(--wp--preset--color--sec)',
    4757                             ),
    4758                         ),
    4759                     ),
    4760                     'blocks'   => array(
    4761                         'core/post-terms' => array(
    4762                             'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--small)' ),
    4763                             'color'      => array( 'background' => 'var:preset|color|secondary' ),
    4764                         ),
    4765                         'core/navigation' => array(
    4766                             'elements' => array(
    4767                                 'link' => array(
    4768                                     'color' => array(
    4769                                         'background' => 'var:preset|color|p',
    4770                                         'text'       => 'var(--wp--preset--color--s)',
    4771                                     ),
    4772                                 ),
    4773                             ),
    4774                         ),
    4775                         'core/quote'      => array(
    4776                             'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--d)' ),
    4777                             'color'      => array( 'background' => 'var:preset|color|d' ),
    4778                             'variations' => array(
    4779                                 'plain' => array(
    4780                                     'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--s)' ),
    4781                                     'color'      => array( 'background' => 'var:preset|color|s' ),
    4782                                 ),
    4783                             ),
    4784                         ),
    4785                     ),
    4786                 ),
    4787             )
    4788         );
    4789         $styles = $result->get_raw_data()['styles'];
    4790 
    4791         $this->assertEquals( 'var(--wp--preset--color--primary)', $styles['color']['background'], 'Top level: Assert the originally correct values are still correct.' );
    4792         $this->assertEquals( 'var(--wp--preset--color--secondary)', $styles['color']['text'], 'Top level: Assert the originally correct values are still correct.' );
    4793 
    4794         $this->assertEquals( 'var(--wp--preset--color--pri)', $styles['elements']['link']['color']['background'], 'Element top level: Assert the originally correct values are still correct.' );
    4795         $this->assertEquals( 'var(--wp--preset--color--sec)', $styles['elements']['link']['color']['text'], 'Element top level: Assert the originally correct values are still correct.' );
    4796 
    4797         $this->assertEquals( 'var(--wp--preset--font-size--small)', $styles['blocks']['core/post-terms']['typography']['fontSize'], 'Top block level: Assert the originally correct values are still correct.' );
    4798         $this->assertEquals( 'var(--wp--preset--color--secondary)', $styles['blocks']['core/post-terms']['color']['background'], 'Top block level: Assert the internal variables are convert to CSS custom variables.' );
    4799 
    4800         $this->assertEquals( 'var(--wp--preset--color--p)', $styles['blocks']['core/navigation']['elements']['link']['color']['background'], 'Elements block level: Assert the originally correct values are still correct.' );
    4801         $this->assertEquals( 'var(--wp--preset--color--s)', $styles['blocks']['core/navigation']['elements']['link']['color']['text'], 'Elements block level: Assert the originally correct values are still correct.' );
    4802 
    4803         $this->assertEquals( 'var(--wp--preset--font-size--s)', $styles['blocks']['core/quote']['variations']['plain']['typography']['fontSize'], 'Style variations: Assert the originally correct values are still correct.' );
    4804         $this->assertEquals( 'var(--wp--preset--color--s)', $styles['blocks']['core/quote']['variations']['plain']['color']['background'], 'Style variations: Assert the internal variables are convert to CSS custom variables.' );
    4805     }
    4806 
    4807     public function test_resolve_variables() {
    4808         $primary_color   = '#9DFF20';
    4809         $secondary_color = '#9DFF21';
    4810         $contrast_color  = '#000';
    4811         $raw_color_value = '#efefef';
    4812         $large_font      = '18px';
    4813         $small_font      = '12px';
    4814         $theme_json      = new WP_Theme_JSON(
    4815             array(
    4816                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    4817                 'settings' => array(
    4818                     'color'      => array(
    4819                         'palette' => array(
    4820                             'theme' => array(
    4821                                 array(
    4822                                     'color' => $primary_color,
    4823                                     'name'  => 'Primary',
    4824                                     'slug'  => 'primary',
    4825                                 ),
    4826                                 array(
    4827                                     'color' => $secondary_color,
    4828                                     'name'  => 'Secondary',
    4829                                     'slug'  => 'secondary',
    4830                                 ),
    4831                                 array(
    4832                                     'color' => $contrast_color,
    4833                                     'name'  => 'Contrast',
    4834                                     'slug'  => 'contrast',
    4835                                 ),
    4836                             ),
    4837                         ),
    4838                     ),
    4839                     'typography' => array(
    4840                         'fontSizes' => array(
    4841                             array(
    4842                                 'size' => $small_font,
    4843                                 'name' => 'Font size small',
    4844                                 'slug' => 'small',
    4845                             ),
    4846                             array(
    4847                                 'size' => $large_font,
    4848                                 'name' => 'Font size large',
    4849                                 'slug' => 'large',
    4850                             ),
    4851                         ),
    4852                     ),
    4853                 ),
    4854                 'styles'   => array(
    4855                     'color'    => array(
    4856                         'background' => 'var(--wp--preset--color--primary)',
    4857                         'text'       => $raw_color_value,
    4858                     ),
    4859                     'elements' => array(
    4860                         'button' => array(
    4861                             'color'      => array(
    4862                                 'text' => 'var(--wp--preset--color--contrast)',
    4863                             ),
    4864                             'typography' => array(
    4865                                 'fontSize' => 'var(--wp--preset--font-size--small)',
    4866                             ),
    4867                         ),
    4868                     ),
    4869                     'blocks'   => array(
    4870                         'core/post-terms'      => array(
    4871                             'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--small)' ),
    4872                             'color'      => array( 'background' => $raw_color_value ),
    4873                         ),
    4874                         'core/more'            => array(
    4875                             'typography' => array( 'fontSize' => 'var(--undefined--font-size--small)' ),
    4876                             'color'      => array( 'background' => 'linear-gradient(90deg, var(--wp--preset--color--primary) 0%, var(--wp--preset--color--secondary) 35%, var(--wp--undefined--color--secondary) 100%)' ),
    4877                         ),
    4878                         'core/comment-content' => array(
    4879                             'typography' => array( 'fontSize' => 'calc(var(--wp--preset--font-size--small, 12px) + 20px)' ),
    4880                             'color'      => array(
    4881                                 'text'       => 'var(--wp--preset--color--primary, red)',
    4882                                 'background' => 'var(--wp--preset--color--primary, var(--wp--preset--font-size--secondary))',
    4883                                 'link'       => 'var(--undefined--color--primary, var(--wp--preset--font-size--secondary))',
    4884                             ),
    4885                         ),
    4886                         'core/comments'        => array(
    4887                             'color' => array(
    4888                                 'text'       => 'var(--undefined--color--primary, var(--wp--preset--font-size--small))',
    4889                                 'background' => 'var(--wp--preset--color--primary, var(--undefined--color--primary))',
    4890                             ),
    4891                         ),
    4892                         'core/navigation'      => array(
    4893                             'elements' => array(
    4894                                 'link' => array(
    4895                                     'color'      => array(
    4896                                         'background' => 'var(--wp--preset--color--primary)',
    4897                                         'text'       => 'var(--wp--preset--color--secondary)',
    4898                                     ),
    4899                                     'typography' => array(
    4900                                         'fontSize' => 'var(--wp--preset--font-size--large)',
    4901                                     ),
    4902                                 ),
    4903                             ),
    4904                         ),
    4905                         'core/quote'           => array(
    4906                             'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--large)' ),
    4907                             'color'      => array( 'background' => 'var(--wp--preset--color--primary)' ),
    4908                             'variations' => array(
    4909                                 'plain' => array(
    4910                                     'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--small)' ),
    4911                                     'color'      => array( 'background' => 'var(--wp--preset--color--secondary)' ),
    4912                                 ),
    4913                             ),
    4914                         ),
    4915                     ),
    4916                 ),
    4917             )
    4918         );
    4919 
    4920         $styles = $theme_json::resolve_variables( $theme_json )->get_raw_data()['styles'];
    4921 
    4922         $this->assertEquals( $primary_color, $styles['color']['background'], 'Top level: Assert values are converted' );
    4923         $this->assertEquals( $raw_color_value, $styles['color']['text'], 'Top level: Assert raw values stay intact' );
    4924 
    4925         $this->assertEquals( $contrast_color, $styles['elements']['button']['color']['text'], 'Elements: color' );
    4926         $this->assertEquals( $small_font, $styles['elements']['button']['typography']['fontSize'], 'Elements: font-size' );
    4927 
    4928         $this->assertEquals( $large_font, $styles['blocks']['core/quote']['typography']['fontSize'], 'Blocks: font-size' );
    4929         $this->assertEquals( $primary_color, $styles['blocks']['core/quote']['color']['background'], 'Blocks: color' );
    4930         $this->assertEquals( $raw_color_value, $styles['blocks']['core/post-terms']['color']['background'], 'Blocks: Raw color value stays intact' );
    4931         $this->assertEquals( $small_font, $styles['blocks']['core/post-terms']['typography']['fontSize'], 'Block core/post-terms: font-size' );
    4932         $this->assertEquals(
    4933             "linear-gradient(90deg, $primary_color 0%, $secondary_color 35%, var(--wp--undefined--color--secondary) 100%)",
    4934             $styles['blocks']['core/more']['color']['background'],
    4935             'Blocks: multiple colors and undefined color'
    4936         );
    4937         $this->assertEquals( 'var(--undefined--font-size--small)', $styles['blocks']['core/more']['typography']['fontSize'], 'Blocks: undefined font-size ' );
    4938         $this->assertEquals( "calc($small_font + 20px)", $styles['blocks']['core/comment-content']['typography']['fontSize'], 'Blocks: font-size in random place' );
    4939         $this->assertEquals( $primary_color, $styles['blocks']['core/comment-content']['color']['text'], 'Blocks: text color with fallback' );
    4940         $this->assertEquals( $primary_color, $styles['blocks']['core/comment-content']['color']['background'], 'Blocks: background color with var as fallback' );
    4941         $this->assertEquals( $primary_color, $styles['blocks']['core/navigation']['elements']['link']['color']['background'], 'Block element: background color' );
    4942         $this->assertEquals( $secondary_color, $styles['blocks']['core/navigation']['elements']['link']['color']['text'], 'Block element: text color' );
    4943         $this->assertEquals( $large_font, $styles['blocks']['core/navigation']['elements']['link']['typography']['fontSize'], 'Block element: font-size' );
    4944 
    4945         $this->assertEquals(
    4946             "var(--undefined--color--primary, $small_font)",
    4947             $styles['blocks']['core/comments']['color']['text'],
    4948             'Blocks: text color with undefined var and fallback'
    4949         );
    4950         $this->assertEquals(
    4951             $primary_color,
    4952             $styles['blocks']['core/comments']['color']['background'],
    4953             'Blocks: background color with variable and undefined fallback'
    4954         );
    4955 
    4956         $this->assertEquals( $small_font, $styles['blocks']['core/quote']['variations']['plain']['typography']['fontSize'], 'Block variations: font-size' );
    4957         $this->assertEquals( $secondary_color, $styles['blocks']['core/quote']['variations']['plain']['color']['background'], 'Block variations: color' );
    4958     }
    4959 
    4960     /**
    4961      * Tests that a custom root selector is correctly applied when generating a stylesheet.
    4962      *
    4963      * @ticket 60343
    4964      */
    4965     public function test_get_stylesheet_custom_root_selector() {
    4966         $theme_json = new WP_Theme_JSON(
    4967             array(
    4968                 'version' => WP_Theme_JSON::LATEST_SCHEMA,
    4969                 'styles'  => array(
    4970                     'color' => array(
    4971                         'text' => 'teal',
    4972                     ),
    4973                 ),
    4974             ),
    4975             'default'
    4976         );
    4977 
    4978         $options = array( 'root_selector' => '.custom' );
    4979         $actual  = $theme_json->get_stylesheet( array( 'styles' ), null, $options );
    4980 
    4981         // Results also include root site blocks styles which hard code
    4982         // `body { margin: 0;}`.
    4983         $this->assertEquals(
    4984             'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.custom{color: teal;}',
    4985             $actual
    49863982        );
    49873983    }
     
    51234119
    51244120    /**
     4121     * @ticket 57583
     4122     *
     4123     * @dataProvider data_sanitize_with_invalid_style_variation
     4124     *
     4125     * @param array $theme_json_variations The theme.json variations to test.
     4126     */
     4127    public function test_sanitize_with_invalid_style_variation( $theme_json_variations ) {
     4128        $theme_json = new WP_Theme_JSON(
     4129            array(
     4130                'version' => 2,
     4131                'styles'  => array(
     4132                    'blocks' => array(
     4133                        'core/quote' => $theme_json_variations,
     4134                    ),
     4135                ),
     4136            )
     4137        );
     4138
     4139        // Validate structure is sanitized.
     4140        $sanitized_theme_json = $theme_json->get_raw_data();
     4141        $this->assertIsArray( $sanitized_theme_json, 'Sanitized theme.json is not an array data type' );
     4142        $this->assertArrayNotHasKey( 'styles', $sanitized_theme_json, 'Sanitized theme.json should not have a "styles" key' );
     4143    }
     4144
     4145    /**
     4146     * Data provider.
     4147     *
     4148     * @return array
     4149     */
     4150    public function data_sanitize_with_invalid_style_variation() {
     4151        return array(
     4152            'empty string variation' => array(
     4153                array(
     4154                    'variations' => '',
     4155                ),
     4156            ),
     4157            'boolean variation'      => array(
     4158                array(
     4159                    'variations' => false,
     4160                ),
     4161            ),
     4162        );
     4163    }
     4164
     4165    /**
     4166     * @ticket 57583
     4167     *
     4168     * @dataProvider data_get_styles_for_block_with_style_variations
     4169     *
     4170     * @param array  $theme_json_variations Theme.json variations to test.
     4171     * @param string $metadata_variations   Style variations to test.
     4172     * @param string $expected              Expected results for styling.
     4173     */
     4174    public function test_get_styles_for_block_with_style_variations( $theme_json_variations, $metadata_variations, $expected ) {
     4175        $theme_json = new WP_Theme_JSON(
     4176            array(
     4177                'version' => 2,
     4178                'styles'  => array(
     4179                    'blocks' => array(
     4180                        'core/quote' => $theme_json_variations,
     4181                    ),
     4182                ),
     4183            )
     4184        );
     4185
     4186        // Validate styles are generated properly.
     4187        $metadata      = array(
     4188            'path'       => array( 'styles', 'blocks', 'core/quote' ),
     4189            'selector'   => '.wp-block-quote',
     4190            'variations' => $metadata_variations,
     4191        );
     4192        $actual_styles = $theme_json->get_styles_for_block( $metadata );
     4193        $this->assertSame( $expected, $actual_styles );
     4194    }
     4195
     4196    /**
     4197     * Data provider.
     4198     *
     4199     * @return array
     4200     */
     4201    public function data_get_styles_for_block_with_style_variations() {
     4202        $plain = array(
     4203            'metadata' => array(
     4204                'path'     => array( 'styles', 'blocks', 'core/quote', 'variations', 'plain' ),
     4205                'selector' => '.is-style-plain.is-style-plain.wp-block-quote',
     4206            ),
     4207            'styles'   => '.is-style-plain.is-style-plain.wp-block-quote{background-color: hotpink;}',
     4208        );
     4209
     4210        return array(
     4211            '1 variation with 1 invalid property'   => array(
     4212                'theme_json_variations' => array(
     4213                    'variations' => array(
     4214                        'plain' => array(
     4215                            'color' => array(
     4216                                'background' => 'hotpink',
     4217                            ),
     4218                        ),
     4219                    ),
     4220                ),
     4221                'metadata_variation'    => array( $plain['metadata'] ),
     4222                'expected'              => $plain['styles'],
     4223            ),
     4224            '1 variation with 2 invalid properties' => array(
     4225                'theme_json_variations' => array(
     4226                    'variations' => array(
     4227                        'plain' => array(
     4228                            'color'            => array(
     4229                                'background' => 'hotpink',
     4230                            ),
     4231                            'invalidProperty1' => 'value1',
     4232                            'invalidProperty2' => 'value2',
     4233                        ),
     4234                    ),
     4235                ),
     4236                'metadata_variation'    => array( $plain['metadata'] ),
     4237                'expected'              => $plain['styles'],
     4238            ),
     4239        );
     4240    }
     4241
     4242    public function test_block_style_variations() {
     4243        wp_set_current_user( static::$administrator_id );
     4244
     4245        $expected = array(
     4246            'version' => WP_Theme_JSON::LATEST_SCHEMA,
     4247            'styles'  => array(
     4248                'blocks' => array(
     4249                    'core/button' => array(
     4250                        'color'      => array(
     4251                            'background' => 'blue',
     4252                        ),
     4253                        'variations' => array(
     4254                            'outline' => array(
     4255                                'color' => array(
     4256                                    'background' => 'purple',
     4257                                ),
     4258                            ),
     4259                        ),
     4260                    ),
     4261                ),
     4262            ),
     4263        );
     4264
     4265        $actual = WP_Theme_JSON::remove_insecure_properties( $expected );
     4266
     4267        $this->assertSameSetsWithIndex( $expected, $actual );
     4268    }
     4269
     4270    public function test_block_style_variations_with_invalid_properties() {
     4271        wp_set_current_user( static::$administrator_id );
     4272
     4273        $partially_invalid_variation = array(
     4274            'version' => WP_Theme_JSON::LATEST_SCHEMA,
     4275            'styles'  => array(
     4276                'blocks' => array(
     4277                    'core/button' => array(
     4278                        'color'      => array(
     4279                            'background' => 'blue',
     4280                        ),
     4281                        'variations' => array(
     4282                            'outline' => array(
     4283                                'color'   => array(
     4284                                    'background' => 'purple',
     4285                                ),
     4286                                'invalid' => array(
     4287                                    'value' => 'should be stripped',
     4288                                ),
     4289                            ),
     4290                        ),
     4291                    ),
     4292                ),
     4293            ),
     4294        );
     4295
     4296        $expected = array(
     4297            'version' => WP_Theme_JSON::LATEST_SCHEMA,
     4298            'styles'  => array(
     4299                'blocks' => array(
     4300                    'core/button' => array(
     4301                        'color'      => array(
     4302                            'background' => 'blue',
     4303                        ),
     4304                        'variations' => array(
     4305                            'outline' => array(
     4306                                'color' => array(
     4307                                    'background' => 'purple',
     4308                                ),
     4309                            ),
     4310                        ),
     4311                    ),
     4312                ),
     4313            ),
     4314        );
     4315
     4316        $actual = WP_Theme_JSON::remove_insecure_properties( $partially_invalid_variation );
     4317
     4318        $this->assertSameSetsWithIndex( $expected, $actual );
     4319    }
     4320
     4321    /**
     4322     * Tests generating the spacing presets array based on the spacing scale provided.
     4323     *
     4324     * @ticket 56467
     4325     *
     4326     * @dataProvider data_set_spacing_sizes
     4327     */
     4328    public function test_set_spacing_sizes( $spacing_scale, $expected_output ) {
     4329        $theme_json = new WP_Theme_JSON(
     4330            array(
     4331                'version'  => 2,
     4332                'settings' => array(
     4333                    'spacing' => array(
     4334                        'spacingScale' => $spacing_scale,
     4335                    ),
     4336                ),
     4337            )
     4338        );
     4339
     4340        $theme_json->set_spacing_sizes();
     4341        $this->assertSame( $expected_output, _wp_array_get( $theme_json->get_raw_data(), array( 'settings', 'spacing', 'spacingSizes', 'default' ) ) );
     4342    }
     4343
     4344    /**
     4345     * Data provider for spacing scale tests.
     4346     *
     4347     * @ticket 56467
     4348     *
     4349     * @return array
     4350     */
     4351    public function data_set_spacing_sizes() {
     4352        return array(
     4353            'only one value when single step in spacing scale' => array(
     4354                'spacing_scale'   => array(
     4355                    'operator'   => '+',
     4356                    'increment'  => 1.5,
     4357                    'steps'      => 1,
     4358                    'mediumStep' => 4,
     4359                    'unit'       => 'rem',
     4360                ),
     4361                'expected_output' => array(
     4362                    array(
     4363                        'name' => '1',
     4364                        'slug' => '50',
     4365                        'size' => '4rem',
     4366                    ),
     4367                ),
     4368            ),
     4369            'one step above medium when two steps in spacing scale' => array(
     4370                'spacing_scale'   => array(
     4371                    'operator'   => '+',
     4372                    'increment'  => 1.5,
     4373                    'steps'      => 2,
     4374                    'mediumStep' => 4,
     4375                    'unit'       => 'rem',
     4376                ),
     4377                'expected_output' => array(
     4378                    array(
     4379                        'name' => '1',
     4380                        'slug' => '50',
     4381                        'size' => '4rem',
     4382                    ),
     4383                    array(
     4384                        'name' => '2',
     4385                        'slug' => '60',
     4386                        'size' => '5.5rem',
     4387                    ),
     4388                ),
     4389            ),
     4390            'one step above medium and one below when three steps in spacing scale' => array(
     4391                'spacing_scale'   => array(
     4392                    'operator'   => '+',
     4393                    'increment'  => 1.5,
     4394                    'steps'      => 3,
     4395                    'mediumStep' => 4,
     4396                    'unit'       => 'rem',
     4397                ),
     4398                'expected_output' => array(
     4399                    array(
     4400                        'name' => '1',
     4401                        'slug' => '40',
     4402                        'size' => '2.5rem',
     4403                    ),
     4404                    array(
     4405                        'name' => '2',
     4406                        'slug' => '50',
     4407                        'size' => '4rem',
     4408                    ),
     4409                    array(
     4410                        'name' => '3',
     4411                        'slug' => '60',
     4412                        'size' => '5.5rem',
     4413                    ),
     4414                ),
     4415            ),
     4416            'extra step added above medium when an even number of steps > 2 specified' => array(
     4417                'spacing_scale'   => array(
     4418                    'operator'   => '+',
     4419                    'increment'  => 1.5,
     4420                    'steps'      => 4,
     4421                    'mediumStep' => 4,
     4422                    'unit'       => 'rem',
     4423                ),
     4424                'expected_output' => array(
     4425                    array(
     4426                        'name' => '1',
     4427                        'slug' => '40',
     4428                        'size' => '2.5rem',
     4429                    ),
     4430                    array(
     4431                        'name' => '2',
     4432                        'slug' => '50',
     4433                        'size' => '4rem',
     4434                    ),
     4435                    array(
     4436                        'name' => '3',
     4437                        'slug' => '60',
     4438                        'size' => '5.5rem',
     4439                    ),
     4440                    array(
     4441                        'name' => '4',
     4442                        'slug' => '70',
     4443                        'size' => '7rem',
     4444                    ),
     4445                ),
     4446            ),
     4447            'extra steps above medium if bottom end will go below zero' => array(
     4448                'spacing_scale'   => array(
     4449                    'operator'   => '+',
     4450                    'increment'  => 2.5,
     4451                    'steps'      => 5,
     4452                    'mediumStep' => 5,
     4453                    'unit'       => 'rem',
     4454                ),
     4455                'expected_output' => array(
     4456                    array(
     4457                        'name' => '1',
     4458                        'slug' => '40',
     4459                        'size' => '2.5rem',
     4460                    ),
     4461                    array(
     4462                        'name' => '2',
     4463                        'slug' => '50',
     4464                        'size' => '5rem',
     4465                    ),
     4466                    array(
     4467                        'name' => '3',
     4468                        'slug' => '60',
     4469                        'size' => '7.5rem',
     4470                    ),
     4471                    array(
     4472                        'name' => '4',
     4473                        'slug' => '70',
     4474                        'size' => '10rem',
     4475                    ),
     4476                    array(
     4477                        'name' => '5',
     4478                        'slug' => '80',
     4479                        'size' => '12.5rem',
     4480                    ),
     4481                ),
     4482            ),
     4483            'multiplier correctly calculated above and below medium' => array(
     4484                'spacing_scale'   => array(
     4485                    'operator'   => '*',
     4486                    'increment'  => 1.5,
     4487                    'steps'      => 5,
     4488                    'mediumStep' => 1.5,
     4489                    'unit'       => 'rem',
     4490                ),
     4491                'expected_output' => array(
     4492                    array(
     4493                        'name' => '1',
     4494                        'slug' => '30',
     4495                        'size' => '0.67rem',
     4496                    ),
     4497                    array(
     4498                        'name' => '2',
     4499                        'slug' => '40',
     4500                        'size' => '1rem',
     4501                    ),
     4502                    array(
     4503                        'name' => '3',
     4504                        'slug' => '50',
     4505                        'size' => '1.5rem',
     4506                    ),
     4507                    array(
     4508                        'name' => '4',
     4509                        'slug' => '60',
     4510                        'size' => '2.25rem',
     4511                    ),
     4512                    array(
     4513                        'name' => '5',
     4514                        'slug' => '70',
     4515                        'size' => '3.38rem',
     4516                    ),
     4517                ),
     4518            ),
     4519            'increment < 1 combined showing * operator acting as divisor above and below medium' => array(
     4520                'spacing_scale'   => array(
     4521                    'operator'   => '*',
     4522                    'increment'  => 0.25,
     4523                    'steps'      => 5,
     4524                    'mediumStep' => 1.5,
     4525                    'unit'       => 'rem',
     4526                ),
     4527                'expected_output' => array(
     4528                    array(
     4529                        'name' => '1',
     4530                        'slug' => '30',
     4531                        'size' => '0.09rem',
     4532                    ),
     4533                    array(
     4534                        'name' => '2',
     4535                        'slug' => '40',
     4536                        'size' => '0.38rem',
     4537                    ),
     4538                    array(
     4539                        'name' => '3',
     4540                        'slug' => '50',
     4541                        'size' => '1.5rem',
     4542                    ),
     4543                    array(
     4544                        'name' => '4',
     4545                        'slug' => '60',
     4546                        'size' => '6rem',
     4547                    ),
     4548                    array(
     4549                        'name' => '5',
     4550                        'slug' => '70',
     4551                        'size' => '24rem',
     4552                    ),
     4553                ),
     4554            ),
     4555            't-shirt sizing used if more than 7 steps in scale' => array(
     4556                'spacing_scale'   => array(
     4557                    'operator'   => '*',
     4558                    'increment'  => 1.5,
     4559                    'steps'      => 8,
     4560                    'mediumStep' => 1.5,
     4561                    'unit'       => 'rem',
     4562                ),
     4563                'expected_output' => array(
     4564                    array(
     4565                        'name' => '2X-Small',
     4566                        'slug' => '20',
     4567                        'size' => '0.44rem',
     4568                    ),
     4569                    array(
     4570                        'name' => 'X-Small',
     4571                        'slug' => '30',
     4572                        'size' => '0.67rem',
     4573                    ),
     4574                    array(
     4575                        'name' => 'Small',
     4576                        'slug' => '40',
     4577                        'size' => '1rem',
     4578                    ),
     4579                    array(
     4580                        'name' => 'Medium',
     4581                        'slug' => '50',
     4582                        'size' => '1.5rem',
     4583                    ),
     4584                    array(
     4585                        'name' => 'Large',
     4586                        'slug' => '60',
     4587                        'size' => '2.25rem',
     4588                    ),
     4589                    array(
     4590                        'name' => 'X-Large',
     4591                        'slug' => '70',
     4592                        'size' => '3.38rem',
     4593                    ),
     4594                    array(
     4595                        'name' => '2X-Large',
     4596                        'slug' => '80',
     4597                        'size' => '5.06rem',
     4598                    ),
     4599                    array(
     4600                        'name' => '3X-Large',
     4601                        'slug' => '90',
     4602                        'size' => '7.59rem',
     4603                    ),
     4604                ),
     4605            ),
     4606        );
     4607    }
     4608
     4609    /**
     4610     * Tests generating the spacing presets array based on the spacing scale provided.
     4611     *
     4612     * @ticket 56467
     4613     *
     4614     * @dataProvider data_set_spacing_sizes_when_invalid
     4615     *
     4616     * @param array $spacing_scale   Example spacing scale definitions from the data provider.
     4617     * @param array $expected_output Expected output from data provider.
     4618     */
     4619    public function test_set_spacing_sizes_when_invalid( $spacing_scale, $expected_output ) {
     4620        $this->expectException( Exception::class );
     4621        $this->expectExceptionMessage( 'Some of the theme.json settings.spacing.spacingScale values are invalid' );
     4622
     4623        $theme_json = new WP_Theme_JSON(
     4624            array(
     4625                'version'  => 2,
     4626                'settings' => array(
     4627                    'spacing' => array(
     4628                        'spacingScale' => $spacing_scale,
     4629                    ),
     4630                ),
     4631            )
     4632        );
     4633
     4634        // Ensure PHPUnit 10 compatibility.
     4635        set_error_handler(
     4636            static function ( $errno, $errstr ) {
     4637                restore_error_handler();
     4638                throw new Exception( $errstr, $errno );
     4639            },
     4640            E_ALL
     4641        );
     4642
     4643        $theme_json->set_spacing_sizes();
     4644
     4645        restore_error_handler();
     4646
     4647        $this->assertSame( $expected_output, _wp_array_get( $theme_json->get_raw_data(), array( 'settings', 'spacing', 'spacingSizes', 'default' ) ) );
     4648    }
     4649
     4650    /**
     4651     * Data provider for spacing scale tests.
     4652     *
     4653     * @ticket 56467
     4654     *
     4655     * @return array
     4656     */
     4657    public function data_set_spacing_sizes_when_invalid() {
     4658        return array(
     4659            'missing operator value'  => array(
     4660                'spacing_scale'   => array(
     4661                    'operator'   => '',
     4662                    'increment'  => 1.5,
     4663                    'steps'      => 1,
     4664                    'mediumStep' => 4,
     4665                    'unit'       => 'rem',
     4666                ),
     4667                'expected_output' => null,
     4668            ),
     4669            'non numeric increment'   => array(
     4670                'spacing_scale'   => array(
     4671                    'operator'   => '+',
     4672                    'increment'  => 'add two to previous value',
     4673                    'steps'      => 1,
     4674                    'mediumStep' => 4,
     4675                    'unit'       => 'rem',
     4676                ),
     4677                'expected_output' => null,
     4678            ),
     4679            'non numeric steps'       => array(
     4680                'spacing_scale'   => array(
     4681                    'operator'   => '+',
     4682                    'increment'  => 1.5,
     4683                    'steps'      => 'spiral staircase preferred',
     4684                    'mediumStep' => 4,
     4685                    'unit'       => 'rem',
     4686                ),
     4687                'expected_output' => null,
     4688            ),
     4689            'non numeric medium step' => array(
     4690                'spacing_scale'   => array(
     4691                    'operator'   => '+',
     4692                    'increment'  => 1.5,
     4693                    'steps'      => 5,
     4694                    'mediumStep' => 'That which is just right',
     4695                    'unit'       => 'rem',
     4696                ),
     4697                'expected_output' => null,
     4698            ),
     4699            'missing unit value'      => array(
     4700                'spacing_scale'   => array(
     4701                    'operator'   => '+',
     4702                    'increment'  => 1.5,
     4703                    'steps'      => 5,
     4704                    'mediumStep' => 4,
     4705                ),
     4706                'expected_output' => null,
     4707            ),
     4708        );
     4709    }
     4710
     4711    /**
     4712     * Tests the core separator block outbut based on various provided settings.
     4713     *
     4714     * @ticket 56903
     4715     * @ticket 58550
     4716     *
     4717     * @dataProvider data_update_separator_declarations
     4718     *
     4719     * @param array $separator_block_settings Example separator block settings from the data provider.
     4720     * @param array $expected_output          Expected output from data provider.
     4721     */
     4722    public function test_update_separator_declarations( $separator_block_settings, $expected_output ) {
     4723        // If only background is defined, test that includes border-color to the style so it is applied on the front end.
     4724        $theme_json = new WP_Theme_JSON(
     4725            array(
     4726                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     4727                'styles'  => array(
     4728                    'blocks' => array(
     4729                        'core/separator' => $separator_block_settings,
     4730                    ),
     4731                ),
     4732            ),
     4733            'default'
     4734        );
     4735
     4736        $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) );
     4737
     4738        $this->assertSame( $expected_output, $stylesheet );
     4739    }
     4740
     4741    /**
     4742     * Data provider for separator declaration tests.
     4743     *
     4744     * @return array
     4745     */
     4746    public function data_update_separator_declarations() {
     4747        return array(
     4748            // If only background is defined, test that includes border-color to the style so it is applied on the front end.
     4749            'only background'                      => array(
     4750                array(
     4751                    'color' => array(
     4752                        'background' => 'blue',
     4753                    ),
     4754                ),
     4755                'expected_output' => 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-separator{background-color: blue;color: blue;}',
     4756            ),
     4757            // If background and text are defined, do not include border-color, as text color is enough.
     4758            'background and text, no border-color' => array(
     4759                array(
     4760                    'color' => array(
     4761                        'background' => 'blue',
     4762                        'text'       => 'red',
     4763                    ),
     4764                ),
     4765                'expected_output' => 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-separator{background-color: blue;color: red;}',
     4766            ),
     4767            // If only text is defined, do not include border-color, as by itself is enough.
     4768            'only text'                            => array(
     4769                array(
     4770                    'color' => array(
     4771                        'text' => 'red',
     4772                    ),
     4773                ),
     4774                'expected_output' => 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-separator{color: red;}',
     4775            ),
     4776            // If background, text, and border-color are defined, include everything, CSS specificity will decide which to apply.
     4777            'background, text, and border-color'   => array(
     4778                array(
     4779                    'color'  => array(
     4780                        'background' => 'blue',
     4781                        'text'       => 'red',
     4782                    ),
     4783                    'border' => array(
     4784                        'color' => 'pink',
     4785                    ),
     4786                ),
     4787                'expected_output' => 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-separator{background-color: blue;border-color: pink;color: red;}',
     4788            ),
     4789            // If background and border color are defined, include everything, CSS specificity will decide which to apply.
     4790            'background, and border-color'         => array(
     4791                array(
     4792                    'color'  => array(
     4793                        'background' => 'blue',
     4794                    ),
     4795                    'border' => array(
     4796                        'color' => 'pink',
     4797                    ),
     4798                ),
     4799                'expected_output' => 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}.wp-block-separator{background-color: blue;border-color: pink;}',
     4800            ),
     4801        );
     4802    }
     4803
     4804    /**
     4805     * @ticket 57559
     4806     */
     4807    public function test_shadow_preset_styles() {
     4808        $theme_json = new WP_Theme_JSON(
     4809            array(
     4810                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     4811                'settings' => array(
     4812                    'shadow' => array(
     4813                        'presets' => array(
     4814                            array(
     4815                                'slug'   => 'natural',
     4816                                'shadow' => '5px 5px 5px 0 black',
     4817                            ),
     4818                            array(
     4819                                'slug'   => 'sharp',
     4820                                'shadow' => '5px 5px black',
     4821                            ),
     4822                        ),
     4823                    ),
     4824                ),
     4825            )
     4826        );
     4827
     4828        $expected_styles = 'body{--wp--preset--shadow--natural: 5px 5px 5px 0 black;--wp--preset--shadow--sharp: 5px 5px black;}';
     4829        $this->assertSame( $expected_styles, $theme_json->get_stylesheet(), 'Styles returned from "::get_stylesheet()" does not match expectations' );
     4830        $this->assertSame( $expected_styles, $theme_json->get_stylesheet( array( 'variables' ) ), 'Styles returned from "::get_stylesheet()" when requiring "variables" type does not match expectations' );
     4831    }
     4832
     4833    /**
     4834     * @ticket 57559
     4835     * @ticket 58550
     4836     */
     4837    public function test_get_shadow_styles_for_blocks() {
     4838        $theme_json = new WP_Theme_JSON(
     4839            array(
     4840                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     4841                'settings' => array(
     4842                    'shadow' => array(
     4843                        'presets' => array(
     4844                            array(
     4845                                'slug'   => 'natural',
     4846                                'shadow' => '5px 5px 0 0 black',
     4847                            ),
     4848                        ),
     4849                    ),
     4850                ),
     4851                'styles'   => array(
     4852                    'blocks'   => array(
     4853                        'core/paragraph' => array(
     4854                            'shadow' => 'var(--wp--preset--shadow--natural)',
     4855                        ),
     4856                    ),
     4857                    'elements' => array(
     4858                        'button' => array(
     4859                            'shadow' => 'var:preset|shadow|natural',
     4860                        ),
     4861                        'link'   => array(
     4862                            'shadow' => array( 'ref' => 'styles.elements.button.shadow' ),
     4863                        ),
     4864                    ),
     4865                ),
     4866            )
     4867        );
     4868
     4869        $global_styles   = 'body{--wp--preset--shadow--natural: 5px 5px 0 0 black;}body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}';
     4870        $element_styles  = 'a:where(:not(.wp-element-button)){box-shadow: var(--wp--preset--shadow--natural);}.wp-element-button, .wp-block-button__link{box-shadow: var(--wp--preset--shadow--natural);}p{box-shadow: var(--wp--preset--shadow--natural);}';
     4871        $expected_styles = $global_styles . $element_styles;
     4872        $this->assertSame( $expected_styles, $theme_json->get_stylesheet() );
     4873    }
     4874
     4875    /**
     4876     * @ticket 57536
     4877     */
     4878    public function test_get_custom_css_handles_global_custom_css() {
     4879        $theme_json = new WP_Theme_JSON(
     4880            array(
     4881                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     4882                'styles'  => array(
     4883                    'css'    => 'body {color:purple;}',
     4884                    'blocks' => array(
     4885                        'core/paragraph' => array(
     4886                            'css' => 'color:red;',
     4887                        ),
     4888                    ),
     4889                ),
     4890            )
     4891        );
     4892
     4893        $custom_css = 'body {color:purple;}p{color:red;}';
     4894        $this->assertSame( $custom_css, $theme_json->get_custom_css() );
     4895    }
     4896
     4897    /**
     4898     * Tests that custom CSS is kept for users with correct capabilities and removed for others.
     4899     *
     4900     * @ticket 57536
     4901     *
     4902     * @dataProvider data_custom_css_for_user_caps
     4903     *
     4904     * @param string $user_property The property name for current user.
     4905     * @param array  $expected      Expected results.
     4906     */
     4907    public function test_custom_css_for_user_caps( $user_property, array $expected ) {
     4908        wp_set_current_user( static::${$user_property} );
     4909
     4910        $actual = WP_Theme_JSON::remove_insecure_properties(
     4911            array(
     4912                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     4913                'styles'  => array(
     4914                    'css'    => 'body { color:purple; }',
     4915                    'blocks' => array(
     4916                        'core/separator' => array(
     4917                            'color' => array(
     4918                                'background' => 'blue',
     4919                            ),
     4920                        ),
     4921                    ),
     4922                ),
     4923            )
     4924        );
     4925
     4926        $this->assertSameSetsWithIndex( $expected, $actual );
     4927    }
     4928
     4929    /**
     4930     * Data provider.
     4931     *
     4932     * @return array[]
     4933     */
     4934    public function data_custom_css_for_user_caps() {
     4935        return array(
     4936            'allows custom css for users with caps'     => array(
     4937                'user_property' => 'administrator_id',
     4938                'expected'      => array(
     4939                    'version' => WP_Theme_JSON::LATEST_SCHEMA,
     4940                    'styles'  => array(
     4941                        'css'    => 'body { color:purple; }',
     4942                        'blocks' => array(
     4943                            'core/separator' => array(
     4944                                'color' => array(
     4945                                    'background' => 'blue',
     4946                                ),
     4947                            ),
     4948                        ),
     4949                    ),
     4950                ),
     4951            ),
     4952            'removes custom css for users without caps' => array(
     4953                'user_property' => 'user_id',
     4954                'expected'      => array(
     4955                    'version' => WP_Theme_JSON::LATEST_SCHEMA,
     4956                    'styles'  => array(
     4957                        'blocks' => array(
     4958                            'core/separator' => array(
     4959                                'color' => array(
     4960                                    'background' => 'blue',
     4961                                ),
     4962                            ),
     4963                        ),
     4964                    ),
     4965                ),
     4966            ),
     4967        );
     4968    }
     4969
     4970    /**
     4971     * @dataProvider data_process_blocks_custom_css
     4972     *
     4973     * @param array  $input    An array containing the selector and css to test.
     4974     * @param string $expected Expected results.
     4975     */
     4976    public function test_process_blocks_custom_css( $input, $expected ) {
     4977        $theme_json = new WP_Theme_JSON(
     4978            array(
     4979                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     4980                'styles'  => array(),
     4981            )
     4982        );
     4983        $reflection = new ReflectionMethod( $theme_json, 'process_blocks_custom_css' );
     4984        $reflection->setAccessible( true );
     4985
     4986        $this->assertSame( $expected, $reflection->invoke( $theme_json, $input['css'], $input['selector'] ) );
     4987    }
     4988
     4989    /**
     4990     * Data provider.
     4991     *
     4992     * @return array[]
     4993     */
     4994    public function data_process_blocks_custom_css() {
     4995        return array(
     4996            // Simple CSS without any nested selectors.
     4997            'no nested selectors'          => array(
     4998                'input'    => array(
     4999                    'selector' => '.foo',
     5000                    'css'      => 'color: red; margin: auto;',
     5001                ),
     5002                'expected' => '.foo{color: red; margin: auto;}',
     5003            ),
     5004            // CSS with nested selectors.
     5005            'with nested selector'         => array(
     5006                'input'    => array(
     5007                    'selector' => '.foo',
     5008                    'css'      => 'color: red; margin: auto; &.one{color: blue;} & .two{color: green;}',
     5009                ),
     5010                'expected' => '.foo{color: red; margin: auto;}.foo.one{color: blue;}.foo .two{color: green;}',
     5011            ),
     5012            // CSS with pseudo elements.
     5013            'with pseudo elements'         => array(
     5014                'input'    => array(
     5015                    'selector' => '.foo',
     5016                    'css'      => 'color: red; margin: auto; &::before{color: blue;} & ::before{color: green;}  &.one::before{color: yellow;} & .two::before{color: purple;}',
     5017                ),
     5018                'expected' => '.foo{color: red; margin: auto;}.foo::before{color: blue;}.foo ::before{color: green;}.foo.one::before{color: yellow;}.foo .two::before{color: purple;}',
     5019            ),
     5020            // CSS with multiple root selectors.
     5021            'with multiple root selectors' => array(
     5022                'input'    => array(
     5023                    'selector' => '.foo, .bar',
     5024                    'css'      => 'color: red; margin: auto; &.one{color: blue;} & .two{color: green;} &::before{color: yellow;} & ::before{color: purple;}  &.three::before{color: orange;} & .four::before{color: skyblue;}',
     5025                ),
     5026                'expected' => '.foo, .bar{color: red; margin: auto;}.foo.one, .bar.one{color: blue;}.foo .two, .bar .two{color: green;}.foo::before, .bar::before{color: yellow;}.foo ::before, .bar ::before{color: purple;}.foo.three::before, .bar.three::before{color: orange;}.foo .four::before, .bar .four::before{color: skyblue;}',
     5027            ),
     5028        );
     5029    }
     5030
     5031    public function test_internal_syntax_is_converted_to_css_variables() {
     5032        $result = new WP_Theme_JSON(
     5033            array(
     5034                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     5035                'styles'  => array(
     5036                    'color'    => array(
     5037                        'background' => 'var:preset|color|primary',
     5038                        'text'       => 'var(--wp--preset--color--secondary)',
     5039                    ),
     5040                    'elements' => array(
     5041                        'link' => array(
     5042                            'color' => array(
     5043                                'background' => 'var:preset|color|pri',
     5044                                'text'       => 'var(--wp--preset--color--sec)',
     5045                            ),
     5046                        ),
     5047                    ),
     5048                    'blocks'   => array(
     5049                        'core/post-terms' => array(
     5050                            'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--small)' ),
     5051                            'color'      => array( 'background' => 'var:preset|color|secondary' ),
     5052                        ),
     5053                        'core/navigation' => array(
     5054                            'elements' => array(
     5055                                'link' => array(
     5056                                    'color' => array(
     5057                                        'background' => 'var:preset|color|p',
     5058                                        'text'       => 'var(--wp--preset--color--s)',
     5059                                    ),
     5060                                ),
     5061                            ),
     5062                        ),
     5063                        'core/quote'      => array(
     5064                            'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--d)' ),
     5065                            'color'      => array( 'background' => 'var:preset|color|d' ),
     5066                            'variations' => array(
     5067                                'plain' => array(
     5068                                    'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--s)' ),
     5069                                    'color'      => array( 'background' => 'var:preset|color|s' ),
     5070                                ),
     5071                            ),
     5072                        ),
     5073                    ),
     5074                ),
     5075            )
     5076        );
     5077        $styles = $result->get_raw_data()['styles'];
     5078
     5079        $this->assertEquals( 'var(--wp--preset--color--primary)', $styles['color']['background'], 'Top level: Assert the originally correct values are still correct.' );
     5080        $this->assertEquals( 'var(--wp--preset--color--secondary)', $styles['color']['text'], 'Top level: Assert the originally correct values are still correct.' );
     5081
     5082        $this->assertEquals( 'var(--wp--preset--color--pri)', $styles['elements']['link']['color']['background'], 'Element top level: Assert the originally correct values are still correct.' );
     5083        $this->assertEquals( 'var(--wp--preset--color--sec)', $styles['elements']['link']['color']['text'], 'Element top level: Assert the originally correct values are still correct.' );
     5084
     5085        $this->assertEquals( 'var(--wp--preset--font-size--small)', $styles['blocks']['core/post-terms']['typography']['fontSize'], 'Top block level: Assert the originally correct values are still correct.' );
     5086        $this->assertEquals( 'var(--wp--preset--color--secondary)', $styles['blocks']['core/post-terms']['color']['background'], 'Top block level: Assert the internal variables are convert to CSS custom variables.' );
     5087
     5088        $this->assertEquals( 'var(--wp--preset--color--p)', $styles['blocks']['core/navigation']['elements']['link']['color']['background'], 'Elements block level: Assert the originally correct values are still correct.' );
     5089        $this->assertEquals( 'var(--wp--preset--color--s)', $styles['blocks']['core/navigation']['elements']['link']['color']['text'], 'Elements block level: Assert the originally correct values are still correct.' );
     5090
     5091        $this->assertEquals( 'var(--wp--preset--font-size--s)', $styles['blocks']['core/quote']['variations']['plain']['typography']['fontSize'], 'Style variations: Assert the originally correct values are still correct.' );
     5092        $this->assertEquals( 'var(--wp--preset--color--s)', $styles['blocks']['core/quote']['variations']['plain']['color']['background'], 'Style variations: Assert the internal variables are convert to CSS custom variables.' );
     5093    }
     5094
     5095    public function test_resolve_variables() {
     5096        $primary_color   = '#9DFF20';
     5097        $secondary_color = '#9DFF21';
     5098        $contrast_color  = '#000';
     5099        $raw_color_value = '#efefef';
     5100        $large_font      = '18px';
     5101        $small_font      = '12px';
     5102        $theme_json      = new WP_Theme_JSON(
     5103            array(
     5104                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     5105                'settings' => array(
     5106                    'color'      => array(
     5107                        'palette' => array(
     5108                            'theme' => array(
     5109                                array(
     5110                                    'color' => $primary_color,
     5111                                    'name'  => 'Primary',
     5112                                    'slug'  => 'primary',
     5113                                ),
     5114                                array(
     5115                                    'color' => $secondary_color,
     5116                                    'name'  => 'Secondary',
     5117                                    'slug'  => 'secondary',
     5118                                ),
     5119                                array(
     5120                                    'color' => $contrast_color,
     5121                                    'name'  => 'Contrast',
     5122                                    'slug'  => 'contrast',
     5123                                ),
     5124                            ),
     5125                        ),
     5126                    ),
     5127                    'typography' => array(
     5128                        'fontSizes' => array(
     5129                            array(
     5130                                'size' => $small_font,
     5131                                'name' => 'Font size small',
     5132                                'slug' => 'small',
     5133                            ),
     5134                            array(
     5135                                'size' => $large_font,
     5136                                'name' => 'Font size large',
     5137                                'slug' => 'large',
     5138                            ),
     5139                        ),
     5140                    ),
     5141                ),
     5142                'styles'   => array(
     5143                    'color'    => array(
     5144                        'background' => 'var(--wp--preset--color--primary)',
     5145                        'text'       => $raw_color_value,
     5146                    ),
     5147                    'elements' => array(
     5148                        'button' => array(
     5149                            'color'      => array(
     5150                                'text' => 'var(--wp--preset--color--contrast)',
     5151                            ),
     5152                            'typography' => array(
     5153                                'fontSize' => 'var(--wp--preset--font-size--small)',
     5154                            ),
     5155                        ),
     5156                    ),
     5157                    'blocks'   => array(
     5158                        'core/post-terms'      => array(
     5159                            'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--small)' ),
     5160                            'color'      => array( 'background' => $raw_color_value ),
     5161                        ),
     5162                        'core/more'            => array(
     5163                            'typography' => array( 'fontSize' => 'var(--undefined--font-size--small)' ),
     5164                            'color'      => array( 'background' => 'linear-gradient(90deg, var(--wp--preset--color--primary) 0%, var(--wp--preset--color--secondary) 35%, var(--wp--undefined--color--secondary) 100%)' ),
     5165                        ),
     5166                        'core/comment-content' => array(
     5167                            'typography' => array( 'fontSize' => 'calc(var(--wp--preset--font-size--small, 12px) + 20px)' ),
     5168                            'color'      => array(
     5169                                'text'       => 'var(--wp--preset--color--primary, red)',
     5170                                'background' => 'var(--wp--preset--color--primary, var(--wp--preset--font-size--secondary))',
     5171                                'link'       => 'var(--undefined--color--primary, var(--wp--preset--font-size--secondary))',
     5172                            ),
     5173                        ),
     5174                        'core/comments'        => array(
     5175                            'color' => array(
     5176                                'text'       => 'var(--undefined--color--primary, var(--wp--preset--font-size--small))',
     5177                                'background' => 'var(--wp--preset--color--primary, var(--undefined--color--primary))',
     5178                            ),
     5179                        ),
     5180                        'core/navigation'      => array(
     5181                            'elements' => array(
     5182                                'link' => array(
     5183                                    'color'      => array(
     5184                                        'background' => 'var(--wp--preset--color--primary)',
     5185                                        'text'       => 'var(--wp--preset--color--secondary)',
     5186                                    ),
     5187                                    'typography' => array(
     5188                                        'fontSize' => 'var(--wp--preset--font-size--large)',
     5189                                    ),
     5190                                ),
     5191                            ),
     5192                        ),
     5193                        'core/quote'           => array(
     5194                            'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--large)' ),
     5195                            'color'      => array( 'background' => 'var(--wp--preset--color--primary)' ),
     5196                            'variations' => array(
     5197                                'plain' => array(
     5198                                    'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--small)' ),
     5199                                    'color'      => array( 'background' => 'var(--wp--preset--color--secondary)' ),
     5200                                ),
     5201                            ),
     5202                        ),
     5203                    ),
     5204                ),
     5205            )
     5206        );
     5207
     5208        $styles = $theme_json::resolve_variables( $theme_json )->get_raw_data()['styles'];
     5209
     5210        $this->assertEquals( $primary_color, $styles['color']['background'], 'Top level: Assert values are converted' );
     5211        $this->assertEquals( $raw_color_value, $styles['color']['text'], 'Top level: Assert raw values stay intact' );
     5212
     5213        $this->assertEquals( $contrast_color, $styles['elements']['button']['color']['text'], 'Elements: color' );
     5214        $this->assertEquals( $small_font, $styles['elements']['button']['typography']['fontSize'], 'Elements: font-size' );
     5215
     5216        $this->assertEquals( $large_font, $styles['blocks']['core/quote']['typography']['fontSize'], 'Blocks: font-size' );
     5217        $this->assertEquals( $primary_color, $styles['blocks']['core/quote']['color']['background'], 'Blocks: color' );
     5218        $this->assertEquals( $raw_color_value, $styles['blocks']['core/post-terms']['color']['background'], 'Blocks: Raw color value stays intact' );
     5219        $this->assertEquals( $small_font, $styles['blocks']['core/post-terms']['typography']['fontSize'], 'Block core/post-terms: font-size' );
     5220        $this->assertEquals(
     5221            "linear-gradient(90deg, $primary_color 0%, $secondary_color 35%, var(--wp--undefined--color--secondary) 100%)",
     5222            $styles['blocks']['core/more']['color']['background'],
     5223            'Blocks: multiple colors and undefined color'
     5224        );
     5225        $this->assertEquals( 'var(--undefined--font-size--small)', $styles['blocks']['core/more']['typography']['fontSize'], 'Blocks: undefined font-size ' );
     5226        $this->assertEquals( "calc($small_font + 20px)", $styles['blocks']['core/comment-content']['typography']['fontSize'], 'Blocks: font-size in random place' );
     5227        $this->assertEquals( $primary_color, $styles['blocks']['core/comment-content']['color']['text'], 'Blocks: text color with fallback' );
     5228        $this->assertEquals( $primary_color, $styles['blocks']['core/comment-content']['color']['background'], 'Blocks: background color with var as fallback' );
     5229        $this->assertEquals( $primary_color, $styles['blocks']['core/navigation']['elements']['link']['color']['background'], 'Block element: background color' );
     5230        $this->assertEquals( $secondary_color, $styles['blocks']['core/navigation']['elements']['link']['color']['text'], 'Block element: text color' );
     5231        $this->assertEquals( $large_font, $styles['blocks']['core/navigation']['elements']['link']['typography']['fontSize'], 'Block element: font-size' );
     5232
     5233        $this->assertEquals(
     5234            "var(--undefined--color--primary, $small_font)",
     5235            $styles['blocks']['core/comments']['color']['text'],
     5236            'Blocks: text color with undefined var and fallback'
     5237        );
     5238        $this->assertEquals(
     5239            $primary_color,
     5240            $styles['blocks']['core/comments']['color']['background'],
     5241            'Blocks: background color with variable and undefined fallback'
     5242        );
     5243
     5244        $this->assertEquals( $small_font, $styles['blocks']['core/quote']['variations']['plain']['typography']['fontSize'], 'Block variations: font-size' );
     5245        $this->assertEquals( $secondary_color, $styles['blocks']['core/quote']['variations']['plain']['color']['background'], 'Block variations: color' );
     5246    }
     5247
     5248    /**
    51255249     * Tests the correct application of a block style variation's selector to
    51265250     * a block's selector.
  • trunk/tests/phpunit/tests/theme/wpThemeJsonResolver.php

    r57260 r57662  
    2121
    2222    /**
     23     * WP_Theme_JSON_Resolver::$blocks_cache property.
     24     *
     25     * @var ReflectionProperty
     26     */
     27    private static $property_blocks_cache;
     28
     29    /**
     30     * Original value of the WP_Theme_JSON_Resolver::$blocks_cache property.
     31     *
     32     * @var array
     33     */
     34    private static $property_blocks_cache_orig_value;
     35
     36    /**
     37     * WP_Theme_JSON_Resolver::$core property.
     38     *
     39     * @var ReflectionProperty
     40     */
     41    private static $property_core;
     42
     43    /**
     44     * Original value of the WP_Theme_JSON_Resolver::$core property.
     45     *
     46     * @var WP_Theme_JSON
     47     */
     48    private static $property_core_orig_value;
     49
     50    /**
    2351     * Theme root directory.
    2452     *
    25      * @var string
     53     * @var string|null
    2654     */
    2755    private $theme_root;
     
    3058     * Original theme directory.
    3159     *
    32      * @var string
     60     * @var array|null
    3361     */
    3462    private $orig_theme_dir;
    3563
    3664    /**
    37      * WP_Theme_JSON_Resolver::$blocks_cache property.
    38      *
    39      * @var ReflectionProperty
    40      */
    41     private static $property_blocks_cache;
    42 
    43     /**
    44      * Original value of the WP_Theme_JSON_Resolver::$blocks_cache property.
    45      *
    46      * @var array
    47      */
    48     private static $property_blocks_cache_orig_value;
    49 
    50     /**
    51      * WP_Theme_JSON_Resolver::$core property.
    52      *
    53      * @var ReflectionProperty
    54      */
    55     private static $property_core;
    56 
    57     /**
    58      * Original value of the WP_Theme_JSON_Resolver::$core property.
    59      *
    60      * @var WP_Theme_JSON
    61      */
    62     private static $property_core_orig_value;
     65     * @var array|null
     66     */
     67    private $queries;
    6368
    6469    public static function set_up_before_class() {
     
    99104        add_filter( 'stylesheet_root', array( $this, 'filter_set_theme_root' ) );
    100105        add_filter( 'template_root', array( $this, 'filter_set_theme_root' ) );
    101 
     106        $this->queries = array();
    102107        // Clear caches.
    103108        wp_clean_themes_cache();
     
    141146        $this->assertSame( 'block-theme', wp_get_theme()->get( 'TextDomain' ) );
    142147        $this->assertSame( 'Motyw blokowy', $theme_data->get_data()['title'] );
    143         $this->assertSameSets(
     148        $this->assertSame(
    144149            array(
    145150                'color'      => array(
     
    219224        $this->assertArrayHasKey( 'page-home', $custom_templates );
    220225        $this->assertSame(
    221             $custom_templates['page-home'],
    222226            array(
    223227                'title'     => 'Szablon strony głównej',
    224228                'postTypes' => array( 'page' ),
    225             )
    226         );
     229            ),
     230            $custom_templates['page-home']
     231        );
     232
    227233        $this->assertSameSets(
    228234            array(
     
    234240            $theme_data->get_template_parts()
    235241        );
     242
    236243        $this->assertSame(
    237244            'Wariant motywu blokowego',
    238             $style_variations[1]['title']
     245            $style_variations[2]['title']
    239246        );
    240247    }
     
    258265
    259266    /**
    260      * Tests when WP_Theme_JSON_Resolver::$blocks_cache is empty or does not match
    261      * the all registered blocks.
     267     * Tests when WP_Theme_JSON_Resolver::$blocks_cache is empty or
     268     * does not match the all registered blocks.
    262269     *
    263270     * Though this is a non-public method, it is vital to other functionality.
     
    332339
    333340    /**
    334      * Tests when WP_Theme_JSON_Resolver::$blocks_cache is empty or does not match
    335      * the all registered blocks.
     341     * Tests when WP_Theme_JSON_Resolver::$blocks_cache is empty or
     342     * does not match the all registered blocks.
    336343     *
    337344     * Though this is a non-public method, it is vital to other functionality.
     
    597604
    598605        $this->assertSame(
    599             WP_Theme_JSON_Resolver::get_theme_data()->get_custom_templates(),
    600606            array(
    601607                'page-home'                   => array(
     
    607613                    'postTypes' => array( 'post' ),
    608614                ),
    609             )
     615            ),
     616            WP_Theme_JSON_Resolver::get_theme_data()->get_custom_templates()
    610617        );
    611618    }
     
    750757     */
    751758    public function test_get_theme_data_theme_supports_overrides_theme_json() {
     759        switch_theme( 'default' );
     760
    752761        // Test that get_theme_data() returns a WP_Theme_JSON object.
    753762        $theme_json_resolver = new WP_Theme_JSON_Resolver();
     
    763772        $previous_line_height = $previous_settings['typography']['lineHeight'];
    764773        $this->assertFalse( $previous_line_height, 'lineHeight setting from theme.json should be false.' );
     774
    765775        add_theme_support( 'custom-line-height' );
    766776        $current_settings = $theme_json_resolver->get_theme_data()->get_settings();
    767777        $line_height      = $current_settings['typography']['lineHeight'];
    768778        $this->assertTrue( $line_height, 'lineHeight setting after add_theme_support() should be true.' );
     779        remove_theme_support( 'custom-line-height' );
    769780    }
    770781
     
    810821     * @param bool   $theme_palette      Whether the theme palette is present.
    811822     * @param string $theme_palette_text Message.
    812      * @param bool   $user_palette        Whether the user palette is present.
    813      * @param string $user_palette_text   Message.
     823     * @param bool   $user_palette       Whether the user palette is present.
     824     * @param string $user_palette_text  Message.
    814825     */
    815826    public function test_get_merged_data_returns_origin( $origin, $core_palette, $core_palette_text, $block_styles, $block_styles_text, $theme_palette, $theme_palette_text, $user_palette, $user_palette_text ) {
     
    818829            'my/block-with-styles',
    819830            array(
    820                 'api_version' => 2,
     831                'api_version' => 3,
    821832                'attributes'  => array(
    822833                    'borderColor' => array(
     
    878889     *
    879890     * @covers WP_Theme_JSON_Resolver::get_merged_data
    880      *
    881891     */
    882892    public function test_get_merged_data_returns_origin_proper() {
     
    915925
    916926    /**
    917      * Data provider.
     927     * Data provider for test_get_merged_data_returns_origin.
    918928     *
    919929     * @return array[]
     
    984994        $expected_settings = array(
    985995            array(
    986                 'version'  => 2,
     996                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     997                'title'    => 'variation-a',
     998                'settings' => array(
     999                    'blocks' => array(
     1000                        'core/paragraph' => array(
     1001                            'color' => array(
     1002                                'palette' => array(
     1003                                    'theme' => array(
     1004                                        array(
     1005                                            'slug'  => 'dark',
     1006                                            'name'  => 'Dark',
     1007                                            'color' => '#010101',
     1008                                        ),
     1009                                    ),
     1010                                ),
     1011                            ),
     1012                        ),
     1013                    ),
     1014                ),
     1015            ),
     1016            array(
     1017                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    9871018                'title'    => 'variation-b',
    9881019                'settings' => array(
     
    10051036            ),
    10061037            array(
    1007                 'version'  => 2,
     1038                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    10081039                'title'    => 'Block theme variation',
    10091040                'settings' => array(
  • trunk/tests/phpunit/tests/theme/wpThemeJsonSchema.php

    r54889 r57662  
    1313class Tests_Theme_wpThemeJsonSchema extends WP_UnitTestCase {
    1414    /**
    15      * The current theme.json schema version.
    16      */
    17     const LATEST_SCHEMA_VERSION = WP_Theme_JSON::LATEST_SCHEMA;
    18 
    19     /**
    2015     * @ticket 54336
    2116     */
    22     public function test_migrate_v1_to_v2() {
     17    public function test_migrate_v1_to_latest() {
    2318        $theme_json_v1 = array(
    2419            'version'  => 1,
     
    107102
    108103        $expected = array(
    109             'version'  => self::LATEST_SCHEMA_VERSION,
     104            'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    110105            'settings' => array(
    111106                'color'      => array(
Note: See TracChangeset for help on using the changeset viewer.