From 97375fc4f257b93b8c37d6743522e1fbe8755dbd Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Thu, 6 Jul 2023 12:58:02 +0200 Subject: [PATCH 01/32] Add behaviors to global styles API --- lib/compat/wordpress-6.3/rest-api.php | 2 +- ...utenberg-rest-global-styles-controller.php | 153 ++++++++++++++++++ lib/load.php | 2 +- ...erg-rest-global-styles-controller-test.php | 9 +- 4 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 lib/experimental/class-gutenberg-rest-global-styles-controller.php diff --git a/lib/compat/wordpress-6.3/rest-api.php b/lib/compat/wordpress-6.3/rest-api.php index 144ad4d50c83f1..55f66d773c34f3 100644 --- a/lib/compat/wordpress-6.3/rest-api.php +++ b/lib/compat/wordpress-6.3/rest-api.php @@ -65,7 +65,7 @@ function gutenberg_register_global_styles_revisions_endpoints() { * Registers the Global Styles REST API routes. */ function gutenberg_register_global_styles_endpoints() { - $global_styles_controller = new Gutenberg_REST_Global_Styles_Controller_6_3(); + $global_styles_controller = new Gutenberg_REST_Global_Styles_Controller(); $global_styles_controller->register_routes(); } add_action( 'rest_api_init', 'gutenberg_register_global_styles_endpoints' ); diff --git a/lib/experimental/class-gutenberg-rest-global-styles-controller.php b/lib/experimental/class-gutenberg-rest-global-styles-controller.php new file mode 100644 index 00000000000000..3ec05c5d535d2a --- /dev/null +++ b/lib/experimental/class-gutenberg-rest-global-styles-controller.php @@ -0,0 +1,153 @@ +schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + + $schema = array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'title' => $this->post_type, + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => __( 'ID of global styles config.' ), + 'type' => 'string', + 'context' => array( 'embed', 'view', 'edit' ), + 'readonly' => true, + ), + 'styles' => array( + 'description' => __( 'Global styles.' ), + 'type' => array( 'object' ), + 'context' => array( 'view', 'edit' ), + ), + 'settings' => array( + 'description' => __( 'Global settings.' ), + 'type' => array( 'object' ), + 'context' => array( 'view', 'edit' ), + ), + 'behaviors' => array( + 'description' => __( 'Global behaviors.' ), + 'type' => array( 'object' ), + 'context' => array( 'view', 'edit' ), + ), + 'title' => array( + 'description' => __( 'Title of the global styles variation.' ), + 'type' => array( 'object', 'string' ), + 'default' => '', + 'context' => array( 'embed', 'view', 'edit' ), + 'properties' => array( + 'raw' => array( + 'description' => __( 'Title for the global styles variation, as it exists in the database.' ), + 'type' => 'string', + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'rendered' => array( + 'description' => __( 'HTML title for the post, transformed for display.' ), + 'type' => 'string', + 'context' => array( 'view', 'edit', 'embed' ), + 'readonly' => true, + ), + ), + ), + ), + ); + + $this->schema = $schema; + + return $this->add_additional_fields_schema( $this->schema ); + } + + /** + * Prepare a global styles config output for response. + * + * @since 5.9.0 + * @since 6.2 Handling of style.css was added to WP_Theme_JSON. + * + * @param WP_Post $post Global Styles post object. + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response Response object. + */ + public function prepare_item_for_response( $post, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + $raw_config = json_decode( $post->post_content, true ); + $is_global_styles_user_theme_json = isset( $raw_config['isGlobalStylesUserThemeJSON'] ) && true === $raw_config['isGlobalStylesUserThemeJSON']; + $config = array(); + if ( $is_global_styles_user_theme_json ) { + $config = ( new WP_Theme_JSON_Gutenberg( $raw_config, 'custom' ) )->get_raw_data(); + } + + // Base fields for every post. + $data = array(); + $fields = $this->get_fields_for_response( $request ); + + if ( rest_is_field_included( 'id', $fields ) ) { + $data['id'] = $post->ID; + } + + if ( rest_is_field_included( 'title', $fields ) ) { + $data['title'] = array(); + } + if ( rest_is_field_included( 'title.raw', $fields ) ) { + $data['title']['raw'] = $post->post_title; + } + if ( rest_is_field_included( 'title.rendered', $fields ) ) { + add_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); + + $data['title']['rendered'] = get_the_title( $post->ID ); + + remove_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); + } + + if ( rest_is_field_included( 'settings', $fields ) ) { + $data['settings'] = ! empty( $config['settings'] ) && $is_global_styles_user_theme_json ? $config['settings'] : new stdClass(); + } + + if ( rest_is_field_included( 'styles', $fields ) ) { + $data['styles'] = ! empty( $config['styles'] ) && $is_global_styles_user_theme_json ? $config['styles'] : new stdClass(); + } + + if ( rest_is_field_included( 'behaviors', $fields ) ) { + $data['behaviors'] = ! empty( $config['behaviors'] ) && $is_global_styles_user_theme_json ? $config['behaviors'] : new stdClass(); + } + + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; + $data = $this->add_additional_fields_to_object( $data, $request ); + $data = $this->filter_response_by_context( $data, $context ); + + // Wrap the data in a response object. + $response = rest_ensure_response( $data ); + + if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { + $links = $this->prepare_links( $post->ID ); + $response->add_links( $links ); + if ( ! empty( $links['self']['href'] ) ) { + $actions = $this->get_available_actions(); + $self = $links['self']['href']; + foreach ( $actions as $rel ) { + $response->add_link( $rel, $self ); + } + } + } + + return $response; + } + +} diff --git a/lib/load.php b/lib/load.php index eeb463f7b762dc..1b30658004ac61 100644 --- a/lib/load.php +++ b/lib/load.php @@ -64,7 +64,7 @@ function gutenberg_is_experiment_enabled( $name ) { require_once __DIR__ . '/experimental/class-wp-rest-customizer-nonces.php'; } require_once __DIR__ . '/experimental/class-gutenberg-rest-template-revision-count.php'; - + require_once __DIR__ . '/experimental/class-gutenberg-rest-global-styles-controller.php'; require_once __DIR__ . '/experimental/rest-api.php'; } diff --git a/phpunit/class-gutenberg-rest-global-styles-controller-test.php b/phpunit/class-gutenberg-rest-global-styles-controller-test.php index 65f8736449acd0..3fcdf32fd22708 100644 --- a/phpunit/class-gutenberg-rest-global-styles-controller-test.php +++ b/phpunit/class-gutenberg-rest-global-styles-controller-test.php @@ -123,13 +123,14 @@ public function test_get_item() { $this->assertEquals( array( - 'id' => self::$global_styles_id, - 'title' => array( + 'id' => self::$global_styles_id, + 'title' => array( 'raw' => 'Custom Styles', 'rendered' => 'Custom Styles', ), - 'settings' => new stdClass(), - 'styles' => new stdClass(), + 'settings' => new stdClass(), + 'styles' => new stdClass(), + 'behaviors' => new stdClass(), ), $data ); From e2b65f638e8e3b6b84e4c3ef34fd5c492f04e054 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Thu, 6 Jul 2023 13:57:59 +0200 Subject: [PATCH 02/32] Add behaviors to global styles API endpoint --- ...utenberg-rest-global-styles-controller.php | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/lib/experimental/class-gutenberg-rest-global-styles-controller.php b/lib/experimental/class-gutenberg-rest-global-styles-controller.php index 3ec05c5d535d2a..a97abda9dc2774 100644 --- a/lib/experimental/class-gutenberg-rest-global-styles-controller.php +++ b/lib/experimental/class-gutenberg-rest-global-styles-controller.php @@ -150,4 +150,61 @@ public function prepare_item_for_response( $post, $request ) { // phpcs:ignore V return $response; } + /** + * Returns the given theme global styles config. + * Duplicated from core. + * The only change is that we call WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( 'theme' ) instead of WP_Theme_JSON_Resolver::get_merged_data( 'theme' ). + * + * @since 6.2.0 + * + * @param WP_REST_Request $request The request instance. + * @return WP_REST_Response|WP_Error + */ + public function get_theme_item( $request ) { + if ( get_stylesheet() !== $request['stylesheet'] ) { + // This endpoint only supports the active theme for now. + return new WP_Error( + 'rest_theme_not_found', + __( 'Theme not found.' ), + array( 'status' => 404 ) + ); + } + + $theme = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( 'theme' ); + $data = array(); + $fields = $this->get_fields_for_response( $request ); + + if ( rest_is_field_included( 'settings', $fields ) ) { + $data['settings'] = $theme->get_settings(); + } + + if ( rest_is_field_included( 'styles', $fields ) ) { + $raw_data = $theme->get_raw_data(); + $data['styles'] = isset( $raw_data['styles'] ) ? $raw_data['styles'] : array(); + } + + if ( rest_is_field_included( 'behaviors', $fields ) ) { + $raw_data = $theme->get_raw_data(); + $data['behaviors'] = isset( $raw_data['behaviors'] ) ? $raw_data['behaviors'] : array(); + } + + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; + $data = $this->add_additional_fields_to_object( $data, $request ); + $data = $this->filter_response_by_context( $data, $context ); + + $response = rest_ensure_response( $data ); + + if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { + $links = array( + 'self' => array( + 'href' => rest_url( sprintf( '%s/%s/themes/%s', $this->namespace, $this->rest_base, $request['stylesheet'] ) ), + ), + ); + $response->add_links( $links ); + } + + return $response; + } + + } From 7a6798ba3a8925cba251fc024e33d44f5e57eb98 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Thu, 6 Jul 2023 15:10:42 +0200 Subject: [PATCH 03/32] Fix coding standards warnings --- ...s-gutenberg-rest-global-styles-controller.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/experimental/class-gutenberg-rest-global-styles-controller.php b/lib/experimental/class-gutenberg-rest-global-styles-controller.php index a97abda9dc2774..14914757493267 100644 --- a/lib/experimental/class-gutenberg-rest-global-styles-controller.php +++ b/lib/experimental/class-gutenberg-rest-global-styles-controller.php @@ -29,39 +29,39 @@ public function get_item_schema() { 'type' => 'object', 'properties' => array( 'id' => array( - 'description' => __( 'ID of global styles config.' ), + 'description' => __( 'ID of global styles config.', 'default' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'styles' => array( - 'description' => __( 'Global styles.' ), + 'description' => __( 'Global styles.', 'default' ), 'type' => array( 'object' ), 'context' => array( 'view', 'edit' ), ), 'settings' => array( - 'description' => __( 'Global settings.' ), + 'description' => __( 'Global settings.', 'default' ), 'type' => array( 'object' ), 'context' => array( 'view', 'edit' ), ), 'behaviors' => array( - 'description' => __( 'Global behaviors.' ), + 'description' => __( 'Global behaviors.', 'default' ), 'type' => array( 'object' ), 'context' => array( 'view', 'edit' ), ), 'title' => array( - 'description' => __( 'Title of the global styles variation.' ), + 'description' => __( 'Title of the global styles variation.', 'default' ), 'type' => array( 'object', 'string' ), 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'properties' => array( 'raw' => array( - 'description' => __( 'Title for the global styles variation, as it exists in the database.' ), + 'description' => __( 'Title for the global styles variation, as it exists in the database.', 'default' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), ), 'rendered' => array( - 'description' => __( 'HTML title for the post, transformed for display.' ), + 'description' => __( 'HTML title for the post, transformed for display.', 'default' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, @@ -165,7 +165,7 @@ public function get_theme_item( $request ) { // This endpoint only supports the active theme for now. return new WP_Error( 'rest_theme_not_found', - __( 'Theme not found.' ), + __( 'Theme not found.', 'default' ), array( 'status' => 404 ) ); } From 82e1f1ca247c1288fc660f0b2d9007db0536bbad Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Thu, 6 Jul 2023 16:58:26 +0200 Subject: [PATCH 04/32] Add behavior selector to the site editor, should read for theme.json --- .../global-styles/behaviors-panel.js | 54 ++++++++++++++ .../src/components/global-styles/hooks.js | 73 ++++++++++++++++++- .../src/components/global-styles/index.js | 5 ++ .../global-styles/global-styles-provider.js | 9 ++- .../components/global-styles/screen-block.js | 19 +++++ 5 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 packages/block-editor/src/components/global-styles/behaviors-panel.js diff --git a/packages/block-editor/src/components/global-styles/behaviors-panel.js b/packages/block-editor/src/components/global-styles/behaviors-panel.js new file mode 100644 index 00000000000000..d378f78da84b01 --- /dev/null +++ b/packages/block-editor/src/components/global-styles/behaviors-panel.js @@ -0,0 +1,54 @@ +/** + * WordPress dependencies + */ +import { SelectControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +export function __experimentalUseHasBehaviorsPanel( blockName ) { + if ( blockName === 'core/image' ) { + return true; + } + return false; +} + +export default function ( { onChange, value, behaviors } ) { + const defaultBehaviors = { + default: { + value: 'default', + label: __( 'Default' ), + }, + noBehaviors: { + value: '', + label: __( 'No behaviors' ), + }, + }; + + const behaviorsOptions = Object.entries( behaviors ).map( + ( [ behaviorName ] ) => ( { + value: behaviorName, + // Capitalize the first letter of the behavior name. + label: `${ behaviorName.charAt( 0 ).toUpperCase() }${ behaviorName + .slice( 1 ) + .toLowerCase() }`, + } ) + ); + + const options = [ + ...Object.values( defaultBehaviors ), + ...behaviorsOptions, + ]; + + return ( +
+ +
+ ); +} diff --git a/packages/block-editor/src/components/global-styles/hooks.js b/packages/block-editor/src/components/global-styles/hooks.js index 3c8b0167279804..a3d642fec1b8c6 100644 --- a/packages/block-editor/src/components/global-styles/hooks.js +++ b/packages/block-editor/src/components/global-styles/hooks.js @@ -19,7 +19,7 @@ import { getValueFromObjectPath, setImmutably } from '../../utils/object'; import { GlobalStylesContext } from './context'; import { unlock } from '../../lock-unlock'; -const EMPTY_CONFIG = { settings: {}, styles: {} }; +const EMPTY_CONFIG = { settings: {}, styles: {}, behaviors: {} }; const VALID_SETTINGS = [ 'appearanceTools', @@ -461,3 +461,74 @@ export function useGradientsPerOrigin( settings ) { shouldDisplayDefaultGradients, ] ); } + +export function __experimentalUseGlobalBehaviors( + path, + blockName, + source = 'all', + { shouldDecodeEncode = true } = {} +) { + const { + merged: mergedConfig, + base: baseConfig, + user: userConfig, + setUserConfig, + } = useContext( GlobalStylesContext ); + const appendedPath = path ? '.' + path : ''; + const finalPath = ! blockName + ? `behaviors${ appendedPath }` + : `behaviors.blocks.${ blockName }${ appendedPath }`; + + const setBehavior = ( newValue ) => { + let newBehavior; + switch ( newValue ) { + case 'default': + break; + case 'lightbox': + newBehavior = { + lightbox: { + enabled: true, + animation: 'zoom', + }, + }; + break; + case '': + newBehavior = { + lightbox: false, + }; + break; + } + setUserConfig( ( currentConfig ) => { + // Deep clone `currentConfig` to avoid mutating it later. + const newUserConfig = JSON.parse( JSON.stringify( currentConfig ) ); + set( newUserConfig, finalPath, newBehavior ); + return newUserConfig; + } ); + }; + + let rawResult, result; + switch ( source ) { + case 'all': + rawResult = get( mergedConfig, finalPath ); + result = shouldDecodeEncode + ? getValueFromVariable( mergedConfig, blockName, rawResult ) + : rawResult; + break; + case 'user': + rawResult = get( userConfig, finalPath ); + result = shouldDecodeEncode + ? getValueFromVariable( mergedConfig, blockName, rawResult ) + : rawResult; + break; + case 'base': + rawResult = get( baseConfig, finalPath ); + result = shouldDecodeEncode + ? getValueFromVariable( baseConfig, blockName, rawResult ) + : rawResult; + break; + default: + throw 'Unsupported source'; + } + + return [ result, setBehavior ]; +} diff --git a/packages/block-editor/src/components/global-styles/index.js b/packages/block-editor/src/components/global-styles/index.js index 24bab543b9ada6..fef9b0adf82c31 100644 --- a/packages/block-editor/src/components/global-styles/index.js +++ b/packages/block-editor/src/components/global-styles/index.js @@ -1,4 +1,5 @@ export { + __experimentalUseGlobalBehaviors, useGlobalStylesReset, useGlobalSetting, useGlobalStyle, @@ -23,5 +24,9 @@ export { default as BorderPanel, useHasBorderPanel } from './border-panel'; export { default as ColorPanel, useHasColorPanel } from './color-panel'; export { default as EffectsPanel, useHasEffectsPanel } from './effects-panel'; export { default as FiltersPanel, useHasFiltersPanel } from './filters-panel'; +export { + default as __experimentalBehaviorsPanel, + __experimentalUseHasBehaviorsPanel, +} from './behaviors-panel'; export { default as AdvancedPanel } from './advanced-panel'; export { areGlobalStyleConfigsEqual } from './utils'; 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 1e2d43e267a2dd..250cca0ebfc6df 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 @@ -31,7 +31,7 @@ export function mergeBaseAndUserConfigs( base, user ) { } function useGlobalStylesUserConfig() { - const { globalStylesId, isReady, settings, styles } = useSelect( + const { globalStylesId, isReady, settings, styles, behaviors } = useSelect( ( select ) => { const { getEditedEntityRecord, hasFinishedResolution } = select( coreStore ); @@ -65,6 +65,7 @@ function useGlobalStylesUserConfig() { isReady: hasResolved, settings: record?.settings, styles: record?.styles, + behaviors: record?.behaviors, }; }, [] @@ -76,8 +77,9 @@ function useGlobalStylesUserConfig() { return { settings: settings ?? {}, styles: styles ?? {}, + behaviors: behaviors ?? {}, }; - }, [ settings, styles ] ); + }, [ settings, styles, behaviors ] ); const setConfig = useCallback( ( callback, options = {} ) => { @@ -89,6 +91,7 @@ function useGlobalStylesUserConfig() { const currentConfig = { styles: record?.styles ?? {}, settings: record?.settings ?? {}, + behaviors: record?.behaviors ?? {}, }; const updatedConfig = callback( currentConfig ); editEntityRecord( @@ -98,6 +101,8 @@ function useGlobalStylesUserConfig() { { styles: cleanEmptyObject( updatedConfig.styles ) || {}, settings: cleanEmptyObject( updatedConfig.settings ) || {}, + behaviors: + cleanEmptyObject( updatedConfig.behaviors ) || {}, }, options ); diff --git a/packages/edit-site/src/components/global-styles/screen-block.js b/packages/edit-site/src/components/global-styles/screen-block.js index b24fd5eb41de15..f45f78804de6d3 100644 --- a/packages/edit-site/src/components/global-styles/screen-block.js +++ b/packages/edit-site/src/components/global-styles/screen-block.js @@ -61,12 +61,15 @@ const { useHasDimensionsPanel, useHasTypographyPanel, useHasBorderPanel, + __experimentalUseHasBehaviorsPanel, useGlobalSetting, useSettingsForBlockElement, useHasColorPanel, useHasEffectsPanel, useHasFiltersPanel, useGlobalStyle, + __experimentalUseGlobalBehaviors, + __experimentalBehaviorsPanel: StylesBehaviorsPanel, BorderPanel: StylesBorderPanel, ColorPanel: StylesColorPanel, TypographyPanel: StylesTypographyPanel, @@ -91,10 +94,15 @@ function ScreenBlock( { name, variation } ) { } ); const [ rawSettings, setSettings ] = useGlobalSetting( '', name ); const settings = useSettingsForBlockElement( rawSettings, name ); + const [ behaviors, setBehaviors ] = __experimentalUseGlobalBehaviors( + '', + name + ); const blockType = getBlockType( name ); const blockVariations = useBlockVariations( name ); const hasTypographyPanel = useHasTypographyPanel( settings ); const hasColorPanel = useHasColorPanel( settings ); + const hasBehaviorsPanel = __experimentalUseHasBehaviorsPanel( name ); const hasBorderPanel = useHasBorderPanel( settings ); const hasDimensionsPanel = useHasDimensionsPanel( settings ); const hasEffectsPanel = useHasEffectsPanel( settings ); @@ -180,6 +188,10 @@ function ScreenBlock( { name, variation } ) { setStyle( { ...newStyle, border: { ...updatedBorder, radius } } ); }; + const onChangeBehaviors = ( newBehaviors ) => { + setBehaviors( newBehaviors ); + }; + return ( <> + { hasBehaviorsPanel && ( + + ) } ) } From 358194d35360cfc3ad45c515db61ccda889721d3 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Thu, 6 Jul 2023 18:04:08 +0200 Subject: [PATCH 05/32] Now the database saves global behaviors --- ...global-styles-revisions-controller-6-3.php | 2 + ...utenberg-rest-global-styles-controller.php | 59 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/lib/compat/wordpress-6.3/class-gutenberg-rest-global-styles-revisions-controller-6-3.php b/lib/compat/wordpress-6.3/class-gutenberg-rest-global-styles-revisions-controller-6-3.php index c45ce23c5d4ea7..4bd781f7b2ae9d 100644 --- a/lib/compat/wordpress-6.3/class-gutenberg-rest-global-styles-revisions-controller-6-3.php +++ b/lib/compat/wordpress-6.3/class-gutenberg-rest-global-styles-revisions-controller-6-3.php @@ -282,6 +282,7 @@ public function prepare_item_for_response( $post, $request ) { $fields = $this->get_fields_for_response( $request ); $data = array(); + // Should we include behaviors here? if ( ! empty( $global_styles_config['styles'] ) || ! empty( $global_styles_config['settings'] ) ) { $global_styles_config = ( new WP_Theme_JSON_Gutenberg( $global_styles_config, 'custom' ) )->get_raw_data(); if ( rest_is_field_included( 'settings', $fields ) ) { @@ -401,6 +402,7 @@ public function get_item_schema() { 'type' => array( 'object' ), 'context' => array( 'view', 'edit' ), ), + // Should we include behaviors here? ), ); diff --git a/lib/experimental/class-gutenberg-rest-global-styles-controller.php b/lib/experimental/class-gutenberg-rest-global-styles-controller.php index 14914757493267..eb4ca56a761373 100644 --- a/lib/experimental/class-gutenberg-rest-global-styles-controller.php +++ b/lib/experimental/class-gutenberg-rest-global-styles-controller.php @@ -206,5 +206,64 @@ public function get_theme_item( $request ) { return $response; } + /** + * Prepares a single global styles config for update. + * + * @since 5.9.0 + * @since 6.2.0 Added validation of styles.css property. + * + * @param WP_REST_Request $request Request object. + * @return stdClass Changes to pass to wp_update_post. + */ + protected function prepare_item_for_database( $request ) { + $changes = new stdClass(); + $changes->ID = $request['id']; + $post = get_post( $request['id'] ); + $existing_config = array(); + if ( $post ) { + $existing_config = json_decode( $post->post_content, true ); + $json_decoding_error = json_last_error(); + if ( JSON_ERROR_NONE !== $json_decoding_error || ! isset( $existing_config['isGlobalStylesUserThemeJSON'] ) || + ! $existing_config['isGlobalStylesUserThemeJSON'] ) { + $existing_config = array(); + } + } + if ( isset( $request['styles'] ) || isset( $request['settings'] ) || isset( $request['behaviors'] ) ) { + $config = array(); + if ( isset( $request['styles'] ) ) { + $config['styles'] = $request['styles']; + if ( isset( $request['styles']['css'] ) ) { + $validate_custom_css = $this->validate_custom_css( $request['styles']['css'] ); + if ( is_wp_error( $validate_custom_css ) ) { + return $validate_custom_css; + } + } + } elseif ( isset( $existing_config['styles'] ) ) { + $config['styles'] = $existing_config['styles']; + } + if ( isset( $request['settings'] ) ) { + $config['settings'] = $request['settings']; + } elseif ( isset( $existing_config['settings'] ) ) { + $config['settings'] = $existing_config['settings']; + } + if ( isset( $request['behaviors'] ) ) { + $config['behaviors'] = $request['behaviors']; + } elseif ( isset( $existing_config['behaviors'] ) ) { + $config['behaviors'] = $existing_config['behaviors']; + } + $config['isGlobalStylesUserThemeJSON'] = true; + $config['version'] = WP_Theme_JSON_Gutenberg::LATEST_SCHEMA; + $changes->post_content = wp_json_encode( $config ); + } + // Post title. + if ( isset( $request['title'] ) ) { + if ( is_string( $request['title'] ) ) { + $changes->post_title = $request['title']; + } elseif ( ! empty( $request['title']['raw'] ) ) { + $changes->post_title = $request['title']['raw']; + } + } + return $changes; + } } From 234904d6a7126c3afb2738fddca9905277ed9ced Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Fri, 7 Jul 2023 10:13:22 +0200 Subject: [PATCH 06/32] Fix selector value according to behavior selected --- .../src/components/global-styles/hooks.js | 26 ++++++++++++++----- .../components/global-styles/screen-block.js | 15 ++++++----- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/hooks.js b/packages/block-editor/src/components/global-styles/hooks.js index a3d642fec1b8c6..5dceff6236d53f 100644 --- a/packages/block-editor/src/components/global-styles/hooks.js +++ b/packages/block-editor/src/components/global-styles/hooks.js @@ -463,10 +463,9 @@ export function useGradientsPerOrigin( settings ) { } export function __experimentalUseGlobalBehaviors( - path, blockName, source = 'all', - { shouldDecodeEncode = true } = {} + { shouldDecodeEncode = true, shouldReturnBehaviors = true } = {} ) { const { merged: mergedConfig, @@ -474,10 +473,9 @@ export function __experimentalUseGlobalBehaviors( user: userConfig, setUserConfig, } = useContext( GlobalStylesContext ); - const appendedPath = path ? '.' + path : ''; const finalPath = ! blockName - ? `behaviors${ appendedPath }` - : `behaviors.blocks.${ blockName }${ appendedPath }`; + ? `behaviors` + : `behaviors.blocks.${ blockName }`; const setBehavior = ( newValue ) => { let newBehavior; @@ -494,7 +492,10 @@ export function __experimentalUseGlobalBehaviors( break; case '': newBehavior = { - lightbox: false, + lightbox: { + enabled: false, + animation: 'zoom', + }, }; break; } @@ -507,6 +508,7 @@ export function __experimentalUseGlobalBehaviors( }; let rawResult, result; + switch ( source ) { case 'all': rawResult = get( mergedConfig, finalPath ); @@ -529,6 +531,16 @@ export function __experimentalUseGlobalBehaviors( default: throw 'Unsupported source'; } + if ( shouldReturnBehaviors ) { + return [ result, setBehavior ]; + } + let behaviorValue = ''; + if ( result === undefined ) { + behaviorValue = 'default'; + } + if ( result?.lightbox.enabled ) { + behaviorValue = 'lightbox'; + } - return [ result, setBehavior ]; + return [ behaviorValue, setBehavior ]; } diff --git a/packages/edit-site/src/components/global-styles/screen-block.js b/packages/edit-site/src/components/global-styles/screen-block.js index f45f78804de6d3..d336ad8a961d6b 100644 --- a/packages/edit-site/src/components/global-styles/screen-block.js +++ b/packages/edit-site/src/components/global-styles/screen-block.js @@ -94,10 +94,13 @@ function ScreenBlock( { name, variation } ) { } ); const [ rawSettings, setSettings ] = useGlobalSetting( '', name ); const settings = useSettingsForBlockElement( rawSettings, name ); - const [ behaviors, setBehaviors ] = __experimentalUseGlobalBehaviors( - '', - name - ); + const [ inheritedBehaviors, setBehaviors ] = + __experimentalUseGlobalBehaviors( name ); + const [ behavior ] = __experimentalUseGlobalBehaviors( name, 'user', { + shouldDecodeEncode: true, + shouldReturnBehaviors: false, + } ); + const blockType = getBlockType( name ); const blockVariations = useBlockVariations( name ); const hasTypographyPanel = useHasTypographyPanel( settings ); @@ -281,9 +284,9 @@ function ScreenBlock( { name, variation } ) { /> { hasBehaviorsPanel && ( ) } From 8f2f1c2035da8d85f511ff927d630417f9a969b0 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Fri, 7 Jul 2023 12:41:20 +0200 Subject: [PATCH 07/32] Add animation to the selector --- .../global-styles/behaviors-panel.js | 25 +++++++++++++++++++ .../src/components/global-styles/hooks.js | 17 ++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/global-styles/behaviors-panel.js b/packages/block-editor/src/components/global-styles/behaviors-panel.js index d378f78da84b01..edb7f4b9aa362f 100644 --- a/packages/block-editor/src/components/global-styles/behaviors-panel.js +++ b/packages/block-editor/src/components/global-styles/behaviors-panel.js @@ -38,6 +38,17 @@ export default function ( { onChange, value, behaviors } ) { ...behaviorsOptions, ]; + const animations = [ + { + value: 'zoom', + label: __( 'Zoom' ), + }, + { + value: 'fade', + label: __( 'Fade' ), + }, + ]; + return (
+ { value === 'lightbox' && ( + + ) }
); } diff --git a/packages/block-editor/src/components/global-styles/hooks.js b/packages/block-editor/src/components/global-styles/hooks.js index 5dceff6236d53f..8624d852d6bc13 100644 --- a/packages/block-editor/src/components/global-styles/hooks.js +++ b/packages/block-editor/src/components/global-styles/hooks.js @@ -490,11 +490,26 @@ export function __experimentalUseGlobalBehaviors( }, }; break; + case 'fade': + newBehavior = { + lightbox: { + enabled: true, + animation: 'fade', + }, + }; + break; + case 'zoom': + newBehavior = { + lightbox: { + enabled: true, + animation: 'zoom', + }, + }; + break; case '': newBehavior = { lightbox: { enabled: false, - animation: 'zoom', }, }; break; From df3f027c00f87a77cd324c3d83d3fe6daab42627 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Fri, 7 Jul 2023 13:17:24 +0200 Subject: [PATCH 08/32] Remove not needed themebehaviors --- .../data/data-core-block-editor.md | 23 ------------------ lib/experimental/behaviors.php | 20 ---------------- lib/load.php | 2 +- packages/block-editor/src/hooks/behaviors.js | 8 +++---- packages/block-editor/src/store/selectors.js | 24 ------------------- 5 files changed, 4 insertions(+), 73 deletions(-) delete mode 100644 lib/experimental/behaviors.php diff --git a/docs/reference-guides/data/data-core-block-editor.md b/docs/reference-guides/data/data-core-block-editor.md index fd29b1c6e1388c..744b7b2896e26a 100644 --- a/docs/reference-guides/data/data-core-block-editor.md +++ b/docs/reference-guides/data/data-core-block-editor.md @@ -168,29 +168,6 @@ _Returns_ - `Array?`: The list of allowed block types. -### getBehaviors - -Returns the behaviors registered with the editor. - -Behaviors are named, reusable pieces of functionality that can be attached to blocks. They are registered with the editor using the `theme.json` file. - -_Usage_ - -```js -const behaviors = select( blockEditorStore ).getBehaviors(); -if ( behaviors?.lightbox ) { - // Do something with the lightbox. -} -``` - -_Parameters_ - -- _state_ `Object`: Editor state. - -_Returns_ - -- `Object`: The editor behaviors object. - ### getBlock Returns a block given its client ID. This is a parsed copy of the block, containing its `blockName`, `clientId`, and current `attributes` state. This is not the block's registration settings, which must be retrieved from the blocks module registration store. diff --git a/lib/experimental/behaviors.php b/lib/experimental/behaviors.php deleted file mode 100644 index 62e7be7a252d49..00000000000000 --- a/lib/experimental/behaviors.php +++ /dev/null @@ -1,20 +0,0 @@ -get_data(); - if ( array_key_exists( 'behaviors', $theme_data ) ) { - $settings['behaviors'] = $theme_data['behaviors']; - } - return $settings; - }, - PHP_INT_MAX -); diff --git a/lib/load.php b/lib/load.php index 1b30658004ac61..a2276dd2c8205c 100644 --- a/lib/load.php +++ b/lib/load.php @@ -103,7 +103,7 @@ function gutenberg_is_experiment_enabled( $name ) { require_once __DIR__ . '/compat/wordpress-6.3/kses.php'; // Experimental features. -require __DIR__ . '/experimental/behaviors.php'; +remove_action( 'plugins_loaded', '_wp_theme_json_webfonts_handler' ); // Turns off WP 6.0's stopgap handler for Webfonts API. require __DIR__ . '/experimental/block-editor-settings-mobile.php'; require __DIR__ . '/experimental/blocks.php'; require __DIR__ . '/experimental/navigation-theme-opt-in.php'; diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 42cb42e8023684..f05c1b7f8b77cc 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -22,15 +22,14 @@ function BehaviorsControl( { onChangeAnimation, disabled = false, } ) { - const { settings, themeBehaviors } = useSelect( + const { settings } = useSelect( ( select ) => { - const { getBehaviors, getSettings } = select( blockEditorStore ); + const { getSettings } = select( blockEditorStore ); return { settings: getSettings()?.__experimentalFeatures?.blocks?.[ blockName ] ?.behaviors, - themeBehaviors: getBehaviors()?.blocks?.[ blockName ], }; }, [ blockName ] @@ -68,7 +67,6 @@ function BehaviorsControl( { const { behaviors, behaviorsValue } = useMemo( () => { const mergedBehaviors = { - ...themeBehaviors, ...( blockBehaviors || {} ), }; @@ -83,7 +81,7 @@ function BehaviorsControl( { behaviors: mergedBehaviors, behaviorsValue: value, }; - }, [ blockBehaviors, themeBehaviors ] ); + }, [ blockBehaviors ] ); // If every behavior is disabled, do not show the behaviors inspector control. if ( behaviorsOptions.length === 0 ) { return null; diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 3aaec39a986ccd..c3d8847b032397 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -2577,30 +2577,6 @@ export function getSettings( state ) { return state.settings; } -/** - * Returns the behaviors registered with the editor. - * - * Behaviors are named, reusable pieces of functionality that can be - * attached to blocks. They are registered with the editor using the - * `theme.json` file. - * - * @example - * - * ```js - * const behaviors = select( blockEditorStore ).getBehaviors(); - * if ( behaviors?.lightbox ) { - * // Do something with the lightbox. - * } - *``` - * - * @param {Object} state Editor state. - * - * @return {Object} The editor behaviors object. - */ -export function getBehaviors( state ) { - return state.settings.behaviors; -} - /** * Returns true if the most recent block change is be considered persistent, or * false otherwise. A persistent change is one committed by BlockEditorProvider From cdc2590a0a40449a677b4609648fce4c257845d1 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Fri, 7 Jul 2023 17:06:33 +0200 Subject: [PATCH 09/32] Use settings for the display --- .../src/components/global-styles/behaviors-panel.js | 7 ++----- .../block-editor/src/components/global-styles/hooks.js | 3 +-- .../edit-site/src/components/global-styles/screen-block.js | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/behaviors-panel.js b/packages/block-editor/src/components/global-styles/behaviors-panel.js index edb7f4b9aa362f..21103472e1e311 100644 --- a/packages/block-editor/src/components/global-styles/behaviors-panel.js +++ b/packages/block-editor/src/components/global-styles/behaviors-panel.js @@ -4,11 +4,8 @@ import { SelectControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -export function __experimentalUseHasBehaviorsPanel( blockName ) { - if ( blockName === 'core/image' ) { - return true; - } - return false; +export function __experimentalUseHasBehaviorsPanel( settings ) { + return settings?.behaviors; } export default function ( { onChange, value, behaviors } ) { diff --git a/packages/block-editor/src/components/global-styles/hooks.js b/packages/block-editor/src/components/global-styles/hooks.js index 8624d852d6bc13..8f191dc15c9ea5 100644 --- a/packages/block-editor/src/components/global-styles/hooks.js +++ b/packages/block-editor/src/components/global-styles/hooks.js @@ -23,6 +23,7 @@ const EMPTY_CONFIG = { settings: {}, styles: {}, behaviors: {} }; const VALID_SETTINGS = [ 'appearanceTools', + 'behaviors', 'useRootPaddingAwareAlignments', 'border.color', 'border.radius', @@ -88,7 +89,6 @@ export const useGlobalStylesReset = () => { export function useGlobalSetting( propertyPath, blockName, source = 'all' ) { const { setUserConfig, ...configs } = useContext( GlobalStylesContext ); - const appendedBlockPath = blockName ? '.blocks.' + blockName : ''; const appendedPropertyPath = propertyPath ? '.' + propertyPath : ''; const contextualPath = `settings${ appendedBlockPath }${ appendedPropertyPath }`; @@ -135,7 +135,6 @@ export function useGlobalSetting( propertyPath, blockName, source = 'all' ) { setImmutably( currentConfig, contextualPath.split( '.' ), newValue ) ); }; - return [ settingValue, setSetting ]; } diff --git a/packages/edit-site/src/components/global-styles/screen-block.js b/packages/edit-site/src/components/global-styles/screen-block.js index d336ad8a961d6b..57edc714230e39 100644 --- a/packages/edit-site/src/components/global-styles/screen-block.js +++ b/packages/edit-site/src/components/global-styles/screen-block.js @@ -105,7 +105,7 @@ function ScreenBlock( { name, variation } ) { const blockVariations = useBlockVariations( name ); const hasTypographyPanel = useHasTypographyPanel( settings ); const hasColorPanel = useHasColorPanel( settings ); - const hasBehaviorsPanel = __experimentalUseHasBehaviorsPanel( name ); + const hasBehaviorsPanel = __experimentalUseHasBehaviorsPanel( rawSettings ); const hasBorderPanel = useHasBorderPanel( settings ); const hasDimensionsPanel = useHasDimensionsPanel( settings ); const hasEffectsPanel = useHasEffectsPanel( settings ); From 8f123a8aa2077c2b32c24f72c1f36da94325fab4 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Fri, 7 Jul 2023 17:41:55 +0200 Subject: [PATCH 10/32] Show theme json default animation in selector --- .../global-styles/behaviors-panel.js | 1 - .../src/components/global-styles/hooks.js | 53 ++++++++++--------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/behaviors-panel.js b/packages/block-editor/src/components/global-styles/behaviors-panel.js index 21103472e1e311..d98bea2973eb6c 100644 --- a/packages/block-editor/src/components/global-styles/behaviors-panel.js +++ b/packages/block-editor/src/components/global-styles/behaviors-panel.js @@ -45,7 +45,6 @@ export default function ( { onChange, value, behaviors } ) { label: __( 'Fade' ), }, ]; - return (
{ let newBehavior; switch ( newValue ) { @@ -485,7 +511,7 @@ export function __experimentalUseGlobalBehaviors( newBehavior = { lightbox: { enabled: true, - animation: 'zoom', + animation, }, }; break; @@ -509,6 +535,7 @@ export function __experimentalUseGlobalBehaviors( newBehavior = { lightbox: { enabled: false, + animation, }, }; break; @@ -521,30 +548,6 @@ export function __experimentalUseGlobalBehaviors( } ); }; - let rawResult, result; - - switch ( source ) { - case 'all': - rawResult = get( mergedConfig, finalPath ); - result = shouldDecodeEncode - ? getValueFromVariable( mergedConfig, blockName, rawResult ) - : rawResult; - break; - case 'user': - rawResult = get( userConfig, finalPath ); - result = shouldDecodeEncode - ? getValueFromVariable( mergedConfig, blockName, rawResult ) - : rawResult; - break; - case 'base': - rawResult = get( baseConfig, finalPath ); - result = shouldDecodeEncode - ? getValueFromVariable( baseConfig, blockName, rawResult ) - : rawResult; - break; - default: - throw 'Unsupported source'; - } if ( shouldReturnBehaviors ) { return [ result, setBehavior ]; } From c439ff94a823faac70871e25b030ecc8f23006b9 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Fri, 7 Jul 2023 18:21:46 +0200 Subject: [PATCH 11/32] If all behaviors are disabled, prevent selector showing on site editor --- .../src/components/global-styles/behaviors-panel.js | 5 ++++- packages/block-editor/src/hooks/behaviors.js | 6 ++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/behaviors-panel.js b/packages/block-editor/src/components/global-styles/behaviors-panel.js index d98bea2973eb6c..1f771804f47bff 100644 --- a/packages/block-editor/src/components/global-styles/behaviors-panel.js +++ b/packages/block-editor/src/components/global-styles/behaviors-panel.js @@ -5,7 +5,10 @@ import { SelectControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; export function __experimentalUseHasBehaviorsPanel( settings ) { - return settings?.behaviors; + // If every behavior is disabled, do not show the behaviors inspector control. + return Object.values( settings?.behaviors ).some( + ( value ) => value === true + ); } export default function ( { onChange, value, behaviors } ) { diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index f05c1b7f8b77cc..27ef5b7afbfe93 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -25,11 +25,10 @@ function BehaviorsControl( { const { settings } = useSelect( ( select ) => { const { getSettings } = select( blockEditorStore ); - return { settings: getSettings()?.__experimentalFeatures?.blocks?.[ blockName ] - ?.behaviors, + ?.behaviors || {}, }; }, [ blockName ] @@ -45,7 +44,6 @@ function BehaviorsControl( { label: __( 'No behaviors' ), }, }; - const behaviorsOptions = Object.entries( settings ) .filter( ( [ behaviorName, behaviorValue ] ) => @@ -59,7 +57,6 @@ function BehaviorsControl( { .slice( 1 ) .toLowerCase() }`, } ) ); - const options = [ ...Object.values( defaultBehaviors ), ...behaviorsOptions, @@ -82,6 +79,7 @@ function BehaviorsControl( { behaviorsValue: value, }; }, [ blockBehaviors ] ); + // If every behavior is disabled, do not show the behaviors inspector control. if ( behaviorsOptions.length === 0 ) { return null; From 0cc415c7227acf5d589656488b58da5081ab8010 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Mon, 10 Jul 2023 12:02:05 +0200 Subject: [PATCH 12/32] Define set function --- .../block-editor/src/components/global-styles/hooks.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/hooks.js b/packages/block-editor/src/components/global-styles/hooks.js index ac9f4665eea463..d60f439a6a46e4 100644 --- a/packages/block-editor/src/components/global-styles/hooks.js +++ b/packages/block-editor/src/components/global-styles/hooks.js @@ -479,19 +479,19 @@ export function __experimentalUseGlobalBehaviors( let rawResult, result; switch ( source ) { case 'all': - rawResult = get( mergedConfig, finalPath ); + rawResult = getValueFromObjectPath( mergedConfig, finalPath ); result = shouldDecodeEncode ? getValueFromVariable( mergedConfig, blockName, rawResult ) : rawResult; break; case 'user': - rawResult = get( userConfig, finalPath ); + rawResult = getValueFromObjectPath( userConfig, finalPath ); result = shouldDecodeEncode ? getValueFromVariable( mergedConfig, blockName, rawResult ) : rawResult; break; case 'base': - rawResult = get( baseConfig, finalPath ); + rawResult = getValueFromObjectPath( baseConfig, finalPath ); result = shouldDecodeEncode ? getValueFromVariable( baseConfig, blockName, rawResult ) : rawResult; @@ -543,7 +543,7 @@ export function __experimentalUseGlobalBehaviors( setUserConfig( ( currentConfig ) => { // Deep clone `currentConfig` to avoid mutating it later. const newUserConfig = JSON.parse( JSON.stringify( currentConfig ) ); - set( newUserConfig, finalPath, newBehavior ); + setImmutably( newUserConfig, finalPath, newBehavior ); return newUserConfig; } ); }; From 1101d4ce7b7a6b33ad9e2994de1435150e0ecd91 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Mon, 10 Jul 2023 13:14:22 +0200 Subject: [PATCH 13/32] Fix if settings behaviors are undefined --- .../src/components/global-styles/behaviors-panel.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/block-editor/src/components/global-styles/behaviors-panel.js b/packages/block-editor/src/components/global-styles/behaviors-panel.js index 1f771804f47bff..6af608a3aa6b95 100644 --- a/packages/block-editor/src/components/global-styles/behaviors-panel.js +++ b/packages/block-editor/src/components/global-styles/behaviors-panel.js @@ -5,6 +5,9 @@ import { SelectControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; export function __experimentalUseHasBehaviorsPanel( settings ) { + if ( ! settings?.behaviors ) { + return false; + } // If every behavior is disabled, do not show the behaviors inspector control. return Object.values( settings?.behaviors ).some( ( value ) => value === true From fa10cbb9a42b059aa21ce2938811ebe313e130eb Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Tue, 11 Jul 2023 12:21:47 +0200 Subject: [PATCH 14/32] Add apply globally, not yet autosaving --- .../push-changes-to-global-styles/index.js | 54 ++++++++++++++++--- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 6e55b89d22b2cf..3253704574fb71 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -25,9 +25,11 @@ import { store as noticesStore } from '@wordpress/notices'; import { useSupportedStyles } from '../../components/global-styles/hooks'; import { unlock } from '../../lock-unlock'; -const { GlobalStylesContext, useBlockEditingMode } = unlock( - blockEditorPrivateApis -); +const { + GlobalStylesContext, + useBlockEditingMode, + __experimentalUseGlobalBehaviors, +} = unlock( blockEditorPrivateApis ); // TODO: Temporary duplication of constant in @wordpress/block-editor. Can be // removed by moving PushChangesToGlobalStylesControl to @@ -179,10 +181,44 @@ function PushChangesToGlobalStylesControl( { const { user: userConfig, setUserConfig } = useContext( GlobalStylesContext ); + const __experimentalBehaviorsIsDirty = !! attributes?.behaviors; + const { __unstableMarkNextChangeAsNotPersistent } = useDispatch( blockEditorStore ); const { createSuccessNotice } = useDispatch( noticesStore ); + const [ inheritedBehaviors, setBehaviors ] = + __experimentalUseGlobalBehaviors( name ); + const pushBehaviorChanges = useCallback( () => { + if ( ! __experimentalBehaviorsIsDirty ) { + return; + } + __unstableMarkNextChangeAsNotPersistent(); + setBehaviors( attributes.behaviors ); + createSuccessNotice( + sprintf( + // translators: %s: Title of the block e.g. 'Heading'. + __( '%s behaviors applied.' ), + getBlockType( name ).title + ), + { + type: 'snackbar', + actions: [ + { + label: __( 'Undo' ), + onClick() { + __unstableMarkNextChangeAsNotPersistent(); + setBehaviors( inheritedBehaviors ); + setUserConfig( () => userConfig, { + undoIgnore: true, + } ); + }, + }, + ], + } + ); + }, [ attributes.behaviors, userConfig ] ); + const pushChanges = useCallback( () => { if ( changes.length === 0 ) { return; @@ -240,7 +276,7 @@ function PushChangesToGlobalStylesControl( { help={ sprintf( // translators: %s: Title of the block e.g. 'Heading'. __( - 'Apply this block’s typography, spacing, dimensions, and color styles to all %s blocks.' + 'Apply this block’s typography, spacing, dimensions, color styles, and behaviors to all %s blocks.' ), getBlockType( name ).title ) } @@ -250,8 +286,14 @@ function PushChangesToGlobalStylesControl( { From 439919401ab31368a0eccdfaf3a59b50ba08db25 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Tue, 11 Jul 2023 16:54:24 +0200 Subject: [PATCH 15/32] Add apply globally, still need to work with styles too --- .../src/components/global-styles/hooks.js | 75 ++++++++++--------- .../components/global-styles/screen-block.js | 8 +- .../push-changes-to-global-styles/index.js | 23 ++---- 3 files changed, 50 insertions(+), 56 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/hooks.js b/packages/block-editor/src/components/global-styles/hooks.js index d60f439a6a46e4..4330071607d3be 100644 --- a/packages/block-editor/src/components/global-styles/hooks.js +++ b/packages/block-editor/src/components/global-styles/hooks.js @@ -504,41 +504,46 @@ export function __experimentalUseGlobalBehaviors( const setBehavior = ( newValue ) => { let newBehavior; - switch ( newValue ) { - case 'default': - break; - case 'lightbox': - newBehavior = { - lightbox: { - enabled: true, - animation, - }, - }; - break; - case 'fade': - newBehavior = { - lightbox: { - enabled: true, - animation: 'fade', - }, - }; - break; - case 'zoom': - newBehavior = { - lightbox: { - enabled: true, - animation: 'zoom', - }, - }; - break; - case '': - newBehavior = { - lightbox: { - enabled: false, - animation, - }, - }; - break; + // The user saves with Apply Globally option. + if ( typeof newValue === 'object' ) { + newBehavior = newValue; + } else { + switch ( newValue ) { + case 'default': + break; + case 'lightbox': + newBehavior = { + lightbox: { + enabled: true, + animation, + }, + }; + break; + case 'fade': + newBehavior = { + lightbox: { + enabled: true, + animation: 'fade', + }, + }; + break; + case 'zoom': + newBehavior = { + lightbox: { + enabled: true, + animation: 'zoom', + }, + }; + break; + case '': + newBehavior = { + lightbox: { + enabled: false, + animation, + }, + }; + break; + } } setUserConfig( ( currentConfig ) => { // Deep clone `currentConfig` to avoid mutating it later. diff --git a/packages/edit-site/src/components/global-styles/screen-block.js b/packages/edit-site/src/components/global-styles/screen-block.js index 57edc714230e39..6b17ada17acc9d 100644 --- a/packages/edit-site/src/components/global-styles/screen-block.js +++ b/packages/edit-site/src/components/global-styles/screen-block.js @@ -94,7 +94,7 @@ function ScreenBlock( { name, variation } ) { } ); const [ rawSettings, setSettings ] = useGlobalSetting( '', name ); const settings = useSettingsForBlockElement( rawSettings, name ); - const [ inheritedBehaviors, setBehaviors ] = + const [ inheritedBehaviors, setBehavior ] = __experimentalUseGlobalBehaviors( name ); const [ behavior ] = __experimentalUseGlobalBehaviors( name, 'user', { shouldDecodeEncode: true, @@ -191,10 +191,6 @@ function ScreenBlock( { name, variation } ) { setStyle( { ...newStyle, border: { ...updatedBorder, radius } } ); }; - const onChangeBehaviors = ( newBehaviors ) => { - setBehaviors( newBehaviors ); - }; - return ( <> ) } diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 3253704574fb71..549575cadaa95a 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -123,7 +123,7 @@ function useChangesToPush( name, attributes ) { : getValueFromObjectPath( attributes.style, path ); return value ? [ { path, value } ] : []; } ), - [ supports, name, attributes ] + [ supports, attributes ] ); } @@ -181,20 +181,15 @@ function PushChangesToGlobalStylesControl( { const { user: userConfig, setUserConfig } = useContext( GlobalStylesContext ); - const __experimentalBehaviorsIsDirty = !! attributes?.behaviors; - const { __unstableMarkNextChangeAsNotPersistent } = useDispatch( blockEditorStore ); const { createSuccessNotice } = useDispatch( noticesStore ); - const [ inheritedBehaviors, setBehaviors ] = + const [ inheritedBehaviors, setBehavior ] = __experimentalUseGlobalBehaviors( name ); const pushBehaviorChanges = useCallback( () => { - if ( ! __experimentalBehaviorsIsDirty ) { - return; - } __unstableMarkNextChangeAsNotPersistent(); - setBehaviors( attributes.behaviors ); + setBehavior( attributes.behaviors ); createSuccessNotice( sprintf( // translators: %s: Title of the block e.g. 'Heading'. @@ -208,7 +203,7 @@ function PushChangesToGlobalStylesControl( { label: __( 'Undo' ), onClick() { __unstableMarkNextChangeAsNotPersistent(); - setBehaviors( inheritedBehaviors ); + setBehavior( inheritedBehaviors ); setUserConfig( () => userConfig, { undoIgnore: true, } ); @@ -270,6 +265,8 @@ function PushChangesToGlobalStylesControl( { ); }, [ changes, attributes, userConfig, name ] ); + const hasBehaviorChanges = !! attributes.behaviors; + return ( From 2280e6760804927e6d902234bc9ebf071b445fdf Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Wed, 12 Jul 2023 16:48:16 +0200 Subject: [PATCH 18/32] Make default option work --- .../src/components/global-styles/hooks.js | 4 +-- .../push-changes-to-global-styles/index.js | 25 ++++--------------- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/hooks.js b/packages/block-editor/src/components/global-styles/hooks.js index f903e8f7642097..861b4ba37ae121 100644 --- a/packages/block-editor/src/components/global-styles/hooks.js +++ b/packages/block-editor/src/components/global-styles/hooks.js @@ -509,8 +509,6 @@ export function __experimentalUseGlobalBehaviors( newBehavior = newValue; } else { switch ( newValue ) { - case 'default': - break; case 'lightbox': newBehavior = { lightbox: { @@ -543,6 +541,8 @@ export function __experimentalUseGlobalBehaviors( }, }; break; + default: + break; } } setUserConfig( ( currentConfig ) => diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 6f42d4005bde18..301781c9cc80de 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -127,19 +127,6 @@ function useChangesToPush( name, attributes ) { ); } -function __experimentalUseBehaviorChangesToPush( attributes ) { - return useMemo( () => { - const behaviors = [ 'lightbox' ]; - return behaviors.flatMap( ( behavior ) => { - if ( ! attributes?.behaviors ) { - return []; - } - const value = attributes?.behaviors[ behavior ]; - return value ? [ { [ behavior ]: value } ] : []; - } ); - }, [ attributes ] ); -} - /** * Sets the value at path of object. * If a portion of path doesn’t exist, it’s created. @@ -190,8 +177,6 @@ function PushChangesToGlobalStylesControl( { setAttributes, } ) { const changes = useChangesToPush( name, attributes ); - const behaviorChanges = - __experimentalUseBehaviorChangesToPush( attributes ); const { user: userConfig, setUserConfig } = useContext( GlobalStylesContext ); @@ -203,8 +188,10 @@ function PushChangesToGlobalStylesControl( { const [ inheritedBehaviors, setBehavior ] = __experimentalUseGlobalBehaviors( name ); + const userHasEditedBehaviors = attributes.hasOwnProperty( 'behaviors' ); + const pushChanges = useCallback( () => { - if ( changes.length === 0 && behaviorChanges.length === 0 ) { + if ( changes.length === 0 && ! userHasEditedBehaviors ) { return; } if ( changes.length > 0 ) { @@ -252,7 +239,7 @@ function PushChangesToGlobalStylesControl( { } ); } - if ( behaviorChanges.length > 0 ) { + if ( userHasEditedBehaviors ) { __unstableMarkNextChangeAsNotPersistent(); setBehavior( attributes.behaviors ); createSuccessNotice( @@ -296,9 +283,7 @@ function PushChangesToGlobalStylesControl( {