diff --git a/docs/designers-developers/developers/block-api/block-edit-save.md b/docs/designers-developers/developers/block-api/block-edit-save.md index c5e35eddb10a72..fc69abc553e9fd 100644 --- a/docs/designers-developers/developers/block-api/block-edit-save.md +++ b/docs/designers-developers/developers/block-api/block-edit-save.md @@ -226,7 +226,9 @@ For most blocks, the return value of `save` should be an [instance of WordPress _Note:_ While it is possible to return a string value from `save`, it _will be escaped_. If the string includes HTML markup, the markup will be shown on the front of the site verbatim, not as the equivalent HTML node content. If you must return raw HTML from `save`, use `wp.element.RawHTML`. As the name implies, this is prone to [cross-site scripting](https://en.wikipedia.org/wiki/Cross-site_scripting) and therefore is discouraged in favor of a WordPress Element hierarchy whenever possible. -For [dynamic blocks](/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md), the return value of `save` could either represent a cached copy of the block's content to be shown only in case the plugin implementing the block is ever disabled. Alternatively, return a `null` (empty) value to save no markup in post content for the dynamic block, instead deferring this to always be calculated when the block is shown on the front of the site. +For [dynamic blocks](/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md), the return value of `save` could represent a cached copy of the block's content to be shown only in case the plugin implementing the block is ever disabled. + +If left unspecified, the default implementation will save no markup in post content for the dynamic block, instead deferring this to always be calculated when the block is shown on the front of the site. ### attributes diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md b/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md index aa785ff85e31f6..ab7543c392c9cb 100644 --- a/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md +++ b/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md @@ -40,11 +40,6 @@ registerBlockType( 'my-plugin/latest-post', { post.title.rendered ); } ), - - save: function() { - // Rendering in PHP - return null; - }, } ); ``` {% ESNext %} @@ -79,16 +74,11 @@ registerBlockType( 'my-plugin/latest-post', { { post.title.rendered } ; } ), - - save() { - // Rendering in PHP - return null; - }, } ); ``` {% end %} -Because it is a dynamic block it also needs a server component. The rendering can be added using the `render_callback` property when using the `register_block_type` function. +Because it is a dynamic block it doesn't need to override the default `save` implementation on the client. Instead, it needs a server component. The rendering can be added using the `render_callback` property when using the `register_block_type` function. ```php ); }, - - save() { - // Rendering in PHP - return null; - }, } ); ``` {% end %} diff --git a/packages/block-library/src/archives/index.js b/packages/block-library/src/archives/index.js index b523701fcfae49..a9a11bca417b9b 100644 --- a/packages/block-library/src/archives/index.js +++ b/packages/block-library/src/archives/index.js @@ -32,9 +32,4 @@ export const settings = { }, edit, - - save() { - // Handled by PHP. - return null; - }, }; diff --git a/packages/block-library/src/calendar/index.js b/packages/block-library/src/calendar/index.js index da8f02dbe4038b..56c3c598686033 100644 --- a/packages/block-library/src/calendar/index.js +++ b/packages/block-library/src/calendar/index.js @@ -26,8 +26,4 @@ export const settings = { }, edit, - - save() { - return null; - }, }; diff --git a/packages/block-library/src/categories/index.js b/packages/block-library/src/categories/index.js index 4c65b50840059a..8eccf1abf963e9 100644 --- a/packages/block-library/src/categories/index.js +++ b/packages/block-library/src/categories/index.js @@ -42,8 +42,4 @@ export const settings = { }, edit, - - save() { - return null; - }, }; diff --git a/packages/block-library/src/latest-comments/index.js b/packages/block-library/src/latest-comments/index.js index 3f0700543f3b1b..4f2e5005023059 100644 --- a/packages/block-library/src/latest-comments/index.js +++ b/packages/block-library/src/latest-comments/index.js @@ -28,8 +28,4 @@ export const settings = { }, edit, - - save() { - return null; - }, }; diff --git a/packages/block-library/src/latest-posts/index.js b/packages/block-library/src/latest-posts/index.js index e1dd91ea70af86..40ad1d03d0e48a 100644 --- a/packages/block-library/src/latest-posts/index.js +++ b/packages/block-library/src/latest-posts/index.js @@ -34,8 +34,4 @@ export const settings = { }, edit, - - save() { - return null; - }, }; diff --git a/packages/block-library/src/legacy-widget/index.js b/packages/block-library/src/legacy-widget/index.js index 43142ec5ca1306..b7a4ae1f021518 100644 --- a/packages/block-library/src/legacy-widget/index.js +++ b/packages/block-library/src/legacy-widget/index.js @@ -25,9 +25,4 @@ export const settings = { }, edit, - - save() { - // Handled by PHP. - return null; - }, }; diff --git a/packages/block-library/src/rss/index.js b/packages/block-library/src/rss/index.js index 6a0f916c7d6e5b..bd8d523eb62856 100644 --- a/packages/block-library/src/rss/index.js +++ b/packages/block-library/src/rss/index.js @@ -26,8 +26,4 @@ export const settings = { }, edit, - - save() { - return null; - }, }; diff --git a/packages/block-library/src/search/index.js b/packages/block-library/src/search/index.js index 0fcfa75722ff48..4d51919e5d663d 100644 --- a/packages/block-library/src/search/index.js +++ b/packages/block-library/src/search/index.js @@ -22,8 +22,4 @@ export const settings = { keywords: [ __( 'find' ) ], edit, - - save() { - return null; - }, }; diff --git a/packages/block-library/src/tag-cloud/index.js b/packages/block-library/src/tag-cloud/index.js index cc785fdb3167a4..92121ce0248acc 100644 --- a/packages/block-library/src/tag-cloud/index.js +++ b/packages/block-library/src/tag-cloud/index.js @@ -25,8 +25,4 @@ export const settings = { }, edit, - - save() { - return null; - }, }; diff --git a/packages/blocks/src/api/registration.js b/packages/blocks/src/api/registration.js index d32a49f8b7ff00..727ee171f2b799 100644 --- a/packages/blocks/src/api/registration.js +++ b/packages/blocks/src/api/registration.js @@ -33,7 +33,7 @@ import { isValidIcon, normalizeIconObject } from './utils'; * @property {?string[]} keywords Additional keywords to produce * block as inserter search result. * @property {?Object} attributes Block attributes. - * @property {Function} save Serialize behavior of a block, + * @property {?Function} save Serialize behavior of a block, * returning an element describing * structure of the block's post * content markup. @@ -66,6 +66,7 @@ export function unstable__bootstrapServerSideBlockDefinitions( definitions ) { / export function registerBlockType( name, settings ) { settings = { name, + save: () => null, ...get( serverSideBlockDefinitions, name ), ...settings, }; diff --git a/packages/blocks/src/api/test/registration.js b/packages/blocks/src/api/test/registration.js index f7b20bcda9db07..7b47b97afb8408 100644 --- a/packages/blocks/src/api/test/registration.js +++ b/packages/blocks/src/api/test/registration.js @@ -3,12 +3,12 @@ /** * External dependencies */ -import { noop } from 'lodash'; +import { noop, omit } from 'lodash'; /** * WordPress dependencies */ -import { addFilter, removeFilter } from '@wordpress/hooks'; +import { addFilter, removeAllFilters } from '@wordpress/hooks'; /** * Internal dependencies @@ -106,12 +106,6 @@ describe( 'blocks', () => { expect( block ).toBeUndefined(); } ); - it( 'should reject blocks without a save function', () => { - const block = registerBlockType( 'my-plugin/fancy-block-5' ); - expect( console ).toHaveErroredWith( 'The "save" property must be specified and must be a valid function.' ); - expect( block ).toBeUndefined(); - } ); - it( 'should reject blocks with an invalid edit function', () => { const blockType = { save: noop, edit: 'not-a-function', category: 'common', title: 'block title' }, block = registerBlockType( 'my-plugin/fancy-block-6', blockType ); @@ -309,7 +303,7 @@ describe( 'blocks', () => { describe( 'applyFilters', () => { afterEach( () => { - removeFilter( 'blocks.registerBlockType', 'core/blocks/without-title' ); + removeAllFilters( 'blocks.registerBlockType' ); } ); it( 'should reject valid blocks when they become invalid after executing filter', () => { @@ -323,6 +317,15 @@ describe( 'blocks', () => { expect( console ).toHaveErroredWith( 'The block "my-plugin/fancy-block-12" must have a title.' ); expect( block ).toBeUndefined(); } ); + + it( 'should reject valid blocks when they become invalid after executing filter which removes save property', () => { + addFilter( 'blocks.registerBlockType', 'core/blocks/without-save', ( settings ) => { + return omit( settings, 'save' ); + } ); + const block = registerBlockType( 'my-plugin/fancy-block-13', defaultBlockSettings ); + expect( console ).toHaveErroredWith( 'The "save" property must be specified and must be a valid function.' ); + expect( block ).toBeUndefined(); + } ); } ); } );