Skip to content
Closed
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ _Parameters_
- _value_ `boolean|Object`: Whether the inserter should be opened (true) or closed (false). To specify an insertion point, use an object.
- _value.rootClientId_ `string`: The root client ID to insert at.
- _value.insertionIndex_ `number`: The index to insert at.
- _value.initialTab_ `string`: The id of the tab to display first when the block editor inserter is opened. A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.

_Returns_

Expand Down
1 change: 1 addition & 0 deletions docs/reference-guides/data/data-core-edit-widgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ _Parameters_
- _value_ `boolean|Object`: Whether the inserter should be opened (true) or closed (false). To specify an insertion point, use an object.
- _value.rootClientId_ `string`: The root client ID to insert at.
- _value.insertionIndex_ `number`: The index to insert at.
- _value.initialTab_ `string`: The id of the tab to display first when the block editor inserter is opened. A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.

_Returns_

Expand Down
1 change: 1 addition & 0 deletions docs/reference-guides/data/data-core-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,7 @@ _Parameters_
- _value_ `boolean|Object`: Whether the inserter should be opened (true) or closed (false). To specify an insertion point, use an object.
- _value.rootClientId_ `string`: The root client ID to insert at.
- _value.insertionIndex_ `number`: The index to insert at.
- _value.initialTab_ `string`: The id of the tab to display first when the block editor inserter is opened. A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.

_Returns_

