-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Editor: Introduce a new dynamic templates mode and add basic post title and content blocks. #17263
Changes from all commits
6574cc7
4a60698
4231591
61556d8
f599c7e
d5f5129
fc18beb
42d9b6d
e2cdc43
de2b90e
b1b0d4a
3c29e6d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"name": "core/post-content", | ||
"category": "layout" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { | ||
useEntityId, | ||
useEntityProp, | ||
__experimentalUseEntitySaving, | ||
} from '@wordpress/core-data'; | ||
import { useMemo, useCallback } from '@wordpress/element'; | ||
import { parse } from '@wordpress/blocks'; | ||
import { Button } from '@wordpress/components'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { InnerBlocks } from '@wordpress/block-editor'; | ||
import { serializeBlocks } from '@wordpress/editor'; | ||
|
||
export default function PostContentEdit() { | ||
const postId = useEntityId( 'postType', 'post' ); | ||
const [ content, _setContent ] = useEntityProp( 'postType', 'post', 'content' ); | ||
const initialBlocks = useMemo( () => { | ||
if ( postId && typeof content !== 'function' ) { | ||
const parsedContent = parse( content ); | ||
return parsedContent.length ? parsedContent : undefined; | ||
} | ||
}, [] ); | ||
const [ blocks = initialBlocks, setBlocks ] = useEntityProp( | ||
'postType', | ||
'post', | ||
'blocks' | ||
); | ||
const [ isDirty, isSaving, save ] = __experimentalUseEntitySaving( | ||
'postType', | ||
'post', | ||
'content' | ||
); | ||
const saveContent = useCallback( () => { | ||
_setContent( content( { blocks } ) ); | ||
save(); | ||
}, [ content, blocks ] ); | ||
const setContent = useCallback( () => { | ||
_setContent( ( { blocks: blocksForSerialization = [] } ) => | ||
serializeBlocks( blocksForSerialization ) | ||
); | ||
}, [] ); | ||
return postId ? ( | ||
<> | ||
<Button | ||
isPrimary | ||
className="wp-block-custom-entity__save-button" | ||
disabled={ ! isDirty || ! content } | ||
isBusy={ isSaving } | ||
onClick={ saveContent } | ||
> | ||
{ __( 'Update' ) } | ||
</Button> | ||
<div className="entry-content"> | ||
<InnerBlocks value={ blocks } onChange={ setBlocks } onInput={ setContent } /> | ||
</div> | ||
</> | ||
) : ( | ||
'Post Content Placeholder' | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { SVG, Path } from '@wordpress/components'; | ||
|
||
export default ( | ||
<SVG xmlns="https://www.w3.org/2000/svg" viewBox="0 0 24 24"> | ||
<Path fill="none" d="M0 0h24v24H0V0z" /> | ||
<Path d="M3 15h18v-2H3v2zm0 4h18v-2H3v2zm0-8h18V9H3v2zm0-6v2h18V5H3z" /> | ||
</SVG> | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import metadata from './block.json'; | ||
import icon from './icon'; | ||
import edit from './edit'; | ||
|
||
const { name } = metadata; | ||
export { metadata, name }; | ||
|
||
export const settings = { | ||
title: __( 'Post Content' ), | ||
icon, | ||
edit, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<?php | ||
/** | ||
* Server-side rendering of the `core/post-content` block. | ||
* | ||
* @package WordPress | ||
*/ | ||
|
||
/** | ||
* Renders the `core/post-content` block on the server. | ||
* | ||
* @return string Returns the filtered post content of the current post. | ||
*/ | ||
function render_block_core_post_content() { | ||
// TODO: Without this temporary fix, an infinite loop can occur. | ||
if ( is_admin() || defined( 'REST_REQUEST' ) ) { | ||
return ''; | ||
} | ||
|
||
if ( ! in_the_loop() ) { | ||
rewind_posts(); | ||
the_post(); | ||
} | ||
|
||
return '<div class="entry-content">' . apply_filters( 'the_content', str_replace( ']]>', ']]>', get_the_content() ) ) . '</div>'; | ||
} | ||
|
||
/** | ||
* Registers the `core/post-content` block on the server. | ||
*/ | ||
function register_block_core_post_content() { | ||
register_block_type( | ||
'core/post-content', | ||
array( | ||
'render_callback' => 'render_block_core_post_content', | ||
) | ||
); | ||
} | ||
add_action( 'init', 'register_block_core_post_content' ); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"name": "core/post-title", | ||
"category": "layout" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { | ||
useEntityId, | ||
useEntityProp, | ||
__experimentalUseEntitySaving, | ||
} from '@wordpress/core-data'; | ||
import { useCallback } from '@wordpress/element'; | ||
import { Button } from '@wordpress/components'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { RichText } from '@wordpress/block-editor'; | ||
import { cleanForSlug } from '@wordpress/editor'; | ||
|
||
const saveProps = [ 'title', 'slug' ]; | ||
export default function PostTitleEdit() { | ||
const postId = useEntityId( 'postType', 'post' ); | ||
const [ title, _setTitle ] = useEntityProp( 'postType', 'post', 'title' ); | ||
const [ , setSlug ] = useEntityProp( 'postType', 'post', 'slug' ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The hard-coding of The problem is that the overall current post being edited appears to be overridden by this implementation, causing I'm a bit wary of overriding the current post context in Gutenberg to become a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The editor already supports editing multiple post types and the editor store has a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you referring to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I thought you were asking how to get the post type of the template. (The template is the actual post being edited after all.) You can get the post that uses the template through editor settings: const { postId, postType, templateId } = getEditorSettings() |
||
const [ isDirty, isSaving, save ] = __experimentalUseEntitySaving( | ||
'postType', | ||
'post', | ||
saveProps | ||
); | ||
const setTitle = useCallback( ( value ) => { | ||
_setTitle( value ); | ||
setSlug( cleanForSlug( value ) ); | ||
}, [] ); | ||
return postId ? ( | ||
<> | ||
<Button | ||
isPrimary | ||
className="wp-block-custom-entity__save-button" | ||
disabled={ ! isDirty || ! title } | ||
isBusy={ isSaving } | ||
onClick={ save } | ||
> | ||
{ __( 'Update' ) } | ||
</Button> | ||
<RichText | ||
tagName="h1" | ||
placeholder={ __( 'Title' ) } | ||
value={ title } | ||
onChange={ setTitle } | ||
allowedFormats={ [] } | ||
/> | ||
</> | ||
) : ( | ||
'Post Title Placeholder' | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { SVG, Path } from '@wordpress/components'; | ||
|
||
export default ( | ||
<SVG xmlns="https://www.w3.org/2000/svg" viewBox="0 0 24 24"> | ||
<Path fill="none" d="M0 0h24v24H0V0z" /> | ||
<Path d="M5 4v3h5.5v12h3V7H19V4H5z" /> | ||
</SVG> | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add inline comments as to how this fixes the infinite loop and why it occurs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@felixarntz
Interesting, are you sure you didn't have nested post content blocks?
What are the repercussions of this fix. Will returning an empty string like this affect anything? If not, I guess we can keep it.