From ebe32577f6e02af5a4fdcd4049a510dfb77cb7b2 Mon Sep 17 00:00:00 2001 From: dhruvikpatel18 Date: Fri, 28 Feb 2025 14:38:25 +0530 Subject: [PATCH 1/2] Add draft page creation capability to button block --- packages/block-library/src/button/edit.js | 94 ++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index 67e1218ca2f65..6f146f8d64787 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -15,7 +15,13 @@ import { useToolsPanelDropdownMenuProps } from '../utils/hooks'; * WordPress dependencies */ import { __, sprintf } from '@wordpress/i18n'; -import { useEffect, useState, useRef, useMemo } from '@wordpress/element'; +import { + useEffect, + useState, + useRef, + useMemo, + createInterpolateElement, +} from '@wordpress/element'; import { TextControl, ToolbarButton, @@ -52,6 +58,49 @@ import { } from '@wordpress/blocks'; import { useMergeRefs, useRefEffect } from '@wordpress/compose'; import { useSelect, useDispatch } from '@wordpress/data'; +import { decodeEntities } from '@wordpress/html-entities'; +import { + store as coreStore, + useResourcePermissions, +} from '@wordpress/core-data'; + +/** + * Given the Link block's type attribute, return the query params to give to + * /wp/v2/search. + * + * @param {string} type Link block's type attribute. + * @param {string} kind Link block's entity of kind (post-type|taxonomy) + * @return {{ type?: string, subtype?: string }} Search query params. + */ +function getSuggestionsQuery( type, kind ) { + switch ( type ) { + case 'post': + case 'page': + return { type: 'post', subtype: type }; + case 'category': + return { type: 'term', subtype: 'category' }; + case 'tag': + return { type: 'term', subtype: 'post_tag' }; + case 'post_format': + return { type: 'post-format' }; + default: + if ( kind === 'taxonomy' ) { + return { type: 'term', subtype: type }; + } + if ( kind === 'post-type' ) { + return { type: 'post', subtype: type }; + } + return { + // for custom link which has no type + // always show pages as initial suggestions + initialSuggestionsSearchOptions: { + type: 'post', + subtype: 'page', + perPage: 20, + }, + }; + } +} const LINK_SETTINGS = [ ...LinkControl.DEFAULT_LINK_SETTINGS, @@ -219,6 +268,28 @@ function ButtonEdit( props ) { const nofollow = !! rel?.includes( NOFOLLOW_REL ); const isLinkTag = 'a' === TagName; + const { saveEntityRecord } = useDispatch( coreStore ); + const postType = 'page'; + const permissions = useResourcePermissions( { + kind: 'postType', + name: postType, + } ); + + async function handleCreate( pageTitle ) { + const page = await saveEntityRecord( 'postType', postType, { + title: pageTitle, + status: 'draft', + } ); + + return { + id: page.id, + type: postType, + title: decodeEntities( page.title.rendered ), + url: page.link, + kind: 'post-type', + }; + } + function startEditing( event ) { event.preventDefault(); setIsEditingURL( true ); @@ -400,6 +471,27 @@ function ButtonEdit( props ) { } } forceIsEditingLink={ isEditingURL } settings={ LINK_SETTINGS } + withCreateSuggestion={ permissions.canCreate } + createSuggestion={ handleCreate } + createSuggestionButtonText={ ( searchTerm ) => { + return createInterpolateElement( + sprintf( + /* translators: %s: search term. */ + __( + 'Create draft page: %s' + ), + searchTerm + ), + { + mark: , + } + ); + } } + showInitialSuggestions + suggestionsQuery={ getSuggestionsQuery( + postType, + 'post-type' + ) } /> ) } From 71daa115db7dda6dbd6217cb6a52792bd8867bbf Mon Sep 17 00:00:00 2001 From: dhruvikpatel18 Date: Thu, 6 Mar 2025 16:11:03 +0530 Subject: [PATCH 2/2] Refactor: Leveraged existing settings to reduced boilerplate --- packages/block-library/src/button/edit.js | 105 +++++++++++----------- 1 file changed, 51 insertions(+), 54 deletions(-) diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index 6f146f8d64787..cfc453aec035d 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -58,11 +58,6 @@ import { } from '@wordpress/blocks'; import { useMergeRefs, useRefEffect } from '@wordpress/compose'; import { useSelect, useDispatch } from '@wordpress/data'; -import { decodeEntities } from '@wordpress/html-entities'; -import { - store as coreStore, - useResourcePermissions, -} from '@wordpress/core-data'; /** * Given the Link block's type attribute, return the query params to give to @@ -268,28 +263,64 @@ function ButtonEdit( props ) { const nofollow = !! rel?.includes( NOFOLLOW_REL ); const isLinkTag = 'a' === TagName; - const { saveEntityRecord } = useDispatch( coreStore ); - const postType = 'page'; - const permissions = useResourcePermissions( { - kind: 'postType', - name: postType, - } ); + const { + createPageEntity, + userCanCreatePages, + lockUrlControls = false, + } = useSelect( + ( select ) => { + if ( ! isSelected ) { + return {}; + } + + const { getSettings } = select( blockEditorStore ); + const _settings = getSettings(); + + const blockBindingsSource = getBlockBindingsSource( + metadata?.bindings?.url?.source + ); + + return { + createPageEntity: _settings.__experimentalCreatePageEntity, + userCanCreatePages: _settings.__experimentalUserCanCreatePages, + lockUrlControls: + !! metadata?.bindings?.url && + ! blockBindingsSource?.canUserEditValue?.( { + select, + context, + args: metadata?.bindings?.url?.args, + } ), + }; + }, + [ context, isSelected, metadata?.bindings?.url ] + ); async function handleCreate( pageTitle ) { - const page = await saveEntityRecord( 'postType', postType, { + const page = await createPageEntity( { title: pageTitle, status: 'draft', } ); return { id: page.id, - type: postType, - title: decodeEntities( page.title.rendered ), + type: page.type, + title: page.title.rendered, url: page.link, kind: 'post-type', }; } + function createButtonText( searchTerm ) { + return createInterpolateElement( + sprintf( + /* translators: %s: search term. */ + __( 'Create page: %s' ), + searchTerm + ), + { mark: } + ); + } + function startEditing( event ) { event.preventDefault(); setIsEditingURL( true ); @@ -320,29 +351,6 @@ function ButtonEdit( props ) { const useEnterRef = useEnter( { content: text, clientId } ); const mergedRef = useMergeRefs( [ useEnterRef, richTextRef ] ); - const { lockUrlControls = false } = useSelect( - ( select ) => { - if ( ! isSelected ) { - return {}; - } - - const blockBindingsSource = getBlockBindingsSource( - metadata?.bindings?.url?.source - ); - - return { - lockUrlControls: - !! metadata?.bindings?.url && - ! blockBindingsSource?.canUserEditValue?.( { - select, - context, - args: metadata?.bindings?.url?.args, - } ), - }; - }, - [ context, isSelected, metadata?.bindings?.url ] - ); - const [ fluidTypographySettings, layout ] = useSettings( 'typography.fluid', 'layout' @@ -471,25 +479,14 @@ function ButtonEdit( props ) { } } forceIsEditingLink={ isEditingURL } settings={ LINK_SETTINGS } - withCreateSuggestion={ permissions.canCreate } - createSuggestion={ handleCreate } - createSuggestionButtonText={ ( searchTerm ) => { - return createInterpolateElement( - sprintf( - /* translators: %s: search term. */ - __( - 'Create draft page: %s' - ), - searchTerm - ), - { - mark: , - } - ); - } } + createSuggestion={ + createPageEntity && handleCreate + } + withCreateSuggestion={ userCanCreatePages } + createSuggestionButtonText={ createButtonText } showInitialSuggestions suggestionsQuery={ getSuggestionsQuery( - postType, + 'page', 'post-type' ) } />