[ 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                  $classnames = static::get_classnames( $style_value, $style_definition );
 458                  if ( ! empty( $classnames ) ) {
 459                      $parsed_styles['classnames'] = array_merge( $parsed_styles['classnames'], $classnames );
 460                  }
 461  
 462                  $css_declarations = static::get_css_declarations( $style_value, $style_definition, $options );
 463                  if ( ! empty( $css_declarations ) ) {
 464                      $parsed_styles['declarations'] = array_merge( $parsed_styles['declarations'], $css_declarations );
 465                  }
 466              }
 467          }
 468  
 469          return $parsed_styles;
 470      }
 471  
 472      /**
 473       * Returns classnames, and generates classname(s) from a CSS preset property pattern,
 474       * e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`.
 475       *
 476       * @since 6.1.0
 477       *
 478       * @param string $style_value      A single raw style value or CSS preset property
 479       *                                 from the `$block_styles` array.
 480       * @param array  $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
 481       * @return string[] An array of CSS classnames, or empty array if there are none.
 482       */
 483  	protected static function get_classnames( $style_value, $style_definition ) {
 484          if ( empty( $style_value ) ) {
 485              return array();
 486          }
 487  
 488          $classnames = array();
 489          if ( ! empty( $style_definition['classnames'] ) ) {
 490              foreach ( $style_definition['classnames'] as $classname => $property_key ) {
 491                  if ( true === $property_key ) {
 492                      $classnames[] = $classname;
 493                      continue;
 494                  }
 495  
 496                  $slug = static::get_slug_from_preset_value( $style_value, $property_key );
 497  
 498                  if ( $slug ) {
 499                      /*
 500                       * Right now we expect a classname pattern to be stored in BLOCK_STYLE_DEFINITIONS_METADATA.
 501                       * One day, if there are no stored schemata, we could allow custom patterns or
 502                       * generate classnames based on other properties
 503                       * such as a path or a value or a prefix passed in options.
 504                       */
 505                      $classnames[] = strtr( $classname, array( '$slug' => $slug ) );
 506                  }
 507              }
 508          }
 509  
 510          return $classnames;
 511      }
 512  
 513      /**
 514       * Returns an array of CSS declarations based on valid block style values.
 515       *
 516       * @since 6.1.0
 517       *
 518       * @param mixed $style_value      A single raw style value from $block_styles array.
 519       * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
 520       * @param array $options          {
 521       *     Optional. An array of options. Default empty array.
 522       *
 523       *     @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns,
 524       *                                            e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`,
 525       *                                            to `var( --wp--preset--* )` values. Default false.
 526       * }
 527       * @return string[] An associative array of CSS definitions, e.g. `array( "$property" => "$value", "$property" => "$value" )`.
 528       */
 529  	protected static function get_css_declarations( $style_value, $style_definition, $options = array() ) {
 530          if ( isset( $style_definition['value_func'] ) && is_callable( $style_definition['value_func'] ) ) {
 531              return call_user_func( $style_definition['value_func'], $style_value, $style_definition, $options );
 532          }
 533  
 534          $css_declarations     = array();
 535          $style_property_keys  = $style_definition['property_keys'];
 536          $should_skip_css_vars = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames'];
 537  
 538          /*
 539           * Build CSS var values from `var:preset|<PRESET_TYPE>|<PRESET_SLUG>` values, e.g, `var(--wp--css--rule-slug )`.
 540           * Check if the value is a CSS preset and there's a corresponding css_var pattern in the style definition.
 541           */
 542          if ( is_string( $style_value ) && str_contains( $style_value, 'var:' ) ) {
 543              if ( ! $should_skip_css_vars && ! empty( $style_definition['css_vars'] ) ) {
 544                  $css_var = static::get_css_var_value( $style_value, $style_definition['css_vars'] );
 545                  if ( static::is_valid_style_value( $css_var ) ) {
 546                      $css_declarations[ $style_property_keys['default'] ] = $css_var;
 547                  }
 548              }
 549              return $css_declarations;
 550          }
 551  
 552          /*
 553           * Default rule builder.
 554           * If the input contains an array, assume box model-like properties
 555           * for styles such as margins and padding.
 556           */
 557          if ( is_array( $style_value ) ) {
 558              // Bail out early if the `'individual'` property is not defined.
 559              if ( ! isset( $style_property_keys['individual'] ) ) {
 560                  return $css_declarations;
 561              }
 562  
 563              foreach ( $style_value as $key => $value ) {
 564                  if ( is_string( $value ) && str_contains( $value, 'var:' ) && ! $should_skip_css_vars && ! empty( $style_definition['css_vars'] ) ) {
 565                      $value = static::get_css_var_value( $value, $style_definition['css_vars'] );
 566                  }
 567  
 568                  $individual_property = sprintf( $style_property_keys['individual'], _wp_to_kebab_case( $key ) );
 569  
 570                  if ( $individual_property && static::is_valid_style_value( $value ) ) {
 571                      $css_declarations[ $individual_property ] = $value;
 572                  }
 573              }
 574  
 575              return $css_declarations;
 576          }
 577  
 578          $css_declarations[ $style_property_keys['default'] ] = $style_value;
 579          return $css_declarations;
 580      }
 581  
 582      /**
 583       * Style value parser that returns a CSS definition array comprising style properties
 584       * that have keys representing individual style properties, otherwise known as longhand CSS properties.
 585       *
 586       * Example:
 587       *
 588       *     "$style_property-$individual_feature: $value;"
 589       *
 590       * Which could represent the following:
 591       *
 592       *     "border-{top|right|bottom|left}-{color|width|style}: {value};"
 593       *
 594       * or:
 595       *
 596       *     "border-image-{outset|source|width|repeat|slice}: {value};"
 597       *
 598       * @since 6.1.0
 599       *
 600       * @param array $style_value                    A single raw style value from `$block_styles` array.
 601       * @param array $individual_property_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA
 602       *                                              representing an individual property of a CSS property,
 603       *                                              e.g. 'top' in 'border-top'.
 604       * @param array $options                        {
 605       *     Optional. An array of options. Default empty array.
 606       *
 607       *     @type bool $convert_vars_to_classnames Whether to skip converting incoming CSS var patterns,
 608       *                                            e.g. `var:preset|<PRESET_TYPE>|<PRESET_SLUG>`,
 609       *                                            to `var( --wp--preset--* )` values. Default false.
 610       * }
 611       * @return string[] An associative array of CSS definitions, e.g. `array( "$property" => "$value", "$property" => "$value" )`.
 612       */
 613  	protected static function get_individual_property_css_declarations( $style_value, $individual_property_definition, $options = array() ) {
 614          if ( ! is_array( $style_value ) || empty( $style_value ) || empty( $individual_property_definition['path'] ) ) {
 615              return array();
 616          }
 617  
 618          /*
 619           * The first item in $individual_property_definition['path'] array
 620           * tells us the style property, e.g. "border". We use this to get a corresponding
 621           * CSS style definition such as "color" or "width" from the same group.
 622           *
 623           * The second item in $individual_property_definition['path'] array
 624           * refers to the individual property marker, e.g. "top".
 625           */
 626          $definition_group_key    = $individual_property_definition['path'][0];
 627          $individual_property_key = $individual_property_definition['path'][1];
 628          $should_skip_css_vars    = isset( $options['convert_vars_to_classnames'] ) && true === $options['convert_vars_to_classnames'];
 629          $css_declarations        = array();
 630  
 631          foreach ( $style_value as $css_property => $value ) {
 632              if ( empty( $value ) ) {
 633                  continue;
 634              }
 635  
 636              // Build a path to the individual rules in definitions.
 637              $style_definition_path = array( $definition_group_key, $css_property );
 638              $style_definition      = _wp_array_get( static::BLOCK_STYLE_DEFINITIONS_METADATA, $style_definition_path, null );
 639  
 640              if ( $style_definition && isset( $style_definition['property_keys']['individual'] ) ) {
 641                  // Set a CSS var if there is a valid preset value.
 642                  if ( is_string( $value ) && str_contains( $value, 'var:' )
 643                      && ! $should_skip_css_vars && ! empty( $individual_property_definition['css_vars'] )
 644                  ) {
 645                      $value = static::get_css_var_value( $value, $individual_property_definition['css_vars'] );
 646                  }
 647  
 648                  $individual_css_property = sprintf( $style_definition['property_keys']['individual'], $individual_property_key );
 649  
 650                  $css_declarations[ $individual_css_property ] = $value;
 651              }
 652          }
 653          return $css_declarations;
 654      }
 655  
 656      /**
 657       * Style value parser that constructs a CSS definition array comprising a single CSS property and value.
 658       * If the provided value is an array containing a `url` property, the function will return a CSS definition array
 659       * with a single property and value, with `url` escaped and injected into a CSS `url()` function,
 660       * e.g., array( 'background-image' => "url( '...' )" ).
 661       *
 662       * @since 6.4.0
 663       *
 664       * @param array $style_value      A single raw style value from $block_styles array.
 665       * @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
 666       * @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ).
 667       */
 668  	protected static function get_url_or_value_css_declaration( $style_value, $style_definition ) {
 669          if ( empty( $style_value ) ) {
 670              return array();
 671          }
 672  
 673          $css_declarations = array();
 674  
 675          if ( isset( $style_definition['property_keys']['default'] ) ) {
 676              $value = null;
 677  
 678              if ( ! empty( $style_value['url'] ) ) {
 679                  $value = "url('" . $style_value['url'] . "')";
 680              } elseif ( is_string( $style_value ) ) {
 681                  $value = $style_value;
 682              }
 683  
 684              if ( null !== $value ) {
 685                  $css_declarations[ $style_definition['property_keys']['default'] ] = $value;
 686              }
 687          }
 688  
 689          return $css_declarations;
 690      }
 691  
 692      /**
 693       * Returns compiled CSS from CSS declarations.
 694       *
 695       * @since 6.1.0
 696       *
 697       * @param string[] $css_declarations An associative array of CSS definitions,
 698       *                                   e.g. `array( "$property" => "$value", "$property" => "$value" )`.
 699       * @param string   $css_selector     When a selector is passed, the function will return
 700       *                                   a full CSS rule `$selector { ...rules }`,
 701       *                                   otherwise a concatenated string of properties and values.
 702       * @return string A compiled CSS string.
 703       */
 704  	public static function compile_css( $css_declarations, $css_selector ) {
 705          if ( empty( $css_declarations ) || ! is_array( $css_declarations ) ) {
 706              return '';
 707          }
 708  
 709          // Return an entire rule if there is a selector.
 710          if ( $css_selector ) {
 711              $css_rule = new WP_Style_Engine_CSS_Rule( $css_selector, $css_declarations );
 712              return $css_rule->get_css();
 713          }
 714  
 715          $css_declarations = new WP_Style_Engine_CSS_Declarations( $css_declarations );
 716          return $css_declarations->get_declarations_string();
 717      }
 718  
 719      /**
 720       * Returns a compiled stylesheet from stored CSS rules.
 721       *
 722       * @since 6.1.0
 723       *
 724       * @param WP_Style_Engine_CSS_Rule[] $css_rules An array of WP_Style_Engine_CSS_Rule objects
 725       *                                              from a store or otherwise.
 726       * @param array                      $options   {
 727       *     Optional. An array of options. Default empty array.
 728       *
 729       *     @type string|null $context  An identifier describing the origin of the style object,
 730       *                                 e.g. 'block-supports' or 'global-styles'. Default 'block-supports'.
 731       *                                 When set, the style engine will attempt to store the CSS rules.
 732       *     @type bool        $optimize Whether to optimize the CSS output, e.g. combine rules.
 733       *                                 Default false.
 734       *     @type bool        $prettify Whether to add new lines and indents to output.
 735       *                                 Defaults to whether the `SCRIPT_DEBUG` constant is defined.
 736       * }
 737       * @return string A compiled stylesheet from stored CSS rules.
 738       */
 739  	public static function compile_stylesheet_from_css_rules( $css_rules, $options = array() ) {
 740          $processor = new WP_Style_Engine_Processor();
 741          $processor->add_rules( $css_rules );
 742          return $processor->get_css( $options );
 743      }
 744  }


Generated : Thu Dec 26 08:20:01 2024 Cross-referenced by PHPXref