[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/style-engine/ -> class-wp-style-engine.php (source)

   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   */
  30  #[AllowDynamicProperties]
  31  final class WP_Style_Engine {
  32      /**
  33       * Style definitions that contain the instructions to parse/output valid Gutenberg styles from a block's attributes.
  34       *
  35       * For every style definition, the following properties are valid:
  36       *
  37       *  - classnames    => (array) an array of classnames to be returned for block styles. The key is a classname or pattern.
  38       *                    A value of `true` means the classname should be applied always. Otherwise, a valid CSS property (string)
  39       *                    to match the incoming value, e.g., "color" to match var:preset|color|somePresetSlug.
  40       *  - css_vars      => (array) an array of key value pairs used to generate CSS var values.
  41       *                     The key should be the CSS property name that matches the second element of the preset string value,
  42       *                     i.e., "color" in var:preset|color|somePresetSlug. The value is a CSS var pattern (e.g. `--wp--preset--color--$slug`),
  43       *                     whose `$slug` fragment will be replaced with the preset slug, which is the third element of the preset string value,
  44       *                     i.e., `somePresetSlug` in var:preset|color|somePresetSlug.
  45       *  - property_keys => (array) array of keys whose values represent a valid CSS property, e.g., "margin" or "border".
  46       *  - path          => (array) a path that accesses the corresponding style value in the block style object.
  47       *  - 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", ... )`.
  48       *
  49       * @since 6.1.0
  50       * @var array
  51       */
  52      const BLOCK_STYLE_DEFINITIONS_METADATA = array(
  53          'background' => array(
  54              'backgroundImage'      => array(
  55                  'property_keys' => array(
  56                      'default' => 'background-image',
  57                  ),
  58                  'value_func'    => array( self::class, 'get_url_or_value_css_declaration' ),
  59                  'path'          => array( 'background', 'backgroundImage' ),
  60              ),
  61              'backgroundPosition'   => array(
  62                  'property_keys' => array(
  63                      'default' => 'background-position',
  64                  ),
  65                  'path'          => array( 'background', 'backgroundPosition' ),
  66              ),
  67              'backgroundRepeat'     => array(
  68                  'property_keys' => array(
  69                      'default' => 'background-repeat',
  70                  ),
  71                  'path'          => array( 'background', 'backgroundRepeat' ),
  72              ),
  73              'backgroundSize'       => array(
  74                  'property_keys' => array(
  75                      'default' => 'background-size',
  76                  ),
  77                  'path'          => array( 'background', 'backgroundSize' ),
  78              ),
  79              'backgroundAttachment' => array(
  80                  'property_keys' => array(
  81                      'default' => 'background-attachment',
  82                  ),
  83                  'path'          => array( 'background', 'backgroundAttachment' ),
  84              ),
  85          ),
  86          'color'      => array(
  87              'text'       => array(
  88                  'property_keys' => array(
  89                      'default' => 'color',
  90                  ),
  91                  'path'          => array( 'color', 'text' ),
  92                  'css_vars'      => array(
  93                      'color' => '--wp--preset--color--$slug',
  94                  ),
  95                  'classnames'    => array(
  96                      'has-text-color'  => true,
  97                      'has-$slug-color' => 'color',
  98                  ),
  99              ),
 100              'background' => array(
 101                  'property_keys' => array(
 102                      'default' => 'background-color',
 103                  ),
 104                  'path'          => array( 'color', 'background' ),
 105                  'css_vars'      => array(
 106                      'color' => '--wp--preset--color--$slug',
 107                  ),
 108                  'classnames'    => array(
 109                      'has-background'             => true,
 110                      'has-$slug-background-color' => 'color',
 111                  ),
 112              ),
 113              'gradient'   => array(
 114                  'property_keys' => array(
 115                      'default' => 'background',
 116                  ),
 117                  'path'          => array( 'color', 'gradient' ),
 118                  'css_vars'      => array(
 119                      'gradient' => '--wp--preset--gradient--$slug',
 120                  ),
 121                  'classnames'    => array(
 122                      'has-background'                => true,
 123                      'has-$slug-gradient-background' => 'gradient',
 124                  ),
 125              ),
 126          ),
 127          'border'     => array(
 128              'color'  => array(
 129                  'property_keys' => array(
 130                      'default'    => 'border-color',
 131                      'individual' => 'border-%s-color',
 132                  ),
 133                  'path'          => array( 'border', 'color' ),
 134                  'classnames'    => array(
 135                      'has-border-color'       => true,
 136                      'has-$slug-border-color' => 'color',
 137                  ),
 138              ),
 139              'radius' => array(
 140                  'property_keys' => array(
 141                      'default'    => 'border-radius',
 142                      'individual' => 'border-%s-radius',
 143                  ),
 144                  'path'          => array( 'border', 'radius' ),
 145              ),
 146              'style'  => array(
 147                  'property_keys' => array(
 148                      'default'    => 'border-style',
 149                      'individual' => 'border-%s-style',
 150                  ),
 151                  'path'          => array( 'border', 'style' ),
 152              ),
 153              'width'  => array(
 154                  'property_keys' => array(
 155                      'default'    => 'border-width',
 156                      'individual' => 'border-%s-width',
 157                  ),
 158                  'path'          => array( 'border', 'width' ),
 159              ),
 160              'top'    => array(
 161                  'value_func' => array( self::class, 'get_individual_property_css_declarations' ),
 162                  'path'       => array( 'border', 'top' ),
 163                  'css_vars'   => array(
 164                      'color' => '--wp--preset--color--$slug',
 165                  ),
 166              ),
 167              'right'  => array(
 168                  'value_func' => array( self::class, 'get_individual_property_css_declarations' ),
 169                  'path'       => array( 'border', 'right' ),
 170                  'css_vars'   => array(
 171                      'color' => '--wp--preset--color--$slug',
 172                  ),
 173              ),
 174              'bottom' => array(
 175                  'value_func' => array( self::class, 'get_individual_property_css_declarations' ),
 176                  'path'       => array( 'border', 'bottom' ),
 177                  'css_vars'   => array(
 178                      'color' => '--wp--preset--color--$slug',
 179                  ),
 180              ),
 181              'left'   => array(
 182                  'value_func' => array( self::class, 'get_individual_property_css_declarations' ),
 183                  'path'       => array( 'border', 'left' ),
 184                  'css_vars'   => array(
 185                      'color' => '--wp--preset--color--$slug',
 186                  ),
 187              ),
 188          ),
 189          'shadow'     => array(
 190              'shadow' => array(
 191                  'property_keys' => array(
 192                      'default' => 'box-shadow',
 193                  ),
 194                  'path'          => array( 'shadow' ),
 195                  'css_vars'      => array(
 196                      'shadow' => '--wp--preset--shadow--$slug',
 197                  ),
 198              ),
 199          ),
 200          'dimensions' => array(
 201              'aspectRatio' => array(
 202                  'property_keys' => array(
 203                      'default' => 'aspect-ratio',
 204                  ),
 205                  'path'          => array( 'dimensions', 'aspectRatio' ),
 206                  'classnames'    => array(
 207                      'has-aspect-ratio' => true,
 208                  ),
 209              ),
 210              'minHeight'   => array(
 211                  'property_keys' => array(
 212                      'default' => 'min-height',
 213                  ),
 214                  'path'          => array( 'dimensions', 'minHeight' ),
 215                  'css_vars'      => array(
 216                      'spacing' => '--wp--preset--spacing--$slug',
 217                  ),
 218              ),
 219          ),
 220          'spacing'    => array(
 221              'padding' => array(
 222                  'property_keys' => array(
 223                      'default'    => 'padding',
 224                      'individual' => 'padding-%s',
 225                  ),
 226                  'path'          => array( 'spacing', 'padding' ),
 227                  'css_vars'      => array(
 228                      'spacing' => '--wp--preset--spacing--$slug',
 229                  ),
 230              ),
 231              'margin'  => array(
 232                  'property_keys' => array(
 233                      'default'    => 'margin',
 234                      'individual' => 'margin-%s',
 235                  ),
 236                  'path'          => array( 'spacing', 'margin' ),
 237                  'css_vars'      => array(
 238                      'spacing' => '--wp--preset--spacing--$slug',
 239                  ),
 240              ),
 241          ),
 242          'typography' => array(
 243              'fontSize'       => array(
 244                  'property_keys' => array(
 245                      'default' => 'font-size',
 246                  ),
 247                  'path'          => array( 'typography', 'fontSize' ),
 248                  'css_vars'      => array(
 249                      'font-size' => '--wp--preset--font-size--$slug',
 250                  ),
 251                  'classnames'    => array(
 252                      'has-$slug-font-size' => 'font-size',
 253                  ),
 254              ),
 255              'fontFamily'     => array(
 256                  'property_keys' => array(
 257                      'default' => 'font-family',
 258                  ),
 259                  'css_vars'      => array(
 260                      'font-family' => '--wp--preset--font-family--$slug',
 261                  ),
 262                  'path'          => array( 'typography', 'fontFamily' ),
 263                  'classnames'    => array(
 264                      'has-$slug-font-family' => 'font-family',
 265                  ),
 266              ),
 267              'fontStyle'      => array(
 268                  'property_keys' => array(
 269                      'default' => 'font-style',
 270                  ),
 271                  'path'          => array( 'typography', 'fontStyle' ),
 272              ),
 273              'fontWeight'     => array(
 274                  'property_keys' => array(
 275                      'default' => 'font-weight',
 276                  ),
 277                  'path'          => array( 'typography', 'fontWeight' ),
 278              ),
 279              'lineHeight'     => array(
 280                  'property_keys' => array(
 281                      'default' => 'line-height',
 282                  ),
 283                  'path'          => array( 'typography', 'lineHeight' ),
 284              ),
 285              'textColumns'    => array(
 286                  'property_keys' => array(
 287                      'default' => 'column-count',
 288                  ),
 289                  'path'          => array( 'typography', 'textColumns' ),
 290              ),
 291              'textDecoration' => array(
 292                  'property_keys' => array(
 293                      'default' => 'text-decoration',
 294                  ),
 295                  'path'          => array( 'typography', 'textDecoration' ),
 296              ),
 297              'textTransform'  => array(
 298                  'property_keys' => array(
 299                      'default' => 'text-transform',
 300                  ),
 301                  'path'          => array( 'typography', 'textTransform' ),
 302              ),
 303              'letterSpacing'  => array(
 304                  'property_keys' => array(
 305                      'default' => 'letter-spacing',
 306                  ),
 307                  'path'          => array( 'typography', 'letterSpacing' ),
 308              ),
 309              'writingMode'    => array(
 310                  'property_keys' => array(
 311                      'default' => 'writing-mode',
 312                  ),
 313                  'path'          => array( 'typography', 'writingMode' ),
 314              ),
 315          ),
 316      );
 317  
 318      /**
 319       * Util: Extracts the slug in kebab case from a preset string,
 320       * e.g. `heavenly-blue` from `var:preset|color|heavenlyBlue`.
 321       *
 322       * @since 6.1.0
 323       *
 324       * @param string $style_value  A single CSS preset value.
 325       * @param string $property_key The CSS property that is the second element of the preset string.
 326       *                             Used for matching.
 327       * @return string The slug, or empty string if not found.
 328       */
 329  	protected static function get_slug_from_preset_value( $style_value, $property_key ) {
 330          if ( is_string( $style_value ) && is_string( $property_key )
 331              && str_contains( $style_value, "var:preset|{$property_key}|" )
 332          ) {
 333              $index_to_splice = strrpos( $style_value, '|' ) + 1;
 334              return _wp_to_kebab_case( substr( $style_value, $index_to_splice ) );
 335          }
 336          return '';
 337      }
 338  
 339      /**
 340       * Util: Generates a CSS var string, e.g. `var(--wp--preset--color--background)`
 341       * from a preset string such as `var:preset|space|50`.
 342       *
 343       * @since 6.1.0
 344       *
 345       * @param string   $style_value  A single CSS preset value.
 346       * @param string[] $css_vars     An associate array of CSS var patterns
 347       *                               used to generate the var string.
 348       * @return string The CSS var, or an empty string if no match for slug found.
 349       */
 350  	protected static function get_css_var_value( $style_value, $css_vars ) {
 351          foreach ( $css_vars as $property_key => $css_var_pattern ) {
 352              $slug = static::get_slug_from_preset_value( $style_value, $property_key );
 353              if ( static::is_valid_style_value( $slug ) ) {
 354                  $var = strtr(
 355                      $css_var_pattern,
 356                      array( '$slug' => $slug )
 357                  );
 358                  return "var($var)";
 359              }
 360          }
 361          return '';
 362      }
 363  
 364      /**
 365       * Util: Checks whether an incoming block style value is valid.
 366       *
 367       * @since 6.1.0
 368       *
 369       * @param string $style_value A single CSS preset value.
 370       * @return bool
 371       */
 372  	protected static function is_valid_style_value( $style_value ) {
 373          return '0' === $style_value || ! empty( $style_value );
 374      }
 375  
 376      /**
 377       * Stores a CSS rule using the provided CSS selector and CSS declarations.
 378       *
 379       * @since 6.1.0
 380       * @since 6.6.0 Added the `$rules_group` parameter.
 381       *
 382       * @param string   $store_name       A valid store key.
 383       * @param string   $css_selector     When a selector is passed, the function will return
 384       *                                   a full CSS rule `$selector { ...rules }`
 385       *                                   otherwise a concatenated string of properties and values.
 386       * @param string[] $css_declarations An associative array of CSS definitions,
 387       *                                   e.g. `array( "$property" => "$value", "$property" => "$value" )`.
 388       * @param string $rules_group        Optional. A parent CSS selector in the case of nested CSS, or a CSS nested @rule,
 389       *                                   such as `@media (min-width: 80rem)` or `@layer module`.
 390       */
 391  	public static function store_css_rule( $store_name, $css_selector, $css_declarations, $rules_group = '' ) {
 392          if ( empty( $store_name ) || empty( $css_selector ) || empty( $css_declarations ) ) {
 393              return;
 394          }
 395          static::get_store( $store_name )->add_rule( $css_selector, $rules_group )->add_declarations( $css_declarations );
 396      }
 397  
 398      /**
 399       * Returns a store by store key.
 400       *
 401       * @since 6.1.0
 402       *
 403       * @param string $store_name A store key.
 404       * @return WP_Style_Engine_CSS_Rules_Store|null
 405       */
 406  	public static function get_store( $store_name ) {
 407          return WP_Style_Engine_CSS_Rules_Store::get_store( $store_name );
 408      }
 409  
 410      /**
 411       * Returns classnames and CSS based on the values in a styles object.
 412       *
 413       * Return values are parsed based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA.
 414       *
 415       * @since 6.1.0
 416       *
 417       * @param array $block_styles The style object.
 418       * @param array $options      {
 419       *     Optional. An array of options. Default empty array.
 420       *
 421       *     @type bool        $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns,
 422       *                                                   e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`,
 423       *                                                   to `var( --wp--preset--* )` values. Default false.
 424       *     @type string      $selector                   Optional. When a selector is passed,
 425       *                                                   the value of `$css` in the return value will comprise
 426       *                                                   a full CSS rule `$selector { ...$css_declarations }`,
 427       *                                                   otherwise, the value will be a concatenated string
 428       *                                                   of CSS declarations.
 429       * }
 430       * @return array {
 431       *     @type string[] $classnames   Array of class names.
 432       *     @type string[] $declarations An associative array of CSS definitions,
 433       *                                  e.g. `array( "$property" => "$value", "$property" => "$value" )`.
 434       * }
 435       */
 436  	public static function parse_block_styles( $block_styles, $options ) {
 437          $parsed_styles = array(
 438              'classnames'   => array(),
 439              'declarations' => array(),
 440          );
 441          if ( empty( $block_styles ) || ! is_array( $block_styles ) ) {
 442              return $parsed_styles;
 443          }
 444  
 445          // Collect CSS and classnames.
 446          foreach ( static::BLOCK_STYLE_DEFINITIONS_METADATA as $definition_group_key => $definition_group_style ) {
 447              if ( empty( $block_styles[ $definition_group_key ] ) ) {
 448                  continue;
 449              }
 450              foreach ( $definition_group_style as $style_definition ) {
 451                  $style_value = _wp_array_get( $block_styles, $style_definition['path'], null );
 452  
 453                  if ( ! static::is_valid_style_value( $style_value ) ) {
 454                      continue;
 455                  }
 456  
 457                  $parsed_styles['classnames']   = array_merge( $parsed_styles['classnames'], static::get_classnames( $style_value, $style_definition ) );
 458                  $parsed_styles['declarations'] = array_merge( $parsed_styles['declarations'], static::get_css_declarations( $style_value, $style_definition, $options ) );
 459              }
 460          }
 461  
 462          return $parsed_styles;
 463      }
 464  
 465      /**
 466       * Returns classnames, and generates classname(s) from a CSS preset property pattern,
 467       * e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`.
 468       *
 469       * @since 6.1.0
 470       *
 471       * @param string $style_value      A single raw style value or CSS preset property
 472       *                                 from the `$block_styles` array.
 473       * @param array  $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
 474       * @return string[] An array of CSS classnames, or empty array if there are none.
 475       */
 476  	protected static function get_classnames( $style_value, $style_definition ) {
 477          if ( empty( $style_value ) ) {
 478              return array();
 479          }
 480  
 481          $classnames = array();
 482          if ( ! empty( $style_definition['classnames'] ) ) {
 483              foreach ( $style_definition['classnames'] as $classname => $property_key ) {
 484                  if ( true === $property_key ) {
 485                      $classnames[] = $classname;
 486                      continue;
 487                  }
 488  
 489                  $slug = static::get_slug_from_preset_value( $style_value, $property_key );
 490  
 491                  if ( $slug ) {
 492                      /*
 493                       * Right now we expect a classname pattern to be stored in BLOCK_STYLE_DEFINITIONS_METADATA.
 494                       * One day, if there are no stored schemata, we could allow custom patterns or
 495                       * generate classnames based on other properties
 496                       * such as a path or a value or a prefix passed in options.
 497                       */
 498                      $classnames[] = strtr( $classname, array( '$slug' => $slug ) );
 499                  }
 500              }
 501          }
 502  
 503          return $classnames;
 504      }
 505  
 506      /**
 507       * Returns an array of CSS declarations based on valid block style values.
 508       *
 509       * @since 6.1.0
 510       *
 511       * @param mixed $style_value      A single raw style value from $block_styles array.
 512       * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
 513       * @param array $options          {
 514       *     Optional. An array of options. Default empty array.
 515       *
 516       *     @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns,
 517       *                                            e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`,
 518       *                                            to `var( --wp--preset--* )` values. Default false.
 519       * }
 520       * @return string[] An associative array of CSS definitions, e.g. `array( "$property" => "$value", "$property" => "$value" )`.
 521       */
 522  	protected static function get_css_declarations( $style_value, $style_definition, $options = array() ) {
 523          if ( isset( $style_definition['value_func'] ) && is_callable( $style_definition['value_func'] ) ) {
 524              return call_user_func( $style_definition['value_func'], $style_value, $style_definition, $options );
 525          }
 526  
 527          $css_declarations     = array();
 528          $style_property_keys  = $style_definition['property_keys'];
 529          $should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames'];
 530  
 531          /*
 532           * Build CSS var values from `var:preset|<PRESET_TYPE>|<PRESET_SLUG>` values, e.g, `var(--wp--css--rule-slug )`.
 533           * Check if the value is a CSS preset and there's a corresponding css_var pattern in the style definition.
 534           */
 535          if ( is_string( $style_value ) && str_contains( $style_value, 'var:' ) ) {
 536              if ( ! $should_skip_css_vars && ! empty( $style_definition['css_vars'] ) ) {
 537                  $css_var = static::get_css_var_value( $style_value, $style_definition['css_vars'] );
 538                  if ( static::is_valid_style_value( $css_var ) ) {
 539                      $css_declarations[ $style_property_keys['default'] ] = $css_var;
 540                  }
 541              }
 542              return $css_declarations;
 543          }
 544  
 545          /*
 546           * Default rule builder.
 547           * If the input contains an array, assume box model-like properties
 548           * for styles such as margins and padding.
 549           */
 550          if ( is_array( $style_value ) ) {
 551              // Bail out early if the `'individual'` property is not defined.
 552              if ( ! isset( $style_property_keys['individual'] ) ) {
 553                  return $css_declarations;
 554              }
 555  
 556              foreach ( $style_value as $key => $value ) {
 557                  if ( is_string( $value ) && str_contains( $value, 'var:' ) && ! $should_skip_css_vars && ! empty( $style_definition['css_vars'] ) ) {
 558                      $value = static::get_css_var_value( $value, $style_definition['css_vars'] );
 559                  }
 560  
 561                  $individual_property = sprintf( $style_property_keys['individual'], _wp_to_kebab_case( $key ) );
 562  
 563                  if ( $individual_property && static::is_valid_style_value( $value ) ) {
 564                      $css_declarations[ $individual_property ] = $value;
 565                  }
 566              }
 567  
 568              return $css_declarations;
 569          }
 570  
 571          $css_declarations[ $style_property_keys['default'] ] = $style_value;
 572          return $css_declarations;
 573      }
 574  
 575      /**
 576       * Style value parser that returns a CSS definition array comprising style properties
 577       * that have keys representing individual style properties, otherwise known as longhand CSS properties.
 578       *
 579       * Example:
 580       *
 581       *     "$style_property-$individual_feature: $value;"
 582       *
 583       * Which could represent the following:
 584       *
 585       *     "border-{top|right|bottom|left}-{color|width|style}: {value};"
 586       *
 587       * or:
 588       *
 589       *     "border-image-{outset|source|width|repeat|slice}: {value};"
 590       *
 591       * @since 6.1.0
 592       *
 593       * @param array $style_value                    A single raw style value from `$block_styles` array.
 594       * @param array $individual_property_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA
 595       *                                              representing an individual property of a CSS property,
 596       *                                              e.g. 'top' in 'border-top'.
 597       * @param array $options                        {
 598       *     Optional. An array of options. Default empty array.
 599       *
 600       *     @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns,
 601       *                                            e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`,
 602       *                                            to `var( --wp--preset--* )` values. Default false.
 603       * }
 604       * @return string[] An associative array of CSS definitions, e.g. `array( "$property" => "$value", "$property" => "$value" )`.
 605       */
 606  	protected static function get_individual_property_css_declarations( $style_value, $individual_property_definition, $options = array() ) {
 607          if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) {
 608              return array();
 609          }
 610  
 611          /*
 612           * The first item in $individual_property_definition['path'] array
 613           * tells us the style property, e.g. "border". We use this to get a corresponding
 614           * CSS style definition such as "color" or "width" from the same group.
 615           *
 616           * The second item in $individual_property_definition['path'] array
 617           * refers to the individual property marker, e.g. "top".
 618           */
 619          $definition_group_key    = $individual_property_definition['path'][0];
 620          $individual_property_key = $individual_property_definition['path'][1];
 621          $should_skip_css_vars    = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames'];
 622          $css_declarations        = array();
 623  
 624          foreach ( $style_value as $css_property => $value ) {
 625              if ( empty( $value ) ) {
 626                  continue;
 627              }
 628  
 629              // Build a path to the individual rules in definitions.
 630              $style_definition_path = array( $definition_group_key, $css_property );
 631              $style_definition      = _wp_array_get( static::BLOCK_STYLE_DEFINITIONS_METADATA, $style_definition_path, null );
 632  
 633              if ( $style_definition && isset( $style_definition['property_keys']['individual'] ) ) {
 634                  // Set a CSS var if there is a valid preset value.
 635                  if ( is_string( $value ) && str_contains( $value, 'var:' )
 636                      && ! $should_skip_css_vars && ! empty( $individual_property_definition['css_vars'] )
 637                  ) {
 638                      $value = static::get_css_var_value( $value, $individual_property_definition['css_vars'] );
 639                  }
 640  
 641                  $individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key );
 642  
 643                  $css_declarations[ $individual_css_property ] = $value;
 644              }
 645          }
 646          return $css_declarations;
 647      }
 648  
 649      /**
 650       * Style value parser that constructs a CSS definition array comprising a single CSS property and value.
 651       * If the provided value is an array containing a `url` property, the function will return a CSS definition array
 652       * with a single property and value, with `url` escaped and injected into a CSS `url()` function,
 653       * e.g., array( 'background-image' => "url( '...' )" ).
 654       *
 655       * @since 6.4.0
 656       *
 657       * @param array $style_value      A single raw style value from $block_styles array.
 658       * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
 659       * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ).
 660       */
 661  	protected static function get_url_or_value_css_declaration( $style_value, $style_definition ) {
 662          if ( empty( $style_value ) ) {
 663              return array();
 664          }
 665  
 666          $css_declarations = array();
 667  
 668          if ( isset( $style_definition['property_keys']['default'] ) ) {
 669              $value = null;
 670  
 671              if ( ! empty( $style_value['url'] ) ) {
 672                  $value = "url('" . $style_value['url'] . "')";
 673              } elseif ( is_string( $style_value ) ) {
 674                  $value = $style_value;
 675              }
 676  
 677              if ( null !== $value ) {
 678                  $css_declarations[ $style_definition['property_keys']['default'] ] = $value;
 679              }
 680          }
 681  
 682          return $css_declarations;
 683      }
 684  
 685      /**
 686       * Returns compiled CSS from CSS declarations.
 687       *
 688       * @since 6.1.0
 689       *
 690       * @param string[] $css_declarations An associative array of CSS definitions,
 691       *                                   e.g. `array( "$property" => "$value", "$property" => "$value" )`.
 692       * @param string   $css_selector     When a selector is passed, the function will return
 693       *                                   a full CSS rule `$selector { ...rules }`,
 694       *                                   otherwise a concatenated string of properties and values.
 695       * @return string A compiled CSS string.
 696       */
 697  	public static function compile_css( $css_declarations, $css_selector ) {
 698          if ( empty( $css_declarations ) || ! is_array( $css_declarations ) ) {
 699              return '';
 700          }
 701  
 702          // Return an entire rule if there is a selector.
 703          if ( $css_selector ) {
 704              $css_rule = new WP_Style_Engine_CSS_Rule( $css_selector, $css_declarations );
 705              return $css_rule->get_css();
 706          }
 707  
 708          $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations );
 709          return $css_declarations->get_declarations_string();
 710      }
 711  
 712      /**
 713       * Returns a compiled stylesheet from stored CSS rules.
 714       *
 715       * @since 6.1.0
 716       *
 717       * @param WP_Style_Engine_CSS_Rule[] $css_rules An array of WP_Style_Engine_CSS_Rule objects
 718       *                                              from a store or otherwise.
 719       * @param array                      $options   {
 720       *     Optional. An array of options. Default empty array.
 721       *
 722       *     @type string|null $context  An identifier describing the origin of the style object,
 723       *                                 e.g. 'block-supports' or 'global-styles'. Default 'block-supports'.
 724       *                                 When set, the style engine will attempt to store the CSS rules.
 725       *     @type bool        $optimize Whether to optimize the CSS output, e.g. combine rules.
 726       *                                 Default false.
 727       *     @type bool        $prettify Whether to add new lines and indents to output.
 728       *                                 Defaults to whether the `SCRIPT_DEBUG` constant is defined.
 729       * }
 730       * @return string A compiled stylesheet from stored CSS rules.
 731       */
 732  	public static function compile_stylesheet_from_css_rules( $css_rules, $options = array() ) {
 733          $processor = new WP_Style_Engine_Processor();
 734          $processor->add_rules( $css_rules );
 735          return $processor->get_css( $options );
 736      }
 737  }


Generated : Thu Oct 24 08:20:01 2024 Cross-referenced by PHPXref