From f592ccb89f74e7b13d2661fd8baf7847857a89d3 Mon Sep 17 00:00:00 2001 From: Jorge Date: Tue, 29 Nov 2022 23:15:10 +0000 Subject: [PATCH] Add: Modal to choose a start pattern on new templates. --- lib/blocks.php | 12 ++ ...utenberg-rest-templates-controller-6-2.php | 22 ++- .../components/block-patterns-list/index.js | 8 +- .../add-new-template/new-template.js | 17 +- .../edit-site/src/components/editor/index.js | 2 + .../start-template-options/index.js | 166 ++++++++++++++++++ .../start-template-options/style.scss | 59 +++++++ packages/edit-site/src/style.scss | 1 + 8 files changed, 264 insertions(+), 23 deletions(-) create mode 100644 packages/edit-site/src/components/start-template-options/index.js create mode 100644 packages/edit-site/src/components/start-template-options/style.scss diff --git a/lib/blocks.php b/lib/blocks.php index add72e77062cb3..ada0e86f73a879 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -352,3 +352,15 @@ function gutenberg_register_legacy_social_link_blocks() { } add_action( 'init', 'gutenberg_register_legacy_social_link_blocks' ); + +register_block_pattern( + 'custom-pattern', + array( + 'title' => _x( 'Start post pattern', 'Block pattern title', 'gutenberg' ), + 'blockTypes' => array( 'core/paragraph', 'core/post-content' ), + // 'postTypes' => array( 'page' ), + 'content' => ' +

A start post pattern

+', + ) +); diff --git a/lib/compat/wordpress-6.2/class-gutenberg-rest-templates-controller-6-2.php b/lib/compat/wordpress-6.2/class-gutenberg-rest-templates-controller-6-2.php index b91ff4180613eb..9931ec2b69188a 100644 --- a/lib/compat/wordpress-6.2/class-gutenberg-rest-templates-controller-6-2.php +++ b/lib/compat/wordpress-6.2/class-gutenberg-rest-templates-controller-6-2.php @@ -17,8 +17,7 @@ class Gutenberg_REST_Templates_Controller_6_2 extends Gutenberg_REST_Templates_C * @return void */ public function register_routes() { - parent::register_routes(); - // Get fallback template content. + register_rest_route( $this->namespace, '/' . $this->rest_base . '/lookup', @@ -41,10 +40,17 @@ public function register_routes() { 'description' => __( 'The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`', 'gutenberg' ), 'type' => 'string', ), + 'ignore_empty' => array( + 'description' => __( 'If true templates with empty content are ignored.', 'gutenberg' ), + 'type' => 'boolean', + 'default' => false, + ), ), ), ) ); + parent::register_routes(); + // Get fallback template content. } /** @@ -56,8 +62,16 @@ public function register_routes() { */ public function get_template_fallback( $request ) { $hierarchy = get_template_hierarchy( $request['slug'], $request['is_custom'], $request['template_prefix'] ); - $fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' ); - $response = $this->prepare_item_for_response( $fallback_template, $request ); + $fallback_template = null; + if ( true === $request['ignore_empty'] ) { + do { + $fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' ); + array_shift( $hierarchy ); + } while ( ! empty( $hierarchy ) && empty( $fallback_template->content ) ); + } else { + $fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' ); + } + $response = $this->prepare_item_for_response( $fallback_template, $request ); return rest_ensure_response( $response ); } } diff --git a/packages/block-editor/src/components/block-patterns-list/index.js b/packages/block-editor/src/components/block-patterns-list/index.js index 925410e760f6a4..63a51cdea6772a 100644 --- a/packages/block-editor/src/components/block-patterns-list/index.js +++ b/packages/block-editor/src/components/block-patterns-list/index.js @@ -49,9 +49,11 @@ function BlockPattern( { isDraggable, pattern, onClick, composite } ) { blocks={ blocks } viewportWidth={ viewportWidth } /> -
- { pattern.title } -
+ { pattern.title && ( +
+ { pattern.title } +
+ ) } { !! pattern.description && ( { pattern.description } diff --git a/packages/edit-site/src/components/add-new-template/new-template.js b/packages/edit-site/src/components/add-new-template/new-template.js index d8458246a8609b..0cc4f5d4e113d0 100644 --- a/packages/edit-site/src/components/add-new-template/new-template.js +++ b/packages/edit-site/src/components/add-new-template/new-template.js @@ -1,8 +1,6 @@ /** * WordPress dependencies */ -import apiFetch from '@wordpress/api-fetch'; -import { addQueryArgs } from '@wordpress/url'; import { DropdownMenu, MenuGroup, @@ -102,19 +100,7 @@ export default function NewTemplate( { postType } ) { } setIsCreatingTemplate( true ); try { - const { title, description, slug, templatePrefix } = template; - let templateContent = template.content; - // Try to find fallback content from existing templates. - if ( ! templateContent ) { - const fallbackTemplate = await apiFetch( { - path: addQueryArgs( '/wp/v2/templates/lookup', { - slug, - is_custom: ! isWPSuggestion, - template_prefix: templatePrefix, - } ), - } ); - templateContent = fallbackTemplate.content.raw; - } + const { title, description, slug } = template; const newTemplate = await saveEntityRecord( 'postType', 'wp_template', @@ -124,7 +110,6 @@ export default function NewTemplate( { postType } ) { slug: slug.toString(), status: 'publish', title, - content: templateContent, // This adds a post meta field in template that is part of `is_custom` value calculation. is_wp_suggestion: isWPSuggestion, }, diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 8ed10e81f626c7..e91863106ab173 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -35,6 +35,7 @@ import useInitEditedEntityFromURL from '../use-init-edited-entity-from-url'; import InserterSidebar from '../secondary-sidebar/inserter-sidebar'; import ListViewSidebar from '../secondary-sidebar/list-view-sidebar'; import WelcomeGuide from '../welcome-guide'; +import StartTemplateOptions from '../start-template-options'; import { store as editSiteStore } from '../../store'; import { GlobalStylesRenderer } from '../global-styles-renderer'; import { GlobalStylesProvider } from '../global-styles/global-styles-provider'; @@ -183,6 +184,7 @@ export default function Editor() { > + { + apiFetch( { + path: addQueryArgs( '/wp/v2/templates/lookup', { + slug, + is_custom: isCustom, + ignore_empty: true, + } ), + } ).then( ( { content } ) => setTemplateContent( content.raw ) ); + }, [ slug ] ); + return templateContent; +} + +function PatternSelection( { fallbackContent, onChoosePattern, postType } ) { + const [ , , onChange ] = useEntityBlockEditor( 'postType', postType ); + const blockPatterns = useMemo( + () => [ + { + name: 'fallback', + blocks: parse( fallbackContent ), + }, + { + name: 'start-blank', + blocks: parse( + '

' + ), + title: __( 'Start blank' ), + }, + ], + [ fallbackContent ] + ); + const shownBlockPatterns = useAsyncList( blockPatterns ); + return ( + { + onChange( 'start-blank' === pattern.name ? [] : blocks, { + selection: undefined, + } ); + onChoosePattern(); + } } + /> + ); +} + +function StartModal( { slug, isCustom, onClose, postType } ) { + const fallbackContent = useFallbackTemplateContent( slug, isCustom ); + if ( ! fallbackContent ) { + return null; + } + return ( + +
+ { + onClose(); + } } + /> +
+
+ ); +} + +const START_TEMPLATE_MODAL_STATES = { + INITIAL: 'INITIAL', + PATTERN: 'PATTERN', + CLOSED: 'CLOSED', +}; + +export default function StartTemplateOptions() { + const [ modalState, setModalState ] = useState( + START_TEMPLATE_MODAL_STATES.INITIAL + ); + const { shouldOpenModel, slug, isCustom, postType } = useSelect( + ( select ) => { + const { getEditedPostType, getEditedPostId } = + select( editSiteStore ); + const _postType = getEditedPostType(); + const postId = getEditedPostId(); + const { + __experimentalGetDirtyEntityRecords, + getEditedEntityRecord, + } = select( coreStore ); + const templateRecord = getEditedEntityRecord( + 'postType', + _postType, + postId + ); + + const hasDirtyEntityRecords = + __experimentalGetDirtyEntityRecords().length > 0; + + return { + shouldOpenModel: + modalState === START_TEMPLATE_MODAL_STATES.INITIAL && + ! hasDirtyEntityRecords && + '' === templateRecord.content && + 'wp_template' === _postType && + ! select( preferencesStore ).get( + 'core/edit-site', + 'welcomeGuide' + ), + slug: templateRecord.slug, + isCustom: templateRecord.is_custom, + postType: _postType, + }; + }, + [ modalState ] + ); + + useEffect( () => { + if ( shouldOpenModel ) { + setModalState( START_TEMPLATE_MODAL_STATES.PATTERN ); + } + }, [ shouldOpenModel ] ); + + if ( + modalState === START_TEMPLATE_MODAL_STATES.INITIAL || + modalState === START_TEMPLATE_MODAL_STATES.CLOSED + ) { + return null; + } + return ( + + setModalState( START_TEMPLATE_MODAL_STATES.CLOSED ) + } + /> + ); +} diff --git a/packages/edit-site/src/components/start-template-options/style.scss b/packages/edit-site/src/components/start-template-options/style.scss new file mode 100644 index 00000000000000..ec015ecb2b3f09 --- /dev/null +++ b/packages/edit-site/src/components/start-template-options/style.scss @@ -0,0 +1,59 @@ +.edit-site-start-template-options__modal.components-modal__frame { + // To keep modal dimensions consistent as subsections are navigated, width + // and height are used instead of max-(width/height). + @include break-small() { + width: calc(100% - #{ $grid-unit-20 * 2 }); + height: calc(100% - #{ $header-height * 2 }); + } + @include break-medium() { + width: 70%; + } + @include break-large() { + height: fit-content; + } +} + +// 2 column masonry layout. +.edit-site-start-template-options__modal-content .block-editor-block-patterns-list { + display: flex; + width: 100%; + margin-top: $grid-unit-05; + gap: $grid-unit-10; + + .block-editor-block-patterns-list__list-item { + break-inside: avoid-column; + margin-bottom: $grid-unit-30; + width: 240px; + + > div { + width: 240px !important; + } + + .block-editor-block-preview__container { + height: 320px; + width: 240px; + } + + .block-editor-block-preview__content { + width: 100%; + position: absolute; + } + } + + // The start blank pattern is the last and we are selecting it. + .block-editor-block-patterns-list__list-item:nth-last-child(2) { + .block-editor-block-patterns-list__item-title { + position: absolute; + padding: 0; + width: 100%; + top: 50%; + margin-top: -1em; + } + .block-editor-block-preview__container { + background: #f0f0f0; + } + iframe { + display: none; + } + } +} diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss index efc6187a39a6b0..9facad5a7a950f 100644 --- a/packages/edit-site/src/style.scss +++ b/packages/edit-site/src/style.scss @@ -16,6 +16,7 @@ @import "./components/create-template-part-modal/style.scss"; @import "./components/secondary-sidebar/style.scss"; @import "./components/welcome-guide/style.scss"; +@import "./components/start-template-options/style.scss"; @import "./components/keyboard-shortcut-help-modal/style.scss"; @import "./components/layout/style.scss"; @import "./components/sidebar/style.scss";