Make WordPress Core

Changeset 58394


Ignore:
Timestamp:
06/12/2024 07:15:06 AM (4 months 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.