| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Style Engine: WP_Style_Engine class 4 * 5 * @package WordPress 6 * @subpackage StyleEngine 7 * @since 6.1.0 8 */ 9 10 /** 11 * The main class integrating all other WP_Style_Engine_* classes. 12 * 13 * The Style Engine aims to provide a consistent API for rendering styling for blocks 14 * across both client-side and server-side applications. 15 * 16 * This class is final and should not be extended. 17 * 18 * This class is for internal Core usage and is not supposed to be used by extenders 19 * (plugins and/or themes). This is a low-level API that may need to do breaking changes. 20 * Please, use wp_style_engine_get_styles() instead. 21 * 22 * @access private 23 * @since 6.1.0 24 * @since 6.3.0 Added support for text-columns. 25 * @since 6.4.0 Added support for background.backgroundImage. 26 * @since 6.5.0 Added support for background.backgroundPosition, 27 * background.backgroundRepeat and dimensions.aspectRatio. 28 * @since 6.7.0 Added support for typography.writingMode. 29 * @since 7.0.0 Added support for typography.textIndent. 30 * @since 7.2.0 Added support for typography.textShadow. 31 */ 32 #[AllowDynamicProperties] 33 final class WP_Style_Engine { 34 /** 35 * The values `background-clip` accepts. 36 * 37 * @since 7.2.0 38 * @var string[] 39 */ 40 const VALID_BACKGROUND_CLIP_VALUES = array( 'border-box', 'padding-box', 'content-box', 'text' ); 41 42 /** 43 * Style definitions that contain the instructions to parse/output valid Gutenberg styles from a block's attributes. 44 * 45 * For every style definition, the following properties are valid: 46 * 47 * - classnames => (array) an array of classnames to be returned for block styles. The key is a classname or pattern. 48 * A value of `true` means the classname should be applied always. Otherwise, a valid CSS property (string) 49 * to match the incoming value, e.g., "color" to match var:preset|color|somePresetSlug. 50 * - css_vars => (array) an array of key value pairs used to generate CSS var values. 51 * The key should be the CSS property name that matches the second element of the preset string value, 52 * i.e., "color" in var:preset|color|somePresetSlug. The value is a CSS var pattern (e.g. `--wp--preset--color--$slug`), 53 * whose `$slug` fragment will be replaced with the preset slug, which is the third element of the preset string value, 54 * i.e., `somePresetSlug` in var:preset|color|somePresetSlug. 55 * - property_keys => (array) array of keys whose values represent a valid CSS property, e.g., "margin" or "border". 56 * - path => (array) a path that accesses the corresponding style value in the block style object. 57 * - value_func => (string) the name of a function to generate a CSS definition array for a particular style object. The output of this function should be `array( "$property" => "$value", ... )`. 58 * 59 * @since 6.1.0 60 * @since 7.1.0 Added `background.gradient` property. 61 * @since 7.2.0 Added `background.backgroundClip` property. 62 * @var array 63 */ 64 const BLOCK_STYLE_DEFINITIONS_METADATA = array( 65 'background' => array( 66 'backgroundImage' => array( 67 'property_keys' => array( 68 'default' => 'background-image', 69 ), 70 'value_func' => array( self::class, 'get_url_or_value_css_declaration' ), 71 'path' => array( 'background', 'backgroundImage' ), 72 ), 73 'backgroundPosition' => array( 74 'property_keys' => array( 75 'default' => 'background-position', 76 ), 77 'path' => array( 'background', 'backgroundPosition' ), 78 ), 79 'backgroundRepeat' => array( 80 'property_keys' => array( 81 'default' => 'background-repeat', 82 ), 83 'path' => array( 'background', 'backgroundRepeat' ), 84 ), 85 'backgroundSize' => array( 86 'property_keys' => array( 87 'default' => 'background-size', 88 ), 89 'path' => array( 'background', 'backgroundSize' ), 90 ), 91 'backgroundAttachment' => array( 92 'property_keys' => array( 93 'default' => 'background-attachment', 94 ), 95 'path' => array( 'background', 'backgroundAttachment' ), 96 ), 97 'gradient' => array( 98 'property_keys' => array( 99 'default' => 'background-image', 100 ), 101 'css_vars' => array( 102 'gradient' => '--wp--preset--gradient--$slug', 103 ), 104 'path' => array( 'background', 'gradient' ), 105 'classnames' => array( 106 'has-background' => true, 107 ), 108 ), 109 'backgroundClip' => array( 110 'value_func' => array( self::class, 'get_background_clip_css_declarations' ), 111 'path' => array( 'background', 'backgroundClip' ), 112 ), 113 ), 114 'color' => array( 115 'text' => array( 116 'property_keys' => array( 117 'default' => 'color', 118 ), 119 'path' => array( 'color', 'text' ), 120 'css_vars' => array( 121 'color' => '--wp--preset--color--$slug', 122 ), 123 'classnames' => array( 124 'has-text-color' => true, 125 'has-$slug-color' => 'color', 126 ), 127 ), 128 'background' => array( 129 'property_keys' => array( 130 'default' => 'background-color', 131 ), 132 'path' => array( 'color', 'background' ), 133 'css_vars' => array( 134 'color' => '--wp--preset--color--$slug', 135 ), 136 'classnames' => array( 137 'has-background' => true, 138 'has-$slug-background-color' => 'color', 139 ), 140 ), 141 'gradient' => array( 142 'property_keys' => array( 143 'default' => 'background', 144 ), 145 'path' => array( 'color', 'gradient' ), 146 'css_vars' => array( 147 'gradient' => '--wp--preset--gradient--$slug', 148 ), 149 'classnames' => array( 150 'has-background' => true, 151 'has-$slug-gradient-background' => 'gradient', 152 ), 153 ), 154 ), 155 'border' => array( 156 'color' => array( 157 'property_keys' => array( 158 'default' => 'border-color', 159 'individual' => 'border-%s-color', 160 ), 161 'path' => array( 'border', 'color' ), 162 'classnames' => array( 163 'has-border-color' => true, 164 'has-$slug-border-color' => 'color', 165 ), 166 ), 167 'radius' => array( 168 'property_keys' => array( 169 'default' => 'border-radius', 170 'individual' => 'border-%s-radius', 171 ), 172 'path' => array( 'border', 'radius' ), 173 'css_vars' => array( 174 'border-radius' => '--wp--preset--border-radius--$slug', 175 ), 176 ), 177 'style' => array( 178 'property_keys' => array( 179 'default' => 'border-style', 180 'individual' => 'border-%s-style', 181 ), 182 'path' => array( 'border', 'style' ), 183 ), 184 'width' => array( 185 'property_keys' => array( 186 'default' => 'border-width', 187 'individual' => 'border-%s-width', 188 ), 189 'path' => array( 'border', 'width' ), 190 ), 191 'top' => array( 192 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), 193 'path' => array( 'border', 'top' ), 194 'css_vars' => array( 195 'color' => '--wp--preset--color--$slug', 196 ), 197 ), 198 'right' => array( 199 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), 200 'path' => array( 'border', 'right' ), 201 'css_vars' => array( 202 'color' => '--wp--preset--color--$slug', 203 ), 204 ), 205 'bottom' => array( 206 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), 207 'path' => array( 'border', 'bottom' ), 208 'css_vars' => array( 209 'color' => '--wp--preset--color--$slug', 210 ), 211 ), 212 'left' => array( 213 'value_func' => array( self::class, 'get_individual_property_css_declarations' ), 214 'path' => array( 'border', 'left' ), 215 'css_vars' => array( 216 'color' => '--wp--preset--color--$slug', 217 ), 218 ), 219 ), 220 'shadow' => array( 221 'shadow' => array( 222 'property_keys' => array( 223 'default' => 'box-shadow', 224 ), 225 'path' => array( 'shadow' ), 226 'css_vars' => array( 227 'shadow' => '--wp--preset--shadow--$slug', 228 ), 229 ), 230 ), 231 'dimensions' => array( 232 'aspectRatio' => array( 233 'property_keys' => array( 234 'default' => 'aspect-ratio', 235 ), 236 'path' => array( 'dimensions', 'aspectRatio' ), 237 'classnames' => array( 238 'has-aspect-ratio' => true, 239 ), 240 ), 241 'height' => array( 242 'property_keys' => array( 243 'default' => 'height', 244 ), 245 'path' => array( 'dimensions', 'height' ), 246 'css_vars' => array( 247 'dimension' => '--wp--preset--dimension--$slug', 248 ), 249 ), 250 'minHeight' => array( 251 'property_keys' => array( 252 'default' => 'min-height', 253 ), 254 'path' => array( 'dimensions', 'minHeight' ), 255 'css_vars' => array( 256 'dimension' => '--wp--preset--dimension--$slug', 257 ), 258 ), 259 'minWidth' => array( 260 'property_keys' => array( 261 'default' => 'min-width', 262 ), 263 'path' => array( 'dimensions', 'minWidth' ), 264 'css_vars' => array( 265 'dimension' => '--wp--preset--dimension--$slug', 266 ), 267 ), 268 'objectFit' => array( 269 'property_keys' => array( 270 'default' => 'object-fit', 271 ), 272 'path' => array( 'dimensions', 'objectFit' ), 273 ), 274 'width' => array( 275 'property_keys' => array( 276 'default' => 'width', 277 ), 278 'path' => array( 'dimensions', 'width' ), 279 'css_vars' => array( 280 'dimension' => '--wp--preset--dimension--$slug', 281 ), 282 ), 283 ), 284 'spacing' => array( 285 'padding' => array( 286 'property_keys' => array( 287 'default' => 'padding', 288 'individual' => 'padding-%s', 289 ), 290 'path' => array( 'spacing', 'padding' ), 291 'css_vars' => array( 292 'spacing' => '--wp--preset--spacing--$slug', 293 ), 294 ), 295 'margin' => array( 296 'property_keys' => array( 297 'default' => 'margin', 298 'individual' => 'margin-%s', 299 ), 300 'path' => array( 'spacing', 'margin' ), 301 'css_vars' => array( 302 'spacing' => '--wp--preset--spacing--$slug', 303 ), 304 ), 305 ), 306 'typography' => array( 307 'fontSize' => array( 308 'property_keys' => array( 309 'default' => 'font-size', 310 ), 311 'path' => array( 'typography', 'fontSize' ), 312 'css_vars' => array( 313 'font-size' => '--wp--preset--font-size--$slug', 314 ), 315 'classnames' => array( 316 'has-$slug-font-size' => 'font-size', 317 ), 318 ), 319 'fontFamily' => array( 320 'property_keys' => array( 321 'default' => 'font-family', 322 ), 323 'css_vars' => array( 324 'font-family' => '--wp--preset--font-family--$slug', 325 ), 326 'path' => array( 'typography', 'fontFamily' ), 327 'classnames' => array( 328 'has-$slug-font-family' => 'font-family', 329 ), 330 ), 331 'fontStyle' => array( 332 'property_keys' => array( 333 'default' => 'font-style', 334 ), 335 'path' => array( 'typography', 'fontStyle' ), 336 ), 337 'fontWeight' => array( 338 'property_keys' => array( 339 'default' => 'font-weight', 340 ), 341 'path' => array( 'typography', 'fontWeight' ), 342 ), 343 'lineHeight' => array( 344 'property_keys' => array( 345 'default' => 'line-height', 346 ), 347 'path' => array( 'typography', 'lineHeight' ), 348 ), 349 'textColumns' => array( 350 'property_keys' => array( 351 'default' => 'column-count', 352 ), 353 'path' => array( 'typography', 'textColumns' ), 354 ), 355 'textDecoration' => array( 356 'property_keys' => array( 357 'default' => 'text-decoration', 358 ), 359 'path' => array( 'typography', 'textDecoration' ), 360 ), 361 'textIndent' => array( 362 'property_keys' => array( 363 'default' => 'text-indent', 364 ), 365 'path' => array( 'typography', 'textIndent' ), 366 ), 367 'textShadow' => array( 368 'property_keys' => array( 369 'default' => 'text-shadow', 370 ), 371 'css_vars' => array( 372 'text-shadow' => '--wp--preset--text-shadow--$slug', 373 ), 374 'path' => array( 'typography', 'textShadow' ), 375 'classnames' => array( 376 'has-$slug-text-shadow' => 'text-shadow', 377 ), 378 ), 379 'textTransform' => array( 380 'property_keys' => array( 381 'default' => 'text-transform', 382 ), 383 'path' => array( 'typography', 'textTransform' ), 384 ), 385 'letterSpacing' => array( 386 'property_keys' => array( 387 'default' => 'letter-spacing', 388 ), 389 'path' => array( 'typography', 'letterSpacing' ), 390 ), 391 'writingMode' => array( 392 'property_keys' => array( 393 'default' => 'writing-mode', 394 ), 395 'path' => array( 'typography', 'writingMode' ), 396 ), 397 ), 398 ); 399 400 /** 401 * Util: Extracts the slug in kebab case from a preset string, 402 * e.g. `heavenly-blue` from `var:preset|color|heavenlyBlue`. 403 * 404 * @since 6.1.0 405 * 406 * @param string $style_value A single CSS preset value. 407 * @param string $property_key The CSS property that is the second element of the preset string. 408 * Used for matching. 409 * @return string The slug, or empty string if not found. 410 */ 411 protected static function get_slug_from_preset_value( $style_value, $property_key ) { 412 if ( is_string( $style_value ) && is_string( $property_key ) 413 && str_contains( $style_value, "var:preset|{$property_key}|" ) 414 ) { 415 $index_to_splice = strrpos( $style_value, '|' ) + 1; 416 return _wp_to_kebab_case( substr( $style_value, $index_to_splice ) ); 417 } 418 return ''; 419 } 420 421 /** 422 * Util: Generates a CSS var string, e.g. `var(--wp--preset--color--background)` 423 * from a preset string such as `var:preset|space|50`. 424 * 425 * @since 6.1.0 426 * 427 * @param string $style_value A single CSS preset value. 428 * @param string[] $css_vars An associate array of CSS var patterns 429 * used to generate the var string. 430 * @return string The CSS var, or an empty string if no match for slug found. 431 */ 432 protected static function get_css_var_value( $style_value, $css_vars ) { 433 foreach ( $css_vars as $property_key => $css_var_pattern ) { 434 $slug = static::get_slug_from_preset_value( $style_value, $property_key ); 435 if ( static::is_valid_style_value( $slug ) ) { 436 $var = strtr( 437 $css_var_pattern, 438 array( '$slug' => $slug ) 439 ); 440 return "var($var)"; 441 } 442 } 443 return ''; 444 } 445 446 /** 447 * Util: Checks whether an incoming block style value is valid. 448 * 449 * @since 6.1.0 450 * 451 * @param string $style_value A single CSS preset value. 452 * @return bool 453 */ 454 protected static function is_valid_style_value( $style_value ) { 455 return '0' === $style_value || ! empty( $style_value ); 456 } 457 458 /** 459 * Stores a CSS rule using the provided CSS selector and CSS declarations. 460 * 461 * @since 6.1.0 462 * @since 6.6.0 Added the `$rules_group` parameter. 463 * @since 7.1.0 Extended `$css_declarations` parameter to accept `WP_Style_Engine_CSS_Declarations` object. 464 * 465 * @param string $store_name A valid store key. 466 * @param string $css_selector When a selector is passed, the function will return 467 * a full CSS rule `$selector { ...rules }` 468 * otherwise a concatenated string of properties and values. 469 * @param string[]|WP_Style_Engine_CSS_Declarations $css_declarations An associative array of CSS definitions, 470 * e.g. `array( "$property" => "$value", "$property" => "$value" )`, 471 * or a WP_Style_Engine_CSS_Declarations object. 472 * @param string $rules_group Optional. A parent CSS selector in the case of nested CSS, 473 * or a CSS nested @rule, such as `@media (min-width: 80rem)` 474 * or `@layer module`. 475 */ 476 public static function store_css_rule( $store_name, $css_selector, $css_declarations, $rules_group = '' ) { 477 if ( empty( $store_name ) || empty( $css_selector ) || empty( $css_declarations ) ) { 478 return; 479 } 480 static::get_store( $store_name )->add_rule( $css_selector, $rules_group )->add_declarations( $css_declarations ); 481 } 482 483 /** 484 * Returns a store by store key. 485 * 486 * @since 6.1.0 487 * 488 * @param string $store_name A store key. 489 * @return WP_Style_Engine_CSS_Rules_Store|null 490 */ 491 public static function get_store( $store_name ) { 492 return WP_Style_Engine_CSS_Rules_Store::get_store( $store_name ); 493 } 494 495 /** 496 * Returns classnames and CSS based on the values in a styles object. 497 * 498 * Return values are parsed based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA. 499 * 500 * @since 6.1.0 501 * 502 * @param array $block_styles The style object. 503 * @param array $options { 504 * Optional. An array of options. Default empty array. 505 * 506 * @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns, 507 * e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`, 508 * to `var( --wp--preset--* )` values. Default false. 509 * @type string $selector Optional. When a selector is passed, 510 * the value of `$css` in the return value will comprise 511 * a full CSS rule `$selector { ...$css_declarations }`, 512 * otherwise, the value will be a concatenated string 513 * of CSS declarations. 514 * } 515 * @return array { 516 * @type string[] $classnames Array of class names. 517 * @type string[] $declarations An associative array of CSS definitions, 518 * e.g. `array( "$property" => "$value", "$property" => "$value" )`. 519 * } 520 */ 521 public static function parse_block_styles( $block_styles, $options ) { 522 $parsed_styles = array( 523 'classnames' => array(), 524 'declarations' => array(), 525 ); 526 if ( empty( $block_styles ) || ! is_array( $block_styles ) ) { 527 return $parsed_styles; 528 } 529 530 // Collect CSS and classnames. 531 foreach ( static::BLOCK_STYLE_DEFINITIONS_METADATA as $definition_group_key => $definition_group_style ) { 532 if ( empty( $block_styles[ $definition_group_key ] ) ) { 533 continue; 534 } 535 foreach ( $definition_group_style as $style_definition ) { 536 $style_value = _wp_array_get( $block_styles, $style_definition['path'], null ); 537 538 if ( ! static::is_valid_style_value( $style_value ) ) { 539 continue; 540 } 541 542 $classnames = static::get_classnames( $style_value, $style_definition ); 543 if ( ! empty( $classnames ) ) { 544 $parsed_styles['classnames'] = array_merge( $parsed_styles['classnames'], $classnames ); 545 } 546 547 $css_declarations = static::get_css_declarations( $style_value, $style_definition, $options ); 548 if ( ! empty( $css_declarations ) ) { 549 /* 550 * Combine background gradient and background image into a single 551 * comma-separated background-image value, matching the JS style engine. 552 */ 553 if ( isset( $css_declarations['background-image'] ) && isset( $parsed_styles['declarations']['background-image'] ) ) { 554 $css_declarations['background-image'] = $css_declarations['background-image'] . ', ' . $parsed_styles['declarations']['background-image']; 555 } 556 $parsed_styles['declarations'] = array_merge( $parsed_styles['declarations'], $css_declarations ); 557 } 558 } 559 } 560 561 return $parsed_styles; 562 } 563 564 /** 565 * Returns classnames, and generates classname(s) from a CSS preset property pattern, 566 * e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`. 567 * 568 * @since 6.1.0 569 * 570 * @param string $style_value A single raw style value or CSS preset property 571 * from the `$block_styles` array. 572 * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA. 573 * @return string[] An array of CSS classnames, or empty array if there are none. 574 */ 575 protected static function get_classnames( $style_value, $style_definition ) { 576 if ( empty( $style_value ) ) { 577 return array(); 578 } 579 580 $classnames = array(); 581 if ( ! empty( $style_definition['classnames'] ) ) { 582 foreach ( $style_definition['classnames'] as $classname => $property_key ) { 583 if ( true === $property_key ) { 584 $classnames[] = $classname; 585 continue; 586 } 587 588 $slug = static::get_slug_from_preset_value( $style_value, $property_key ); 589 590 if ( $slug ) { 591 /* 592 * Right now we expect a classname pattern to be stored in BLOCK_STYLE_DEFINITIONS_METADATA. 593 * One day, if there are no stored schemata, we could allow custom patterns or 594 * generate classnames based on other properties 595 * such as a path or a value or a prefix passed in options. 596 */ 597 $classnames[] = strtr( $classname, array( '$slug' => $slug ) ); 598 } 599 } 600 } 601 602 return $classnames; 603 } 604 605 /** 606 * Returns an array of CSS declarations based on valid block style values. 607 * 608 * @since 6.1.0 609 * 610 * @param mixed $style_value A single raw style value from $block_styles array. 611 * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA. 612 * @param array $options { 613 * Optional. An array of options. Default empty array. 614 * 615 * @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns, 616 * e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`, 617 * to `var( --wp--preset--* )` values. Default false. 618 * } 619 * @return string[] An associative array of CSS definitions, e.g. `array( "$property" => "$value", "$property" => "$value" )`. 620 */ 621 protected static function get_css_declarations( $style_value, $style_definition, $options = array() ) { 622 if ( isset( $style_definition['value_func'] ) && is_callable( $style_definition['value_func'] ) ) { 623 return call_user_func( $style_definition['value_func'], $style_value, $style_definition, $options ); 624 } 625 626 $css_declarations = array(); 627 $style_property_keys = $style_definition['property_keys']; 628 $should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames']; 629 630 /* 631 * Build CSS var values from `var:preset|<PRESET_TYPE>|<PRESET_SLUG>` values, e.g, `var(--wp--css--rule-slug )`. 632 * Check if the value is a CSS preset and there's a corresponding css_var pattern in the style definition. 633 */ 634 if ( is_string( $style_value ) && str_contains( $style_value, 'var:' ) ) { 635 if ( ! $should_skip_css_vars && ! empty( $style_definition['css_vars'] ) ) { 636 $css_var = static::get_css_var_value( $style_value, $style_definition['css_vars'] ); 637 if ( static::is_valid_style_value( $css_var ) ) { 638 $css_declarations[ $style_property_keys['default'] ] = $css_var; 639 } 640 } 641 return $css_declarations; 642 } 643 644 /* 645 * Default rule builder. 646 * If the input contains an array, assume box model-like properties 647 * for styles such as margins and padding. 648 */ 649 if ( is_array( $style_value ) ) { 650 // Bail out early if the `'individual'` property is not defined. 651 if ( ! isset( $style_property_keys['individual'] ) ) { 652 return $css_declarations; 653 } 654 655 foreach ( $style_value as $key => $value ) { 656 if ( is_string( $value ) && str_contains( $value, 'var:' ) && ! $should_skip_css_vars && ! empty( $style_definition['css_vars'] ) ) { 657 $value = static::get_css_var_value( $value, $style_definition['css_vars'] ); 658 } 659 660 $individual_property = sprintf( $style_property_keys['individual'], _wp_to_kebab_case( $key ) ); 661 662 if ( $individual_property && static::is_valid_style_value( $value ) ) { 663 $css_declarations[ $individual_property ] = $value; 664 } 665 } 666 667 return $css_declarations; 668 } 669 670 $css_declarations[ $style_property_keys['default'] ] = $style_value; 671 return $css_declarations; 672 } 673 674 /** 675 * Style value parser that returns a CSS definition array comprising style properties 676 * that have keys representing individual style properties, otherwise known as longhand CSS properties. 677 * 678 * Example: 679 * 680 * "$style_property-$individual_feature: $value;" 681 * 682 * Which could represent the following: 683 * 684 * "border-{top|right|bottom|left}-{color|width|style}: {value};" 685 * 686 * or: 687 * 688 * "border-image-{outset|source|width|repeat|slice}: {value};" 689 * 690 * @since 6.1.0 691 * 692 * @param array $style_value A single raw style value from `$block_styles` array. 693 * @param array $individual_property_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA 694 * representing an individual property of a CSS property, 695 * e.g. 'top' in 'border-top'. 696 * @param array $options { 697 * Optional. An array of options. Default empty array. 698 * 699 * @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns, 700 * e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`, 701 * to `var( --wp--preset--* )` values. Default false. 702 * } 703 * @return string[] An associative array of CSS definitions, e.g. `array( "$property" => "$value", "$property" => "$value" )`. 704 */ 705 protected static function get_individual_property_css_declarations( $style_value, $individual_property_definition, $options = array() ) { 706 if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) { 707 return array(); 708 } 709 710 /* 711 * The first item in $individual_property_definition['path'] array 712 * tells us the style property, e.g. "border". We use this to get a corresponding 713 * CSS style definition such as "color" or "width" from the same group. 714 * 715 * The second item in $individual_property_definition['path'] array 716 * refers to the individual property marker, e.g. "top". 717 */ 718 $definition_group_key = $individual_property_definition['path'][0]; 719 $individual_property_key = $individual_property_definition['path'][1]; 720 $should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames']; 721 $css_declarations = array(); 722 723 foreach ( $style_value as $css_property => $value ) { 724 if ( empty( $value ) ) { 725 continue; 726 } 727 728 // Build a path to the individual rules in definitions. 729 $style_definition_path = array( $definition_group_key, $css_property ); 730 $style_definition = _wp_array_get( static::BLOCK_STYLE_DEFINITIONS_METADATA, $style_definition_path, null ); 731 732 if ( $style_definition && isset( $style_definition['property_keys']['individual'] ) ) { 733 // Set a CSS var if there is a valid preset value. 734 if ( is_string( $value ) && str_contains( $value, 'var:' ) 735 && ! $should_skip_css_vars && ! empty( $individual_property_definition['css_vars'] ) 736 ) { 737 $value = static::get_css_var_value( $value, $individual_property_definition['css_vars'] ); 738 } 739 740 $individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key ); 741 742 $css_declarations[ $individual_css_property ] = $value; 743 } 744 } 745 return $css_declarations; 746 } 747 748 /** 749 * Style value parser that constructs a CSS definition array comprising a single CSS property and value. 750 * If the provided value is an array containing a `url` property, the function will return a CSS definition array 751 * with a single property and value, with `url` escaped and injected into a CSS `url()` function, 752 * e.g., array( 'background-image' => "url( '...' )" ). 753 * 754 * @since 6.4.0 755 * 756 * @param array $style_value A single raw style value from $block_styles array. 757 * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA. 758 * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ). 759 */ 760 protected static function get_url_or_value_css_declaration( $style_value, $style_definition ) { 761 if ( empty( $style_value ) ) { 762 return array(); 763 } 764 765 $css_declarations = array(); 766 767 if ( isset( $style_definition['property_keys']['default'] ) ) { 768 $value = null; 769 770 if ( ! empty( $style_value['url'] ) ) { 771 $value = "url('" . $style_value['url'] . "')"; 772 } elseif ( is_string( $style_value ) ) { 773 $value = $style_value; 774 } 775 776 if ( null !== $value ) { 777 $css_declarations[ $style_definition['property_keys']['default'] ] = $value; 778 } 779 } 780 781 return $css_declarations; 782 } 783 784 /** 785 * Style value parser that returns the CSS declarations for background clipping. 786 * 787 * For the `text` value the background is clipped to the block's text, which 788 * requires the vendor prefixed properties and a transparent fill color. 789 * 790 * @since 7.2.0 791 * 792 * @param string $style_value A single raw style value from $block_styles array. 793 * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA. 794 * @return array<string, string> An associative array of CSS definitions, mapping properties to values. 795 * 796 * @phpstan-return array<non-falsy-string, non-falsy-string> 797 */ 798 protected static function get_background_clip_css_declarations( $style_value, $style_definition ) { 799 if ( ! in_array( $style_value, static::VALID_BACKGROUND_CLIP_VALUES, true ) ) { 800 return array(); 801 } 802 803 $css_declarations = array( 804 'background-clip' => $style_value, 805 ); 806 807 if ( 'text' === $style_value ) { 808 $css_declarations['-webkit-background-clip'] = 'text'; 809 $css_declarations['-webkit-text-fill-color'] = 'transparent'; 810 } else { 811 /* 812 * Only the fill color is restored. `-webkit-background-clip` is an 813 * alias of `background-clip` in Chromium, so resetting it here would 814 * discard the value set above. The fill color is inherited, so it 815 * needs its initial value rather than `unset`, which would take a 816 * transparent fill from an ancestor clipping to text. 817 */ 818 $css_declarations['-webkit-text-fill-color'] = 'currentColor'; 819 } 820 821 return $css_declarations; 822 } 823 824 /** 825 * Returns compiled CSS from CSS declarations. 826 * 827 * @since 6.1.0 828 * 829 * @param string[] $css_declarations An associative array of CSS definitions, 830 * e.g. `array( "$property" => "$value", "$property" => "$value" )`. 831 * @param string $css_selector When a selector is passed, the function will return 832 * a full CSS rule `$selector { ...rules }`, 833 * otherwise a concatenated string of properties and values. 834 * @return string A compiled CSS string. 835 */ 836 public static function compile_css( $css_declarations, $css_selector ) { 837 if ( empty( $css_declarations ) || ! is_array( $css_declarations ) ) { 838 return ''; 839 } 840 841 // Return an entire rule if there is a selector. 842 if ( $css_selector ) { 843 $css_rule = new WP_Style_Engine_CSS_Rule( $css_selector, $css_declarations ); 844 return $css_rule->get_css(); 845 } 846 847 $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations ); 848 return $css_declarations->get_declarations_string(); 849 } 850 851 /** 852 * Returns a compiled stylesheet from stored CSS rules. 853 * 854 * @since 6.1.0 855 * 856 * @param WP_Style_Engine_CSS_Rule[] $css_rules An array of WP_Style_Engine_CSS_Rule objects 857 * from a store or otherwise. 858 * @param array $options { 859 * Optional. An array of options. Default empty array. 860 * 861 * @type string|null $context An identifier describing the origin of the style object, 862 * e.g. 'block-supports' or 'global-styles'. Default 'block-supports'. 863 * When set, the style engine will attempt to store the CSS rules. 864 * @type bool $optimize Whether to optimize the CSS output, e.g. combine rules. 865 * Default false. 866 * @type bool $prettify Whether to add new lines and indents to output. 867 * Defaults to whether the `SCRIPT_DEBUG` constant is defined. 868 * } 869 * @return string A compiled stylesheet from stored CSS rules. 870 */ 871 public static function compile_stylesheet_from_css_rules( $css_rules, $options = array() ) { 872 $processor = new WP_Style_Engine_Processor(); 873 $processor->add_rules( $css_rules ); 874 return $processor->get_css( $options ); 875 } 876 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sun Oct 25 08:20:35 2026 | Cross-referenced by PHPXref |