@@ -346,9 +346,11 @@ class WP_Theme_JSON {
346346 * @since 5.9.0 Renamed from `ALLOWED_TOP_LEVEL_KEYS` to `VALID_TOP_LEVEL_KEYS`,
347347 * added the `customTemplates` and `templateParts` values.
348348 * @since 6.3.0 Added the `description` value.
349+ * @since 6.6.0 Added `blockTypes` to support block style variation theme.json partials.
349350 * @var string[]
350351 */
351352 const VALID_TOP_LEVEL_KEYS = array (
353+ 'blockTypes ' ,
352354 'customTemplates ' ,
353355 'description ' ,
354356 'patterns ' ,
@@ -823,6 +825,7 @@ protected static function do_opt_in_into_settings( &$context ) {
823825 * @since 5.8.0
824826 * @since 5.9.0 Added the `$valid_block_names` and `$valid_element_name` parameters.
825827 * @since 6.3.0 Added the `$valid_variations` parameter.
828+ * @since 6.6.0 Updated schema to allow extended block style variations.
826829 *
827830 * @param array $input Structure to sanitize.
828831 * @param array $valid_block_names List of valid block names.
@@ -881,6 +884,27 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n
881884
882885 $ schema_styles_blocks = array ();
883886 $ schema_settings_blocks = array ();
887+
888+ /*
889+ * Generate a schema for blocks.
890+ * - Block styles can contain `elements` & `variations` definitions.
891+ * - Variations definitions cannot be nested.
892+ * - Variations can contain styles for inner `blocks`.
893+ * - Variation inner `blocks` styles can contain `elements`.
894+ *
895+ * As each variation needs a `blocks` schema but further nested
896+ * inner `blocks`, the overall schema will be generated in multiple passes.
897+ */
898+ foreach ( $ valid_block_names as $ block ) {
899+ $ schema_settings_blocks [ $ block ] = static ::VALID_SETTINGS ;
900+ $ schema_styles_blocks [ $ block ] = $ styles_non_top_level ;
901+ $ schema_styles_blocks [ $ block ]['elements ' ] = $ schema_styles_elements ;
902+ }
903+
904+ $ block_style_variation_styles = static ::VALID_STYLES ;
905+ $ block_style_variation_styles ['blocks ' ] = $ schema_styles_blocks ;
906+ $ block_style_variation_styles ['elements ' ] = $ schema_styles_elements ;
907+
884908 foreach ( $ valid_block_names as $ block ) {
885909 // Build the schema for each block style variation.
886910 $ style_variation_names = array ();
@@ -897,12 +921,9 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n
897921
898922 $ schema_styles_variations = array ();
899923 if ( ! empty ( $ style_variation_names ) ) {
900- $ schema_styles_variations = array_fill_keys ( $ style_variation_names , $ styles_non_top_level );
924+ $ schema_styles_variations = array_fill_keys ( $ style_variation_names , $ block_style_variation_styles );
901925 }
902926
903- $ schema_settings_blocks [ $ block ] = static ::VALID_SETTINGS ;
904- $ schema_styles_blocks [ $ block ] = $ styles_non_top_level ;
905- $ schema_styles_blocks [ $ block ]['elements ' ] = $ schema_styles_elements ;
906927 $ schema_styles_blocks [ $ block ]['variations ' ] = $ schema_styles_variations ;
907928 }
908929
@@ -913,6 +934,12 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n
913934 $ schema ['settings ' ]['blocks ' ] = $ schema_settings_blocks ;
914935 $ schema ['settings ' ]['typography ' ]['fontFamilies ' ] = static ::schema_in_root_and_per_origin ( static ::FONT_FAMILY_SCHEMA );
915936
937+ /*
938+ * Shared block style variations can be registered from the theme.json data so we can't
939+ * validate them against pre-registered block style variations.
940+ */
941+ $ schema ['styles ' ]['blocks ' ]['variations ' ] = null ;
942+
916943 // Remove anything that's not present in the schema.
917944 foreach ( array ( 'styles ' , 'settings ' ) as $ subtree ) {
918945 if ( ! isset ( $ input [ $ subtree ] ) ) {
@@ -1016,16 +1043,36 @@ protected static function prepend_to_selector( $selector, $to_prepend ) {
10161043 * @since 5.9.0 Added `duotone` key with CSS selector.
10171044 * @since 6.1.0 Added `features` key with block support feature level selectors.
10181045 * @since 6.3.0 Refactored and stabilized selectors API.
1046+ * @since 6.6.0 Updated to include block style variations from the block styles registry.
10191047 *
10201048 * @return array Block metadata.
10211049 */
10221050 protected static function get_blocks_metadata () {
1023- $ registry = WP_Block_Type_Registry::get_instance ();
1024- $ blocks = $ registry ->get_all_registered ();
1051+ $ registry = WP_Block_Type_Registry::get_instance ();
1052+ $ blocks = $ registry ->get_all_registered ();
1053+ $ style_registry = WP_Block_Styles_Registry::get_instance ();
10251054
10261055 // Is there metadata for all currently registered blocks?
10271056 $ blocks = array_diff_key ( $ blocks , static ::$ blocks_metadata );
10281057 if ( empty ( $ blocks ) ) {
1058+ /*
1059+ * New block styles may have been registered within WP_Block_Styles_Registry.
1060+ * Update block metadata for any new block style variations.
1061+ */
1062+ $ registered_styles = $ style_registry ->get_all_registered ();
1063+ foreach ( static ::$ blocks_metadata as $ block_name => $ block_metadata ) {
1064+ if ( ! empty ( $ registered_styles [ $ block_name ] ) ) {
1065+ $ style_selectors = $ block_metadata ['styleVariations ' ] ?? array ();
1066+
1067+ foreach ( $ registered_styles [ $ block_name ] as $ block_style ) {
1068+ if ( ! isset ( $ style_selectors [ $ block_style ['name ' ] ] ) ) {
1069+ $ style_selectors [ $ block_style ['name ' ] ] = static ::get_block_style_variation_selector ( $ block_style ['name ' ], $ block_metadata ['selector ' ] );
1070+ }
1071+ }
1072+
1073+ static ::$ blocks_metadata [ $ block_name ]['styleVariations ' ] = $ style_selectors ;
1074+ }
1075+ }
10291076 return static ::$ blocks_metadata ;
10301077 }
10311078
@@ -1060,11 +1107,20 @@ protected static function get_blocks_metadata() {
10601107 }
10611108
10621109 // If the block has style variations, append their selectors to the block metadata.
1110+ $ style_selectors = array ();
10631111 if ( ! empty ( $ block_type ->styles ) ) {
1064- $ style_selectors = array ();
10651112 foreach ( $ block_type ->styles as $ style ) {
10661113 $ style_selectors [ $ style ['name ' ] ] = static ::get_block_style_variation_selector ( $ style ['name ' ], static ::$ blocks_metadata [ $ block_name ]['selector ' ] );
10671114 }
1115+ }
1116+
1117+ // Block style variations can be registered through the WP_Block_Styles_Registry as well as block.json.
1118+ $ registered_styles = $ style_registry ->get_registered_styles_for_block ( $ block_name );
1119+ foreach ( $ registered_styles as $ style ) {
1120+ $ style_selectors [ $ style ['name ' ] ] = static ::get_block_style_variation_selector ( $ style ['name ' ], static ::$ blocks_metadata [ $ block_name ]['selector ' ] );
1121+ }
1122+
1123+ if ( ! empty ( $ style_selectors ) ) {
10681124 static ::$ blocks_metadata [ $ block_name ]['styleVariations ' ] = $ style_selectors ;
10691125 }
10701126 }
@@ -1158,16 +1214,18 @@ public function get_settings() {
11581214 * @since 5.8.0
11591215 * @since 5.9.0 Removed the `$type` parameter, added the `$types` and `$origins` parameters.
11601216 * @since 6.3.0 Add fallback layout styles for Post Template when block gap support isn't available.
1217+ * @since 6.6.0 Added `skip_root_layout_styles` option to omit layout styles if desired.
11611218 *
11621219 * @param string[] $types Types of styles to load. Will load all by default. It accepts:
11631220 * - `variables`: only the CSS Custom Properties for presets & custom ones.
11641221 * - `styles`: only the styles section in theme.json.
11651222 * - `presets`: only the classes for the presets.
11661223 * @param string[] $origins A list of origins to include. By default it includes VALID_ORIGINS.
11671224 * @param array $options An array of options for now used for internal purposes only (may change without notice).
1168- * The options currently supported are 'scope' that makes sure all style are scoped to a
1169- * given selector, and root_selector which overwrites and forces a given selector to be
1170- * used on the root node.
1225+ * The options currently supported are:
1226+ * - 'scope' that makes sure all style are scoped to a given selector
1227+ * - `root_selector` which overwrites and forces a given selector to be used on the root node
1228+ * - `skip_root_layout_styles` which omits root layout styles from the generated stylesheet.
11711229 * @return string The resulting stylesheet.
11721230 */
11731231 public function get_stylesheet ( $ types = array ( 'variables ' , 'styles ' , 'presets ' ), $ origins = null , $ options = array () ) {
@@ -1220,7 +1278,7 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets'
12201278 }
12211279
12221280 if ( in_array ( 'styles ' , $ types , true ) ) {
1223- if ( false !== $ root_style_key ) {
1281+ if ( false !== $ root_style_key && empty ( $ options [ ' skip_root_layout_styles ' ] ) ) {
12241282 $ stylesheet .= $ this ->get_root_layout_rules ( $ style_nodes [ $ root_style_key ]['selector ' ], $ style_nodes [ $ root_style_key ] );
12251283 }
12261284 $ stylesheet .= $ this ->get_block_classes ( $ style_nodes );
@@ -3114,6 +3172,7 @@ protected static function filter_slugs( $node, $slugs ) {
31143172 *
31153173 * @since 5.9.0
31163174 * @since 6.3.2 Preserves global styles block variations when securing styles.
3175+ * @since 6.6.0 Updated to allow variation element styles.
31173176 *
31183177 * @param array $theme_json Structure to sanitize.
31193178 * @return array Sanitized structure.
@@ -3175,6 +3234,29 @@ public static function remove_insecure_properties( $theme_json ) {
31753234 }
31763235
31773236 $ variation_output = static ::remove_insecure_styles ( $ variation_input );
3237+
3238+ // Process a variation's elements and element pseudo selector styles.
3239+ if ( isset ( $ variation_input ['elements ' ] ) ) {
3240+ foreach ( $ valid_element_names as $ element_name ) {
3241+ $ element_input = $ variation_input ['elements ' ][ $ element_name ] ?? null ;
3242+ if ( $ element_input ) {
3243+ $ element_output = static ::remove_insecure_styles ( $ element_input );
3244+
3245+ if ( isset ( static ::VALID_ELEMENT_PSEUDO_SELECTORS [ $ element_name ] ) ) {
3246+ foreach ( static ::VALID_ELEMENT_PSEUDO_SELECTORS [ $ element_name ] as $ pseudo_selector ) {
3247+ if ( isset ( $ element_input [ $ pseudo_selector ] ) ) {
3248+ $ element_output [ $ pseudo_selector ] = static ::remove_insecure_styles ( $ element_input [ $ pseudo_selector ] );
3249+ }
3250+ }
3251+ }
3252+
3253+ if ( ! empty ( $ element_output ) ) {
3254+ _wp_array_set ( $ variation_output , array ( 'elements ' , $ element_name ), $ element_output );
3255+ }
3256+ }
3257+ }
3258+ }
3259+
31783260 if ( ! empty ( $ variation_output ) ) {
31793261 _wp_array_set ( $ sanitized , $ variation ['path ' ], $ variation_output );
31803262 }
0 commit comments