Make WordPress Core

Changeset 58394


Ignore:
Timestamp:
06/12/2024 07:15:06 AM (2 years ago)
Author:
oandregal
Message:

Editor: register block style variations defined by the theme using the init action.

Props oandregal, aaronrobertshaw, annezazu.

Follow-up to [58264].
See #61312.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/block-supports/block-style-variations.php

    r58264 r58394  
    214214/**
    215215 * Collects block style variation data for merging with theme.json data.
    216  * As each block style variation is processed it is registered if it hasn't
    217  * been already. This registration is required for later sanitization of
    218  * theme.json data.
    219216 *
    220217 * @since 6.6.0
     
    225222 * @return array Block variations data to be merged under `styles.blocks`.
    226223 */
    227 function wp_resolve_and_register_block_style_variations( $variations ) {
     224function wp_resolve_block_style_variations( $variations ) {
    228225        $variations_data = array();
    229226
    230227        if ( empty( $variations ) ) {
    231228                return $variations_data;
     229        }
     230
     231        $have_named_variations = ! wp_is_numeric_array( $variations );
     232
     233        foreach ( $variations as $key => $variation ) {
     234                $supported_blocks = $variation['blockTypes'] ?? array();
     235
     236                /*
     237                 * Standalone theme.json partial files for block style variations
     238                 * will have their styles under a top-level property by the same name.
     239                 * Variations defined within an existing theme.json or theme style
     240                 * variation will themselves already be the required styles data.
     241                 */
     242                $variation_data = $variation['styles'] ?? $variation;
     243
     244                if ( empty( $variation_data ) ) {
     245                        continue;
     246                }
     247
     248                /*
     249                 * Block style variations read in via standalone theme.json partials
     250                 * need to have their name set to the kebab case version of their title.
     251                 */
     252                $variation_name = $have_named_variations ? $key : _wp_to_kebab_case( $variation['title'] );
     253
     254                foreach ( $supported_blocks as $block_type ) {
     255                        // Add block style variation data under current block type.
     256                        $path = array( $block_type, 'variations', $variation_name );
     257                        _wp_array_set( $variations_data, $path, $variation_data );
     258                }
     259        }
     260
     261        return $variations_data;
     262}
     263
     264/**
     265 * Merges variations data with existing theme.json data ensuring that the
     266 * current theme.json data values take precedence.
     267 *
     268 * @since 6.6.0
     269 * @access private
     270 *
     271 * @param array              $variations_data Block style variations data keyed by block type.
     272 * @param WP_Theme_JSON_Data $theme_json      Current theme.json data.
     273 * @param string             $origin          Origin for the theme.json data.
     274 *
     275 * @return WP_Theme_JSON The merged theme.json data.
     276 */
     277function wp_merge_block_style_variations_data( $variations_data, $theme_json, $origin = 'theme' ) {
     278        if ( empty( $variations_data ) ) {
     279                return $theme_json;
     280        }
     281
     282        $variations_theme_json_data = array(
     283                'version' => WP_Theme_JSON::LATEST_SCHEMA,
     284                'styles'  => array( 'blocks' => $variations_data ),
     285        );
     286
     287        $variations_theme_json = new WP_Theme_JSON_Data( $variations_theme_json_data, $origin );
     288
     289        /*
     290         * Merge the current theme.json data over shared variation data so that
     291         * any explicit per block variation values take precedence.
     292         */
     293        return $variations_theme_json->update_with( $theme_json->get_data() );
     294}
     295
     296/**
     297 * Merges any shared block style variation definitions from a theme style
     298 * variation into their appropriate block type within theme json styles. Any
     299 * custom user selections already made will take precedence over the shared
     300 * style variation value.
     301 *
     302 * @since 6.6.0
     303 * @access private
     304 *
     305 * @param WP_Theme_JSON_Data $theme_json Current theme.json data.
     306 *
     307 * @return WP_Theme_JSON_Data
     308 */
     309function wp_resolve_block_style_variations_from_theme_style_variation( $theme_json ) {
     310        $theme_json_data   = $theme_json->get_data();
     311        $shared_variations = $theme_json_data['styles']['blocks']['variations'] ?? array();
     312        $variations_data   = wp_resolve_block_style_variations( $shared_variations );
     313
     314        return wp_merge_block_style_variations_data( $variations_data, $theme_json, 'user' );
     315}
     316
     317/**
     318 * Merges block style variation data sourced from standalone partial
     319 * theme.json files.
     320 *
     321 * @since 6.6.0
     322 * @access private
     323 *
     324 * @param WP_Theme_JSON_Data $theme_json Current theme.json data.
     325 *
     326 * @return WP_Theme_JSON_Data
     327 */
     328function wp_resolve_block_style_variations_from_theme_json_partials( $theme_json ) {
     329        $block_style_variations = WP_Theme_JSON_Resolver::get_style_variations( 'block' );
     330        $variations_data        = wp_resolve_block_style_variations( $block_style_variations );
     331
     332        return wp_merge_block_style_variations_data( $variations_data, $theme_json );
     333}
     334
     335/**
     336 * Merges shared block style variations registered within the
     337 * `styles.blocks.variations` property of the primary theme.json file.
     338 *
     339 * @since 6.6.0
     340 * @access private
     341 *
     342 * @param WP_Theme_JSON_Data $theme_json Current theme.json data.
     343 *
     344 * @return WP_Theme_JSON_Data
     345 */
     346function wp_resolve_block_style_variations_from_primary_theme_json( $theme_json ) {
     347        $theme_json_data        = $theme_json->get_data();
     348        $block_style_variations = $theme_json_data['styles']['blocks']['variations'] ?? array();
     349        $variations_data        = wp_resolve_block_style_variations( $block_style_variations );
     350
     351        return wp_merge_block_style_variations_data( $variations_data, $theme_json );
     352}
     353
     354/**
     355 * Merges block style variations registered via the block styles registry with a
     356 * style object, under their appropriate block types within theme.json styles.
     357 * Any variation values defined within the theme.json specific to a block type
     358 * will take precedence over these shared definitions.
     359 *
     360 * @since 6.6.0
     361 * @access private
     362 *
     363 * @param WP_Theme_JSON_Data $theme_json Current theme.json data.
     364 *
     365 * @return WP_Theme_JSON_Data
     366 */
     367function wp_resolve_block_style_variations_from_styles_registry( $theme_json ) {
     368        $registry        = WP_Block_Styles_Registry::get_instance();
     369        $styles          = $registry->get_all_registered();
     370        $variations_data = array();
     371
     372        foreach ( $styles as $block_type => $variations ) {
     373                foreach ( $variations as $variation_name => $variation ) {
     374                        if ( ! empty( $variation['style_data'] ) ) {
     375                                $path = array( $block_type, 'variations', $variation_name );
     376                                _wp_array_set( $variations_data, $path, $variation['style_data'] );
     377                        }
     378                }
     379        }
     380
     381        return wp_merge_block_style_variations_data( $variations_data, $theme_json );
     382}
     383
     384/**
     385 * Enqueues styles for block style variations.
     386 *
     387 * @since 6.6.0
     388 * @access private
     389 */
     390function wp_enqueue_block_style_variation_styles() {
     391        wp_enqueue_style( 'block-style-variation-styles' );
     392}
     393
     394// Register the block support.
     395WP_Block_Supports::get_instance()->register( 'block-style-variation', array() );
     396
     397add_filter( 'render_block_data', 'wp_render_block_style_variation_support_styles', 10, 2 );
     398add_filter( 'render_block', 'wp_render_block_style_variation_class_name', 10, 2 );
     399add_action( 'wp_enqueue_scripts', 'wp_enqueue_block_style_variation_styles', 1 );
     400
     401// Resolve block style variations from all their potential sources. The order here is deliberate.
     402add_filter( 'wp_theme_json_data_theme', 'wp_resolve_block_style_variations_from_primary_theme_json', 10, 1 );
     403add_filter( 'wp_theme_json_data_theme', 'wp_resolve_block_style_variations_from_theme_json_partials', 10, 1 );
     404add_filter( 'wp_theme_json_data_theme', 'wp_resolve_block_style_variations_from_styles_registry', 10, 1 );
     405
     406add_filter( 'wp_theme_json_data_user', 'wp_resolve_block_style_variations_from_theme_style_variation', 10, 1 );
     407
     408/**
     409 * Registers any block style variations contained within the provided
     410 * theme.json data.
     411 *
     412 * @since 6.6.0
     413 * @access private
     414 *
     415 * @param array $variations Shared block style variations.
     416 */
     417function wp_register_block_style_variations_from_theme_json_data( $variations ) {
     418        if ( empty( $variations ) ) {
     419                return $variations;
    232420        }
    233421
     
    270458                                );
    271459                        }
    272 
    273                         // Add block style variation data under current block type.
    274                         $path = array( $block_type, 'variations', $variation_name );
    275                         _wp_array_set( $variations_data, $path, $variation_data );
    276460                }
    277461        }
    278 
    279         return $variations_data;
    280 }
    281 
    282 /**
    283  * Merges variations data with existing theme.json data ensuring that the
    284  * current theme.json data values take precedence.
    285  *
    286  * @since 6.6.0
    287  * @access private
    288  *
    289  * @param array              $variations_data Block style variations data keyed by block type.
    290  * @param WP_Theme_JSON_Data $theme_json      Current theme.json data.
    291  * @param string             $origin          Origin for the theme.json data.
    292  *
    293  * @return WP_Theme_JSON The merged theme.json data.
    294  */
    295 function wp_merge_block_style_variations_data( $variations_data, $theme_json, $origin = 'theme' ) {
    296         if ( empty( $variations_data ) ) {
    297                 return $theme_json;
    298         }
    299 
    300         $variations_theme_json_data = array(
    301                 'version' => WP_Theme_JSON::LATEST_SCHEMA,
    302                 'styles'  => array( 'blocks' => $variations_data ),
    303         );
    304 
    305         $variations_theme_json = new WP_Theme_JSON_Data( $variations_theme_json_data, $origin );
     462}
     463
     464/**
     465 * Register shared block style variations defined by the theme.
     466 *
     467 * These can come in three forms:
     468 * - the theme's theme.json
     469 * - the theme's partials (standalone files in `/styles` that only define block style variations)
     470 * - the user's theme.json (for example, theme style variations the user selected)
     471 *
     472 * @since 6.6.0
     473 * @access private
     474 */
     475function wp_register_block_style_variations_from_theme() {
     476        // Partials from `/styles`.
     477        $variations_partials = WP_Theme_JSON_Resolver::get_style_variations( 'block' );
     478        wp_register_block_style_variations_from_theme_json_data( $variations_partials );
    306479
    307480        /*
    308          * Merge the current theme.json data over shared variation data so that
    309          * any explicit per block variation values take precedence.
     481         * Pull the data from the specific origin instead of the merged data.
     482         * This is because, for 6.6, we only support registering block style variations
     483         * for the 'theme' and 'custom' origins but not for 'default' (core theme.json)
     484         * or 'custom' (theme.json in a block).
     485         *
     486         * When/If we add support for every origin, we should switch to using the public API
     487         * instead, e.g.: wp_get_global_styles( array( 'blocks', 'variations' ) ).
    310488         */
    311         return $variations_theme_json->update_with( $theme_json->get_data() );
    312 }
    313 
    314 /**
    315  * Merges any shared block style variation definitions from a theme style
    316  * variation into their appropriate block type within theme json styles. Any
    317  * custom user selections already made will take precedence over the shared
    318  * style variation value.
    319  *
    320  * @since 6.6.0
    321  * @access private
    322  *
    323  * @param WP_Theme_JSON_Data $theme_json Current theme.json data.
    324  *
    325  * @return WP_Theme_JSON_Data
    326  */
    327 function wp_resolve_block_style_variations_from_theme_style_variation( $theme_json ) {
    328         $theme_json_data   = $theme_json->get_data();
    329         $shared_variations = $theme_json_data['styles']['blocks']['variations'] ?? array();
    330         $variations_data   = wp_resolve_and_register_block_style_variations( $shared_variations );
    331 
    332         return wp_merge_block_style_variations_data( $variations_data, $theme_json, 'user' );
    333 }
    334 
    335 /**
    336  * Merges block style variation data sourced from standalone partial
    337  * theme.json files.
    338  *
    339  * @since 6.6.0
    340  * @access private
    341  *
    342  * @param WP_Theme_JSON_Data $theme_json Current theme.json data.
    343  *
    344  * @return WP_Theme_JSON_Data
    345  */
    346 function wp_resolve_block_style_variations_from_theme_json_partials( $theme_json ) {
    347         $block_style_variations = WP_Theme_JSON_Resolver::get_style_variations( 'block' );
    348         $variations_data        = wp_resolve_and_register_block_style_variations( $block_style_variations );
    349 
    350         return wp_merge_block_style_variations_data( $variations_data, $theme_json );
    351 }
    352 
    353 /**
    354  * Merges shared block style variations registered within the
    355  * `styles.blocks.variations` property of the primary theme.json file.
    356  *
    357  * @since 6.6.0
    358  * @access private
    359  *
    360  * @param WP_Theme_JSON_Data $theme_json Current theme.json data.
    361  *
    362  * @return WP_Theme_JSON_Data
    363  */
    364 function wp_resolve_block_style_variations_from_primary_theme_json( $theme_json ) {
    365         $theme_json_data        = $theme_json->get_data();
    366         $block_style_variations = $theme_json_data['styles']['blocks']['variations'] ?? array();
    367         $variations_data        = wp_resolve_and_register_block_style_variations( $block_style_variations );
    368 
    369         return wp_merge_block_style_variations_data( $variations_data, $theme_json );
    370 }
    371 
    372 /**
    373  * Merges block style variations registered via the block styles registry with a
    374  * style object, under their appropriate block types within theme.json styles.
    375  * Any variation values defined within the theme.json specific to a block type
    376  * will take precedence over these shared definitions.
    377  *
    378  * @since 6.6.0
    379  * @access private
    380  *
    381  * @param WP_Theme_JSON_Data $theme_json Current theme.json data.
    382  *
    383  * @return WP_Theme_JSON_Data
    384  */
    385 function wp_resolve_block_style_variations_from_styles_registry( $theme_json ) {
    386         $registry        = WP_Block_Styles_Registry::get_instance();
    387         $styles          = $registry->get_all_registered();
    388         $variations_data = array();
    389 
    390         foreach ( $styles as $block_type => $variations ) {
    391                 foreach ( $variations as $variation_name => $variation ) {
    392                         if ( ! empty( $variation['style_data'] ) ) {
    393                                 $path = array( $block_type, 'variations', $variation_name );
    394                                 _wp_array_set( $variations_data, $path, $variation['style_data'] );
    395                         }
    396                 }
    397         }
    398 
    399         return wp_merge_block_style_variations_data( $variations_data, $theme_json );
    400 }
    401 
    402 /**
    403  * Enqueues styles for block style variations.
    404  *
    405  * @since 6.6.0
    406  * @access private
    407  */
    408 function wp_enqueue_block_style_variation_styles() {
    409         wp_enqueue_style( 'block-style-variation-styles' );
    410 }
    411 
    412 // Register the block support.
    413 WP_Block_Supports::get_instance()->register( 'block-style-variation', array() );
    414 
    415 add_filter( 'render_block_data', 'wp_render_block_style_variation_support_styles', 10, 2 );
    416 add_filter( 'render_block', 'wp_render_block_style_variation_class_name', 10, 2 );
    417 add_action( 'wp_enqueue_scripts', 'wp_enqueue_block_style_variation_styles', 1 );
    418 
    419 // Resolve block style variations from all their potential sources. The order here is deliberate.
    420 add_filter( 'wp_theme_json_data_theme', 'wp_resolve_block_style_variations_from_primary_theme_json', 10, 1 );
    421 add_filter( 'wp_theme_json_data_theme', 'wp_resolve_block_style_variations_from_theme_json_partials', 10, 1 );
    422 add_filter( 'wp_theme_json_data_theme', 'wp_resolve_block_style_variations_from_styles_registry', 10, 1 );
    423 
    424 add_filter( 'wp_theme_json_data_user', 'wp_resolve_block_style_variations_from_theme_style_variation', 10, 1 );
     489
     490        // theme.json of the theme.
     491        $theme_json_theme = WP_Theme_JSON_Resolver::get_theme_data();
     492        $variations_theme = $theme_json_theme->get_data()['styles']['blocks']['variations'] ?? array();
     493        wp_register_block_style_variations_from_theme_json_data( $variations_theme );
     494
     495        // User data linked for this theme.
     496        $theme_json_user = WP_Theme_JSON_Resolver::get_user_data();
     497        $variations_user = $theme_json_user->get_data()['styles']['blocks']['variations'] ?? array();
     498        wp_register_block_style_variations_from_theme_json_data( $variations_user );
     499}
     500add_action( 'init', 'wp_register_block_style_variations_from_theme' );
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php

    r58262 r58394  
    232232         * @since 5.9.0
    233233         * @since 6.2.0 Added validation of styles.css property.
     234         * @since 6.6.0 Added registration of newly created style variations provided by the user.
    234235         *
    235236         * @param WP_REST_Request $request Request object.
     
    264265                                $config['styles'] = $existing_config['styles'];
    265266                        }
     267
     268                        /*
     269                         * If the incoming request is going to create a new variation
     270                         * that is not yet registered, we register it here.
     271                         * This is because the variations are registered on init,
     272                         * but we want this endpoint to return the new variation immediately:
     273                         * if we don't register it, it'll be stripped out of the response
     274                         * just in this request (subsequent ones will be ok).
     275                         * Take the variations defined in styles.blocks.variations from the incoming request
     276                         * that are not part of the $exsting_config.
     277                         */
     278                        if ( isset( $request['styles']['blocks']['variations'] ) ) {
     279                                $existing_variations = isset( $existing_config['styles']['blocks']['variations'] ) ? $existing_config['styles']['blocks']['variations'] : array();
     280                                $new_variations      = array_diff_key( $request['styles']['blocks']['variations'], $existing_variations );
     281                                if ( ! empty( $new_variations ) ) {
     282                                        wp_register_block_style_variations_from_theme_json_data( $new_variations );
     283                                }
     284                        }
     285
    266286                        if ( isset( $request['settings'] ) ) {
    267287                                $config['settings'] = $request['settings'];
  • trunk/tests/phpunit/tests/block-supports/block-style-variations.php

    r58264 r58394  
    6666                switch_theme( 'block-theme' );
    6767
     68                /*
     69                 * Trigger block style registration that occurs on `init` action.
     70                 * do_action( 'init' ) could be used here however this direct call
     71                 * means only the updates being tested are performed.
     72                 */
     73                wp_register_block_style_variations_from_theme();
     74
    6875                $variation_styles_data = array(
    6976                        'color'    => array(
  • trunk/tests/phpunit/tests/rest-api/rest-global-styles-controller.php

    r58328 r58394  
    604604
    605605        /**
     606         * Tests the submission of a custom block style variation that was defined
     607         * within a theme style variation and wouldn't be registered at the time
     608         * of saving via the API.
     609         *
     610         * @covers WP_REST_Global_Styles_Controller_Gutenberg::update_item
     611         * @ticket 61312
     612         */
     613        public function test_update_item_with_custom_block_style_variations() {
     614                wp_set_current_user( self::$admin_id );
     615                if ( is_multisite() ) {
     616                        grant_super_admin( self::$admin_id );
     617                }
     618
     619                $group_variations = array(
     620                        'fromThemeStyleVariation' => array(
     621                                'color' => array(
     622                                        'background' => '#ffffff',
     623                                        'text'       => '#000000',
     624                                ),
     625                        ),
     626                );
     627
     628                $request = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
     629                $request->set_body_params(
     630                        array(
     631                                'styles' => array(
     632                                        'blocks' => array(
     633                                                'variations' => array(
     634                                                        'fromThemeStyleVariation' => array(
     635                                                                'blockTypes' => array( 'core/group', 'core/columns' ),
     636                                                                'color'      => array(
     637                                                                        'background' => '#000000',
     638                                                                        'text'       => '#ffffff',
     639                                                                ),
     640                                                        ),
     641                                                ),
     642                                                'core/group' => array(
     643                                                        'variations' => $group_variations,
     644                                                ),
     645                                        ),
     646                                ),
     647                        )
     648                );
     649                $response = rest_get_server()->dispatch( $request );
     650                $data     = $response->get_data();
     651                $this->assertSame( $group_variations, $data['styles']['blocks']['core/group']['variations'] );
     652        }
     653
     654        /**
    606655         * @doesNotPerformAssertions
    607656         */
Note: See TracChangeset for help on using the changeset viewer.