From abe0925af3ad5716a7d30f465ac205b1fc8ca45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Mon, 24 Jun 2024 13:30:05 +0200 Subject: [PATCH 1/5] Template Part: Improve how the tag name attribute is handled (#62785) Only valid tags should be allowed rather than characters that can't be a part of HTML tags. Co-authored-by: gziolo Co-authored-by: aaronjorbin --- packages/block-library/src/template-part/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/template-part/index.php b/packages/block-library/src/template-part/index.php index b9cae2d48ed17c..be867c4ced1660 100644 --- a/packages/block-library/src/template-part/index.php +++ b/packages/block-library/src/template-part/index.php @@ -161,7 +161,7 @@ function render_block_core_template_part( $attributes ) { global $wp_embed; $content = $wp_embed->autoembed( $content ); - if ( empty( $attributes['tagName'] ) ) { + if ( empty( $attributes['tagName'] ) || tag_escape( $attributes['tagName'] ) !== $attributes['tagName'] ) { $area_tag = 'div'; if ( $area_definition && isset( $area_definition['area_tag'] ) ) { $area_tag = $area_definition['area_tag']; From 5e2050a0b890c365958af693bf3b25c582aabe2f Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Mon, 24 Jun 2024 14:56:37 +0200 Subject: [PATCH 2/5] Fix: Include permission management on permanently delete, rename, and restore. (#62754) Co-authored-by: jorgefilipecosta Co-authored-by: ellatrix --- .../src/components/post-actions/actions.js | 94 ++++++++++++++----- 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index cdc1f75dda2ebd..edf67bb1da9244 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -307,34 +307,29 @@ const trashPostAction = { }, }; -function useTrashPostAction( postType ) { +function useCanUserEligibilityCheckPostType( capability, resource, action ) { const registry = useRegistry(); - const { resource, cachedCanUserResolvers } = useSelect( - ( select ) => { - const { getPostType, getCachedResolvers } = select( coreStore ); - return { - resource: getPostType( postType )?.rest_base || '', - cachedCanUserResolvers: getCachedResolvers().canUser, - }; - }, - [ postType ] - ); return useMemo( () => ( { - ...trashPostAction, + ...action, isEligible( item ) { return ( - trashPostAction.isEligible( item ) && + action.isEligible( item ) && registry .select( coreStore ) - .canUser( 'delete', resource, item.id ) + .canUser( capability, resource, item.id ) ); }, } ), - // We are making this use memo depend on cachedCanUserResolvers as a way to make the component using this hook re-render - // when user capabilities are resolved. This makes sure the isEligible function is re-evaluated. - // eslint-disable-next-line react-hooks/exhaustive-deps - [ registry, resource, cachedCanUserResolvers ] + [ action, registry, capability, resource ] + ); +} + +function useTrashPostAction( resource ) { + return useCanUserEligibilityCheckPostType( + 'delete', + resource, + trashPostAction ); } @@ -428,6 +423,14 @@ const permanentlyDeletePostAction = { }, }; +function usePermanentlyDeletePostAction( resource ) { + return useCanUserEligibilityCheckPostType( + 'delete', + resource, + permanentlyDeletePostAction + ); +} + const restorePostAction = { id: 'restore', label: __( 'Restore' ), @@ -535,6 +538,14 @@ const restorePostAction = { }, }; +function useRestorePostAction( resource ) { + return useCanUserEligibilityCheckPostType( + 'update', + resource, + restorePostAction + ); +} + const viewPostAction = { id: 'view-post', label: __( 'View' ), @@ -694,6 +705,14 @@ const renamePostAction = { }, }; +function useRenamePostAction( resource ) { + return useCanUserEligibilityCheckPostType( + 'update', + resource, + renamePostAction + ); +} + const useDuplicatePostAction = ( postType ) => { const { userCanCreatePost } = useSelect( ( select ) => { @@ -1038,23 +1057,36 @@ export const duplicateTemplatePartAction = { }; export function usePostActions( { postType, onActionPerformed, context } ) { - const { defaultActions, postTypeObject, userCanCreatePostType } = useSelect( + const { + defaultActions, + postTypeObject, + userCanCreatePostType, + resource, + cachedCanUserResolvers, + } = useSelect( ( select ) => { - const { getPostType, canUser } = select( coreStore ); + const { getPostType, canUser, getCachedResolvers } = + select( coreStore ); const { getEntityActions } = unlock( select( editorStore ) ); const _postTypeObject = getPostType( postType ); - const resource = _postTypeObject?.rest_base || ''; + const _resource = _postTypeObject?.rest_base || ''; return { postTypeObject: _postTypeObject, defaultActions: getEntityActions( 'postType', postType ), - userCanCreatePostType: canUser( 'create', resource ), + userCanCreatePostType: canUser( 'create', _resource ), + resource: _resource, + cachedCanUserResolvers: getCachedResolvers()?.canUser, }; }, [ postType ] ); const duplicatePostAction = useDuplicatePostAction( postType ); - const trashPostActionForPostType = useTrashPostAction( postType ); + const trashPostActionForPostType = useTrashPostAction( resource ); + const permanentlyDeletePostActionForPostType = + usePermanentlyDeletePostAction( resource ); + const renamePostActionForPostType = useRenamePostAction( resource ); + const restorePostActionForPostType = useRestorePostAction( resource ); const isTemplateOrTemplatePart = [ TEMPLATE_POST_TYPE, TEMPLATE_PART_POST_TYPE, @@ -1080,13 +1112,16 @@ export function usePostActions( { postType, onActionPerformed, context } ) { userCanCreatePostType && duplicateTemplatePartAction, isPattern && userCanCreatePostType && duplicatePatternAction, - supportsTitle && renamePostAction, + supportsTitle && renamePostActionForPostType, isPattern && exportPatternAsJSONAction, - isTemplateOrTemplatePart ? resetTemplateAction : restorePostAction, + isTemplateOrTemplatePart + ? resetTemplateAction + : restorePostActionForPostType, isTemplateOrTemplatePart || isPattern ? deletePostAction : trashPostActionForPostType, - ! isTemplateOrTemplatePart && permanentlyDeletePostAction, + ! isTemplateOrTemplatePart && + permanentlyDeletePostActionForPostType, ...defaultActions, ].filter( Boolean ); // Filter actions based on provided context. If not provided @@ -1144,6 +1179,9 @@ export function usePostActions( { postType, onActionPerformed, context } ) { } return actions; + // We are making this use memo depend on cachedCanUserResolvers as a way to make the component using this hook re-render + // when user capabilities are resolved. This makes sure the isEligible functions of actions dependent on capabilities are re-evaluated. + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ defaultActions, userCanCreatePostType, @@ -1152,10 +1190,14 @@ export function usePostActions( { postType, onActionPerformed, context } ) { postTypeObject?.viewable, duplicatePostAction, trashPostActionForPostType, + restorePostActionForPostType, + renamePostActionForPostType, + permanentlyDeletePostActionForPostType, onActionPerformed, isLoaded, supportsRevisions, supportsTitle, context, + cachedCanUserResolvers, ] ); } From 9b945db54141468a7ba5d4805b9b1b6e12045976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Mon, 24 Jun 2024 15:40:34 +0200 Subject: [PATCH 3/5] Create Block: Add missing changelog entries (#62791) Co-authored-by: gziolo Co-authored-by: fabiankaegy --- packages/create-block/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/create-block/CHANGELOG.md b/packages/create-block/CHANGELOG.md index 1d88d6d7a09c45..01ad3cf768276b 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -4,10 +4,18 @@ ## 4.44.0 (2024-06-15) +### Bug fix + +- Pin the `@wordpress/scripts` version to a version supported by WordPress 6.5 ([#62234](https://github.com/WordPress/gutenberg/pull/62234)). + ## 4.43.0 (2024-05-31) ## 4.42.0 (2024-05-16) +### Breaking Change + +- Increase the minimum required Node.js version to v20.10.0 matching the support defined for Gutenberg and WordPress core ([#61430](https://github.com/WordPress/gutenberg/pull/61430)). + ## 4.41.0 (2024-05-02) ## 4.40.0 (2024-04-19) From c41857c246e8382163e8413d8474936f5ab7ee66 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Mon, 24 Jun 2024 17:36:20 +0300 Subject: [PATCH 4/5] Pattern overrides: disallow override for image with caption/href (#62747) Co-authored-by: ellatrix Co-authored-by: talldan Co-authored-by: SantosGuillamot Co-authored-by: carolinan Co-authored-by: afercia --- packages/block-library/src/image/image.js | 11 +++++++-- .../editor/src/hooks/pattern-overrides.js | 5 ++-- .../components/pattern-overrides-controls.js | 24 +++++++++++++++---- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 6095ef2fee24d1..c96eb4e45117d9 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -426,6 +426,9 @@ export default function Image( { ); + const arePatternOverridesEnabled = + metadata?.bindings?.__default?.source === 'core/pattern-overrides'; + const { lockUrlControls = false, lockHrefControls = false, @@ -470,7 +473,7 @@ export default function Image( { lockHrefControls: // Disable editing the link of the URL if the image is inside a pattern instance. // This is a temporary solution until we support overriding the link on the frontend. - hasParentPattern, + hasParentPattern || arePatternOverridesEnabled, lockCaption: // Disable editing the caption if the image is inside a pattern instance. // This is a temporary solution until we support overriding the caption on the frontend. @@ -971,7 +974,11 @@ export default function Image( { isSelected={ isSingleSelected } insertBlocksAfter={ insertBlocksAfter } label={ __( 'Image caption text' ) } - showToolbarButton={ isSingleSelected && hasNonContentControls } + showToolbarButton={ + isSingleSelected && + hasNonContentControls && + ! arePatternOverridesEnabled + } readOnly={ lockCaption } /> diff --git a/packages/editor/src/hooks/pattern-overrides.js b/packages/editor/src/hooks/pattern-overrides.js index 485cc3725d8d71..36a67bb9c5d244 100644 --- a/packages/editor/src/hooks/pattern-overrides.js +++ b/packages/editor/src/hooks/pattern-overrides.js @@ -34,9 +34,8 @@ const { */ const withPatternOverrideControls = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { - const isSupportedBlock = Object.keys( - PARTIAL_SYNCING_SUPPORTED_BLOCKS - ).includes( props.name ); + const isSupportedBlock = + !! PARTIAL_SYNCING_SUPPORTED_BLOCKS[ props.name ]; return ( <> diff --git a/packages/patterns/src/components/pattern-overrides-controls.js b/packages/patterns/src/components/pattern-overrides-controls.js index 9869c5b072c856..e2c74e76965839 100644 --- a/packages/patterns/src/components/pattern-overrides-controls.js +++ b/packages/patterns/src/components/pattern-overrides-controls.js @@ -31,7 +31,11 @@ function addBindings( bindings ) { }; } -function PatternOverridesControls( { attributes, setAttributes } ) { +function PatternOverridesControls( { + attributes, + setAttributes, + name: blockName, +} ) { const controlId = useId(); const [ showAllowOverridesModal, setShowAllowOverridesModal ] = useState( false ); @@ -71,15 +75,25 @@ function PatternOverridesControls( { attributes, setAttributes } ) { return null; } + const hasUnsupportedImageAttributes = + blockName === 'core/image' && + ( !! attributes.caption?.length || !! attributes.href?.length ); + + const helpText = hasUnsupportedImageAttributes + ? __( + `Overrides currently don't support image captions or links. Remove the caption or link first before enabling overrides.` + ) + : __( + 'Allow changes to this block throughout instances of this pattern.' + ); + return ( <>