diff --git a/docs/reference-guides/data/data-core-customize-widgets.md b/docs/reference-guides/data/data-core-customize-widgets.md index 13476f94fdb398..78433e8991a81c 100644 --- a/docs/reference-guides/data/data-core-customize-widgets.md +++ b/docs/reference-guides/data/data-core-customize-widgets.md @@ -10,6 +10,25 @@ Namespace: `core/customize-widgets`. Returns true if the inserter is opened. +_Usage_ + +```js +import { store as customizeWidgetsStore } from '@wordpress/customize-widgets'; +import { __ } from '@wordpress/i18n'; +import { useSelect } from '@wordpress/data'; + +const ExampleComponent = () => { + const { isInserterOpened } = useSelect( + ( select ) => select( customizeWidgetsStore ), + [] + ); + + return isInserterOpened() + ? __( 'Inserter is open' ) + : __( 'Inserter is closed.' ); +}; +``` + _Parameters_ - _state_ `Object`: Global application state. @@ -28,6 +47,32 @@ _Returns_ Returns an action object used to open/close the inserter. +_Usage_ + +```js +import { store as customizeWidgetsStore } from '@wordpress/customize-widgets'; +import { __ } from '@wordpress/i18n'; +import { useDispatch } from '@wordpress/data'; +import { Button } from '@wordpress/components'; +import { useState } from '@wordpress/element'; + +const ExampleComponent = () => { + const { setIsInserterOpened } = useDispatch( customizeWidgetsStore ); + const [ isOpen, setIsOpen ] = useState( false ); + + return ( + + ); +}; +``` + _Parameters_ - _value_ `boolean|Object`: Whether the inserter should be opened (true) or closed (false). To specify an insertion point, use an object. diff --git a/lib/blocks.php b/lib/blocks.php index 8185567db1b804..e98f711b5c85a5 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -372,3 +372,31 @@ function gutenberg_register_legacy_social_link_blocks() { } add_action( 'init', 'gutenberg_register_legacy_social_link_blocks' ); + +/** + * Migrate the legacy `sync_status` meta key (added 16.1) to the new `wp_pattern_sync_status` meta key (16.1.1). + * + * This filter is INTENTIONALLY left out of core as the meta key was fist introduced to core in 6.3 as `wp_pattern_sync_status`. + * see https://github.com/WordPress/gutenberg/pull/52232 + * + * @param mixed $value The value to return, either a single metadata value or an array of values depending on the value of $single. + * @param int $object_id ID of the object metadata is for. + * @param string $meta_key Metadata key. + * @param bool $single Whether to return only the first value of the specified $meta_key. + */ +function gutenberg_legacy_wp_block_post_meta( $value, $object_id, $meta_key, $single ) { + if ( 'wp_pattern_sync_status' !== $meta_key ) { + return $value; + } + + $sync_status = get_post_meta( $object_id, 'sync_status', $single ); + + if ( $single && 'unsynced' === $sync_status ) { + return $sync_status; + } elseif ( isset( $sync_status[0] ) && 'unsynced' === $sync_status[0] ) { + return $sync_status; + } + + return $value; +} +add_filter( 'default_post_metadata', 'gutenberg_legacy_wp_block_post_meta', 10, 4 ); diff --git a/lib/compat/wordpress-6.3/blocks.php b/lib/compat/wordpress-6.3/blocks.php index b338d0a2467096..ccc68786dc6adb 100644 --- a/lib/compat/wordpress-6.3/blocks.php +++ b/lib/compat/wordpress-6.3/blocks.php @@ -60,6 +60,7 @@ function gutenberg_rename_reusable_block_cpt_to_pattern( $args, $post_type ) { $args['labels']['item_reverted_to_draft'] = __( 'Pattern reverted to draft.' ); $args['labels']['item_scheduled'] = __( 'Pattern scheduled.' ); $args['labels']['item_updated'] = __( 'Pattern updated.' ); + $args['rest_controller_class'] = 'Gutenberg_REST_Blocks_Controller'; } return $args; @@ -89,7 +90,7 @@ function gutenberg_add_custom_fields_to_wp_block( $args, $post_type ) { add_filter( 'register_post_type_args', 'gutenberg_add_custom_fields_to_wp_block', 10, 2 ); /** - * Adds sync_status meta fields to the wp_block post type so an unsynced option can be added. + * Adds wp_pattern_sync_status meta fields to the wp_block post type so an unsynced option can be added. * * Note: This should be removed when the minimum required WP version is >= 6.3. * @@ -101,39 +102,21 @@ function gutenberg_wp_block_register_post_meta() { $post_type = 'wp_block'; register_post_meta( $post_type, - 'sync_status', + 'wp_pattern_sync_status', array( 'auth_callback' => function() { return current_user_can( 'edit_posts' ); }, - 'sanitize_callback' => 'gutenberg_wp_block_sanitize_post_meta', + 'sanitize_callback' => 'sanitize_text_field', 'single' => true, 'type' => 'string', 'show_in_rest' => array( 'schema' => array( - 'type' => 'string', - 'properties' => array( - 'sync_status' => array( - 'type' => 'string', - ), - ), + 'type' => 'string', + 'enum' => array( 'partial', 'unsynced' ), ), ), ) ); } -/** - * Sanitizes the array of wp_block post meta sync_status string. - * - * Note: This should be removed when the minimum required WP version is >= 6.3. - * - * @see https://github.com/WordPress/gutenberg/pull/51144 - * - * @param array $meta_value String to sanitize. - * - * @return array Sanitized string. - */ -function gutenberg_wp_block_sanitize_post_meta( $meta_value ) { - return sanitize_text_field( $meta_value ); -} add_action( 'init', 'gutenberg_wp_block_register_post_meta' ); diff --git a/lib/compat/wordpress-6.3/class-gutenberg-rest-blocks-controller.php b/lib/compat/wordpress-6.3/class-gutenberg-rest-blocks-controller.php new file mode 100644 index 00000000000000..08108e1638334c --- /dev/null +++ b/lib/compat/wordpress-6.3/class-gutenberg-rest-blocks-controller.php @@ -0,0 +1,47 @@ + { const { getBlockName, getBlockParents, getSelectedBlockClientId, getSettings, - } = select( blockEditorStore ); + getBlockEditingMode, + } = unlock( select( blockEditorStore ) ); const { hasBlockSupport } = select( blocksStore ); const selectedBlockClientId = getSelectedBlockClientId(); const parents = getBlockParents( selectedBlockClientId ); @@ -41,11 +43,14 @@ export default function BlockParentSelector() { const settings = getSettings(); return { firstParentClientId: _firstParentClientId, - shouldHide: ! hasBlockSupport( - _parentBlockType, - '__experimentalParentSelector', - true - ), + isVisible: + _firstParentClientId && + getBlockEditingMode( _firstParentClientId ) === 'default' && + hasBlockSupport( + _parentBlockType, + '__experimentalParentSelector', + true + ), isDistractionFree: settings.isDistractionFree, }; }, @@ -66,7 +71,7 @@ export default function BlockParentSelector() { }, } ); - if ( shouldHide || firstParentClientId === undefined ) { + if ( ! isVisible ) { return null; } diff --git a/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js b/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js index d9c06f0324701c..743a07b4bb8818 100644 --- a/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js +++ b/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js @@ -57,6 +57,7 @@ function BlockContextualToolbar( { focusOnMount, isFixed, ...props } ) { hasParents: parents.length, showParentSelector: parentBlockType && + getBlockEditingMode( firstParentClientId ) === 'default' && hasBlockSupport( parentBlockType, '__experimentalParentSelector', diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 5876eb4ec01e9e..db93f112a366d3 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -165,3 +165,8 @@ export { default as __experimentalInspectorPopoverHeader } from './inspector-pop export { default as BlockEditorProvider } from './provider'; export { default as useSetting } from './use-setting'; + +/* + * The following rename hint component can be removed in 6.4. + */ +export { default as ReusableBlocksRenameHint } from './inserter/reusable-block-rename-hint'; diff --git a/packages/block-editor/src/components/inserter/reusable-block-rename-hint.js b/packages/block-editor/src/components/inserter/reusable-block-rename-hint.js new file mode 100644 index 00000000000000..09861d9b97f1c9 --- /dev/null +++ b/packages/block-editor/src/components/inserter/reusable-block-rename-hint.js @@ -0,0 +1,52 @@ +/** + * WordPress dependencies + */ +import { Button } from '@wordpress/components'; +import { useDispatch, useSelect } from '@wordpress/data'; +import { focus } from '@wordpress/dom'; +import { useRef } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { close } from '@wordpress/icons'; +import { store as preferencesStore } from '@wordpress/preferences'; + +const PREFERENCE_NAME = 'isResuableBlocksrRenameHintVisible'; + +export default function ReusableBlocksRenameHint() { + const isReusableBlocksRenameHint = useSelect( + ( select ) => + select( preferencesStore ).get( 'core', PREFERENCE_NAME ) ?? true, + [] + ); + + const ref = useRef(); + + const { set: setPreference } = useDispatch( preferencesStore ); + if ( ! isReusableBlocksRenameHint ) { + return null; + } + + return ( +