diff --git a/packages/block-library/src/template-part/edit/index.js b/packages/block-library/src/template-part/edit/index.js index b7934216f61d4..4dc0b89640c8e 100644 --- a/packages/block-library/src/template-part/edit/index.js +++ b/packages/block-library/src/template-part/edit/index.js @@ -12,7 +12,7 @@ import { } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { chevronUp, chevronDown } from '@wordpress/icons'; - +import { serialize } from '@wordpress/blocks'; /** * Internal dependencies */ @@ -27,44 +27,64 @@ export default function TemplatePartEdit( { setAttributes, clientId, } ) { - const initialPostId = useRef( _postId ); const initialSlug = useRef( slug ); const initialTheme = useRef( theme ); + const initialContent = useRef(); // Resolve the post ID if not set, and load its post. const postId = useTemplatePartPost( _postId, slug, theme ); - // Set the post ID, once found, so that edits persist, - // but wait until the third inner blocks change, - // because the first 2 are just the template part - // content loading. - const { innerBlocks } = useSelect( + // Set the postId block attribute if it did not exist, + // but wait until the inner blocks have loaded to allow + // new edits to trigger this. + const { innerBlocks, expectedContent } = useSelect( ( select ) => { const { getBlocks } = select( 'core/block-editor' ); + const entityRecord = select( 'core' ).getEntityRecord( + 'postType', + 'wp_template_part', + postId + ); + return { innerBlocks: getBlocks( clientId ), + expectedContent: entityRecord?.content.raw, }; }, - [ clientId ] + [ clientId, postId ] ); const { editEntityRecord } = useDispatch( 'core' ); - const blockChanges = useRef( 0 ); useEffect( () => { - if ( blockChanges.current < 4 ) blockChanges.current++; + // If postId (entity) has not resolved or _postId (block attr) is set, + // then we have no need for this effect. + if ( ! postId || _postId ) { + return; + } + + const innerContent = serialize( innerBlocks ); + + // If we havent set initialContent, check if innerBlocks are loaded. + if ( ! initialContent.current ) { + // If the content of innerBlocks and the content from entity match, + // then we can consider innerBlocks as loaded and set initialContent. + if ( innerContent === expectedContent ) { + initialContent.current = innerContent; + } + // Continue to return early until this effect is triggered + // with innerBlocks already loaded (as denoted by initialContent being set). + return; + } - if ( - blockChanges.current === 3 && - ( initialPostId.current === undefined || - initialPostId.current === null ) && - postId !== undefined && - postId !== null - ) { + // After initialContent is set and the content is updated, we can set the + // postId block attribute and set the post status to 'publish'. + // After this is done the hook will no longer run due to the first return above. + if ( initialContent.current !== innerContent ) { setAttributes( { postId } ); editEntityRecord( 'postType', 'wp_template_part', postId, { status: 'publish', } ); } - }, [ innerBlocks ] ); + }, [ innerBlocks, expectedContent ] ); const blockProps = useBlockProps();