From 8107f7ec2e2a640b3b64394cfbf6296b391914b0 Mon Sep 17 00:00:00 2001 From: Carolina Nymark Date: Tue, 14 Jan 2025 12:11:05 +0100 Subject: [PATCH] Warn if a template does not have one main element Adds a new component that checks if a template has exactly one main HTML element, and creates a warning notice if the main HTML element is used incorrectly. --- packages/editor/README.md | 4 ++ .../src/components/editor-interface/index.js | 6 +- packages/editor/src/components/index.js | 1 + .../components/main-element-warnings/index.js | 57 +++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 packages/editor/src/components/main-element-warnings/index.js diff --git a/packages/editor/README.md b/packages/editor/README.md index 3119f3f289637..935545afc54bd 100644 --- a/packages/editor/README.md +++ b/packages/editor/README.md @@ -478,6 +478,10 @@ Monitors local autosaves of a post in the editor. It uses several hooks and func The module also checks for sessionStorage support and conditionally exports the `LocalAutosaveMonitor` component based on that. +### MainElementWarnings + +Undocumented declaration. + ### MediaPlaceholder > **Deprecated** since 5.3, use `wp.blockEditor.MediaPlaceholder` instead. diff --git a/packages/editor/src/components/editor-interface/index.js b/packages/editor/src/components/editor-interface/index.js index 6f6ffbec7b9c3..ae2452e01879b 100644 --- a/packages/editor/src/components/editor-interface/index.js +++ b/packages/editor/src/components/editor-interface/index.js @@ -26,6 +26,7 @@ import SavePublishPanels from '../save-publish-panels'; import TextEditor from '../text-editor'; import VisualEditor from '../visual-editor'; import EditorContentSlotFill from './content-slot-fill'; +import MainElementWarnings from '../main-element-warnings'; const interfaceLabels = { /* translators: accessibility text for the editor top bar landmark region. */ @@ -139,7 +140,10 @@ export default function EditorInterface( { content={ <> { ! isDistractionFree && ! isPreviewMode && ( - + <> + + + ) } diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index d940532be75a3..4ab2295f97fc0 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -21,6 +21,7 @@ export { default as EntitiesSavedStates } from './entities-saved-states'; export { useIsDirty as useEntitiesSavedStatesIsDirty } from './entities-saved-states/hooks/use-is-dirty'; export { default as ErrorBoundary } from './error-boundary'; export { default as LocalAutosaveMonitor } from './local-autosave-monitor'; +export { default as MainElementWarnings } from './main-element-warnings'; export { default as PageAttributesCheck } from './page-attributes/check'; export { default as PageAttributesOrder } from './page-attributes/order'; export { default as PageAttributesPanel } from './page-attributes/panel'; diff --git a/packages/editor/src/components/main-element-warnings/index.js b/packages/editor/src/components/main-element-warnings/index.js new file mode 100644 index 0000000000000..cc5bdf621076a --- /dev/null +++ b/packages/editor/src/components/main-element-warnings/index.js @@ -0,0 +1,57 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; +import { store as blockEditorStore } from '@wordpress/block-editor'; +import { store as noticesStore } from '@wordpress/notices'; + +/** + * Internal dependencies + */ +import { store as editorStore } from '../../store'; + +const checkMainTag = ( blocks, mainTagCount ) => { + blocks.forEach( ( block ) => { + if ( block.attributes.tagName === 'main' ) { + mainTagCount++; + } + // If the block has innerBlocks, call the function again. + if ( block.innerBlocks.length > 0 ) { + mainTagCount = checkMainTag( block.innerBlocks, mainTagCount ); + } + } ); + + return mainTagCount; +}; + +export default function MainElementWarnings() { + const { type, blocks } = useSelect( ( select ) => { + const postType = select( editorStore ).getCurrentPostType(); + const { getBlocks } = select( blockEditorStore ); + return { + type: postType, + blocks: getBlocks(), + }; + }, [] ); + + const { createWarningNotice, removeNotice } = useDispatch( noticesStore ); + + useEffect( () => { + if ( 'wp_template' === type ) { + const mainTagCount = checkMainTag( blocks, 0 ); + + removeNotice( 'edit-site-main-notice' ); + + if ( 0 === mainTagCount || 1 < mainTagCount ) { + createWarningNotice( + __( 'Your template should have exactly one main element.' ), + { id: 'edit-site-main-notice' } + ); + } + } + }, [ type, blocks, createWarningNotice, removeNotice ] ); + + return null; +}