diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js
index 3980dd7b2aead..bfddb75538776 100644
--- a/packages/block-editor/src/components/block-list/block.js
+++ b/packages/block-editor/src/components/block-list/block.js
@@ -96,6 +96,7 @@ function BlockListBlock( {
onInsertBlocksAfter,
onMerge,
toggleSelection,
+ params,
} ) {
const {
themeSupportsLayout,
@@ -155,6 +156,7 @@ function BlockListBlock( {
__unstableParentLayout={
Object.keys( parentLayout ).length ? parentLayout : undefined
}
+ params={ params }
/>
);
@@ -283,7 +285,7 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId } ) => {
// This function should never be called when a block is not present in
// the state. It happens now because the order in withSelect rendering
// is not correct.
- const { name, attributes, isValid } = block || {};
+ const { name, attributes, isValid, params } = block || {};
// Do not add new properties here, use `useSelect` instead to avoid
// leaking new props to the public API (editor.BlockListBlock filter).
@@ -302,6 +304,7 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId } ) => {
attributes,
isValid,
isSelected,
+ params,
};
} );
diff --git a/packages/block-library/src/file/edit.js b/packages/block-library/src/file/edit.js
index 733cdf9a9351f..33986f2620ff1 100644
--- a/packages/block-library/src/file/edit.js
+++ b/packages/block-library/src/file/edit.js
@@ -23,7 +23,7 @@ import {
store as blockEditorStore,
__experimentalGetElementClassName,
} from '@wordpress/block-editor';
-import { useEffect } from '@wordpress/element';
+import { useEffect, useState } from '@wordpress/element';
import { useCopyToClipboard } from '@wordpress/compose';
import { __, _x } from '@wordpress/i18n';
import { file as icon } from '@wordpress/icons';
@@ -59,7 +59,13 @@ function ClipboardToolbarButton( { text, disabled } ) {
);
}
-function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
+function FileEdit( {
+ attributes,
+ isSelected,
+ setAttributes,
+ clientId,
+ params,
+} ) {
const {
id,
fileId,
@@ -72,6 +78,9 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
displayPreview,
previewHeight,
} = attributes;
+
+ const { blobURL } = params;
+
const { media, mediaUpload } = useSelect(
( select ) => ( {
media:
@@ -87,22 +96,27 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
const { toggleSelection, __unstableMarkNextChangeAsNotPersistent } =
useDispatch( blockEditorStore );
+ const [ isUploadingBlob, setIsUploadingBlob ] = useState( false );
+
useEffect( () => {
// Upload a file drag-and-dropped into the editor.
- if ( isBlobURL( href ) ) {
- const file = getBlobByURL( href );
+ const file = getBlobByURL( blobURL );
+ if ( file ) {
+ setIsUploadingBlob( true );
mediaUpload( {
filesList: [ file ],
- onFileChange: ( [ newMedia ] ) => onSelectFile( newMedia ),
- onError: onUploadError,
+ onFileChange: ( [ newMedia ] ) => {
+ onSelectFile( newMedia, { isPersistent: false } );
+ setIsUploadingBlob( false );
+ },
+ onError: ( message ) => {
+ onUploadError( message, { isPersistent: false } );
+ setIsUploadingBlob( false );
+ },
} );
- revokeBlobURL( href );
- }
-
- if ( downloadButtonText === undefined ) {
- changeDownloadButtonText( _x( 'Download', 'button label' ) );
+ revokeBlobURL( blobURL );
}
}, [] );
@@ -114,9 +128,12 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
}
}, [ href, fileId, clientId ] );
- function onSelectFile( newMedia ) {
- if ( newMedia && newMedia.url ) {
+ function onSelectFile( newMedia, { isPersistent = true } = {} ) {
+ if ( newMedia && newMedia.url && ! isBlobURL( newMedia.url ) ) {
const isPdf = newMedia.url.endsWith( '.pdf' );
+ if ( ! isPersistent ) {
+ __unstableMarkNextChangeAsNotPersistent();
+ }
setAttributes( {
href: newMedia.url,
fileName: newMedia.title,
@@ -178,9 +195,9 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
const blockProps = useBlockProps( {
className: classnames(
- isBlobURL( href ) && getAnimateClassName( { type: 'loading' } ),
+ isUploadingBlob && getAnimateClassName( { type: 'loading' } ),
{
- 'is-transient': isBlobURL( href ),
+ 'is-transient': isUploadingBlob,
}
),
} );
@@ -232,7 +249,7 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
/>
@@ -297,7 +314,10 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
'button'
)
) }
- value={ downloadButtonText }
+ value={
+ downloadButtonText ??
+ _x( 'Download', 'button label' )
+ }
withoutInteractiveFormatting
placeholder={ __( 'Add text…' ) }
onChange={ ( text ) =>
diff --git a/packages/block-library/src/file/transforms.js b/packages/block-library/src/file/transforms.js
index 35dd9807daddd..06ef30a78937d 100644
--- a/packages/block-library/src/file/transforms.js
+++ b/packages/block-library/src/file/transforms.js
@@ -25,10 +25,8 @@ const transforms = {
// File will be uploaded in componentDidMount()
blocks.push(
- createBlock( 'core/file', {
- href: blobURL,
- fileName: file.name,
- textLinkHref: blobURL,
+ createBlock( 'core/file', {}, [], {
+ blobURL,
} )
);
} );
diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js
index 16cc4c014cf90..a2d2f6ac094f6 100644
--- a/packages/block-library/src/navigation/edit/index.js
+++ b/packages/block-library/src/navigation/edit/index.js
@@ -83,6 +83,7 @@ function Navigation( {
setOverlayBackgroundColor,
overlayTextColor,
setOverlayTextColor,
+ params,
// These props are used by the navigation editor to override specific
// navigation block settings.
@@ -402,18 +403,34 @@ function Navigation( {
] = useState();
const [ detectedOverlayColor, setDetectedOverlayColor ] = useState();
- const onSelectClassicMenu = async ( classicMenu ) => {
- const navMenu = await convertClassicMenu(
- classicMenu.id,
- classicMenu.name,
- 'draft'
- );
- if ( navMenu ) {
- handleUpdateMenu( navMenu.id, {
- focusNavigationBlock: true,
- } );
+ const onSelectClassicMenu = useCallback(
+ async ( classicMenu ) => {
+ const navMenu = await convertClassicMenu(
+ classicMenu.id,
+ classicMenu.name,
+ 'draft'
+ );
+ if ( navMenu ) {
+ handleUpdateMenu( navMenu.id, {
+ focusNavigationBlock: true,
+ } );
+ }
+ },
+ [ convertClassicMenu, handleUpdateMenu ]
+ );
+
+ // Convert the classic menu provided by the Legacy Widget block transform if
+ // it exists.
+ useEffect( () => {
+ if ( params.menuId ) {
+ const classicMenu = classicMenus?.find(
+ ( menu ) => menu.id === params.menuId
+ );
+ if ( classicMenu ) {
+ onSelectClassicMenu( classicMenu );
+ }
}
- };
+ }, [ params.menuId, classicMenus, onSelectClassicMenu ] );
const onSelectNavigationMenu = ( menuId ) => {
handleUpdateMenu( menuId );
diff --git a/packages/blocks/README.md b/packages/blocks/README.md
index 27f6010786b18..64cabbc3dd7dd 100644
--- a/packages/blocks/README.md
+++ b/packages/blocks/README.md
@@ -205,8 +205,9 @@ Returns a block object given its type and attributes.
_Parameters_
- _name_ `string`: Block name.
-- _attributes_ `Object`: Block attributes.
-- _innerBlocks_ `?Array`: Nested blocks.
+- _attributes_ `[Object]`: Block attributes.
+- _innerBlocks_ `[Array]`: Nested blocks.
+- _params_ `[Object]`: Block params.
_Returns_
diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js
index 6df8eb00005a8..983da72a964e7 100644
--- a/packages/blocks/src/api/factory.js
+++ b/packages/blocks/src/api/factory.js
@@ -24,13 +24,20 @@ import {
/**
* Returns a block object given its type and attributes.
*
- * @param {string} name Block name.
- * @param {Object} attributes Block attributes.
- * @param {?Array} innerBlocks Nested blocks.
+ * @param {string} name Block name.
+ * @param {Object} [attributes] Block attributes.
+ * @param {Array} [innerBlocks] Nested blocks.
+ * @param {Object} [params] Block params.
*
* @return {Object} Block object.
+ *
*/
-export function createBlock( name, attributes = {}, innerBlocks = [] ) {
+export function createBlock(
+ name,
+ attributes = {},
+ innerBlocks = [],
+ params = {}
+) {
const sanitizedAttributes = __experimentalSanitizeBlockAttributes(
name,
attributes
@@ -46,6 +53,7 @@ export function createBlock( name, attributes = {}, innerBlocks = [] ) {
isValid: true,
attributes: sanitizedAttributes,
innerBlocks,
+ params,
};
}
diff --git a/packages/edit-widgets/src/store/actions.js b/packages/edit-widgets/src/store/actions.js
index 8124ace66bdb3..2ed29ad268831 100644
--- a/packages/edit-widgets/src/store/actions.js
+++ b/packages/edit-widgets/src/store/actions.js
@@ -235,9 +235,9 @@ export const saveWidgetArea =
const widget = preservedRecords[ i ];
const { block, position } = batchMeta[ i ];
- // Set __internalWidgetId on the block. This will be persisted to the
- // store when we dispatch receiveEntityRecords( post ) below.
- post.blocks[ position ].attributes.__internalWidgetId = widget.id;
+ // Set widget ID on the block. This will be persisted to the store
+ // when we dispatch receiveEntityRecords( post ) below.
+ post.blocks[ position ].params.widgetId = widget.id;
const error = registry
.select( coreStore )
diff --git a/packages/widgets/src/blocks/legacy-widget/transforms.js b/packages/widgets/src/blocks/legacy-widget/transforms.js
index 3e4aab3cc0b5b..242a224bd880f 100644
--- a/packages/widgets/src/blocks/legacy-widget/transforms.js
+++ b/packages/widgets/src/blocks/legacy-widget/transforms.js
@@ -3,100 +3,96 @@
*/
import { createBlock } from '@wordpress/blocks';
-const legacyWidgetTransforms = [
+const toTransforms = [
{
- block: 'core/calendar',
- widget: 'calendar',
+ idBase: 'calendar',
+ blockName: 'core/calendar',
+ convert: () => createBlock( 'core/calendar' ),
},
{
- block: 'core/search',
- widget: 'search',
+ idBase: 'search',
+ blockName: 'core/search',
+ convert: () => createBlock( 'core/search' ),
},
{
- block: 'core/html',
- widget: 'custom_html',
- transform: ( { content } ) => ( {
- content,
- } ),
+ idBase: 'custom_html',
+ blockName: 'core/html',
+ convert: ( { content } ) =>
+ createBlock( 'core/html', {
+ content,
+ } ),
},
{
- block: 'core/archives',
- widget: 'archives',
- transform: ( { count, dropdown } ) => {
- return {
+ idBase: 'archives',
+ blockName: 'core/archives',
+ convert: ( { count, dropdown } ) =>
+ createBlock( 'core/archives', {
displayAsDropdown: !! dropdown,
showPostCounts: !! count,
- };
- },
+ } ),
},
{
- block: 'core/latest-posts',
- widget: 'recent-posts',
- transform: ( { show_date: displayPostDate, number } ) => {
- return {
+ idBase: 'recent-posts',
+ blockName: 'core/latest-posts',
+ convert: ( { show_date: displayPostDate, number } ) =>
+ createBlock( 'core/latest-posts', {
displayPostDate: !! displayPostDate,
postsToShow: number,
- };
- },
+ } ),
},
{
- block: 'core/latest-comments',
- widget: 'recent-comments',
- transform: ( { number } ) => {
- return {
+ idBase: 'recent-comments',
+ blockName: 'core/latest-comments',
+ convert: ( { number } ) =>
+ createBlock( 'core/latest-comments', {
commentsToShow: number,
- };
- },
+ } ),
},
{
- block: 'core/tag-cloud',
- widget: 'tag_cloud',
- transform: ( { taxonomy, count } ) => {
- return {
+ idBase: 'tag_cloud',
+ blockName: 'core/tag-cloud',
+ convert: ( { taxonomy, count } ) =>
+ createBlock( 'core/tag-cloud', {
showTagCounts: !! count,
taxonomy,
- };
- },
+ } ),
},
{
- block: 'core/categories',
- widget: 'categories',
- transform: ( { count, dropdown, hierarchical } ) => {
- return {
+ idBase: 'categories',
+ blockName: 'core/categories',
+ convert: ( { count, dropdown, hierarchical } ) =>
+ createBlock( 'core/categories', {
displayAsDropdown: !! dropdown,
showPostCounts: !! count,
showHierarchy: !! hierarchical,
- };
- },
+ } ),
},
{
- block: 'core/audio',
- widget: 'media_audio',
- transform: ( { url, preload, loop, attachment_id: id } ) => {
- return {
+ idBase: 'media_audio',
+ blockName: 'core/audio',
+ convert: ( { url, preload, loop, attachment_id: id } ) =>
+ createBlock( 'core/audio', {
src: url,
id,
preload,
loop,
- };
- },
+ } ),
},
{
- block: 'core/video',
- widget: 'media_video',
- transform: ( { url, preload, loop, attachment_id: id } ) => {
- return {
+ idBase: 'media_video',
+ blockName: 'core/video',
+ convert: ( { url, preload, loop, attachment_id: id } ) =>
+ createBlock( 'core/video', {
src: url,
id,
preload,
loop,
- };
- },
+ } ),
},
{
- block: 'core/image',
- widget: 'media_image',
- transform: ( {
+ idBase: 'media_image',
+ blockName: 'core/image',
+ convert: ( {
alt,
attachment_id: id,
caption,
@@ -109,8 +105,8 @@ const legacyWidgetTransforms = [
size: sizeSlug,
url,
width,
- } ) => {
- return {
+ } ) =>
+ createBlock( 'core/image', {
alt,
caption,
height,
@@ -123,14 +119,13 @@ const legacyWidgetTransforms = [
sizeSlug,
url,
width,
- };
- },
+ } ),
},
{
- block: 'core/gallery',
- widget: 'media_gallery',
- transform: ( { ids, link_type: linkTo, size, number } ) => {
- return {
+ idBase: 'media_gallery',
+ blockName: 'core/gallery',
+ convert: ( { ids, link_type: linkTo, size, number } ) =>
+ createBlock( 'core/gallery', {
ids,
columns: number,
linkTo,
@@ -138,55 +133,56 @@ const legacyWidgetTransforms = [
images: ids.map( ( id ) => ( {
id,
} ) ),
- };
- },
+ } ),
},
{
- block: 'core/rss',
- widget: 'rss',
- transform: ( {
+ idBase: 'rss',
+ blockName: 'core/rss',
+ convert: ( {
url,
show_author: displayAuthor,
show_date: displayDate,
show_summary: displayExcerpt,
items,
- } ) => {
- return {
+ } ) =>
+ createBlock( 'core/rss', {
feedURL: url,
displayAuthor: !! displayAuthor,
displayDate: !! displayDate,
displayExcerpt: !! displayExcerpt,
itemsToShow: items,
- };
- },
+ } ),
},
-].map( ( { block, widget, transform } ) => {
+ {
+ idBase: 'nav_menu',
+ blockName: 'core/navigation',
+ convert: ( { nav_menu: navMenu } ) =>
+ createBlock( 'core/navigation', {}, [], { menuId: navMenu } ),
+ },
+].map( ( { idBase, blockName, convert } ) => {
return {
type: 'block',
- blocks: [ block ],
- isMatch: ( { idBase, instance } ) => {
- return idBase === widget && !! instance?.raw;
+ blocks: [ blockName ],
+ isMatch( attributes ) {
+ return attributes.idBase === idBase && !! attributes.instance?.raw;
},
- transform: ( { instance } ) => {
- const transformedBlock = createBlock(
- block,
- transform ? transform( instance.raw ) : undefined
- );
- if ( ! instance.raw?.title ) {
- return transformedBlock;
+ transform( attributes ) {
+ const block = convert( attributes.instance.raw );
+ if ( ! attributes.instance.raw?.title ) {
+ return block;
}
return [
createBlock( 'core/heading', {
- content: instance.raw.title,
+ content: attributes.instance.raw.title,
} ),
- transformedBlock,
+ block,
];
},
};
} );
const transforms = {
- to: legacyWidgetTransforms,
+ to: toTransforms,
};
export default transforms;
diff --git a/packages/widgets/src/utils.js b/packages/widgets/src/utils.js
index 75b1f3d08140e..0d0c1f5b0e238 100644
--- a/packages/widgets/src/utils.js
+++ b/packages/widgets/src/utils.js
@@ -3,31 +3,26 @@
/**
* Get the internal widget id from block.
*
- * @typedef {Object} Attributes
- * @property {string} __internalWidgetId The internal widget id.
- * @typedef {Object} Block
- * @property {Attributes} attributes The attributes of the block.
- *
- * @param {Block} block The block.
+ * @param {Object} block The block.
* @return {string} The internal widget id.
*/
export function getWidgetIdFromBlock( block ) {
- return block.attributes.__internalWidgetId;
+ return block.params.widgetId;
}
/**
* Add internal widget id to block's attributes.
*
- * @param {Block} block The block.
+ * @param {Object} block The block.
* @param {string} widgetId The widget id.
- * @return {Block} The updated block.
+ * @return {Object} The updated block.
*/
export function addWidgetIdToBlock( block, widgetId ) {
return {
...block,
- attributes: {
- ...( block.attributes || {} ),
- __internalWidgetId: widgetId,
+ params: {
+ ...block.params,
+ widgetId,
},
};
}