diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 1b5cba91fe811e..ecb9ade8ea2b3f 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -301,7 +301,9 @@ public function __construct( $theme_json = array(), $origin = 'theme' ) { $path = array_merge( $node['path'], $preset_metadata['path'] ); $preset = _wp_array_get( $this->theme_json, $path, null ); if ( null !== $preset ) { - _wp_array_set( $this->theme_json, $path, array( $origin => $preset ) ); + if ( 'user' !== $origin || isset( $preset[0] ) ) { + _wp_array_set( $this->theme_json, $path, array( $origin => $preset ) ); + } } } } @@ -1333,48 +1335,52 @@ public function merge( $incoming ) { * @return array */ private static function remove_insecure_settings( $input ) { + $origins = array( 'default', 'theme', 'user' ); + $output = array(); foreach ( self::PRESETS_METADATA as $preset_metadata ) { - $presets = _wp_array_get( $input, $preset_metadata['path'], null ); - if ( null === $presets ) { - continue; - } + foreach ( $origins as $origin ) { + $path_with_origin = array_merge( $preset_metadata['path'], array( $origin ) ); + $presets = _wp_array_get( $input, $path_with_origin, null ); + if ( null === $presets ) { + continue; + } - $escaped_preset = array(); - foreach ( $presets as $preset ) { - if ( - esc_attr( esc_html( $preset['name'] ) ) === $preset['name'] && - sanitize_html_class( $preset['slug'] ) === $preset['slug'] - ) { - $value = null; - if ( isset( $preset_metadata['value_key'] ) ) { - $value = $preset[ $preset_metadata['value_key'] ]; - } elseif ( - isset( $preset_metadata['value_func'] ) && - is_callable( $preset_metadata['value_func'] ) + $escaped_preset = array(); + foreach ( $presets as $preset ) { + if ( + esc_attr( esc_html( $preset['name'] ) ) === $preset['name'] && + sanitize_html_class( $preset['slug'] ) === $preset['slug'] ) { - $value = call_user_func( $preset_metadata['value_func'], $preset ); - } + $value = null; + if ( isset( $preset_metadata['value_key'] ) ) { + $value = $preset[ $preset_metadata['value_key'] ]; + } elseif ( + isset( $preset_metadata['value_func'] ) && + is_callable( $preset_metadata['value_func'] ) + ) { + $value = call_user_func( $preset_metadata['value_func'], $preset ); + } - $preset_is_valid = true; - foreach ( $preset_metadata['properties'] as $property ) { - if ( ! self::is_safe_css_declaration( $property, $value ) ) { - $preset_is_valid = false; - break; + $preset_is_valid = true; + foreach ( $preset_metadata['properties'] as $property ) { + if ( ! self::is_safe_css_declaration( $property, $value ) ) { + $preset_is_valid = false; + break; + } } - } - if ( $preset_is_valid ) { - $escaped_preset[] = $preset; + if ( $preset_is_valid ) { + $escaped_preset[] = $preset; + } } } - } - if ( ! empty( $escaped_preset ) ) { - _wp_array_set( $output, $preset_metadata['path'], $escaped_preset ); + if ( ! empty( $escaped_preset ) ) { + _wp_array_set( $output, $path_with_origin, $escaped_preset ); + } } } - return $output; } diff --git a/packages/components/src/color-edit/index.js b/packages/components/src/color-edit/index.js index c3f8c4a82129cf..a9dafeae2c8a69 100644 --- a/packages/components/src/color-edit/index.js +++ b/packages/components/src/color-edit/index.js @@ -49,12 +49,14 @@ function ColorNameInput( { value, onChange } ) { } function ColorOption( { + canOnlyChangeValues, color, onChange, isEditing, onStartEditing, onRemove, onStopEditing, + slugPrefix, } ) { const focusOutsideProps = useFocusOutside( onStopEditing ); return ( @@ -68,14 +70,14 @@ function ColorOption( { - { isEditing ? ( + { isEditing && ! canOnlyChangeValues ? ( onChange( { ...color, name: nextName, - slug: kebabCase( nextName ), + slug: slugPrefix + kebabCase( nextName ), } ) } /> @@ -83,7 +85,7 @@ function ColorOption( { { color.name } ) } - { isEditing && ( + { isEditing && ! canOnlyChangeValues && ( { colors.map( ( color, index ) => ( { @@ -177,6 +182,7 @@ function ColorPaletteEditListView( { setEditingColor( null ); } } } + slugPrefix={ slugPrefix } /> ) ) } @@ -186,7 +192,15 @@ function ColorPaletteEditListView( { const EMPTY_ARRAY = []; -export default function ColorEdit( { colors = EMPTY_ARRAY, onChange } ) { +export default function ColorEdit( { + colors = EMPTY_ARRAY, + onChange, + paletteLabel, + emptyMessage, + canOnlyChangeValues, + canReset, + slugPrefix = '', +} ) { const [ isEditing, setIsEditing ] = useState( false ); const [ editingColor, setEditingColor ] = useState( null ); const isAdding = @@ -200,7 +214,7 @@ export default function ColorEdit( { colors = EMPTY_ARRAY, onChange } ) { return ( - { __( 'Custom' ) } + { paletteLabel } { isEditing && ( ) } - + { ! canOnlyChangeValues && ( + + ) } + { canReset && ( + + ) } ) } @@ -275,10 +305,12 @@ export default function ColorEdit( { colors = EMPTY_ARRAY, onChange } ) { <> { isEditing && ( ) } { ! isEditing && ( @@ -291,10 +323,7 @@ export default function ColorEdit( { colors = EMPTY_ARRAY, onChange } ) { ) } ) } - { ! hasColors && - __( - 'Custom colors are empty! Add some colors to create your own color palette.' - ) } + { ! hasColors && emptyMessage } ); } diff --git a/packages/edit-site/src/components/global-styles/color-palette-panel.js b/packages/edit-site/src/components/global-styles/color-palette-panel.js index b069738de3fa07..281f3c5fe48721 100644 --- a/packages/edit-site/src/components/global-styles/color-palette-panel.js +++ b/packages/edit-site/src/components/global-styles/color-palette-panel.js @@ -1,7 +1,11 @@ /** * WordPress dependencies */ -import { __experimentalColorEdit as ColorEdit } from '@wordpress/components'; +import { + __experimentalColorEdit as ColorEdit, + __experimentalVStack as VStack, +} from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -9,14 +13,60 @@ import { __experimentalColorEdit as ColorEdit } from '@wordpress/components'; import { useSetting } from './hooks'; export default function ColorPalettePanel( { name } ) { - const [ userColors, setColors ] = useSetting( - 'color.palette', + const [ themeColors, setThemeColors ] = useSetting( + 'color.palette.theme', + name + ); + const [ baseThemeColors ] = useSetting( + 'color.palette.theme', name, - 'user' + 'base' + ); + const [ defaultColors, setDefaultColors ] = useSetting( + 'color.palette.default', + name + ); + const [ baseDefaultColors ] = useSetting( + 'color.palette.default', + name, + 'base' + ); + const [ customColors, setCustomColors ] = useSetting( + 'color.palette.user', + name ); return ( -
- -
+ + { !! themeColors && !! themeColors.length && ( + + ) } + { !! defaultColors && !! defaultColors.length && ( + + ) } + + ); } diff --git a/packages/edit-site/src/components/global-styles/global-styles-provider.js b/packages/edit-site/src/components/global-styles/global-styles-provider.js index f18eff6c728be8..25dd5d04796780 100644 --- a/packages/edit-site/src/components/global-styles/global-styles-provider.js +++ b/packages/edit-site/src/components/global-styles/global-styles-provider.js @@ -2,9 +2,6 @@ * External dependencies */ import { - get, - cloneDeep, - set, mergeWith, pickBy, isEmpty, @@ -23,7 +20,6 @@ import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies */ -import { PRESET_METADATA } from './utils'; import { GlobalStylesContext } from './context'; function mergeTreesCustomizer( _, srcValue ) { @@ -39,29 +35,6 @@ function mergeBaseAndUserConfigs( base, user ) { return mergeWith( {}, base, user, mergeTreesCustomizer ); } -function addUserOriginToSettings( settingsToAdd ) { - const newSettings = cloneDeep( settingsToAdd ); - PRESET_METADATA.forEach( ( { path } ) => { - const presetData = get( newSettings, path ); - if ( presetData ) { - set( newSettings, path, { - user: presetData, - } ); - } - } ); - return newSettings; -} - -function removeUserOriginFromSettings( settingsToRemove ) { - const newSettings = cloneDeep( settingsToRemove ); - PRESET_METADATA.forEach( ( { path } ) => { - const presetData = get( newSettings, path ); - if ( presetData ) { - set( newSettings, path, ( presetData ?? {} ).user ); - } - } ); - return newSettings; -} const cleanEmptyObject = ( object ) => { if ( ! isObject( object ) || Array.isArray( object ) ) { return object; @@ -97,7 +70,7 @@ function useGlobalStylesUserConfig() { const config = useMemo( () => { return { - settings: addUserOriginToSettings( settings ?? {} ), + settings: settings ?? {}, styles: styles ?? {}, }; }, [ settings, styles ] ); @@ -111,15 +84,12 @@ function useGlobalStylesUserConfig() { ); const currentConfig = { styles: record?.styles ?? {}, - settings: addUserOriginToSettings( record?.settings ?? {} ), + settings: record?.settings ?? {}, }; const updatedConfig = callback( currentConfig ); editEntityRecord( 'root', 'globalStyles', globalStylesId, { styles: cleanEmptyObject( updatedConfig.styles ) || {}, - settings: - cleanEmptyObject( - removeUserOriginFromSettings( updatedConfig.settings ) - ) || {}, + settings: cleanEmptyObject( updatedConfig.settings ) || {}, } ); }, [ globalStylesId ] diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index fb2388dda5444a..f772b4371a7269 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -1237,20 +1237,22 @@ function test_remove_insecure_properties_removes_non_preset_settings() { 'color' => array( 'custom' => true, 'palette' => array( - array( - 'name' => 'Red', - 'slug' => 'red', - 'color' => '#ff0000', - ), - array( - 'name' => 'Green', - 'slug' => 'green', - 'color' => '#00ff00', - ), - array( - 'name' => 'Blue', - 'slug' => 'blue', - 'color' => '#0000ff', + 'user' => array( + array( + 'name' => 'Red', + 'slug' => 'red', + 'color' => '#ff0000', + ), + array( + 'name' => 'Green', + 'slug' => 'green', + 'color' => '#00ff00', + ), + array( + 'name' => 'Blue', + 'slug' => 'blue', + 'color' => '#0000ff', + ), ), ), ), @@ -1262,20 +1264,22 @@ function test_remove_insecure_properties_removes_non_preset_settings() { 'color' => array( 'custom' => true, 'palette' => array( - array( - 'name' => 'Yellow', - 'slug' => 'yellow', - 'color' => '#ff0000', - ), - array( - 'name' => 'Pink', - 'slug' => 'pink', - 'color' => '#00ff00', - ), - array( - 'name' => 'Orange', - 'slug' => 'orange', - 'color' => '#0000ff', + 'user' => array( + array( + 'name' => 'Yellow', + 'slug' => 'yellow', + 'color' => '#ff0000', + ), + array( + 'name' => 'Pink', + 'slug' => 'pink', + 'color' => '#00ff00', + ), + array( + 'name' => 'Orange', + 'slug' => 'orange', + 'color' => '#0000ff', + ), ), ), ), @@ -1293,20 +1297,22 @@ function test_remove_insecure_properties_removes_non_preset_settings() { 'settings' => array( 'color' => array( 'palette' => array( - array( - 'name' => 'Red', - 'slug' => 'red', - 'color' => '#ff0000', - ), - array( - 'name' => 'Green', - 'slug' => 'green', - 'color' => '#00ff00', - ), - array( - 'name' => 'Blue', - 'slug' => 'blue', - 'color' => '#0000ff', + 'user' => array( + array( + 'name' => 'Red', + 'slug' => 'red', + 'color' => '#ff0000', + ), + array( + 'name' => 'Green', + 'slug' => 'green', + 'color' => '#00ff00', + ), + array( + 'name' => 'Blue', + 'slug' => 'blue', + 'color' => '#0000ff', + ), ), ), ), @@ -1314,20 +1320,22 @@ function test_remove_insecure_properties_removes_non_preset_settings() { 'core/group' => array( 'color' => array( 'palette' => array( - array( - 'name' => 'Yellow', - 'slug' => 'yellow', - 'color' => '#ff0000', - ), - array( - 'name' => 'Pink', - 'slug' => 'pink', - 'color' => '#00ff00', - ), - array( - 'name' => 'Orange', - 'slug' => 'orange', - 'color' => '#0000ff', + 'user' => array( + array( + 'name' => 'Yellow', + 'slug' => 'yellow', + 'color' => '#ff0000', + ), + array( + 'name' => 'Pink', + 'slug' => 'pink', + 'color' => '#00ff00', + ), + array( + 'name' => 'Orange', + 'slug' => 'orange', + 'color' => '#0000ff', + ), ), ), ), @@ -1345,49 +1353,53 @@ function test_remove_insecure_properties_removes_unsafe_preset_settings() { 'settings' => array( 'color' => array( 'palette' => array( - array( - 'name' => 'Red/>ok', - 'slug' => 'red', - 'color' => '#ff0000', - ), - array( - 'name' => 'Green', - 'slug' => 'a" attr', - 'color' => '#00ff00', - ), - array( - 'name' => 'Blue', - 'slug' => 'blue', - 'color' => 'var(--color, var(--unsafe-fallback))', - ), - array( - 'name' => 'Pink', - 'slug' => 'pink', - 'color' => '#FFC0CB', + 'user' => array( + array( + 'name' => 'Red/>ok', + 'slug' => 'red', + 'color' => '#ff0000', + ), + array( + 'name' => 'Green', + 'slug' => 'a" attr', + 'color' => '#00ff00', + ), + array( + 'name' => 'Blue', + 'slug' => 'blue', + 'color' => 'var(--color, var(--unsafe-fallback))', + ), + array( + 'name' => 'Pink', + 'slug' => 'pink', + 'color' => '#FFC0CB', + ), ), ), ), 'typography' => array( 'fontFamilies' => array( - array( - 'name' => 'Helvetica Arial/>test', - 'slug' => 'helvetica-arial', - 'fontFamily' => 'Helvetica Neue, Helvetica, Arial, sans-serif', - ), - array( - 'name' => 'Geneva', - 'slug' => 'geneva#asa', - 'fontFamily' => 'Geneva, Tahoma, Verdana, sans-serif', - ), - array( - 'name' => 'Cambria', - 'slug' => 'cambria', - 'fontFamily' => 'Cambria, Georgia, serif', - ), - array( - 'name' => 'Helvetica Arial', - 'slug' => 'helvetica-arial', - 'fontFamily' => 'var(--fontFamily, var(--unsafe-fallback))', + 'user' => array( + array( + 'name' => 'Helvetica Arial/>test', + 'slug' => 'helvetica-arial', + 'fontFamily' => 'Helvetica Neue, Helvetica, Arial, sans-serif', + ), + array( + 'name' => 'Geneva', + 'slug' => 'geneva#asa', + 'fontFamily' => 'Geneva, Tahoma, Verdana, sans-serif', + ), + array( + 'name' => 'Cambria', + 'slug' => 'cambria', + 'fontFamily' => 'Cambria, Georgia, serif', + ), + array( + 'name' => 'Helvetica Arial', + 'slug' => 'helvetica-arial', + 'fontFamily' => 'var(--fontFamily, var(--unsafe-fallback))', + ), ), ), ), @@ -1395,25 +1407,27 @@ function test_remove_insecure_properties_removes_unsafe_preset_settings() { 'core/group' => array( 'color' => array( 'palette' => array( - array( - 'name' => 'Red/>ok', - 'slug' => 'red', - 'color' => '#ff0000', - ), - array( - 'name' => 'Green', - 'slug' => 'a" attr', - 'color' => '#00ff00', - ), - array( - 'name' => 'Blue', - 'slug' => 'blue', - 'color' => 'var(--color, var(--unsafe--fallback))', - ), - array( - 'name' => 'Pink', - 'slug' => 'pink', - 'color' => '#FFC0CB', + 'user' => array( + array( + 'name' => 'Red/>ok', + 'slug' => 'red', + 'color' => '#ff0000', + ), + array( + 'name' => 'Green', + 'slug' => 'a" attr', + 'color' => '#00ff00', + ), + array( + 'name' => 'Blue', + 'slug' => 'blue', + 'color' => 'var(--color, var(--unsafe--fallback))', + ), + array( + 'name' => 'Pink', + 'slug' => 'pink', + 'color' => '#FFC0CB', + ), ), ), ), @@ -1428,19 +1442,23 @@ function test_remove_insecure_properties_removes_unsafe_preset_settings() { 'settings' => array( 'color' => array( 'palette' => array( - array( - 'name' => 'Pink', - 'slug' => 'pink', - 'color' => '#FFC0CB', + 'user' => array( + array( + 'name' => 'Pink', + 'slug' => 'pink', + 'color' => '#FFC0CB', + ), ), ), ), 'typography' => array( 'fontFamilies' => array( - array( - 'name' => 'Cambria', - 'slug' => 'cambria', - 'fontFamily' => 'Cambria, Georgia, serif', + 'user' => array( + array( + 'name' => 'Cambria', + 'slug' => 'cambria', + 'fontFamily' => 'Cambria, Georgia, serif', + ), ), ), ), @@ -1448,10 +1466,12 @@ function test_remove_insecure_properties_removes_unsafe_preset_settings() { 'core/group' => array( 'color' => array( 'palette' => array( - array( - 'name' => 'Pink', - 'slug' => 'pink', - 'color' => '#FFC0CB', + 'user' => array( + array( + 'name' => 'Pink', + 'slug' => 'pink', + 'color' => '#FFC0CB', + ), ), ), ),