Skip to content

Commit

Permalink
Migrate get_block_classes to 6.1
Browse files Browse the repository at this point in the history
Add prettify option
  • Loading branch information
ramonjd committed Jun 2, 2022
1 parent a82e9ea commit f5d4eba
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 70 deletions.
8 changes: 1 addition & 7 deletions lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,6 @@ protected function get_block_classes( $style_nodes ) {
$settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
$declarations = static::compute_style_properties( $node, $settings );



// 1. Separate the ones who use the general selector
// and the ones who use the duotone selector.
$declarations_duotone = array();
Expand All @@ -355,11 +353,7 @@ protected function get_block_classes( $style_nodes ) {
}

// 2. Generate the rules that use the general selector.
$styles = gutenberg_style_engine_generate( $node, array( 'selector' => $selector ) );
if ( isset( $styles['css'] ) ) {
$block_rules .= $styles['css'];
}

$block_rules .= static::to_ruleset( $selector, $declarations );

// 3. Generate the rules that use the duotone selector.
if ( isset( $metadata['duotone'] ) && ! empty( $declarations_duotone ) ) {
Expand Down
86 changes: 86 additions & 0 deletions lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,90 @@ public function get_styles_for_block( $block_metadata ) {
$block_rules = static::to_ruleset( $selector, $declarations );
return $block_rules;
}

/**
* Converts each style section into a list of rulesets
* containing the block styles to be appended to the stylesheet.
*
* See glossary at https://developer.mozilla.org/en-US/docs/Web/CSS/Syntax
*
* For each section this creates a new ruleset such as:
*
* block-selector {
* style-property-one: value;
* }
*
* @param array $style_nodes Nodes with styles.
* @return string The new stylesheet.
*/
protected function get_block_classes( $style_nodes ) {
$block_rules = '';

foreach ( $style_nodes as $metadata ) {
if ( null === $metadata['selector'] ) {
continue;
}

$node = _wp_array_get( $this->theme_json, $metadata['path'], array() );
$selector = $metadata['selector'];
$settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
$declarations = static::compute_style_properties( $node, $settings );

// 1. Separate the ones who use the general selector
// and the ones who use the duotone selector.
$declarations_duotone = array();
foreach ( $declarations as $index => $declaration ) {
if ( 'filter' === $declaration['name'] ) {
unset( $declarations[ $index ] );
$declarations_duotone[] = $declaration;
}
}

/*
* Reset default browser margin on the root body element.
* This is set on the root selector **before** generating the ruleset
* from the `theme.json`. This is to ensure that if the `theme.json` declares
* `margin` in its `spacing` declaration for the `body` element then these
* user-generated values take precedence in the CSS cascade.
* @link https://github.com/WordPress/gutenberg/issues/36147.
*/
if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
$block_rules .= "body { margin: 0; }\n";
}

// 2. Generate the rules that use the general selector.
//$block_rules .= static::to_ruleset( $selector, $declarations );
// @TODO check duotone
$styles = gutenberg_style_engine_generate(
$node,
array(
'selector' => $selector,
'prettify' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG,
)
);
if ( isset( $styles['css'] ) ) {
$block_rules .= $styles['css'];
}

// 3. Generate the rules that use the duotone selector.
if ( isset( $metadata['duotone'] ) && ! empty( $declarations_duotone ) ) {
$selector_duotone = static::scope_selector( $metadata['selector'], $metadata['duotone'] );
$block_rules .= static::to_ruleset( $selector_duotone, $declarations_duotone );
}

if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
$block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
$block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
$block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';

$has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
if ( $has_block_gap_support ) {
$block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
$block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
}
}
}

return $block_rules;
}
}
130 changes: 69 additions & 61 deletions packages/style-engine/class-wp-style-engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ public static function get_instance() {
/**
* Extracts the slug in kebab case from a preset string, e.g., "heavenly-blue" from 'var:preset|color|heavenlyBlue'.
*
* @param string $style_value A single css preset value.
* @param string $property_key The CSS property that is the second element of the preset string. Used for matching.
* @param string? $style_value A single css preset value.
* @param string $property_key The CSS property that is the second element of the preset string. Used for matching.
*
* @return string|null The slug, or null if not found.
*/
Expand Down Expand Up @@ -190,40 +190,66 @@ protected static function get_classnames( $style_value, $style_definition ) {
* @return array An array of CSS rules.
*/
protected static function get_css( $style_value, $style_definition ) {
// Low-specificity check to see if the value is a CSS preset.
$rules = array();

if ( ! $style_value ) {
return $rules;
}

// Before default processing, style definitions could define a callable `value_func` to generate custom CSS rules at this point.
$style_property = $style_definition['property_key'];

// Here we could build CSS var values from `var:preset|?` style values, e.g, `var(--wp--css--rule-slug )`
// For now, just skip such values.
if ( is_string( $style_value ) && strpos( $style_value, 'var:' ) !== false ) {
return array();
return $rules;
}

// Default rule builder.
// If the input contains an array, ee assume box model-like properties
// for styles such as margins and padding.
if ( is_array( $style_value ) ) {
foreach ( $style_value as $key => $value ) {
$rules[ "$style_property-$key" ] = $value;
}
} else {
$rules[ $style_property ] = $style_value;
}

// If required in the future, style definitions could define a callable `value_func` to generate custom CSS rules.
return static::get_css_rules( $style_value, $style_definition['property_key'] );
return $rules;
}

/**
* Returns an CSS ruleset.
* Styles are bundled based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA.
*
* @param array $styles An array of Gutenberg styles from a block's attributes or theme JSON.
* @param array $options An array of options to determine the output.
* @param array $block_styles An array of styles from a block's attributes.
* @param array $options array(
* 'selector' => (string) When a selector is passed, `generate()` will return a full CSS rule `$selector { ...rules }`, otherwise a concatenated string of properties and values.
* 'prettify' => (boolean) If `true` adds space formatting to CSS selector + rules.
* );.
*
* @return array|null array(
* 'styles' => (string) A CSS ruleset formatted to be placed in an HTML `style` attribute or tag. Default is a string of inline styles.
* 'css' => (string) A CSS ruleset formatted to be placed in an HTML `style` attribute or tag. Default is a string of inline styles.
* 'classnames' => (string) Classnames separated by a space.
* );
*/
public function generate( $styles, $options ) {
if ( empty( $styles ) || ! is_array( $styles ) ) {
public function generate( $block_styles, $options ) {
if ( empty( $block_styles ) || ! is_array( $block_styles ) ) {
return null;
}

$css_rules = array();
$classnames = array();
$styles_output = array();
$css_rules = array();
$classnames = array();

// Collect CSS and classnames.
foreach ( self::BLOCK_STYLE_DEFINITIONS_METADATA as $definition_group ) {
if ( ! $definition_group ) {
continue;
}

foreach ( $definition_group as $style_definition ) {
$style_value = _wp_array_get( $styles, $style_definition['path'], null );
$style_value = _wp_array_get( $block_styles, $style_definition['path'], null );

if ( empty( $style_value ) ) {
continue;
Expand All @@ -235,71 +261,51 @@ public function generate( $styles, $options ) {
}

// Build CSS rules output.
$selector = isset( $options['selector'] ) ? $options['selector'] : null;
$css_output = array();
$selector = isset( $options['selector'] ) ? $options['selector'] : null;
$should_prettify = isset( $options['prettify'] ) ? $options['prettify'] : null;
$css = array();
$styles_output = array();

if ( ! empty( $css_rules ) ) {
// Generate inline style rules.
foreach ( $css_rules as $rule => $value ) {
$filtered_css = esc_html( safecss_filter_attr( "{$rule}: {$value}" ) );
if ( ! empty( $filtered_css ) ) {
$css_output[] = $filtered_css . ';';
if ( $should_prettify ) {
$css[] = "\t$filtered_css;\n";
} else {
$css[] = $filtered_css . ';';
}
}
}
}

if ( ! empty( $css_output ) ) {
// Return css, if any.
if ( ! empty( $css ) ) {
// Return an entire rule if there is a selector.
if ( $selector ) {
$style_block = "$selector {\n";
$css_output = array_map(
function ( $value ) {
return "\t$value\n";
},
$css_output
);
$style_block .= implode( '', $css_output );
$style_block .= "}\n";
if ( $should_prettify ) {
$style_block = "$selector {\n";
$style_block .= implode( '', $css );
$style_block .= "}\n";
} else {
$style_block = "$selector { ";
$style_block .= implode( ' ', $css );
$style_block .= ' }';
}
$styles_output['css'] = $style_block;
} else {
$styles_output['css'] = implode( ' ', $css_output );
$styles_output['css'] = implode( ' ', $css );
}
}

// Return classnames, if any.
if ( ! empty( $classnames ) ) {
$styles_output['classnames'] = implode( ' ', array_unique( $classnames ) );
}

return $styles_output;
}

/**
* Default style value parser that returns a CSS ruleset.
* If the input contains an array, it will be treated like a box model
* for styles such as margins and padding
*
* @param string|array $style_value A single raw Gutenberg style attributes value for a CSS property.
* @param string $style_property The CSS property for which we're creating a rule.
*
* @return array The class name for the added style.
*/
protected static function get_css_rules( $style_value, $style_property ) {
$rules = array();

if ( ! $style_value ) {
return $rules;
}

// We assume box model-like properties.
if ( is_array( $style_value ) ) {
foreach ( $style_value as $key => $value ) {
$rules[ "$style_property-$key" ] = $value;
}
} else {
$rules[ $style_property ] = $style_value;
}

return $rules;
}
}

/**
Expand All @@ -308,18 +314,20 @@ protected static function get_css_rules( $style_value, $style_property ) {
* Returns an CSS ruleset.
* Styles are bundled based on the instructions in BLOCK_STYLE_DEFINITIONS_METADATA.
*
* @param array $styles An array of Gutenberg styles from a block's attributes or theme JSON.
* @access public
*
* @param array $block_styles An array of styles from a block's attributes.
* @param array $options An array of options to determine the output.
*
* @return array|null array(
* 'styles' => (string) A CSS ruleset formatted to be placed in an HTML `style` attribute or tag.
* 'classnames' => (string) Classnames separated by a space.
* );
*/
function wp_style_engine_generate( $styles, $options = array() ) {
function wp_style_engine_generate( $block_styles, $options = array() ) {
if ( class_exists( 'WP_Style_Engine' ) ) {
$style_engine = WP_Style_Engine::get_instance();
return $style_engine->generate( $styles, $options );
return $style_engine->generate( $block_styles, $options );
}
return null;
}
Loading

0 comments on commit f5d4eba

Please sign in to comment.