diff --git a/assets/src/block-editor/helpers/index.js b/assets/src/block-editor/helpers/index.js index 13286b59676..c7faca51c44 100644 --- a/assets/src/block-editor/helpers/index.js +++ b/assets/src/block-editor/helpers/index.js @@ -2,7 +2,8 @@ * External dependencies */ import PropTypes from 'prop-types'; -import { ReactElement } from 'react'; +import { ReactElement, useEffect } from 'react'; +import { v4 as uuid } from 'uuid'; /** * WordPress dependencies @@ -265,7 +266,14 @@ export const getLayoutOptions = ( block ) => { */ export const filterBlocksEdit = ( BlockEdit ) => { const EnhancedBlockEdit = function( props ) { - const { attributes: { ampLayout }, name } = props; + const { attributes: { ampLayout, amp_uuid: ampUuid }, name, setAttributes } = props; + + // Set the block's AMP UUID if it has not been set yet. + useEffect( () => { + if ( ! ampUuid ) { + setAttributes( { amp_uuid: uuid() } ); + } + }, [ ampUuid, setAttributes ] ); let inspectorControls; @@ -296,6 +304,7 @@ export const filterBlocksEdit = ( BlockEdit ) => { EnhancedBlockEdit.propTypes = { attributes: PropTypes.shape( { + amp_uuid: PropTypes.oneOf( [ false, PropTypes.string ] ), text: PropTypes.string, ampLayout: PropTypes.string, } ), diff --git a/assets/src/block-validation/use-validation-error-state-updates.js b/assets/src/block-validation/use-validation-error-state-updates.js index 3892f14e03c..1cdccd592d5 100644 --- a/assets/src/block-validation/use-validation-error-state-updates.js +++ b/assets/src/block-validation/use-validation-error-state-updates.js @@ -27,10 +27,11 @@ export function useValidationErrorStateUpdates() { const { setValidationErrors } = useDispatch( BLOCK_VALIDATION_STORE_KEY ); - const { blockOrder, currentPost, getBlock, validationErrorsFromPost } = useSelect( ( select ) => ( { + const { blockOrder, currentPost, getBlock, getBlocks, validationErrorsFromPost } = useSelect( ( select ) => ( { blockOrder: select( 'core/block-editor' ).getClientIdsWithDescendants(), currentPost: select( 'core/editor' ).getCurrentPost(), getBlock: select( 'core/block-editor' ).getBlock, + getBlocks: select( 'core/block-editor' ).getBlocks, validationErrorsFromPost: select( 'core/editor' ).getEditedPostAttribute( AMP_VALIDITY_REST_FIELD_NAME )?.results || [], } ) ); @@ -47,6 +48,8 @@ export function useValidationErrorStateUpdates() { * Adds clientIds to the validation errors that are associated with blocks. */ useEffect( () => { + const blocks = getBlocks(); + const newValidationErrors = trackedValidationErrorsFromPost.map( ( validationError ) => { if ( ! validationError.error.sources ) { return validationError; @@ -58,6 +61,16 @@ export function useValidationErrorStateUpdates() { } for ( const source of validationError.error.sources ) { + // First, attempt to retrieve the block from the amp_uuid. + if ( source.block_attrs && source.block_attrs.amp_uuid ) { + for ( const block of blocks ) { + if ( block.attributes.amp_uuid === source.block_attrs.amp_uuid ) { + return { ...validationError, clientId: block.clientId }; + } + } + } + + // If retrieving the source from amp_uuid didn't work, fall back to relying on the block_content_index if set. if ( ! source.block_name || undefined === source.block_content_index ) { continue; } @@ -90,7 +103,7 @@ export function useValidationErrorStateUpdates() { } ); setValidationErrors( newValidationErrors ); - }, [ blockOrder, currentPost.id, getBlock, setValidationErrors, trackedValidationErrorsFromPost ] ); + }, [ blockOrder, currentPost.id, getBlock, getBlocks, setValidationErrors, trackedValidationErrorsFromPost ] ); return null; } diff --git a/includes/validation/class-amp-validation-manager.php b/includes/validation/class-amp-validation-manager.php index d54f3e068aa..9713a8e8d4e 100644 --- a/includes/validation/class-amp-validation-manager.php +++ b/includes/validation/class-amp-validation-manager.php @@ -2459,6 +2459,28 @@ static function ( $plugin ) { $data ); + // Add the amp_uuid attribute to every block. + // This is done as an inline script to ensure the filter is added before any blocks are registered. + wp_add_inline_script( + 'wp-hooks', + "wp.hooks.addFilter( + 'blocks.registerBlockType', + 'amp/block-validation/uuid-attribute', + function ( settings ) { + if ( ! settings.attributes ) { + settings.attributes = {}; + } + + settings.attributes.amp_uuid = { + type: 'string', + default: false, + }; + + return settings; + } + );" + ); + if ( function_exists( 'wp_set_script_translations' ) ) { wp_set_script_translations( $slug, 'amp' ); } elseif ( function_exists( 'wp_get_jed_locale_data' ) || function_exists( 'gutenberg_get_jed_locale_data' ) ) {