diff --git a/lib/load.php b/lib/load.php index 5504e8bd3fc3d0..c6777d3a86186f 100644 --- a/lib/load.php +++ b/lib/load.php @@ -156,6 +156,9 @@ function gutenberg_is_experiment_enabled( $name ) { if ( file_exists( __DIR__ . '/../build/style-engine/class-wp-style-engine-gutenberg.php' ) ) { require_once __DIR__ . '/../build/style-engine/class-wp-style-engine-gutenberg.php'; } +if ( file_exists( __DIR__ . '/../build/style-engine/class-wp-style-engine-css-declarations-gutenberg.php' ) ) { + require_once __DIR__ . '/../build/style-engine/class-wp-style-engine-css-declarations-gutenberg.php'; +} // Block supports overrides. require __DIR__ . '/block-supports/utils.php'; diff --git a/packages/style-engine/class-wp-style-engine-css-declarations.php b/packages/style-engine/class-wp-style-engine-css-declarations.php new file mode 100644 index 00000000000000..cde6b51355195e --- /dev/null +++ b/packages/style-engine/class-wp-style-engine-css-declarations.php @@ -0,0 +1,119 @@ + value pairs). + * + * @var array + */ + protected $styles = array(); + + /** + * Contructor for this object. + * + * If a `$styles` array is passed, it will be used to populate + * the initial $styles prop of the object by calling add_declarations(). + * + * @param array $styles An array of styles (property => value pairs). + */ + public function __construct( $styles = array() ) { + if ( empty( $styles ) ) { + return; + } + $this->add_declarations( $styles ); + } + + /** + * Add a single declaration. + * + * @param string $property The CSS property. + * @param string $value The CSS value. + * + * @return void + */ + public function add_declaration( $property, $value ) { + + // Sanitize the property. + $property = $this->sanitize_property( $property ); + // Bail early if the property is empty. + if ( empty( $property ) ) { + return; + } + + // Trim the value. If empty, bail early. + $value = trim( $value ); + if ( '' === $value ) { + return; + } + + // Add the style. + $this->styles[ $property ] = $value; + } + + /** + * Add multiple declarations. + * + * @param array $declarations An array of declarations. + * + * @return void + */ + public function add_declarations( $declarations ) { + foreach ( $declarations as $property => $value ) { + $this->add_declaration( $property, $value ); + } + } + + /** + * Get the styles array. + * + * @return array + */ + public function get_styles() { + return $this->styles; + } + + /** + * Get the CSS styles. + * + * @return string The CSS styles. + */ + public function get_styles_string() { + $styles_array = $this->get_styles(); + $styles = ''; + foreach ( $styles_array as $property => $value ) { + $css = esc_html( safecss_filter_attr( "{$property}: {$value}" ) ); + if ( $css ) { + $styles .= $css . '; '; + } + } + return rtrim( $styles ); + } + + /** + * Sanitize property names. + * + * @param string $property The CSS property. + * + * @return string The sanitized property name. + */ + protected function sanitize_property( $property ) { + return sanitize_key( $property ); + } +} diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php index c4cdd0c19419cb..160abd65e484be 100644 --- a/packages/style-engine/class-wp-style-engine.php +++ b/packages/style-engine/class-wp-style-engine.php @@ -396,32 +396,19 @@ public function generate( $block_styles, $options ) { } // Build CSS rules output. - $css_selector = isset( $options['selector'] ) ? $options['selector'] : null; - $filtered_css_declarations = array(); - - if ( ! empty( $css_declarations ) ) { - // Generate inline style declarations. - foreach ( $css_declarations as $css_property => $css_value ) { - $filtered_css_declaration = esc_html( safecss_filter_attr( "{$css_property}: {$css_value}" ) ); - if ( ! empty( $filtered_css_declaration ) ) { - $filtered_css_declarations[] = $filtered_css_declaration . ';'; - } - } - } + $css_selector = isset( $options['selector'] ) ? $options['selector'] : null; + $style_rules = new WP_Style_Engine_CSS_Declarations( $css_declarations ); // The return object. $styles_output = array(); + $css = $style_rules->get_styles_string(); // Return css, if any. - if ( ! empty( $filtered_css_declarations ) ) { + if ( ! empty( $css ) ) { + $styles_output['css'] = $css; // Return an entire rule if there is a selector. if ( $css_selector ) { - $css_rule = "$css_selector { "; - $css_rule .= implode( ' ', $filtered_css_declarations ); - $css_rule .= ' }'; - $styles_output['css'] = $css_rule; - } else { - $styles_output['css'] = implode( ' ', $filtered_css_declarations ); + $styles_output['css'] = $css_selector . ' { ' . $css . ' }'; } } @@ -433,7 +420,6 @@ public function generate( $block_styles, $options ) { return $styles_output; } - /** * Style value parser that returns a CSS definition array comprising style properties * that have keys representing individual style properties, otherwise known as longhand CSS properties. diff --git a/packages/style-engine/phpunit/class-wp-style-engine-test.php b/packages/style-engine/phpunit/class-wp-style-engine-test.php index e8274e85425fa3..30557f50e15cd9 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-test.php @@ -6,6 +6,7 @@ * @subpackage style-engine */ +require __DIR__ . '/../class-wp-style-engine-css-declarations.php'; require __DIR__ . '/../class-wp-style-engine.php'; /** diff --git a/tools/webpack/packages.js b/tools/webpack/packages.js index dc161ab4dd75fd..c13ceea5de9ecc 100644 --- a/tools/webpack/packages.js +++ b/tools/webpack/packages.js @@ -35,7 +35,10 @@ const bundledPackagesPhpConfig = [ { from: './packages/style-engine/', to: 'build/style-engine/', - replaceClasses: [ 'WP_Style_Engine' ], + replaceClasses: [ + 'WP_Style_Engine_CSS_Declarations', + 'WP_Style_Engine', + ], }, ].map( ( { from, to, replaceClasses } ) => ( { from: `${ from }/*.php`,