-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Block Library: Implement Template Part block editing 2. (#19203)
* Template Loader: Create auto drafts for template parts in the currently edited post. * Core Data: Evaluate optimized function edits on save. * Core Data: Implement hooks for syncing blocks to entities. * Template Part: Implement edit component. * Editor: Make entity save labels clearer. * Block Editor: Go back to controlled inner blocks approach. * Template Parts: Add missing CPT REST config params. * Inner Blocks: Guard against trying to reset selection when replacing inner blocks with an empty list. * Block Library: Modularize Template Part block editing and add a placeholder for choosing or creating template parts. * Core Data: Add missing default argument to `useEntityBlockEditor`. * Template Part Block: Show preview when choosing an existing template part. * Template Loader: Don't load template parts if experiment is off. * Template Part: Fix mobile placeholder layout. * Template Part: Disable edit as HTML support. * Template Part: Swap `onChange` for `onInput`. * URL: Add editor's slug cleaning utility and use it in the template part block. * Entity Provider: Clarify why we don't import `select` directly. * Core Data: Remove unused block editor dependency. * Template Part: Update placeholder layout. * Inner Blocks: Make blocks prop experimental. * Core Data: Pass edited entity record to optimized function edits on evaluation.
- Loading branch information
Showing
22 changed files
with
504 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,5 +11,8 @@ | |
"theme": { | ||
"type": "string" | ||
} | ||
}, | ||
"supports": { | ||
"html": false | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useRef, useEffect } from '@wordpress/element'; | ||
import { EntityProvider } from '@wordpress/core-data'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import useTemplatePartPost from './use-template-part-post'; | ||
import TemplatePartInnerBlocks from './inner-blocks'; | ||
import TemplatePartPlaceholder from './placeholder'; | ||
|
||
export default function TemplatePartEdit( { | ||
attributes: { postId: _postId, slug, theme }, | ||
setAttributes, | ||
} ) { | ||
const initialPostId = useRef( _postId ); | ||
const initialSlug = useRef( slug ); | ||
const initialTheme = useRef( theme ); | ||
|
||
// Resolve the post ID if not set, and load its post. | ||
const postId = useTemplatePartPost( _postId, slug, theme ); | ||
|
||
// Set the post ID, once found, so that edits persist. | ||
useEffect( () => { | ||
if ( | ||
( initialPostId.current === undefined || initialPostId.current === null ) && | ||
postId !== undefined && | ||
postId !== null | ||
) { | ||
setAttributes( { postId } ); | ||
} | ||
}, [ postId ] ); | ||
|
||
if ( postId ) { | ||
// Part of a template file, post ID already resolved. | ||
return ( | ||
<EntityProvider kind="postType" type="wp_template_part" id={ postId }> | ||
<TemplatePartInnerBlocks /> | ||
</EntityProvider> | ||
); | ||
} | ||
if ( ! initialSlug.current && ! initialTheme.current ) { | ||
// Fresh new block. | ||
return <TemplatePartPlaceholder setAttributes={ setAttributes } />; | ||
} | ||
// Part of a template file, post ID not resolved yet. | ||
return null; | ||
} |
22 changes: 22 additions & 0 deletions
22
packages/block-library/src/template-part/edit/inner-blocks.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useEntityBlockEditor } from '@wordpress/core-data'; | ||
import { InnerBlocks } from '@wordpress/block-editor'; | ||
|
||
export default function TemplatePartInnerBlocks() { | ||
const [ blocks, onInput, onChange ] = useEntityBlockEditor( | ||
'postType', | ||
'wp_template_part', | ||
{ | ||
initialEdits: { status: 'publish' }, | ||
} | ||
); | ||
return ( | ||
<InnerBlocks | ||
__experimentalBlocks={ blocks } | ||
onInput={ onInput } | ||
onChange={ onChange } | ||
/> | ||
); | ||
} |
122 changes: 122 additions & 0 deletions
122
packages/block-library/src/template-part/edit/placeholder.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useEntityBlockEditor, EntityProvider } from '@wordpress/core-data'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { BlockPreview } from '@wordpress/block-editor'; | ||
import { useState, useCallback } from '@wordpress/element'; | ||
import { useSelect, useDispatch } from '@wordpress/data'; | ||
import { cleanForSlug } from '@wordpress/url'; | ||
import { Placeholder, TextControl, Button } from '@wordpress/components'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import useTemplatePartPost from './use-template-part-post'; | ||
|
||
function TemplatePartPreview() { | ||
const [ blocks ] = useEntityBlockEditor( 'postType', 'wp_template_part' ); | ||
return ( | ||
<div className="wp-block-template-part__placeholder-preview"> | ||
<div className="wp-block-template-part__placeholder-preview-title"> | ||
{ __( 'Preview' ) } | ||
</div> | ||
<BlockPreview blocks={ blocks } /> | ||
</div> | ||
); | ||
} | ||
|
||
export default function TemplatePartPlaceholder( { setAttributes } ) { | ||
const [ slug, _setSlug ] = useState(); | ||
const [ theme, setTheme ] = useState(); | ||
const [ help, setHelp ] = useState(); | ||
|
||
// Try to find an existing template part. | ||
const postId = useTemplatePartPost( null, slug, theme ); | ||
|
||
// If found, get its preview. | ||
const preview = useSelect( | ||
( select ) => { | ||
if ( ! postId ) { | ||
return; | ||
} | ||
const templatePart = select( 'core' ).getEntityRecord( | ||
'postType', | ||
'wp_template_part', | ||
postId | ||
); | ||
if ( templatePart ) { | ||
return ( | ||
<EntityProvider kind="postType" type="wp_template_part" id={ postId }> | ||
<TemplatePartPreview /> | ||
</EntityProvider> | ||
); | ||
} | ||
}, | ||
[ postId ] | ||
); | ||
|
||
const setSlug = useCallback( ( nextSlug ) => { | ||
_setSlug( nextSlug ); | ||
setHelp( cleanForSlug( nextSlug ) ); | ||
}, [] ); | ||
|
||
const { saveEntityRecord } = useDispatch( 'core' ); | ||
const onChooseOrCreate = useCallback( async () => { | ||
const nextAttributes = { slug, theme }; | ||
if ( postId !== undefined && postId !== null ) { | ||
// Existing template part found. | ||
nextAttributes.postId = postId; | ||
} else { | ||
// Create a new template part. | ||
try { | ||
const cleanSlug = cleanForSlug( slug ); | ||
const templatePart = await saveEntityRecord( | ||
'postType', | ||
'wp_template_part', | ||
{ | ||
title: cleanSlug, | ||
status: 'publish', | ||
slug: cleanSlug, | ||
meta: { theme }, | ||
} | ||
); | ||
nextAttributes.postId = templatePart.id; | ||
} catch ( err ) { | ||
setHelp( __( 'Error adding template.' ) ); | ||
} | ||
} | ||
setAttributes( nextAttributes ); | ||
}, [ postId, slug, theme ] ); | ||
return ( | ||
<Placeholder | ||
icon="layout" | ||
label={ __( 'Template Part' ) } | ||
instructions={ __( | ||
'Choose a template part by slug and theme, or create a new one.' | ||
) } | ||
> | ||
<div className="wp-block-template-part__placeholder-input-container"> | ||
<TextControl | ||
label={ __( 'Slug' ) } | ||
placeholder={ __( 'header' ) } | ||
value={ slug } | ||
onChange={ setSlug } | ||
help={ help } | ||
className="wp-block-template-part__placeholder-input" | ||
/> | ||
<TextControl | ||
label={ __( 'Theme' ) } | ||
placeholder={ __( 'twentytwenty' ) } | ||
value={ theme } | ||
onChange={ setTheme } | ||
className="wp-block-template-part__placeholder-input" | ||
/> | ||
</div> | ||
{ preview } | ||
<Button isPrimary disabled={ ! slug || ! theme } onClick={ onChooseOrCreate }> | ||
{ postId ? __( 'Choose' ) : __( 'Create' ) } | ||
</Button> | ||
</Placeholder> | ||
); | ||
} |
Oops, something went wrong.