Skip to content

Commit

Permalink
Site Editor: Add 'Show template' toggle when editing pages (#52674)
Browse files Browse the repository at this point in the history
* Site Editor: First pass at adding a Show Template toggle when editing pages

* Bit of clean up

* Use a toggle in sidebar

* Make toggling 'Show template' on/off faster

* Use blocks in same order as template

* Tidy up code

* Add unit tests

* Add doc comment

* Formatting
Remove unused component import
Doc update

* With icon and updated copy

* Use only the check icon and set min width of dropdown to minimize the effect of the dropdown width toggling between narrow and wide

* This commit tries to get around a peculiarity of __experimentalGetGlobalBlocksByName, which doesn't seem to be able to find the post-content block in a new block tree (if it even exists in state).
We're sidestepping the issue, but with fewer selectors, so overall hopefully it's more sustainable.

* Removing the filter iteration layer and adding it to the flattenBlock helper function
Checking for disallowed blocks as well, e.g., core/query

* Extract usePageContentBlocks and write basic tests
Moving PAGE_CONTENT_BLOCK_TYPES to utils/constants and creating a map

* Updates selectors to include canvas mode so we can show any hidden templates in focus mode

* Moving getPageContentFocusType and setPageContentFocusType selector/action to locked, private methods
In the use-page-content-blocks.js test, add innerblocks to the query test block

---------

Co-authored-by: ramon <ramonjd@gmail.com>
  • Loading branch information
2 people authored and mikachan committed Sep 22, 2023
1 parent 986f18f commit 32472b3
Show file tree
Hide file tree
Showing 16 changed files with 406 additions and 115 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* WordPress dependencies
*/
import { useEntityBlockEditor } from '@wordpress/core-data';
import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import { store as editSiteStore } from '../../../store';
import { unlock } from '../../../lock-unlock';
import useSiteEditorSettings from '../use-site-editor-settings';
import usePageContentBlocks from './use-page-content-blocks';

const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis );

const noop = () => {};

