diff --git a/package-lock.json b/package-lock.json index 872170280c7a02..ca1c7e71efad57 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15715,6 +15715,7 @@ "@wordpress/icons": "file:packages/icons", "@wordpress/notices": "file:packages/notices", "@wordpress/plugins": "file:packages/plugins", + "@wordpress/url": "file:packages/url", "lodash": "^4.17.21" } }, diff --git a/packages/block-directory/package.json b/packages/block-directory/package.json index 3be89b09859641..e2f468e2ef090b 100644 --- a/packages/block-directory/package.json +++ b/packages/block-directory/package.json @@ -43,6 +43,7 @@ "@wordpress/icons": "file:../icons", "@wordpress/notices": "file:../notices", "@wordpress/plugins": "file:../plugins", + "@wordpress/url": "file:../url", "lodash": "^4.17.21" }, "publishConfig": { diff --git a/packages/block-directory/src/store/actions.js b/packages/block-directory/src/store/actions.js index 2ab21b6cf9fdd8..e3348dd64036c5 100644 --- a/packages/block-directory/src/store/actions.js +++ b/packages/block-directory/src/store/actions.js @@ -1,10 +1,19 @@ +/** + * External dependencies + */ +import { pick } from 'lodash'; + /** * WordPress dependencies */ -import { store as blocksStore } from '@wordpress/blocks'; +import { + store as blocksStore, + unstable__bootstrapServerSideBlockDefinitions, // eslint-disable-line camelcase +} from '@wordpress/blocks'; import { __, sprintf } from '@wordpress/i18n'; import apiFetch from '@wordpress/api-fetch'; import { store as noticesStore } from '@wordpress/notices'; +import { addQueryArgs } from '@wordpress/url'; /** * Internal dependencies @@ -52,7 +61,7 @@ export const installBlockType = ( block ) => async ( { registry, dispatch, } ) => { - const { id } = block; + const { id, name } = block; let success = false; dispatch.clearErrorNotice( id ); try { @@ -82,9 +91,42 @@ export const installBlockType = ( block ) => async ( { links: { ...block.links, ...links }, } ); + // Ensures that the block metadata is propagated to the editor when registered on the server. + const metadataFields = [ + 'api_version', + 'title', + 'category', + 'parent', + 'icon', + 'description', + 'keywords', + 'attributes', + 'provides_context', + 'uses_context', + 'supports', + 'styles', + 'example', + 'variations', + ]; + await apiFetch( { + path: addQueryArgs( `/wp/v2/block-types/${ name }`, { + _fields: metadataFields, + } ), + } ) + // Ignore when the block is not registered on the server. + .catch( () => {} ) + .then( ( response ) => { + if ( ! response ) { + return; + } + unstable__bootstrapServerSideBlockDefinitions( { + [ name ]: pick( response, metadataFields ), + } ); + } ); + await loadAssets(); const registeredBlocks = registry.select( blocksStore ).getBlockTypes(); - if ( ! registeredBlocks.some( ( i ) => i.name === block.name ) ) { + if ( ! registeredBlocks.some( ( i ) => i.name === name ) ) { throw new Error( __( 'Error registering block. Try reloading the page.' ) ); diff --git a/packages/block-directory/src/store/test/actions.js b/packages/block-directory/src/store/test/actions.js index 5520f2ac1149d7..78789706074804 100644 --- a/packages/block-directory/src/store/test/actions.js +++ b/packages/block-directory/src/store/test/actions.js @@ -75,6 +75,12 @@ describe( 'actions', () => { }, }; + const blockTypePath = '/wp/v2/block-types/block/block'; + const blockTypeResponse = { + name: 'block/block', + title: 'Test Block', + }; + describe( 'installBlockType', () => { it( 'should install a block successfully', async () => { const registry = createRegistryWithStores(); @@ -84,6 +90,8 @@ describe( 'actions', () => { switch ( path ) { case 'wp/v2/plugins': return pluginResponse; + case blockTypePath: + return blockTypeResponse; default: throw new Error( `unexpected API endpoint: ${ path }` ); } @@ -121,14 +129,14 @@ describe( 'actions', () => { const registry = createRegistryWithStores(); // mock the api-fetch and load-assets modules - apiFetch.mockImplementation( async ( p ) => { - const { url } = p; - switch ( url ) { - case pluginEndpoint: - return pluginResponse; - default: - throw new Error( `unexpected API endpoint: ${ url }` ); + apiFetch.mockImplementation( async ( { path, url } ) => { + if ( path === blockTypePath ) { + return blockTypeResponse; + } + if ( url === pluginEndpoint ) { + return pluginResponse; } + throw new Error( `unexpected API endpoint: ${ url }` ); } ); loadAssets.mockImplementation( loadAssetsMock( registry ) ); diff --git a/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js b/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js index a659716602715c..5ca7c7370b41b0 100644 --- a/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js +++ b/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js @@ -10,12 +10,21 @@ import { createJSONResponse, } from '@wordpress/e2e-test-utils'; +const BLOCK1_NAME = 'block-directory-test-block/main-block'; + // Urls to mock const SEARCH_URLS = [ '/wp/v2/block-directory/search', `rest_route=${ encodeURIComponent( '/wp/v2/block-directory/search' ) }`, ]; +const BLOCK_TYPE_URLS = [ + `/wp/v2/block-types/${ BLOCK1_NAME }`, + `rest_route=${ encodeURIComponent( + `/wp/v2/block-types/${ BLOCK1_NAME }` + ) }`, +]; + const INSTALL_URLS = [ '/wp/v2/plugins', `rest_route=${ encodeURIComponent( '/wp/v2/plugins' ) }`, @@ -23,7 +32,7 @@ const INSTALL_URLS = [ // Example Blocks const MOCK_BLOCK1 = { - name: 'block-directory-test-block/main-block', + name: BLOCK1_NAME, title: 'Block Directory Test Block', description: 'This plugin is useful for the block.', id: 'block-directory-test-block', @@ -109,6 +118,11 @@ const MOCK_BLOCKS_RESPONSES = [ request.method() === 'GET', onRequestMatch: createJSONResponse( [ MOCK_BLOCK1, MOCK_BLOCK2 ] ), }, + { + // Mock response for block type + match: ( request ) => matchUrl( request.url(), BLOCK_TYPE_URLS ), + onRequestMatch: createJSONResponse( {} ), + }, { // Mock response for install match: ( request ) => matchUrl( request.url(), INSTALL_URLS ),