| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Block support to enable per-section styling of block types via 4 * block style variations. 5 * 6 * @package WordPress 7 * @since 6.6.0 8 */ 9 10 /** 11 * Determines the block style variation names within a CSS class string. 12 * 13 * @since 6.6.0 14 * 15 * @param string $class_string CSS class string to look for a variation in. 16 * 17 * @return array|null The block style variation name if found. 18 */ 19 function wp_get_block_style_variation_name_from_class( $class_string ) { 20 if ( ! is_string( $class_string ) ) { 21 return null; 22 } 23 24 preg_match_all( '/\bis-style-(?!default)(\S+)\b/', $class_string, $matches ); 25 return $matches[1] ?? null; 26 } 27 28 /** 29 * Recursively resolves any `ref` values within a block style variation's data. 30 * 31 * @since 6.6.0 32 * @access private 33 * 34 * @param array $variation_data Reference to the variation data being processed. 35 * @param array $theme_json Theme.json data to retrieve referenced values from. 36 */ 37 function wp_resolve_block_style_variation_ref_values( &$variation_data, $theme_json ) { 38 foreach ( $variation_data as $key => &$value ) { 39 // Only need to potentially process arrays. 40 if ( is_array( $value ) ) { 41 // If ref value is set, attempt to find its matching value and update it. 42 if ( array_key_exists( 'ref', $value ) ) { 43 // Clean up any invalid ref value. 44 if ( empty( $value['ref'] ) || ! is_string( $value['ref'] ) ) { 45 unset( $variation_data[ $key ] ); 46 } 47 48 $value_path = explode( '.', $value['ref'] ?? '' ); 49 $ref_value = _wp_array_get( $theme_json, $value_path ); 50 51 // Only update the current value if the referenced path matched a value. 52 if ( null === $ref_value ) { 53 unset( $variation_data[ $key ] ); 54 } else { 55 $value = $ref_value; 56 } 57 } else { 58 // Recursively look for ref instances. 59 wp_resolve_block_style_variation_ref_values( $value, $theme_json ); 60 } 61 } 62 } 63 } 64 /** 65 * Renders the block style variation's styles. 66 * 67 * In the case of nested blocks with variations applied, we want the parent 68 * variation's styles to be rendered before their descendants. This solves the 69 * issue of a block type being styled in both the parent and descendant: we want 70 * the descendant style to take priority, and this is done by loading it after, 71 * in the DOM order. This is why the variation stylesheet generation is in a 72 * different filter. 73 * 74 * @since 6.6.0 75 * @access private 76 * 77 * @param array $parsed_block The parsed block. 78 * 79 * @return array The parsed block with block style variation classname added. 80 */ 81 function wp_render_block_style_variation_support_styles( $parsed_block ) { 82 $classes = $parsed_block['attrs']['className'] ?? null; 83 $variations = wp_get_block_style_variation_name_from_class( $classes ); 84 85 if ( ! $variations ) { 86 return $parsed_block; 87 } 88 89 $tree = WP_Theme_JSON_Resolver::get_merged_data(); 90 $theme_json = $tree->get_raw_data(); 91 92 // Only the first block style variation with data is supported. 93 $variation_data = array(); 94 foreach ( $variations as $variation ) { 95 $variation_data = $theme_json['styles']['blocks'][ $parsed_block['blockName'] ]['variations'][ $variation ] ?? array(); 96 97 if ( ! empty( $variation_data ) ) { 98 break; 99 } 100 } 101 102 if ( empty( $variation_data ) ) { 103 return $parsed_block; 104 } 105 106 /* 107 * Recursively resolve any ref values with the appropriate value within the 108 * theme_json data. 109 */ 110 wp_resolve_block_style_variation_ref_values( $variation_data, $theme_json ); 111 112 $variation_instance = wp_unique_id( $variation . '--' ); 113 $class_name = "is-style-$variation_instance"; 114 $updated_class_name = $parsed_block['attrs']['className'] . " $class_name"; 115 116 /* 117 * Even though block style variations are effectively theme.json partials, 118 * they can't be processed completely as though they are. 119 * 120 * Block styles support custom selectors to direct specific types of styles 121 * to inner elements. For example, borders on Image block's get applied to 122 * the inner `img` element rather than the wrapping `figure`. 123 * 124 * The following relocates the "root" block style variation styles to 125 * under an appropriate blocks property to leverage the preexisting style 126 * generation for simple block style variations. This way they get the 127 * custom selectors they need. 128 * 129 * The inner elements and block styles for the variation itself are 130 * still included at the top level but scoped by the variation's selector 131 * when the stylesheet is generated. 132 */ 133 $elements_data = $variation_data['elements'] ?? array(); 134 $blocks_data = $variation_data['blocks'] ?? array(); 135 unset( $variation_data['elements'] ); 136 unset( $variation_data['blocks'] ); 137 138 _wp_array_set( 139 $blocks_data, 140 array( $parsed_block['blockName'], 'variations', $variation_instance ), 141 $variation_data 142 ); 143 144 $config = array( 145 'version' => WP_Theme_JSON::LATEST_SCHEMA, 146 'settings' => array( 147 'spacing' => array( 148 'blockGap' => true, 149 ), 150 ), 151 'styles' => array( 152 'elements' => $elements_data, 153 'blocks' => $blocks_data, 154 ), 155 ); 156 157 // Turn off filter that excludes block nodes. They are needed here for the variation's inner block types. 158 if ( ! is_admin() ) { 159 remove_filter( 'wp_theme_json_get_style_nodes', 'wp_filter_out_block_nodes' ); 160 } 161 162 // Temporarily prevent variation instance from being sanitized while processing theme.json. 163 $styles_registry = WP_Block_Styles_Registry::get_instance(); 164 $styles_registry->register( $parsed_block['blockName'], array( 'name' => $variation_instance ) ); 165 166 $variation_theme_json = new WP_Theme_JSON( $config, 'blocks' ); 167 $variation_styles = $variation_theme_json->get_stylesheet( 168 array( 'styles' ), 169 array( 'custom' ), 170 array( 171 'include_block_style_variations' => true, 172 'skip_root_layout_styles' => true, 173 'scope' => ".$class_name", 174 ) 175 ); 176 177 // Clean up temporary block style now instance styles have been processed. 178 $styles_registry->unregister( $parsed_block['blockName'], $variation_instance ); 179 180 // Restore filter that excludes block nodes. 181 if ( ! is_admin() ) { 182 add_filter( 'wp_theme_json_get_style_nodes', 'wp_filter_out_block_nodes' ); 183 } 184 185 if ( empty( $variation_styles ) ) { 186 return $parsed_block; 187 } 188 189 wp_register_style( 'block-style-variation-styles', false, array( 'wp-block-library', 'global-styles' ) ); 190 wp_add_inline_style( 'block-style-variation-styles', $variation_styles ); 191 192 /* 193 * Add variation instance class name to block's className string so it can 194 * be enforced in the block markup via render_block filter. 195 */ 196 _wp_array_set( $parsed_block, array( 'attrs', 'className' ), $updated_class_name ); 197 198 return $parsed_block; 199 } 200 201 /** 202 * Ensures the variation block support class name generated and added to 203 * block attributes in the `render_block_data` filter gets applied to the 204 * block's markup. 205 * 206 * @since 6.6.0 207 * @access private 208 * 209 * @see wp_render_block_style_variation_support_styles 210 * 211 * @param string $block_content Rendered block content. 212 * @param array $block Block object. 213 * 214 * @return string Filtered block content. 215 */ 216 function wp_render_block_style_variation_class_name( $block_content, $block ) { 217 if ( ! $block_content || empty( $block['attrs']['className'] ) ) { 218 return $block_content; 219 } 220 221 /* 222 * Matches a class prefixed by `is-style`, followed by the 223 * variation slug, then `--`, and finally an instance number. 224 */ 225 preg_match( '/\bis-style-(\S+?--\d+)\b/', $block['attrs']['className'], $matches ); 226 227 if ( empty( $matches ) ) { 228 return $block_content; 229 } 230 231 $tags = new WP_HTML_Tag_Processor( $block_content ); 232 233 if ( $tags->next_tag() ) { 234 /* 235 * Ensure the variation instance class name set in the 236 * `render_block_data` filter is applied in markup. 237 * See `wp_render_block_style_variation_support_styles`. 238 */ 239 $tags->add_class( $matches[0] ); 240 } 241 242 return $tags->get_updated_html(); 243 } 244 245 /** 246 * Enqueues styles for block style variations. 247 * 248 * @since 6.6.0 249 * @access private 250 */ 251 function wp_enqueue_block_style_variation_styles() { 252 wp_enqueue_style( 'block-style-variation-styles' ); 253 } 254 255 // Register the block support. 256 WP_Block_Supports::get_instance()->register( 'block-style-variation', array() ); 257 258 add_filter( 'render_block_data', 'wp_render_block_style_variation_support_styles', 10, 2 ); 259 add_filter( 'render_block', 'wp_render_block_style_variation_class_name', 10, 2 ); 260 add_action( 'wp_enqueue_scripts', 'wp_enqueue_block_style_variation_styles', 1 ); 261 262 /** 263 * Registers block style variations read in from theme.json partials. 264 * 265 * @since 6.6.0 266 * @access private 267 * 268 * @param array $variations Shared block style variations. 269 */ 270 function wp_register_block_style_variations_from_theme_json_partials( $variations ) { 271 if ( empty( $variations ) ) { 272 return; 273 } 274 275 $registry = WP_Block_Styles_Registry::get_instance(); 276 277 foreach ( $variations as $variation ) { 278 if ( empty( $variation['blockTypes'] ) || empty( $variation['styles'] ) ) { 279 continue; 280 } 281 282 $variation_name = $variation['slug'] ?? _wp_to_kebab_case( $variation['title'] ); 283 $variation_label = $variation['title'] ?? $variation_name; 284 285 foreach ( $variation['blockTypes'] as $block_type ) { 286 $registered_styles = $registry->get_registered_styles_for_block( $block_type ); 287 288 // Register block style variation if it hasn't already been registered. 289 if ( ! array_key_exists( $variation_name, $registered_styles ) ) { 290 register_block_style( 291 $block_type, 292 array( 293 'name' => $variation_name, 294 'label' => $variation_label, 295 ) 296 ); 297 } 298 } 299 } 300 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sat Jun 20 08:20:11 2026 | Cross-referenced by PHPXref |