Expand Down
2 changes: 2 additions & 0 deletions packages/block-editor/src/components/inserter/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function InserterLibrary(
showMostUsedBlocks = false,
__experimentalInsertionIndex,
__experimentalFilterValue,
initialInserterTab,
onSelect = noop,
shouldFocusBlock = false,
},
Expand All @@ -46,6 +47,7 @@ function InserterLibrary(
isAppender={ isAppender }
showInserterHelpPanel={ showInserterHelpPanel }
showMostUsedBlocks={ showMostUsedBlocks }
initialInserterTab={ initialInserterTab }
__experimentalInsertionIndex={ __experimentalInsertionIndex }
__experimentalFilterValue={ __experimentalFilterValue }
shouldFocusBlock={ shouldFocusBlock }
Expand Down
7 changes: 5 additions & 2 deletions packages/block-editor/src/components/inserter/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function InserterMenu(
showMostUsedBlocks,
__experimentalFilterValue = '',
shouldFocusBlock = true,
initialInserterTab,
},
ref
) {
Expand All @@ -56,8 +57,9 @@ function InserterMenu(
const [ patternFilter, setPatternFilter ] = useState( 'all' );
const [ selectedMediaCategory, setSelectedMediaCategory ] =
useState( null );
const [ selectedTab, setSelectedTab ] = useState( null );

const [ selectedTab, setSelectedTab ] = useState(
initialInserterTab || null
);
const [ destinationRootClientId, onInsertBlocks, onToggleInsertionPoint ] =
useInsertionPoint( {
rootClientId,
Expand Down Expand Up @@ -259,6 +261,7 @@ function InserterMenu(
showMedia={ showMedia }
onSelect={ handleSetSelectedTab }
tabsContents={ inserterTabsContents }
initialTabId={ initialInserterTab }
/>
) }
{ ! delayedFilterValue && ! showAsTabs && (
Expand Down
7 changes: 6 additions & 1 deletion packages/block-editor/src/components/inserter/tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,21 @@ function InserterTabs( {
showMedia = false,
onSelect,
tabsContents,
initialTabId,
} ) {
const tabs = [
blocksTab,
showPatterns && patternsTab,
showMedia && mediaTab,
].filter( Boolean );

initialTabId = !! tabs.find( ( { name } ) => initialTabId === name )
? initialTabId
: 'blocks';

return (
<div className="block-editor-inserter__tabs">
<Tabs onSelect={ onSelect }>
<Tabs initialTabId={ initialTabId } onSelect={ onSelect }>
<Tabs.TabList>
{ tabs.map( ( tab ) => (
<Tabs.Tab key={ tab.name } tabId={ tab.name }>
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
@import "./nextpage/editor.scss";
@import "./page-list/editor.scss";
@import "./paragraph/editor.scss";
@import "./post-content/editor.scss";
@import "./post-excerpt/editor.scss";
@import "./pullquote/editor.scss";
@import "./rss/editor.scss";
Expand Down
143 changes: 96 additions & 47 deletions packages/block-library/src/post-content/edit.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
Expand All @@ -8,13 +13,14 @@ import {
__experimentalRecursionProvider as RecursionProvider,
__experimentalUseHasRecursion as useHasRecursion,
Warning,
store as blockEditorStore,
} from '@wordpress/block-editor';
import {
useEntityProp,
useEntityBlockEditor,
store as coreStore,
} from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { useEntityProp, useEntityBlockEditor } from '@wordpress/core-data';
import { useSelect, useDispatch } from '@wordpress/data';
import { Placeholder, Button } from '@wordpress/components';
import { postContent as icon } from '@wordpress/icons';
import { createBlock } from '@wordpress/blocks';

/**
* Internal dependencies
*/
Expand Down Expand Up @@ -45,40 +51,104 @@ function ReadOnlyContent( {
);
}

function EditableContent( { context = {} } ) {
const { postType, postId } = context;
function EmptyContentPlaceholder( { context, onClose, openInserter } ) {
const { postType } = context;
const label =
'page' === postType
? __( 'This page’s content is empty' )
: __( 'This post’s content is empty' );
Comment on lines +56 to +59
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a fallback string for when the post type is neither a post nor a page? I.e. something like:

let label = __( 'This content is empty' );
if ( 'page' === postType ) {
    label = __( 'This page’s content is empty' );
} else if ( 'post' === postType ) {
    label = __( 'This post’s content is empty' );
}

return (
<Placeholder
icon={ icon }
label={ label }
instructions={ __(
'Add your first block or pattern to get started.'
) }
>
<Button variant="primary" onClick={ openInserter }>
{ __( 'Choose a pattern' ) }
</Button>

<Button variant="secondary" onClick={ onClose }>
{ __( 'Start blank' ) }
</Button>
</Placeholder>
);
}

function PostContentPlaceholder( { layoutClassNames } ) {
const blockProps = useBlockProps( { className: layoutClassNames } );
return (
<div { ...blockProps }>
<Placeholder
className="wp-block-post-content__content-placeholder"
withIllustration
>
<p>
{ __( 'This block will be replaced with your content.' ) }
</p>
</Placeholder>
</div>
);
}

function EditableContent( { context = {}, clientId } ) {
const { postType, postId } = context;
const { selectBlock, insertBlock } = useDispatch( blockEditorStore );
const [ blocks, onInput, onChange ] = useEntityBlockEditor(
'postType',
postType,
{ id: postId }
);

const entityRecord = useSelect(
( select ) => {
return select( coreStore ).getEntityRecord(
'postType',
postType,
postId
);
},
const setInserterIsOpened = useSelect(
( select ) =>
select( blockEditorStore ).getSettings()
.__experimentalSetIsInserterOpened,
[ postType, postId ]
);

const hasInnerBlocks = !! entityRecord?.content?.raw || blocks?.length;

const initialInnerBlocks = [ [ 'core/paragraph' ] ];
const hasInnerBlocks = blocks?.length;

const props = useInnerBlocksProps(
useBlockProps( { className: 'entry-content' } ),
const { children, ...props } = useInnerBlocksProps(
useBlockProps( {
className: classnames( 'entry-content', {
'wp-block-post-content__placeholder': ! hasInnerBlocks,
} ),
} ),
{
value: blocks,
onInput,
onChange,
template: ! hasInnerBlocks ? initialInnerBlocks : undefined,
}
);
return <div { ...props } />;

const onClose = () => {
const initialBlock = createBlock( 'core/paragraph' );
insertBlock( initialBlock, 0, clientId );
selectBlock( initialBlock.clientId );
};

const openInserter = () => {
setInserterIsOpened( {
initialTab: 'patterns',
rootClientId: clientId,
insertionIndex: 0,
} );
};

return (
<div { ...props }>
{ children }
{ ! hasInnerBlocks && (
<EmptyContentPlaceholder
context={ context }
onClose={ onClose }
openInserter={ openInserter }
/>
) }
</div>
);
}

function Content( props ) {
Expand All @@ -104,29 +174,6 @@ function Content( props ) {
);
}

function Placeholder( { layoutClassNames } ) {
const blockProps = useBlockProps( { className: layoutClassNames } );
return (
<div { ...blockProps }>
<p>
{ __(
'This is the Content block, it will display all the blocks in any single post or page.'
) }
</p>
<p>
{ __(
'That might be a simple arrangement like consecutive paragraphs in a blog post, or a more elaborate composition that includes image galleries, videos, tables, columns, and any other block types.'
) }
</p>
<p>
{ __(
'If there are any Custom Post Types registered at your site, the Content block can display the contents of those entries as well.'
) }
</p>
</div>
);
}

function RecursionError() {
const blockProps = useBlockProps();
return (
Expand All @@ -139,6 +186,7 @@ function RecursionError() {
}

export default function PostContentEdit( {
clientId,
context,
__unstableLayoutClassNames: layoutClassNames,
} ) {
Expand All @@ -153,11 +201,12 @@ export default function PostContentEdit( {
<RecursionProvider uniqueId={ contextPostId }>
{ contextPostId && contextPostType ? (
<Content
clientId={ clientId }
context={ context }
layoutClassNames={ layoutClassNames }
/>
) : (
<Placeholder layoutClassNames={ layoutClassNames } />
<PostContentPlaceholder layoutClassNames={ layoutClassNames } />
) }
</RecursionProvider>
);
Expand Down
26 changes: 26 additions & 0 deletions packages/block-library/src/post-content/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.wp-block-post-content__placeholder {
.components-placeholder {
min-height: auto;
box-shadow: none;
padding: $grid-unit-30;
}
}

.wp-block-post-content__content-placeholder {
&.has-illustration::before {
border: 1px solid currentColor;
background: none;
}
.components-placeholder__illustration {
opacity: 0.1;
}
.components-placeholder__fieldset {
font-size: inherit;
font-family: inherit;
align-self: center;
p {
font-size: inherit;
font-family: inherit;
}
}
}
2 changes: 2 additions & 0 deletions packages/customize-widgets/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* use an object.
* @param {string} value.rootClientId The root client ID to insert at.
* @param {number} value.insertionIndex The index to insert at.
* @param {string} value.initialTab The id of the tab to display first when the block editor inserter is opened.
* A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.
*
* @example
* ```js
Expand Down
2 changes: 2 additions & 0 deletions packages/edit-widgets/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,8 @@ export function setIsWidgetAreaOpen( clientId, isOpen ) {
* use an object.
* @param {string} value.rootClientId The root client ID to insert at.
* @param {number} value.insertionIndex The index to insert at.
* @param {string} value.initialTab The id of the tab to display first when the block editor inserter is opened.
* A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.
*
* @return {Object} Action object.
*/
Expand Down
21 changes: 13 additions & 8 deletions packages/editor/src/components/inserter-sidebar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ import { unlock } from '../../lock-unlock';
import { store as editorStore } from '../../store';

export default function InserterSidebar() {
const { insertionPoint, showMostUsedBlocks } = useSelect( ( select ) => {
const { getInsertionPoint } = unlock( select( editorStore ) );
const { get } = select( preferencesStore );
return {
insertionPoint: getInsertionPoint(),
showMostUsedBlocks: get( 'core', 'mostUsedBlocks' ),
};
}, [] );
const { insertionPoint, initialInserterTab, showMostUsedBlocks } =
useSelect( ( select ) => {
const { getInsertionPoint, getInserterInitialTab } = unlock(
select( editorStore )
);
const { get } = select( preferencesStore );
return {
insertionPoint: getInsertionPoint(),
initialInserterTab: getInserterInitialTab(),
showMostUsedBlocks: get( 'core', 'mostUsedBlocks' ),
};
}, [] );
const { setIsInserterOpened } = useDispatch( editorStore );

const isMobileViewport = useViewportMatch( 'medium', '<' );
Expand Down Expand Up @@ -64,6 +68,7 @@ export default function InserterSidebar() {
__experimentalInsertionIndex={
insertionPoint.insertionIndex
}
initialInserterTab={ initialInserterTab }
__experimentalFilterValue={ insertionPoint.filterValue }
ref={ libraryRef }
/>
Expand Down
2 changes: 2 additions & 0 deletions packages/editor/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,8 @@ export function removeEditorPanel( panelName ) {
* use an object.
* @param {string} value.rootClientId The root client ID to insert at.
* @param {number} value.insertionIndex The index to insert at.
* @param {string} value.initialTab The id of the tab to display first when the block editor inserter is opened.
* A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.
*
* @return {Object} Action object.
*/
Expand Down
Loading