Make WordPress Core


Ignore:
Timestamp:
02/10/2026 03:19:36 PM (8 months ago)
Author:
scruffian
Message:

Editor: Add support for pseudo elements for the block and its variations on theme.json.

Adds support for pseudo elements on the core/button block for ( ':hover', ':focus', ':focus-visible', ':active' ) at the theme.json level. This is also allowing the block's variations to control the same pseudo elements, so now we can style hover for the outline variation too.

Example usage:

"styles": {
	"blocks": {
		"core/button": {
			"color": {
				"background": "blue"
			},
			":hover": {
				"color": {
					"background": "green"
				}
			},
			":focus": {
				"color": {
					"background": "purple"
				}
			},
			"variations": {
				"outline": {
					":hover": {
						"color": {
							"background": "pink"
						}
					}
				}
			}
		}
	}
}

Reviewed by palak678, getdave, MaggieCabrera.

Props MaggieCabrera, scruffian, palak678. joedolson, getdave, mikachan.
Fixes #64263.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-theme-json.php

    r61570 r61607  
    611611
    612612        /**
     613         * The valid pseudo-selectors that can be used for blocks.
     614         *
     615         * @since 7.0
     616         * @var array
     617         */
     618        const VALID_BLOCK_PSEUDO_SELECTORS = array(
     619                'core/button' => array( ':hover', ':focus', ':focus-visible', ':active' ),
     620        );
     621
     622        /**
    613623         * The valid elements that can be found under styles.
    614624         *
    … …  
    700710        }
    701711
     712
     713        /**
     714         * Processes pseudo-selectors for any node (block or variation).
     715         *
     716         * @param array  $node The node data (block or variation).
     717         * @param string $base_selector The base selector.
     718         * @param array  $settings The theme settings.
     719         * @param string $block_name The block name.
     720         * @return array Array of pseudo-selector declarations.
     721         */
     722        private static function process_pseudo_selectors( $node, $base_selector, $settings, $block_name ) {
     723                $pseudo_declarations = array();
     724
     725                if ( ! isset( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block_name ] ) ) {
     726                        return $pseudo_declarations;
     727                }
     728
     729                foreach ( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block_name ] as $pseudo_selector ) {
     730                        if ( isset( $node[ $pseudo_selector ] ) ) {
     731                                $combined_selector                         = static::append_to_selector( $base_selector, $pseudo_selector );
     732                                $declarations                              = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, null );
     733                                $pseudo_declarations[ $combined_selector ] = $declarations;
     734                        }
     735                }
     736
     737                return $pseudo_declarations;
     738        }
     739
     740
    702741        /**
    703742         * Returns a class name by an element name.
    … …  
    10191058                        $schema_styles_blocks[ $block ]             = $styles_non_top_level;
    10201059                        $schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
     1060
     1061                        // Add pseudo-selectors for blocks that support them
     1062                        if ( isset( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block ] ) ) {
     1063                                foreach ( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block ] as $pseudo_selector ) {
     1064                                        $schema_styles_blocks[ $block ][ $pseudo_selector ] = $styles_non_top_level;
     1065                                }
     1066                        }
    10211067                }
    10221068
    … …  
    10411087                        $schema_styles_variations = array();
    10421088                        if ( ! empty( $style_variation_names ) ) {
    1043                                 $schema_styles_variations = array_fill_keys( $style_variation_names, $block_style_variation_styles );
     1089                                foreach ( $style_variation_names as $variation_name ) {
     1090                                        $variation_schema = $block_style_variation_styles;
     1091
     1092                                        // Add pseudo-selectors to variations for blocks that support them
     1093                                        if ( isset( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block ] ) ) {
     1094                                                foreach ( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block ] as $pseudo_selector ) {
     1095                                                        $variation_schema[ $pseudo_selector ] = $styles_non_top_level;
     1096                                                }
     1097                                        }
     1098
     1099                                        $schema_styles_variations[ $variation_name ] = $variation_schema;
     1100                                }
    10441101                        }
    10451102
    … …  
    27432800                                        'css'        => $selector,
    27442801                                );
     2802
     2803                                // Handle any pseudo selectors for the block.
     2804                                if ( isset( static::VALID_BLOCK_PSEUDO_SELECTORS[ $name ] ) ) {
     2805                                        foreach ( static::VALID_BLOCK_PSEUDO_SELECTORS[ $name ] as $pseudo_selector ) {
     2806                                                if ( isset( $theme_json['styles']['blocks'][ $name ][ $pseudo_selector ] ) ) {
     2807                                                        $nodes[] = array(
     2808                                                                'name'       => $name,
     2809                                                                'path'       => array( 'styles', 'blocks', $name, $pseudo_selector ),
     2810                                                                'selector'   => static::append_to_selector( $selector, $pseudo_selector ),
     2811                                                                'selectors'  => $feature_selectors,
     2812                                                                'duotone'    => $duotone_selector,
     2813                                                                'variations' => $variation_selectors,
     2814                                                                'css'        => static::append_to_selector( $selector, $pseudo_selector ),
     2815                                                        );
     2816                                                }
     2817                                        }
     2818                                }
    27452819                        }
    27462820
    … …  
    28392913                                // Compute declarations for remaining styles not covered by feature level selectors.
    28402914                                $style_variation_declarations[ $style_variation['selector'] ] = static::compute_style_properties( $style_variation_node, $settings, null, $this->theme_json );
     2915
     2916                                // Process pseudo-selectors for this variation (e.g., :hover, :focus)
     2917                                $block_name                    = isset( $block_metadata['name'] ) ? $block_metadata['name'] : ( in_array( 'blocks', $block_metadata['path'], true ) && count( $block_metadata['path'] ) >= 3 ? $block_metadata['path'][2] : null );
     2918                                $variation_pseudo_declarations = static::process_pseudo_selectors( $style_variation_node, $style_variation['selector'], $settings, $block_name );
     2919                                $style_variation_declarations  = array_merge( $style_variation_declarations, $variation_pseudo_declarations );
     2920
    28412921                                // Store custom CSS for the style variation.
    28422922                                if ( isset( $style_variation_node['css'] ) ) {
    … …  
    28712951                if ( isset( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] ) ) {
    28722952                        $element_pseudo_allowed = static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ];
     2953                }
     2954
     2955                /*
     2956                 * Check if we're processing a block pseudo-selector.
     2957                 * $block_metadata['path'] = array( 'styles', 'blocks', 'core/button', ':hover' );
     2958                 */
     2959                $is_processing_block_pseudo = false;
     2960                $block_pseudo_selector      = null;
     2961                if ( in_array( 'blocks', $block_metadata['path'], true ) && count( $block_metadata['path'] ) >= 4 ) {
     2962                        $block_name        = $block_metadata['path'][2]; // 'core/button'
     2963                        $last_path_element = $block_metadata['path'][ count( $block_metadata['path'] ) - 1 ]; // ':hover'
     2964
     2965                        if ( isset( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block_name ] ) &&
     2966                                in_array( $last_path_element, static::VALID_BLOCK_PSEUDO_SELECTORS[ $block_name ], true ) ) {
     2967                                $is_processing_block_pseudo = true;
     2968                                $block_pseudo_selector      = $last_path_element;
     2969                        }
    28732970                }
    28742971
    … …  
    29022999                ) {
    29033000                        $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json, $selector, $use_root_padding );
     3001                } elseif ( $is_processing_block_pseudo ) {
     3002                        // Process block pseudo-selector styles
     3003                        // For block pseudo-selectors, we need to get the block data first, then access the pseudo-selector
     3004                        $block_name  = $block_metadata['path'][2]; // 'core/button'
     3005                        $block_data  = _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $block_name ), array() );
     3006                        $pseudo_data = isset( $block_data[ $block_pseudo_selector ] ) ? $block_data[ $block_pseudo_selector ] : array();
     3007
     3008                        $declarations = static::compute_style_properties( $pseudo_data, $settings, null, $this->theme_json, $selector, $use_root_padding );
    29043009                } else {
    29053010                        $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json, $selector, $use_root_padding );
Note: See TracChangeset for help on using the changeset viewer.