/**
* The default block editor provider for the site editor. Typically used when
* the post type is `'wp_template_part'` or `'wp_template'` and allows editing
* of the template and its nested entities.
*
* If the page content focus type is `'hideTemplate'`, the provider will provide
* a set of page content blocks wrapped in a container that, together,
* mimic the look and feel of the post editor and
* allow editing of the page content only.
*
* @param {Object} props
* @param {WPElement} props.children
*/
export default function DefaultBlockEditorProvider( { children } ) {
const settings = useSiteEditorSettings();

const { templateType, isTemplateHidden } = useSelect( ( select ) => {
const { getEditedPostType } = select( editSiteStore );
const { getPageContentFocusType, getCanvasMode } = unlock(
select( editSiteStore )
);
return {
templateType: getEditedPostType(),
isTemplateHidden:
getCanvasMode() === 'edit' &&
getPageContentFocusType() === 'hideTemplate',
canvasMode: unlock( select( editSiteStore ) ).getCanvasMode(),
};
}, [] );

const [ blocks, onInput, onChange ] = useEntityBlockEditor(
'postType',
templateType
);
const pageContentBlock = usePageContentBlocks( blocks, isTemplateHidden );
return (
<ExperimentalBlockEditorProvider
settings={ settings }
value={
isTemplateHidden && pageContentBlock.length
? pageContentBlock
: blocks
}
onInput={ isTemplateHidden ? noop : onInput }
onChange={ isTemplateHidden ? noop : onChange }
useSubRegistry={ false }
>
{ children }
</ExperimentalBlockEditorProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import { store as editSiteStore } from '../../../store';
import DefaultBlockEditorProvider from './default-block-editor-provider';
import NavigationBlockEditorProvider from './navigation-block-editor-provider';

export default function BlockEditorProvider( { children } ) {
const entityType = useSelect(
( select ) => select( editSiteStore ).getEditedPostType(),
[]
);
if ( entityType === 'wp_navigation' ) {
return (
<NavigationBlockEditorProvider>
{ children }
</NavigationBlockEditorProvider>
);
}
return (
<DefaultBlockEditorProvider>{ children }</DefaultBlockEditorProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* External dependencies
*/
import { renderHook } from '@testing-library/react';
/**
* WordPress dependencies
*/
import { createBlock } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import usePageContentBlocks from '../use-page-content-blocks';

jest.mock( '@wordpress/blocks', () => {
return {
__esModule: true,
...jest.requireActual( '@wordpress/blocks' ),
createBlock( name, attributes = {}, innerBlocks = [] ) {
return {
name,
attributes,
innerBlocks,
};
},
};
} );

describe( 'usePageContentBlocks', () => {
const blocksList = [
createBlock( 'core/group', {}, [
createBlock( 'core/post-title' ),
createBlock( 'core/post-featured-image' ),
createBlock( 'core/query', {}, [
createBlock( 'core/post-title' ),
createBlock( 'core/post-featured-image' ),
createBlock( 'core/post-content' ),
] ),
createBlock( 'core/post-content' ),
] ),
createBlock( 'core/query' ),
createBlock( 'core/paragraph' ),
createBlock( 'core/post-content' ),
];
it( 'should return empty array if `isPageContentFocused` is `false`', () => {
const { result } = renderHook( () =>
usePageContentBlocks( blocksList, false )
);
expect( result.current ).toEqual( [] );
} );
it( 'should return empty array if `blocks` is undefined', () => {
const { result } = renderHook( () =>
usePageContentBlocks( undefined, true )
);
expect( result.current ).toEqual( [] );
} );
it( 'should return empty array if `blocks` is an empty array', () => {
const { result } = renderHook( () => usePageContentBlocks( [], true ) );
expect( result.current ).toEqual( [] );
} );
it( 'should return new block list', () => {
const { result } = renderHook( () =>
usePageContentBlocks( blocksList, true )
);
expect( result.current ).toEqual( [
{
name: 'core/group',
attributes: {
layout: { type: 'constrained' },
style: {
spacing: {
margin: {
top: '4em', // Mimics the post editor.
},
},
},
},
innerBlocks: [
createBlock( 'core/post-title' ),
createBlock( 'core/post-featured-image' ),
createBlock( 'core/post-content' ),
createBlock( 'core/post-content' ),
],
},
] );
} );
} );
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* WordPress dependencies
*/
import { useMemo } from '@wordpress/element';
import { createBlock } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { PAGE_CONTENT_BLOCK_TYPES } from '../../../utils/constants';

/**
* Helper method to iterate through all blocks, recursing into allowed inner blocks.
* Returns a flattened object of transformed blocks.
*
* @param {Array} blocks Blocks to flatten.
* @param {Function} transform Transforming function to be applied to each block. If transform returns `undefined`, the block is skipped.
*
* @return {Array} Flattened object.
*/
function flattenBlocks( blocks, transform ) {
const result = [];
for ( let i = 0; i < blocks.length; i++ ) {
// Since the Query Block could contain PAGE_CONTENT_BLOCK_TYPES block types,
// we skip it because we only want to render stand-alone page content blocks in the block list.
if ( [ 'core/query' ].includes( blocks[ i ].name ) ) {
continue;
}
const transformedBlock = transform( blocks[ i ] );
if ( transformedBlock ) {
result.push( transformedBlock );
}
result.push( ...flattenBlocks( blocks[ i ].innerBlocks, transform ) );
}

return result;
}

/**
* Returns a memoized array of blocks that contain only page content blocks,
* surrounded by a group block to mimic the post editor.
*
* @param {Array} blocks Block list.
* @param {boolean} isPageContentFocused Whether the page content has focus. If `true` return page content blocks. Default `false`.
*
* @return {Array} Page content blocks.
*/
export default function usePageContentBlocks(
blocks,
isPageContentFocused = false
) {
return useMemo( () => {
if ( ! isPageContentFocused || ! blocks || ! blocks.length ) {
return [];
}
return [
createBlock(
'core/group',
{
layout: { type: 'constrained' },
style: {
spacing: {
margin: {
top: '4em', // Mimics the post editor.
},
},
},
},
flattenBlocks( blocks, ( block ) => {
if ( PAGE_CONTENT_BLOCK_TYPES[ block.name ] ) {
return createBlock( block.name );
}
} )
),
];
}, [ blocks, isPageContentFocused ] );
}

This file was deleted.

15 changes: 1 addition & 14 deletions packages/edit-site/src/components/block-editor/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { BlockInspector } from '@wordpress/block-editor';
import { privateApis as editPatternsPrivateApis } from '@wordpress/patterns';

Expand All @@ -10,31 +9,19 @@ import { privateApis as editPatternsPrivateApis } from '@wordpress/patterns';
*/
import TemplatePartConverter from '../template-part-converter';
import { SidebarInspectorFill } from '../sidebar-edit-mode';
import { store as editSiteStore } from '../../store';
import SiteEditorCanvas from './site-editor-canvas';
import getBlockEditorProvider from './get-block-editor-provider';
import BlockEditorProvider from './block-editor-provider';

import { unlock } from '../../lock-unlock';
const { PatternsMenuItems } = unlock( editPatternsPrivateApis );
export default function BlockEditor() {
const entityType = useSelect(
( select ) => select( editSiteStore ).getEditedPostType(),
[]
);

// Choose the provider based on the entity type currently
// being edited.
const BlockEditorProvider = getBlockEditorProvider( entityType );

return (
<BlockEditorProvider>
<TemplatePartConverter />
<SidebarInspectorFill>
<BlockInspector />
</SidebarInspectorFill>

<SiteEditorCanvas />

<PatternsMenuItems />
</BlockEditorProvider>
);
Expand Down

This file was deleted.

Loading

0 comments on commit 32472b3

Please sign in to comment.