diff --git a/lib/blocks.php b/lib/blocks.php index 3e35685e0c7a90..d0f6dede5a3134 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -36,6 +36,7 @@ function gutenberg_reregister_core_block_types() { 'navigation-link', 'navigation-submenu', 'nextpage', + 'pattern', 'paragraph', 'preformatted', 'pullquote', @@ -69,6 +70,7 @@ function gutenberg_reregister_core_block_types() { 'social-link.php' => 'core/social-link', 'tag-cloud.php' => 'core/tag-cloud', 'page-list.php' => 'core/page-list', + 'pattern.php' => 'core/pattern', 'post-author.php' => 'core/post-author', 'post-comment.php' => 'core/post-comment', 'post-comment-author.php' => 'core/post-comment-author', diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js index 27ff83cdb817ae..acc997d899ef2b 100644 --- a/packages/block-library/src/index.js +++ b/packages/block-library/src/index.js @@ -42,6 +42,7 @@ import * as list from './list'; import * as missing from './missing'; import * as more from './more'; import * as nextpage from './nextpage'; +import * as pattern from './pattern'; import * as pageList from './page-list'; import * as preformatted from './preformatted'; import * as pullquote from './pullquote'; @@ -195,6 +196,7 @@ export const __experimentalGetCoreBlocks = () => [ postTerms, logInOut, + pattern, ]; /** diff --git a/packages/block-library/src/pattern/block.json b/packages/block-library/src/pattern/block.json new file mode 100644 index 00000000000000..78423e8d491232 --- /dev/null +++ b/packages/block-library/src/pattern/block.json @@ -0,0 +1,17 @@ +{ + "apiVersion": 2, + "name": "core/pattern", + "title": "Pattern", + "category": "design", + "description": "Show a block pattern.", + "supports": { + "html": false, + "inserter": false + }, + "textdomain": "default", + "attributes": { + "slug": { + "type": "string" + } + } +} diff --git a/packages/block-library/src/pattern/edit.js b/packages/block-library/src/pattern/edit.js new file mode 100644 index 00000000000000..e0cab9c7b86e4d --- /dev/null +++ b/packages/block-library/src/pattern/edit.js @@ -0,0 +1,64 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; +import { + store as blockEditorStore, + useBlockProps, + __experimentalUseInnerBlocksProps as useInnerBlocksProps, +} from '@wordpress/block-editor'; +import { createBlock } from '@wordpress/blocks'; + +const PatternEdit = ( { attributes, clientId, isSelected } ) => { + const selectedPattern = useSelect( + ( select ) => + select( blockEditorStore ).__experimentalGetParsedPattern( + attributes.slug + ), + [ attributes.slug ] + ); + + const hasSelection = useSelect( + ( select ) => + isSelected || + select( blockEditorStore ).hasSelectedInnerBlock( clientId, true ), + [ isSelected, clientId ] + ); + + const { + replaceBlocks, + replaceInnerBlocks, + __unstableMarkNextChangeAsNotPersistent, + } = useDispatch( blockEditorStore ); + + // Run this effect when the block, or any of its InnerBlocks are selected. + // This replaces the Pattern block wrapper with a Group block. + // This ensures the markup structure and alignment are consistent between editor and view. + // This change won't be saved unless further changes are made to the InnerBlocks. + useEffect( () => { + if ( hasSelection && selectedPattern?.blocks ) { + __unstableMarkNextChangeAsNotPersistent(); + replaceBlocks( + clientId, + createBlock( 'core/group', {}, selectedPattern.blocks ) + ); + } + }, [ hasSelection, selectedPattern?.blocks ] ); + + // Run this effect when the component loads. + // This adds the Pattern block template as InnerBlocks. + // This change won't be saved. + useEffect( () => { + if ( selectedPattern?.blocks ) { + __unstableMarkNextChangeAsNotPersistent(); + replaceInnerBlocks( clientId, selectedPattern.blocks ); + } + }, [ selectedPattern?.blocks ] ); + + const props = useInnerBlocksProps( useBlockProps(), {} ); + + return
; +}; + +export default PatternEdit; diff --git a/packages/block-library/src/pattern/index.js b/packages/block-library/src/pattern/index.js new file mode 100644 index 00000000000000..5ab74fdd0c967a --- /dev/null +++ b/packages/block-library/src/pattern/index.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import metadata from './block.json'; +import PatternEdit from './edit'; + +const { name } = metadata; +export { metadata, name }; + +export const settings = { + edit: PatternEdit, +}; diff --git a/packages/block-library/src/pattern/index.php b/packages/block-library/src/pattern/index.php new file mode 100644 index 00000000000000..3c2888a9a77274 --- /dev/null +++ b/packages/block-library/src/pattern/index.php @@ -0,0 +1,44 @@ + 'render_block_core_pattern', + ) + ); +} + +/** + * Renders the `core/pattern` block on the server. + * + * @param array $attributes Block attributes. + * + * @return string Returns the output of the pattern. + */ +function render_block_core_pattern( $attributes ) { + if ( empty( $attributes['slug'] ) ) { + return ''; + } + + $slug = $attributes['slug']; + $registry = WP_Block_Patterns_Registry::get_instance(); + if ( ! $registry->is_registered( $slug ) ) { + return ''; + } + + $pattern = $registry->get_registered( $slug ); + return do_blocks( '
' . $pattern['content'] . '
' ); +} + +add_action( 'init', 'register_block_core_pattern' ); diff --git a/test/integration/fixtures/blocks/core__pattern.html b/test/integration/fixtures/blocks/core__pattern.html new file mode 100644 index 00000000000000..7e54c15b02123f --- /dev/null +++ b/test/integration/fixtures/blocks/core__pattern.html @@ -0,0 +1 @@ + diff --git a/test/integration/fixtures/blocks/core__pattern.json b/test/integration/fixtures/blocks/core__pattern.json new file mode 100644 index 00000000000000..55ac2e12b5d56b --- /dev/null +++ b/test/integration/fixtures/blocks/core__pattern.json @@ -0,0 +1,12 @@ +[ + { + "clientId": "_clientId_0", + "name": "core/pattern", + "isValid": true, + "attributes": { + "slug": "core/text-two-columns" + }, + "innerBlocks": [], + "originalContent": "" + } +] diff --git a/test/integration/fixtures/blocks/core__pattern.parsed.json b/test/integration/fixtures/blocks/core__pattern.parsed.json new file mode 100644 index 00000000000000..e37cee551dda78 --- /dev/null +++ b/test/integration/fixtures/blocks/core__pattern.parsed.json @@ -0,0 +1,11 @@ +[ + { + "blockName": "core/pattern", + "attrs": { + "slug": "core/text-two-columns" + }, + "innerBlocks": [], + "innerHTML": "", + "innerContent": [] + } +] diff --git a/test/integration/fixtures/blocks/core__pattern.serialized.html b/test/integration/fixtures/blocks/core__pattern.serialized.html new file mode 100644 index 00000000000000..7e54c15b02123f --- /dev/null +++ b/test/integration/fixtures/blocks/core__pattern.serialized.html @@ -0,0 +1 @@ +