From 4d0ce99809506564a6cb443c145ccb50b964aad5 Mon Sep 17 00:00:00 2001 From: Carolina Nymark Date: Tue, 13 Dec 2022 14:35:41 +0100 Subject: [PATCH 01/16] WIP, try adding per block custom css to global styles --- .../components/global-styles/context-menu.js | 129 ++++++++++++------ .../components/global-styles/custom-css.js | 10 +- .../components/global-styles/screen-css.js | 32 +++-- .../src/components/global-styles/ui.js | 7 +- 4 files changed, 123 insertions(+), 55 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/context-menu.js b/packages/edit-site/src/components/global-styles/context-menu.js index d4c229fe831b2..d8bdd98423d35 100644 --- a/packages/edit-site/src/components/global-styles/context-menu.js +++ b/packages/edit-site/src/components/global-styles/context-menu.js @@ -1,9 +1,23 @@ /** * WordPress dependencies */ -import { __experimentalItemGroup as ItemGroup } from '@wordpress/components'; -import { typography, border, color, layout } from '@wordpress/icons'; -import { __ } from '@wordpress/i18n'; +import { + __experimentalItemGroup as ItemGroup, + __experimentalHStack as HStack, + __experimentalSpacer as Spacer, + FlexItem, + CardBody, + CardDivider, +} from '@wordpress/components'; +import { + typography, + border, + color, + layout, + chevronLeft, + chevronRight, +} from '@wordpress/icons'; +import { isRTL, __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -13,6 +27,7 @@ import { useHasColorPanel } from './color-utils'; import { useHasDimensionsPanel } from './dimensions-panel'; import { useHasTypographyPanel } from './typography-panel'; import { NavigationButtonAsItem } from './navigation-button'; +import { IconWithCurrentColor } from './icon-with-current-color'; function ContextMenu( { name, parentMenu = '' } ) { const hasTypographyPanel = useHasTypographyPanel( name ); @@ -22,44 +37,78 @@ function ContextMenu( { name, parentMenu = '' } ) { const hasLayoutPanel = hasDimensionsPanel; return ( - - { hasTypographyPanel && ( - - { __( 'Typography' ) } - + <> + + { hasTypographyPanel && ( + + { __( 'Typography' ) } + + ) } + { hasColorPanel && ( + + { __( 'Colors' ) } + + ) } + { hasBorderPanel && ( + + { __( 'Border' ) } + + ) } + { hasLayoutPanel && ( + + { __( 'Layout' ) } + + ) } + + { !! parentMenu && ( + <> + + + + { __( + 'Add your own CSS to customize the block appearance.' + ) } + + + + + { __( 'Custom' ) } + + + + + + ) } - { hasColorPanel && ( - - { __( 'Colors' ) } - - ) } - { hasBorderPanel && ( - - { __( 'Border' ) } - - ) } - { hasLayoutPanel && ( - - { __( 'Layout' ) } - - ) } - + ); } diff --git a/packages/edit-site/src/components/global-styles/custom-css.js b/packages/edit-site/src/components/global-styles/custom-css.js index 61aad940cd372..d625691dc034f 100644 --- a/packages/edit-site/src/components/global-styles/custom-css.js +++ b/packages/edit-site/src/components/global-styles/custom-css.js @@ -9,9 +9,13 @@ import { __ } from '@wordpress/i18n'; */ import { useStyle } from './hooks'; -function CustomCSSControl() { - const [ customCSS, setCustomCSS ] = useStyle( 'css' ); - const [ themeCSS ] = useStyle( 'css', null, 'base' ); +function CustomCSSControl( { blockName } ) { + // If blockName is defined, we are customizing CSS at the block level: + // styles.blocks.blockName.css + const block = !! blockName ? blockName : null; + + const [ customCSS, setCustomCSS ] = useStyle( 'css', block ); + const [ themeCSS ] = useStyle( 'css', block, 'base' ); const ignoreThemeCustomCSS = '/* IgnoreThemeCustomCSS */'; // If there is custom css from theme.json show it in the edit box diff --git a/packages/edit-site/src/components/global-styles/screen-css.js b/packages/edit-site/src/components/global-styles/screen-css.js index 74480a0677bd1..afd228673bc6d 100644 --- a/packages/edit-site/src/components/global-styles/screen-css.js +++ b/packages/edit-site/src/components/global-styles/screen-css.js @@ -1,8 +1,9 @@ /** * WordPress dependencies */ -import { __ } from '@wordpress/i18n'; +import { sprintf, __ } from '@wordpress/i18n'; import { __experimentalVStack as VStack } from '@wordpress/components'; +import { getBlockType } from '@wordpress/blocks'; /** * Internal dependencies @@ -11,19 +12,32 @@ import ScreenHeader from './header'; import Subtitle from './subtitle'; import CustomCSSControl from './custom-css'; -function ScreenCSS() { +function ScreenCSS( { name } ) { + // If name is defined, we are customizing CSS at the block level. + // Display the block title in the description. + const blockType = getBlockType( name ); + const title = blockType?.title; + + const description = + title !== undefined + ? sprintf( + // translators: %s: is the name of a block e.g., 'Image' or 'Table'. + __( + 'Add your own CSS to customize the appearance of the %s block.' + ), + title + ) + : __( + 'Add your own CSS to customize the appearance and layout of your site.' + ); + return ( <> - +
{ __( 'ADDITIONAL CSS' ) } - +
diff --git a/packages/edit-site/src/components/global-styles/ui.js b/packages/edit-site/src/components/global-styles/ui.js index d7c9eed7d8474..e7f47790d6b9b 100644 --- a/packages/edit-site/src/components/global-styles/ui.js +++ b/packages/edit-site/src/components/global-styles/ui.js @@ -120,6 +120,10 @@ function ContextScreens( { name } ) { + + + + ); } @@ -192,9 +196,6 @@ function GlobalStylesUI( { isStyleBookOpened, onCloseStyleBook } ) { { isStyleBookOpened && ( ) } - - - ); } From 24465f74d0ff060207b302fee7e883fdaaaf1bcb Mon Sep 17 00:00:00 2001 From: Carolina Nymark Date: Wed, 14 Dec 2022 07:37:34 +0100 Subject: [PATCH 02/16] Update class-wp-theme-json-6-2.php --- lib/class-wp-theme-json-gutenberg.php | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 001798e5a326e..2a5d9025f64e7 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -908,6 +908,27 @@ public function get_settings() { } } + /** + * Processes the CSS, to apply nesting. + * + * @param string $css The CSS to process. + * @param string $selector The selector to nest. + * + * @return string The processed CSS. + */ + private function process_nested_css( $css, $selector ) { + $processed_css = ''; + + // Split CSS nested rules. + $parts = explode( '&', $css ); + foreach ( $parts as $part ) { + $processed_css .= ( ! str_contains( $part, '{' ) ) + ? $selector . '{' . $part . '}' // If the part doesn't contain braces, it applies to the root level. + : $selector . $part; // Prepend the selector, which effectively replaces the "&" character. + } + return $processed_css; + } + /** * Returns the stylesheet that results of processing * the theme.json structure this object represents. @@ -1014,7 +1035,19 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' // Load the custom CSS last so it has the highest specificity. if ( in_array( 'custom-css', $types, true ) ) { + // Add the global styles root CSS. $stylesheet .= _wp_array_get( $this->theme_json, array( 'styles', 'css' ) ); + + // Add the global styles block CSS. + if ( isset( $this->theme_json['styles']['blocks'] ) ) { + foreach ( $this->theme_json['styles']['blocks'] as $name => $node ) { + if ( _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $name, 'css' ) ) ) { + $selector = static::$blocks_metadata[ $name ]['selector']; + $custom_block_css = _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $name, 'css' ) ); + $stylesheet .= $this->process_nested_css( $custom_block_css, $selector ); + } + } + } } return $stylesheet; From d5f0bf4ac9740fabd4448c8b7aace5ccdca9cc0c Mon Sep 17 00:00:00 2001 From: Carolina Nymark Date: Wed, 14 Dec 2022 15:44:05 +0100 Subject: [PATCH 03/16] Update use-global-styles-output.js --- .../global-styles/use-global-styles-output.js | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/edit-site/src/components/global-styles/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/use-global-styles-output.js index d83693757b035..47ef9ffde742a 100644 --- a/packages/edit-site/src/components/global-styles/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/use-global-styles-output.js @@ -846,6 +846,18 @@ export const getBlockSelectors = ( blockTypes ) => { return result; }; +export const getBlockNames = ( blockTypes ) => { + const result = {}; + blockTypes.forEach( ( blockType ) => { + const name = blockType.name; + result[ name ] = { + name, + }; + } ); + + return result; +}; + /** * If there is a separator block whose color is defined in theme.json via background, * update the separator color to the same value by using border color. @@ -898,6 +910,7 @@ export function useGlobalStylesOutput() { } mergedConfig = updateConfigWithSeparator( mergedConfig ); const blockSelectors = getBlockSelectors( getBlockTypes() ); + const blockNames = getBlockNames( getBlockTypes() ); const customProperties = toCustomProperties( mergedConfig, blockSelectors @@ -926,6 +939,23 @@ export function useGlobalStylesOutput() { }, ]; + // WIP + // Loop through the blocks to check if there are custom CSS values. + // If there are, get the block selector and push the selector together with + // CSS value to the 'stylesheets' array. + // Below, the p selector is used so that we can test it with the paragraph block. + Object.entries( blockNames ).forEach( ( name ) => { + if ( mergedConfig.styles.blocks[ name[ 0 ] ]?.css ) { + stylesheets.push( { + css: + 'p{ ' + + mergedConfig.styles.blocks[ name[ 0 ] ]?.css + + ';}', + isGlobalStyles: true, + } ); + } + } ); + return [ stylesheets, mergedConfig.settings, filters ]; }, [ hasBlockGapSupport, From d4dee8b01b20cd1a53ffeec5300216560a533330 Mon Sep 17 00:00:00 2001 From: Carolina Nymark Date: Thu, 15 Dec 2022 06:32:55 +0100 Subject: [PATCH 04/16] Add the CSS selector to the global styles output in the editor. --- .../components/global-styles/use-global-styles-output.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/use-global-styles-output.js index 47ef9ffde742a..7825778e032eb 100644 --- a/packages/edit-site/src/components/global-styles/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/use-global-styles-output.js @@ -939,16 +939,16 @@ export function useGlobalStylesOutput() { }, ]; - // WIP // Loop through the blocks to check if there are custom CSS values. // If there are, get the block selector and push the selector together with - // CSS value to the 'stylesheets' array. - // Below, the p selector is used so that we can test it with the paragraph block. + // the CSS value to the 'stylesheets' array. Object.entries( blockNames ).forEach( ( name ) => { if ( mergedConfig.styles.blocks[ name[ 0 ] ]?.css ) { + const selector = blockSelectors[ name[ 0 ] ].selector; stylesheets.push( { css: - 'p{ ' + + selector + + '{' + mergedConfig.styles.blocks[ name[ 0 ] ]?.css + ';}', isGlobalStyles: true, From e36ebbfbb6116161b03c1c34be1c3e563c0f7d3b Mon Sep 17 00:00:00 2001 From: Carolina Nymark Date: Thu, 15 Dec 2022 06:48:06 +0100 Subject: [PATCH 05/16] Update use-global-styles-output.js --- .../src/components/global-styles/use-global-styles-output.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/global-styles/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/use-global-styles-output.js index 7825778e032eb..93ee152d5839c 100644 --- a/packages/edit-site/src/components/global-styles/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/use-global-styles-output.js @@ -950,7 +950,7 @@ export function useGlobalStylesOutput() { selector + '{' + mergedConfig.styles.blocks[ name[ 0 ] ]?.css + - ';}', + '}', isGlobalStyles: true, } ); } From 16a7720cfef315bddc69bdfeaa266479b9992920 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Thu, 15 Dec 2022 09:36:34 +0200 Subject: [PATCH 06/16] Process CSS nesting --- .../global-styles/use-global-styles-output.js | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/use-global-styles-output.js index 93ee152d5839c..b10e6e090ab32 100644 --- a/packages/edit-site/src/components/global-styles/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/use-global-styles-output.js @@ -939,6 +939,19 @@ export function useGlobalStylesOutput() { }, ]; + const processCSSNesting = ( css, blockSelector ) => { + let processedCSS = ''; + + // Split CSS nested rules. + const parts = css.split( '&' ); + parts.forEach( ( part ) => { + processedCSS += ! part.includes( '{' ) + ? blockSelector + '{' + part + '}' // If the part doesn't contain braces, it applies to the root level. + : blockSelector + part; // Prepend the selector, which effectively replaces the "&" character. + } ); + return processedCSS; + }; + // Loop through the blocks to check if there are custom CSS values. // If there are, get the block selector and push the selector together with // the CSS value to the 'stylesheets' array. @@ -946,11 +959,10 @@ export function useGlobalStylesOutput() { if ( mergedConfig.styles.blocks[ name[ 0 ] ]?.css ) { const selector = blockSelectors[ name[ 0 ] ].selector; stylesheets.push( { - css: - selector + - '{' + - mergedConfig.styles.blocks[ name[ 0 ] ]?.css + - '}', + css: processCSSNesting( + mergedConfig.styles.blocks[ name[ 0 ] ]?.css, + selector + ), isGlobalStyles: true, } ); } From 6480d15654394e2072f4712d23652d70cc24970e Mon Sep 17 00:00:00 2001 From: Carolina Nymark Date: Tue, 17 Jan 2023 07:28:59 +0100 Subject: [PATCH 07/16] Add permission check Check for permission to edit CSS before displaying the panel. Fix duplication after merge conflict. --- .../components/global-styles/context-menu.js | 115 ++++++++---------- 1 file changed, 52 insertions(+), 63 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/context-menu.js b/packages/edit-site/src/components/global-styles/context-menu.js index b81493f9b9afb..a011a402eddd3 100644 --- a/packages/edit-site/src/components/global-styles/context-menu.js +++ b/packages/edit-site/src/components/global-styles/context-menu.js @@ -18,6 +18,8 @@ import { chevronRight, } from '@wordpress/icons'; import { isRTL, __ } from '@wordpress/i18n'; +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies @@ -39,6 +41,21 @@ function ContextMenu( { name, parentMenu = '' } ) { const hasLayoutPanel = hasDimensionsPanel; const hasVariationsPanel = useHasVariationsPanel( name, parentMenu ); + const { canEditCSS } = useSelect( ( select ) => { + const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = + select( coreStore ); + + const globalStylesId = __experimentalGetCurrentGlobalStylesId(); + const globalStyles = globalStylesId + ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) + : undefined; + + return { + canEditCSS: + !! globalStyles?._links?.[ 'wp:action-edit-css' ] ?? false, + }; + }, [] ); + return ( <> @@ -78,71 +95,43 @@ function ContextMenu( { name, parentMenu = '' } ) { { __( 'Layout' ) } ) } + { hasVariationsPanel && ( + + ) } + { !! parentMenu && !! canEditCSS && ( + <> + + + + { __( + 'Add your own CSS to customize the block appearance.' + ) } + + + + + + { __( 'Additional block CSS' ) } + + + + + + + + + ) } - { !! parentMenu && ( - <> - - - - { __( - 'Add your own CSS to customize the block appearance.' - ) } - - - - - { __( 'Custom' ) } - - - - - - - ) } - { hasColorPanel && ( - - { __( 'Colors' ) } - - ) } - { hasBorderPanel && ( - - { __( 'Border' ) } - - ) } - { hasLayoutPanel && ( - - { __( 'Layout' ) } - - ) } - { hasVariationsPanel && ( - - ) } - ); } From 165e47a12bed4011ef927a5cb112c1f84526c149 Mon Sep 17 00:00:00 2001 From: Carolina Nymark Date: Tue, 17 Jan 2023 08:11:16 +0100 Subject: [PATCH 08/16] Fix CS issue, spacing --- .../src/components/global-styles/use-global-styles-output.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/global-styles/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/use-global-styles-output.js index 23d3dd2d76531..e2be291c2e1f0 100644 --- a/packages/edit-site/src/components/global-styles/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/use-global-styles-output.js @@ -1029,7 +1029,7 @@ export function useGlobalStylesOutput() { } mergedConfig = updateConfigWithSeparator( mergedConfig ); - const blockSelectors = getBlockSelectors( + const blockSelectors = getBlockSelectors( getBlockTypes(), getBlockStyles ); From b58f823b234a858512370fa2fd5fb8fc83ed4248 Mon Sep 17 00:00:00 2001 From: Carolina Nymark Date: Wed, 18 Jan 2023 09:21:17 +0100 Subject: [PATCH 09/16] Update context menu, simplify condition when loading the CSS --- lib/class-wp-theme-json-gutenberg.php | 8 ++++---- .../src/components/global-styles/context-menu.js | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index eff48d973860e..dc6d2be6a572a 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -1089,10 +1089,10 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' // Add the global styles block CSS. if ( isset( $this->theme_json['styles']['blocks'] ) ) { foreach ( $this->theme_json['styles']['blocks'] as $name => $node ) { - if ( _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $name, 'css' ) ) ) { - $selector = static::$blocks_metadata[ $name ]['selector']; - $custom_block_css = _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $name, 'css' ) ); - $stylesheet .= $this->process_nested_css( $custom_block_css, $selector ); + $custom_block_css = _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $name, 'css' ) ); + if ( $custom_block_css ) { + $selector = static::$blocks_metadata[ $name ]['selector']; + $stylesheet .= $this->process_nested_css( $custom_block_css, $selector ); } } } diff --git a/packages/edit-site/src/components/global-styles/context-menu.js b/packages/edit-site/src/components/global-styles/context-menu.js index a011a402eddd3..ed56c3ffacc77 100644 --- a/packages/edit-site/src/components/global-styles/context-menu.js +++ b/packages/edit-site/src/components/global-styles/context-menu.js @@ -56,6 +56,10 @@ function ContextMenu( { name, parentMenu = '' } ) { }; }, [] ); + const isBlocksPanel = + parentMenu.includes( 'blocks' ) && + ! parentMenu.includes( 'variations' ); + return ( <> @@ -98,7 +102,7 @@ function ContextMenu( { name, parentMenu = '' } ) { { hasVariationsPanel && ( ) } - { !! parentMenu && !! canEditCSS && ( + { isBlocksPanel && canEditCSS && ( <> From 2c91d0378c692f22c2b2c61916e3335ffddc67da Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 18 Jan 2023 12:00:37 +0200 Subject: [PATCH 10/16] rename method --- lib/class-wp-theme-json-gutenberg.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index dc6d2be6a572a..b09ab3650f26a 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -964,7 +964,7 @@ public function get_settings() { * * @return string The processed CSS. */ - private function process_nested_css( $css, $selector ) { + private function process_blocks_custom_css_nested_styles( $css, $selector ) { $processed_css = ''; // Split CSS nested rules. @@ -1092,7 +1092,7 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' $custom_block_css = _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $name, 'css' ) ); if ( $custom_block_css ) { $selector = static::$blocks_metadata[ $name ]['selector']; - $stylesheet .= $this->process_nested_css( $custom_block_css, $selector ); + $stylesheet .= $this->process_blocks_custom_css_nested_styles( $custom_block_css, $selector ); } } } From 7e943bc8d7433ea73c9d2038a20b0566661ff2ab Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 18 Jan 2023 12:10:47 +0200 Subject: [PATCH 11/16] make method public --- lib/class-wp-theme-json-gutenberg.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index b09ab3650f26a..6445168f25ed4 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -964,7 +964,7 @@ public function get_settings() { * * @return string The processed CSS. */ - private function process_blocks_custom_css_nested_styles( $css, $selector ) { + public function process_blocks_custom_css_nested_styles( $css, $selector ) { $processed_css = ''; // Split CSS nested rules. From db2c12b2412781fa01f756bb6781c6cce48b26a9 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 18 Jan 2023 13:06:30 +0200 Subject: [PATCH 12/16] Add unit tests --- lib/class-wp-theme-json-gutenberg.php | 4 +-- phpunit/class-wp-theme-json-test.php | 51 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 6445168f25ed4..94daf325f6dfd 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -971,8 +971,8 @@ public function process_blocks_custom_css_nested_styles( $css, $selector ) { $parts = explode( '&', $css ); foreach ( $parts as $part ) { $processed_css .= ( ! str_contains( $part, '{' ) ) - ? $selector . '{' . $part . '}' // If the part doesn't contain braces, it applies to the root level. - : $selector . $part; // Prepend the selector, which effectively replaces the "&" character. + ? trim( $selector ) . '{' . trim( $part ) . '}' // If the part doesn't contain braces, it applies to the root level. + : trim( $selector . $part ); // Prepend the selector, which effectively replaces the "&" character. } return $processed_css; } diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 795ad0ab4c811..db4abb5ea0b68 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -1697,4 +1697,55 @@ public function data_custom_css_for_user_caps() { ), ); } + + /** + * @dataProvider data_process_blocks_custom_css_nested_styles + * + * @param array $input An array containing the selector and css to test. + * @param string $expected Expected results. + */ + public function test_process_blocks_custom_css_nested_styles( $input, $expected ) { + $theme_json = new WP_Theme_JSON_Gutenberg( + array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array(), + ) + ); + + $this->assertEquals( $expected, $theme_json->process_blocks_custom_css_nested_styles( $input['css'], $input['selector'] ) ); + } + + /** + * Data provider. + * + * @return array[] + */ + public function data_process_blocks_custom_css_nested_styles() { + return array( + // Simple CSS without any child selectors. + 'no child selectors' => array( + 'input' => array( + 'selector' => '.foo', + 'css' => 'color: red; margin: auto;', + ), + 'expected' => '.foo{color: red; margin: auto;}', + ), + // CSS with child selectors. + 'with children' => array( + 'input' => array( + 'selector' => '.foo', + 'css' => 'color: red; margin: auto; & .bar{color: blue;}', + ), + 'expected' => '.foo{color: red; margin: auto;}.foo .bar{color: blue;}', + ), + // CSS with child selectors and pseudo elements. + 'with children and pseudo elements' => array( + 'input' => array( + 'selector' => '.foo', + 'css' => 'color: red; margin: auto; & .bar{color: blue;} &::before{color: green;}', + ), + 'expected' => '.foo{color: red; margin: auto;}.foo .bar{color: blue;}.foo::before{color: green;}', + ), + ); + } } From d21809031a967f5408c0437891c094ea5de5c530 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Thu, 19 Jan 2023 09:12:21 +0200 Subject: [PATCH 13/16] rename method --- lib/class-wp-theme-json-gutenberg.php | 4 ++-- phpunit/class-wp-theme-json-test.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 94daf325f6dfd..2e4ed38d36a4d 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -964,7 +964,7 @@ public function get_settings() { * * @return string The processed CSS. */ - public function process_blocks_custom_css_nested_styles( $css, $selector ) { + public function process_blocks_custom_css( $css, $selector ) { $processed_css = ''; // Split CSS nested rules. @@ -1092,7 +1092,7 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' $custom_block_css = _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $name, 'css' ) ); if ( $custom_block_css ) { $selector = static::$blocks_metadata[ $name ]['selector']; - $stylesheet .= $this->process_blocks_custom_css_nested_styles( $custom_block_css, $selector ); + $stylesheet .= $this->process_blocks_custom_css( $custom_block_css, $selector ); } } } diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index db4abb5ea0b68..655eda083951f 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -1699,12 +1699,12 @@ public function data_custom_css_for_user_caps() { } /** - * @dataProvider data_process_blocks_custom_css_nested_styles + * @dataProvider data_process_blocks_custom_css * * @param array $input An array containing the selector and css to test. * @param string $expected Expected results. */ - public function test_process_blocks_custom_css_nested_styles( $input, $expected ) { + public function test_process_blocks_custom_css( $input, $expected ) { $theme_json = new WP_Theme_JSON_Gutenberg( array( 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, @@ -1712,7 +1712,7 @@ public function test_process_blocks_custom_css_nested_styles( $input, $expected ) ); - $this->assertEquals( $expected, $theme_json->process_blocks_custom_css_nested_styles( $input['css'], $input['selector'] ) ); + $this->assertEquals( $expected, $theme_json->process_blocks_custom_css( $input['css'], $input['selector'] ) ); } /** @@ -1720,7 +1720,7 @@ public function test_process_blocks_custom_css_nested_styles( $input, $expected * * @return array[] */ - public function data_process_blocks_custom_css_nested_styles() { + public function data_process_blocks_custom_css() { return array( // Simple CSS without any child selectors. 'no child selectors' => array( From 7f3a74e74961a8ec9d75d464b23bf6626310d33e Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 23 Jan 2023 10:18:33 +0200 Subject: [PATCH 14/16] Move processCSSNesting function --- .../global-styles/use-global-styles-output.js | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/use-global-styles-output.js index e2be291c2e1f0..c6172a9c7eb3f 100644 --- a/packages/edit-site/src/components/global-styles/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/use-global-styles-output.js @@ -1008,6 +1008,19 @@ function updateConfigWithSeparator( config ) { return config; } +const processCSSNesting = ( css, blockSelector ) => { + let processedCSS = ''; + + // Split CSS nested rules. + const parts = css.split( '&' ); + parts.forEach( ( part ) => { + processedCSS += ! part.includes( '{' ) + ? blockSelector + '{' + part + '}' // If the part doesn't contain braces, it applies to the root level. + : blockSelector + part; // Prepend the selector, which effectively replaces the "&" character. + } ); + return processedCSS; +}; + export function useGlobalStylesOutput() { let { merged: mergedConfig } = useContext( GlobalStylesContext ); @@ -1064,19 +1077,6 @@ export function useGlobalStylesOutput() { }, ]; - const processCSSNesting = ( css, blockSelector ) => { - let processedCSS = ''; - - // Split CSS nested rules. - const parts = css.split( '&' ); - parts.forEach( ( part ) => { - processedCSS += ! part.includes( '{' ) - ? blockSelector + '{' + part + '}' // If the part doesn't contain braces, it applies to the root level. - : blockSelector + part; // Prepend the selector, which effectively replaces the "&" character. - } ); - return processedCSS; - }; - // Loop through the blocks to check if there are custom CSS values. // If there are, get the block selector and push the selector together with // the CSS value to the 'stylesheets' array. From ccdc5df59f66f39fb6948b34e690c03b3b86b3cf Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 23 Jan 2023 10:44:49 +0200 Subject: [PATCH 15/16] simplify code - props @mamaduka --- .../global-styles/use-global-styles-output.js | 39 +++++++------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/use-global-styles-output.js index c6172a9c7eb3f..69a4c152900cd 100644 --- a/packages/edit-site/src/components/global-styles/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/use-global-styles-output.js @@ -961,18 +961,6 @@ export const getBlockSelectors = ( blockTypes, getBlockStyles ) => { return result; }; -export const getBlockNames = ( blockTypes ) => { - const result = {}; - blockTypes.forEach( ( blockType ) => { - const name = blockType.name; - result[ name ] = { - name, - }; - } ); - - return result; -}; - /** * If there is a separator block whose color is defined in theme.json via background, * update the separator color to the same value by using border color. @@ -1046,7 +1034,6 @@ export function useGlobalStylesOutput() { getBlockTypes(), getBlockStyles ); - const blockNames = getBlockNames( getBlockTypes() ); const customProperties = toCustomProperties( mergedConfig, @@ -1080,18 +1067,20 @@ export function useGlobalStylesOutput() { // Loop through the blocks to check if there are custom CSS values. // If there are, get the block selector and push the selector together with // the CSS value to the 'stylesheets' array. - Object.entries( blockNames ).forEach( ( name ) => { - if ( mergedConfig.styles.blocks[ name[ 0 ] ]?.css ) { - const selector = blockSelectors[ name[ 0 ] ].selector; - stylesheets.push( { - css: processCSSNesting( - mergedConfig.styles.blocks[ name[ 0 ] ]?.css, - selector - ), - isGlobalStyles: true, - } ); - } - } ); + getBlockTypes() + .map( ( blockType ) => blockType.name ) + .forEach( ( name ) => { + if ( mergedConfig.styles.blocks[ name ]?.css ) { + const selector = blockSelectors[ name ].selector; + stylesheets.push( { + css: processCSSNesting( + mergedConfig.styles.blocks[ name ]?.css, + selector + ), + isGlobalStyles: true, + } ); + } + } ); return [ stylesheets, mergedConfig.settings, filters ]; }, [ From 241a383152643774acfa54a50142e06ec1945ba2 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 23 Jan 2023 11:06:40 +0200 Subject: [PATCH 16/16] Simplify the loop some more - props @mamaduka --- .../global-styles/use-global-styles-output.js | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/use-global-styles-output.js b/packages/block-editor/src/components/global-styles/use-global-styles-output.js index b0d7389eafb54..d4a5512167260 100644 --- a/packages/block-editor/src/components/global-styles/use-global-styles-output.js +++ b/packages/block-editor/src/components/global-styles/use-global-styles-output.js @@ -1065,20 +1065,18 @@ export function useGlobalStylesOutput() { // Loop through the blocks to check if there are custom CSS values. // If there are, get the block selector and push the selector together with // the CSS value to the 'stylesheets' array. - getBlockTypes() - .map( ( blockType ) => blockType.name ) - .forEach( ( name ) => { - if ( mergedConfig.styles.blocks[ name ]?.css ) { - const selector = blockSelectors[ name ].selector; - stylesheets.push( { - css: processCSSNesting( - mergedConfig.styles.blocks[ name ]?.css, - selector - ), - isGlobalStyles: true, - } ); - } - } ); + getBlockTypes().forEach( ( blockType ) => { + if ( mergedConfig.styles.blocks[ blockType.name ]?.css ) { + const selector = blockSelectors[ blockType.name ].selector; + stylesheets.push( { + css: processCSSNesting( + mergedConfig.styles.blocks[ blockType.name ]?.css, + selector + ), + isGlobalStyles: true, + } ); + } + } ); return [ stylesheets, mergedConfig.settings, filters ]; }, [