Make WordPress Core

Changeset 57662


Ignore:
Timestamp:
02/20/2024 09:53:11 AM (3 years 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.