diff --git a/lib/block-supports/variations.php b/lib/block-supports/variations.php new file mode 100644 index 0000000000000..b4511f1abdd84 --- /dev/null +++ b/lib/block-supports/variations.php @@ -0,0 +1,118 @@ +next_tag() ) { + preg_match( '/\bis-style-(\S+)\b/', $tags->get_attribute( 'class' ), $matches ); + $variation = $matches[1] ?? null; + + if ( $variation ) { + $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data(); + $theme_json = $tree->get_raw_data(); + + if ( ! empty( $theme_json['styles']['blocks'][ $block['blockName'] ]['variations'][ $variation ] ) ) { + $tags->add_class( gutenberg_get_variation_class_name( $block, $variation ) ); + } + } + } + + return $tags->get_updated_html(); +} + +/** + * Render the block style variation's styles. + * + * In the case of nested blocks with variations applies, we want the parent + * variation's styles to be rendered before their descendants. This solves the + * issue of a block type being styled in both the parent and descendant: we want + * the descendant style to take priority, and this is done by loading it after, + * in the DOM order. This is why the variation stylesheet generation is in a + * different filter. + * + * @param string|null $pre_render The pre-rendered content. Default null. + * @param array $block The block being rendered. + * + * @return null + */ +function gutenberg_render_variation_support_styles( $pre_render, $block ) { + $variation = $block['attrs']['style']['variation'] ?? null; + + if ( ! $variation ) { + return null; + } + + $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data(); + $theme_json = $tree->get_raw_data(); + $variation_data = $theme_json['styles']['blocks'][ $block['blockName'] ]['variations'][ $variation ] ?? array(); + + if ( empty( $variation_data['elements'] ) && empty( $variation_data['blocks'] ) ) { + return null; + } + + $config = array( + 'version' => 2, + 'styles' => $variation_data, + ); + + $class_name = gutenberg_get_variation_class_name( $block, $variation ); + $class_name = ".$class_name"; + + $variation_theme_json = new WP_Theme_JSON_Gutenberg( $config, 'blocks' ); + $variation_styles = $variation_theme_json->get_stylesheet( + array( 'styles' ), + array( 'custom' ), + array( + 'root_selector' => $class_name, + 'skip_root_layout_styles' => true, + 'scope' => $class_name, + ) + ); + + if ( empty( $variation_styles ) ) { + return null; + } + + wp_register_style( 'variation-styles', false ); + wp_add_inline_style( 'variation-styles', $variation_styles ); + wp_enqueue_style( 'variation-styles' ); +} + + +// Register the block support. +WP_Block_Supports::get_instance()->register( 'variation', array() ); + +add_filter( 'pre_render_block', 'gutenberg_render_variation_support_styles', 10, 2 ); +add_filter( 'render_block', 'gutenberg_render_variation_support', 10, 2 ); diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 8d6c8d75759ba..2837cd059179e 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -1267,7 +1267,7 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' } if ( in_array( 'styles', $types, true ) ) { - if ( false !== $root_style_key ) { + if ( false !== $root_style_key && empty( $options['skip_root_layout_styles'] ) ) { $stylesheet .= $this->get_root_layout_rules( $style_nodes[ $root_style_key ]['selector'], $style_nodes[ $root_style_key ] ); } $stylesheet .= $this->get_block_classes( $style_nodes ); diff --git a/lib/load.php b/lib/load.php index b111c8e0d7921..b98dc222cd16b 100644 --- a/lib/load.php +++ b/lib/load.php @@ -216,6 +216,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/block-supports/duotone.php'; require __DIR__ . '/block-supports/shadow.php'; require __DIR__ . '/block-supports/background.php'; +require __DIR__ . '/block-supports/variations.php'; // Data views. require_once __DIR__ . '/experimental/data-views.php';