| [ 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 // Ensure variation state styles know about any custom viewport breakpoints. 158 if ( isset( $theme_json['settings']['viewport'] ) ) { 159 $config['settings']['viewport'] = $theme_json['settings']['viewport']; 160 } 161 162 // Turn off filter that excludes block nodes. They are needed here for the variation's inner block types. 163 if ( ! is_admin() ) { 164 remove_filter( 'wp_theme_json_get_style_nodes', 'wp_filter_out_block_nodes' ); 165 } 166 167 // Temporarily prevent variation instance from being sanitized while processing theme.json. 168 $styles_registry = WP_Block_Styles_Registry::get_instance(); 169 $styles_registry->register( $parsed_block['blockName'], array( 'name' => $variation_instance ) ); 170 171 $variation_theme_json = new WP_Theme_JSON( $config, 'blocks' ); 172 $variation_styles = $variation_theme_json->get_stylesheet( 173 array( 'styles' ), 174 array( 'custom' ), 175 array( 176 'include_block_style_variations' => true, 177 'skip_root_layout_styles' => true, 178 'scope' => ".$class_name", 179 ) 180 ); 181 182 // Clean up temporary block style now instance styles have been processed. 183 $styles_registry->unregister( $parsed_block['blockName'], $variation_instance ); 184 185 // Restore filter that excludes block nodes. 186 if ( ! is_admin() ) { 187 add_filter( 'wp_theme_json_get_style_nodes', 'wp_filter_out_block_nodes' ); 188 } 189 190 if ( empty( $variation_styles ) ) { 191 return $parsed_block; 192 } 193 194 wp_register_style( 'block-style-variation-styles', false, array( 'wp-block-library', 'global-styles' ) ); 195 wp_add_inline_style( 'block-style-variation-styles', $variation_styles ); 196 197 /* 198 * Add variation instance class name to block's className string so it can 199 * be enforced in the block markup via render_block filter. 200 */ 201 _wp_array_set( $parsed_block, array( 'attrs', 'className' ), $updated_class_name ); 202 203 return $parsed_block; 204 } 205 206 /** 207 * Ensures the variation block support class name generated and added to 208 * block attributes in the `render_block_data` filter gets applied to the 209 * block's markup. 210 * 211 * @since 6.6.0 212 * @access private 213 * 214 * @see wp_render_block_style_variation_support_styles 215 * 216 * @param string $block_content Rendered block content. 217 * @param array $block Block object. 218 * 219 * @return string Filtered block content. 220 */ 221 function wp_render_block_style_variation_class_name( $block_content, $block ) { 222 if ( ! $block_content || empty( $block['attrs']['className'] ) ) { 223 return $block_content; 224 } 225 226 /* 227 * Matches a class prefixed by `is-style`, followed by the 228 * variation slug, then `--`, and finally an instance number. 229 */ 230 preg_match( '/\bis-style-(\S+?--\d+)\b/', $block['attrs']['className'], $matches ); 231 232 if ( empty( $matches ) ) { 233 return $block_content; 234 } 235 236 $tags = new WP_HTML_Tag_Processor( $block_content ); 237 238 if ( $tags->next_tag() ) { 239 /* 240 * Ensure the variation instance class name set in the 241 * `render_block_data` filter is applied in markup. 242 * See `wp_render_block_style_variation_support_styles`. 243 */ 244 $tags->add_class( $matches[0] ); 245 } 246 247 return $tags->get_updated_html(); 248 } 249 250 /** 251 * Enqueues styles for block style variations. 252 * 253 * @since 6.6.0 254 * @access private 255 */ 256 function wp_enqueue_block_style_variation_styles() { 257 wp_enqueue_style( 'block-style-variation-styles' ); 258 } 259 260 // Register the block support. 261 WP_Block_Supports::get_instance()->register( 'block-style-variation', array() ); 262 263 add_filter( 'render_block_data', 'wp_render_block_style_variation_support_styles', 10, 2 ); 264 add_filter( 'render_block', 'wp_render_block_style_variation_class_name', 10, 2 ); 265 add_action( 'wp_enqueue_scripts', 'wp_enqueue_block_style_variation_styles', 1 ); 266 267 /** 268 * Registers block style variations read in from theme.json partials. 269 * 270 * @since 6.6.0 271 * @access private 272 * 273 * @param array $variations Shared block style variations. 274 */ 275 function wp_register_block_style_variations_from_theme_json_partials( $variations ) { 276 if ( empty( $variations ) ) { 277 return; 278 } 279 280 $registry = WP_Block_Styles_Registry::get_instance(); 281 282 foreach ( $variations as $variation ) { 283 if ( empty( $variation['blockTypes'] ) || empty( $variation['styles'] ) ) { 284 continue; 285 } 286 287 $variation_name = $variation['slug'] ?? _wp_to_kebab_case( $variation['title'] ); 288 $variation_label = $variation['title'] ?? $variation_name; 289 290 foreach ( $variation['blockTypes'] as $block_type ) { 291 $registered_styles = $registry->get_registered_styles_for_block( $block_type ); 292 293 // Register block style variation if it hasn't already been registered. 294 if ( ! array_key_exists( $variation_name, $registered_styles ) ) { 295 register_block_style( 296 $block_type, 297 array( 298 'name' => $variation_name, 299 'label' => $variation_label, 300 ) 301 ); 302 } 303 } 304 } 305 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Fri Jul 10 08:20:14 2026 | Cross-referenced by PHPXref |