diff --git a/packages/block-library/src/block/edit.js b/packages/block-library/src/block/edit.js index 6e6379571cc9e..2dd24a5fbd959 100644 --- a/packages/block-library/src/block/edit.js +++ b/packages/block-library/src/block/edit.js @@ -38,7 +38,7 @@ import { name as patternBlockName } from './index'; import { unlock } from '../lock-unlock'; const { useLayoutClasses } = unlock( blockEditorPrivateApis ); -const { PARTIAL_SYNCING_SUPPORTED_BLOCKS } = unlock( patternsPrivateApis ); +const { isOverridableBlock } = unlock( patternsPrivateApis ); const fullAlignments = [ 'full', 'wide', 'left', 'right' ]; @@ -90,21 +90,9 @@ const useInferredLayout = ( blocks, parentLayout ) => { }, [ blocks, parentLayout ] ); }; -function hasOverridableAttributes( block ) { - return ( - Object.keys( PARTIAL_SYNCING_SUPPORTED_BLOCKS ).includes( - block.name - ) && - !! block.attributes.metadata?.bindings && - Object.values( block.attributes.metadata.bindings ).some( - ( binding ) => binding.source === 'core/pattern-overrides' - ) - ); -} - function hasOverridableBlocks( blocks ) { return blocks.some( ( block ) => { - if ( hasOverridableAttributes( block ) ) return true; + if ( isOverridableBlock( block ) ) return true; return hasOverridableBlocks( block.innerBlocks ); } ); } @@ -133,7 +121,7 @@ function applyInitialContentValuesToInnerBlocks( const metadataName = legacyIdMap?.[ block.clientId ] ?? block.attributes.metadata?.name; - if ( ! metadataName || ! hasOverridableAttributes( block ) ) { + if ( ! metadataName || ! isOverridableBlock( block ) ) { return { ...block, innerBlocks }; } @@ -184,7 +172,7 @@ function getContentValuesFromInnerBlocks( blocks, defaultValues, legacyIdMap ) { } const metadataName = legacyIdMap?.[ block.clientId ] ?? block.attributes.metadata?.name; - if ( ! metadataName || ! hasOverridableAttributes( block ) ) { + if ( ! metadataName || ! isOverridableBlock( block ) ) { continue; } @@ -217,7 +205,7 @@ function setBlockEditMode( setEditMode, blocks, mode ) { blocks.forEach( ( block ) => { const editMode = mode || - ( hasOverridableAttributes( block ) ? 'contentOnly' : 'disabled' ); + ( isOverridableBlock( block ) ? 'contentOnly' : 'disabled' ); setEditMode( block.clientId, editMode ); setBlockEditMode( diff --git a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js index 50e103cb8b444..2264dfaaa56d1 100644 --- a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js +++ b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js @@ -43,6 +43,7 @@ import { unlock } from '../../../lock-unlock'; const { PostCardPanel } = unlock( editorPrivateApis ); const { Tabs } = unlock( componentsPrivateApis ); +const { PatternOverridesPanel } = unlock( editorPrivateApis ); const SIDEBAR_ACTIVE_BY_DEFAULT = Platform.select( { web: true, @@ -123,6 +124,7 @@ const SidebarContent = ( { + ) } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js index c19cf45e4551b..38e2ad4694906 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js @@ -9,8 +9,8 @@ import { PostExcerptPanel, PostLastRevisionPanel, PostTaxonomiesPanel, - store as editorStore, privateApis as editorPrivateApis, + store as editorStore, } from '@wordpress/editor'; import { store as coreStore } from '@wordpress/core-data'; import { __ } from '@wordpress/i18n'; @@ -31,7 +31,7 @@ import { TEMPLATE_PART_POST_TYPE } from '../../../utils/constants'; import { unlock } from '../../../lock-unlock'; const { PostCardPanel } = unlock( editorPrivateApis ); - +const { PatternOverridesPanel } = unlock( editorPrivateApis ); const { useHistory } = unlock( routerPrivateApis ); function TemplatesList( { availableTemplates, onSelect } ) { @@ -141,6 +141,7 @@ export default function TemplatePanel() { + ); } diff --git a/packages/editor/src/components/pattern-overrides-panel/index.js b/packages/editor/src/components/pattern-overrides-panel/index.js new file mode 100644 index 0000000000000..47cd6282b3fed --- /dev/null +++ b/packages/editor/src/components/pattern-overrides-panel/index.js @@ -0,0 +1,26 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { privateApis as patternsPrivateApis } from '@wordpress/patterns'; + +/** + * Internal dependencies + */ +import { store as editorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; + +const { OverridesPanel } = unlock( patternsPrivateApis ); + +export default function PatternOverridesPanel() { + const supportsPatternOverridesPanel = useSelect( + ( select ) => select( editorStore ).getCurrentPostType() === 'wp_block', + [] + ); + + if ( ! supportsPatternOverridesPanel ) { + return null; + } + + return ; +} diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index 10143bdf00262..ea42d6ad5fde5 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -10,6 +10,7 @@ import DocumentTools from './components/document-tools'; import InserterSidebar from './components/inserter-sidebar'; import ListViewSidebar from './components/list-view-sidebar'; import ModeSwitcher from './components/mode-switcher'; +import PatternOverridesPanel from './components/pattern-overrides-panel'; import PluginPostExcerpt from './components/post-excerpt/plugin'; import PostPanelRow from './components/post-panel-row'; import PostViewLink from './components/post-view-link'; @@ -27,6 +28,7 @@ lock( privateApis, { InserterSidebar, ListViewSidebar, ModeSwitcher, + PatternOverridesPanel, PluginPostExcerpt, PostPanelRow, PostViewLink, diff --git a/packages/patterns/src/api/index.js b/packages/patterns/src/api/index.js new file mode 100644 index 0000000000000..07f3b2321a127 --- /dev/null +++ b/packages/patterns/src/api/index.js @@ -0,0 +1,23 @@ +/** + * Internal dependencies + */ +import { PARTIAL_SYNCING_SUPPORTED_BLOCKS } from '../constants'; + +/** + * Determines whether a block is overridable. + * + * @param {WPBlock} block The block to test. + * + * @return {boolean} `true` if a block is overridable, `false` otherwise. + */ +export function isOverridableBlock( block ) { + return ( + Object.keys( PARTIAL_SYNCING_SUPPORTED_BLOCKS ).includes( + block.name + ) && + !! block.attributes.metadata?.bindings && + Object.values( block.attributes.metadata.bindings ).some( + ( binding ) => binding.source === 'core/pattern-overrides' + ) + ); +} diff --git a/packages/patterns/src/components/overrides-panel.js b/packages/patterns/src/components/overrides-panel.js new file mode 100644 index 0000000000000..b567b3c372daa --- /dev/null +++ b/packages/patterns/src/components/overrides-panel.js @@ -0,0 +1,45 @@ +/** + * WordPress dependencies + */ +import { + privateApis as blockEditorPrivateApis, + store as blockEditorStore, +} from '@wordpress/block-editor'; +import { PanelBody } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { useMemo } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import { isOverridableBlock } from '../api'; +import { unlock } from '../lock-unlock'; + +const { BlockQuickNavigation } = unlock( blockEditorPrivateApis ); + +export default function OverridesPanel() { + const allClientIds = useSelect( + ( select ) => select( blockEditorStore ).getClientIdsWithDescendants(), + [] + ); + const { getBlock } = useSelect( blockEditorStore ); + const clientIdsWithOverrides = useMemo( + () => + allClientIds.filter( ( clientId ) => { + const block = getBlock( clientId ); + return isOverridableBlock( block ); + } ), + [ allClientIds, getBlock ] + ); + + if ( ! clientIdsWithOverrides?.length ) { + return null; + } + + return ( + + + + ); +} diff --git a/packages/patterns/src/private-apis.js b/packages/patterns/src/private-apis.js index 54ad5a4aa47d1..15ff161305f4a 100644 --- a/packages/patterns/src/private-apis.js +++ b/packages/patterns/src/private-apis.js @@ -2,6 +2,7 @@ * Internal dependencies */ import { lock } from './lock-unlock'; +import OverridesPanel from './components/overrides-panel'; import { default as CreatePatternModal, CreatePatternModalContents, @@ -10,6 +11,7 @@ import { default as DuplicatePatternModal, useDuplicatePatternProps, } from './components/duplicate-pattern-modal'; +import { isOverridableBlock } from './api'; import RenamePatternModal from './components/rename-pattern-modal'; import PatternsMenuItems from './components'; import RenamePatternCategoryModal from './components/rename-pattern-category-modal'; @@ -27,9 +29,11 @@ import { export const privateApis = {}; lock( privateApis, { + OverridesPanel, CreatePatternModal, CreatePatternModalContents, DuplicatePatternModal, + isOverridableBlock, useDuplicatePatternProps, RenamePatternModal, PatternsMenuItems,