From 80089eafaf59ae47f6fdae66dd7c8dbeca744204 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Thu, 18 Nov 2021 01:27:55 +0800 Subject: [PATCH 1/5] Add "Add New" feature for templates list in Site Editor --- lib/full-site-editing/edit-site-page.php | 30 ++-- packages/base-styles/_z-index.scss | 2 +- .../src/components/add-new-template/index.js | 30 ++++ .../add-new-template/new-template-part.js | 66 ++++++++ .../add-new-template/new-template.js | 118 +++++++++++++++ .../components/add-new-template/style.scss | 11 ++ .../create-template-part-modal/index.js | 129 ++++++++++++++++ .../style.scss | 18 +-- .../edit-site/src/components/list/header.js | 14 +- .../edit-site/src/components/list/style.scss | 5 + .../convert-to-template-part.js | 142 ++---------------- packages/edit-site/src/index.js | 9 +- packages/edit-site/src/style.scss | 3 +- 13 files changed, 415 insertions(+), 162 deletions(-) create mode 100644 packages/edit-site/src/components/add-new-template/index.js create mode 100644 packages/edit-site/src/components/add-new-template/new-template-part.js create mode 100644 packages/edit-site/src/components/add-new-template/new-template.js create mode 100644 packages/edit-site/src/components/add-new-template/style.scss create mode 100644 packages/edit-site/src/components/create-template-part-modal/index.js rename packages/edit-site/src/components/{template-part-converter => create-template-part-modal}/style.scss (64%) diff --git a/lib/full-site-editing/edit-site-page.php b/lib/full-site-editing/edit-site-page.php index 3a0a8557ec5c7b..3ee017395b6eef 100644 --- a/lib/full-site-editing/edit-site-page.php +++ b/lib/full-site-editing/edit-site-page.php @@ -78,8 +78,10 @@ function gutenberg_get_editor_styles() { /** * Initialize the Gutenberg Templates List Page. + * + * @param array $settings The editor settings. */ -function gutenberg_edit_site_list_init() { +function gutenberg_edit_site_list_init( $settings ) { wp_enqueue_script( 'wp-edit-site' ); wp_enqueue_style( 'wp-edit-site' ); wp_enqueue_media(); @@ -111,10 +113,11 @@ function gutenberg_edit_site_list_init() { 'wp-edit-site', sprintf( 'wp.domReady( function() { - wp.editSite.initializeList( "%s", "%s" ); + wp.editSite.initializeList( "%s", "%s", %s ); } );', 'edit-site-editor', - $template_type + $template_type, + wp_json_encode( $settings ) ) ); } @@ -142,8 +145,18 @@ static function( $classes ) { } ); + $custom_settings = array( + 'siteUrl' => site_url(), + 'postsPerPage' => get_option( 'posts_per_page' ), + 'styles' => gutenberg_get_editor_styles(), + 'defaultTemplateTypes' => gutenberg_get_indexed_default_template_types(), + 'defaultTemplatePartAreas' => get_allowed_block_template_part_areas(), + '__experimentalBlockPatterns' => WP_Block_Patterns_Registry::get_instance()->get_all_registered(), + '__experimentalBlockPatternCategories' => WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(), + ); + if ( gutenberg_is_edit_site_list_page() ) { - return gutenberg_edit_site_list_init(); + return gutenberg_edit_site_list_init( $custom_settings ); } /** @@ -154,15 +167,6 @@ static function( $classes ) { */ $current_screen->is_block_editor( true ); - $custom_settings = array( - 'siteUrl' => site_url(), - 'postsPerPage' => get_option( 'posts_per_page' ), - 'styles' => gutenberg_get_editor_styles(), - 'defaultTemplateTypes' => gutenberg_get_indexed_default_template_types(), - 'defaultTemplatePartAreas' => get_allowed_block_template_part_areas(), - '__experimentalBlockPatterns' => WP_Block_Patterns_Registry::get_instance()->get_all_registered(), - '__experimentalBlockPatternCategories' => WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(), - ); $site_editor_context = new WP_Block_Editor_Context(); $settings = gutenberg_get_block_editor_settings( $custom_settings, $site_editor_context ); $active_global_styles_id = WP_Theme_JSON_Resolver_Gutenberg::get_user_custom_post_type_id(); diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss index d9651201a3873e..f1c59559f31fcb 100644 --- a/packages/base-styles/_z-index.scss +++ b/packages/base-styles/_z-index.scss @@ -139,7 +139,7 @@ $z-layers: ( // Should be above the popover (dropdown) ".reusable-blocks-menu-items__convert-modal": 1000001, - ".edit-site-template-part-converter__modal": 1000001, + ".edit-site-create-template-part-modal": 1000001, // ...Except for popovers immediately beneath wp-admin menu on large breakpoints ".components-popover.block-editor-inserter__popover": 99999, diff --git a/packages/edit-site/src/components/add-new-template/index.js b/packages/edit-site/src/components/add-new-template/index.js new file mode 100644 index 00000000000000..89abbc0aa4614c --- /dev/null +++ b/packages/edit-site/src/components/add-new-template/index.js @@ -0,0 +1,30 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; + +/** + * Internal dependencies + */ +import NewTemplate from './new-template'; +import NewTemplatePart from './new-template-part'; + +export default function AddNewTemplate( { templateType = 'wp_template' } ) { + const postType = useSelect( + ( select ) => select( coreStore ).getPostType( templateType ), + [ templateType ] + ); + + if ( ! postType ) { + return null; + } + + if ( templateType === 'wp_template' ) { + return ; + } else if ( templateType === 'wp_template_part' ) { + return ; + } + + return null; +} diff --git a/packages/edit-site/src/components/add-new-template/new-template-part.js b/packages/edit-site/src/components/add-new-template/new-template-part.js new file mode 100644 index 00000000000000..cbe6f2e8b1e0c9 --- /dev/null +++ b/packages/edit-site/src/components/add-new-template/new-template-part.js @@ -0,0 +1,66 @@ +/** + * External dependencies + */ +import { kebabCase } from 'lodash'; + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; +import { Button } from '@wordpress/components'; +import { useDispatch } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { addQueryArgs } from '@wordpress/url'; + +/** + * Internal dependencies + */ +import CreateTemplatePartModal from '../create-template-part-modal'; + +export default function NewTemplatePart( { postType } ) { + const [ isModalOpen, setIsModalOpen ] = useState( false ); + const { saveEntityRecord } = useDispatch( coreStore ); + + async function createTemplatePart( { title, area } ) { + if ( ! title || ! area ) { + return; + } + + const templatePart = await saveEntityRecord( + 'postType', + 'wp_template_part', + { + slug: kebabCase( title ), + title, + content: '', + area, + } + ); + + // Navigate to the created template part editor. + window.location.search = addQueryArgs( '', { + page: 'gutenberg-edit-site', + postId: templatePart.id, + postType: 'wp_template_part', + } ); + } + + return ( + <> + + { isModalOpen && ( + setIsModalOpen( false ) } + onCreate={ createTemplatePart } + /> + ) } + + ); +} 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 new file mode 100644 index 00000000000000..022090351941c8 --- /dev/null +++ b/packages/edit-site/src/components/add-new-template/new-template.js @@ -0,0 +1,118 @@ +/** + * External dependencies + */ +import { filter, find, includes, map } from 'lodash'; + +/** + * WordPress dependencies + */ +import { + DropdownMenu, + MenuGroup, + MenuItem, + NavigableMenu, +} from '@wordpress/components'; +import { useDispatch, useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { store as editorStore } from '@wordpress/editor'; +import { addQueryArgs } from '@wordpress/url'; + +/** + * Internal dependencies + */ +import { store as editSiteStore } from '../../store'; + +const DEFAULT_TEMPLATE_SLUGS = [ + 'front-page', + 'single-post', + 'page', + 'archive', + 'search', + '404', + 'index', +]; + +export default function NewTemplate( { postType } ) { + const { templates, defaultTemplateTypes } = useSelect( + ( select ) => ( { + templates: select( coreStore ).getEntityRecords( + 'postType', + 'wp_template' + ), + defaultTemplateTypes: select( + editorStore + ).__experimentalGetDefaultTemplateTypes(), + } ), + [] + ); + const { addTemplate } = useDispatch( editSiteStore ); + + async function createTemplate( slug ) { + const { title, description } = find( defaultTemplateTypes, { slug } ); + + const { templateId } = await addTemplate( { + excerpt: description, + // Slugs need to be strings, so this is for template `404` + slug: slug.toString(), + status: 'publish', + title, + } ); + + // Navigate to the created template editor. + window.location.search = addQueryArgs( '', { + page: 'gutenberg-edit-site', + postId: templateId, + postType: 'wp_template', + } ); + } + + const existingTemplateSlugs = map( templates, 'slug' ); + + const missingTemplates = filter( + defaultTemplateTypes, + ( template ) => + includes( DEFAULT_TEMPLATE_SLUGS, template.slug ) && + ! includes( existingTemplateSlugs, template.slug ) + ); + + if ( ! missingTemplates.length ) { + return null; + } + + return ( + + { ( { onClose } ) => ( + + + { map( + missingTemplates, + ( { title, description, slug } ) => ( + { + createTemplate( slug ); + onClose(); + } } + > + { title } + + ) + ) } + + + ) } + + ); +} diff --git a/packages/edit-site/src/components/add-new-template/style.scss b/packages/edit-site/src/components/add-new-template/style.scss new file mode 100644 index 00000000000000..78527882b330cf --- /dev/null +++ b/packages/edit-site/src/components/add-new-template/style.scss @@ -0,0 +1,11 @@ +.edit-site-new-template-dropdown { + .components-dropdown-menu__toggle { + padding: 6px 12px; + } + + .edit-site-new-template-dropdown__popover { + @include break-small() { + min-width: 300px; + } + } +} diff --git a/packages/edit-site/src/components/create-template-part-modal/index.js b/packages/edit-site/src/components/create-template-part-modal/index.js new file mode 100644 index 00000000000000..a0644fe7701ceb --- /dev/null +++ b/packages/edit-site/src/components/create-template-part-modal/index.js @@ -0,0 +1,129 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { + Icon, + BaseControl, + TextControl, + Flex, + FlexItem, + FlexBlock, + Button, + Modal, + __experimentalRadioGroup as RadioGroup, + __experimentalRadio as Radio, +} from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { useState } from '@wordpress/element'; +import { useInstanceId } from '@wordpress/compose'; +import { store as editorStore } from '@wordpress/editor'; +import { check } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +import { TEMPLATE_PART_AREA_GENERAL } from '../../store/constants'; + +export default function CreateTemplatePartModal( { closeModal, onCreate } ) { + const [ title, setTitle ] = useState( '' ); + const [ area, setArea ] = useState( TEMPLATE_PART_AREA_GENERAL ); + const instanceId = useInstanceId( CreateTemplatePartModal ); + + const templatePartAreas = useSelect( + ( select ) => + select( editorStore ).__experimentalGetDefaultTemplatePartAreas(), + [] + ); + + return ( + +
{ + event.preventDefault(); + if ( ! title || ! area ) { + return; + } + await onCreate( { title, area } ); + closeModal(); + } } + > + + + + { templatePartAreas.map( + ( { icon, label, area: value, description } ) => ( + + + + + + + { label } +
{ description }
+
+ + + { area === value && ( + + ) } + +
+
+ ) + ) } +
+
+ + + + + + + + + +
+ ); +} diff --git a/packages/edit-site/src/components/template-part-converter/style.scss b/packages/edit-site/src/components/create-template-part-modal/style.scss similarity index 64% rename from packages/edit-site/src/components/template-part-converter/style.scss rename to packages/edit-site/src/components/create-template-part-modal/style.scss index 9a3ab7aa41c742..71bba3db9974d1 100644 --- a/packages/edit-site/src/components/template-part-converter/style.scss +++ b/packages/edit-site/src/components/create-template-part-modal/style.scss @@ -1,5 +1,5 @@ -.edit-site-template-part-converter__modal { - z-index: z-index(".edit-site-template-part-converter__modal"); +.edit-site-create-template-part-modal { + z-index: z-index(".edit-site-create-template-part-modal"); .components-modal__frame { @include break-small { @@ -9,21 +9,21 @@ } -.edit-site-template-part-converter__convert-modal-actions { +.edit-site-create-template-part-modal__modal-actions { padding-top: $grid-unit-15; } -.edit-site-template-part-converter__area-base-control .components-base-control__label { +.edit-site-create-template-part-modal__area-base-control .components-base-control__label { margin: $grid-unit-20 0 $grid-unit-10; cursor: auto; } -.edit-site-template-part-converter__area-radio-group { +.edit-site-create-template-part-modal__area-radio-group { width: 100%; border: $border-width solid $gray-700; border-radius: 2px; - .components-button.edit-site-template-part-converter__area-radio { + .components-button.edit-site-create-template-part-modal__area-radio { display: block; width: 100%; height: 100%; @@ -56,12 +56,12 @@ color: $gray-900; cursor: auto; - .edit-site-template-part-converter__option-label div { + .edit-site-create-template-part-modal__option-label div { color: $gray-600; } } - .edit-site-template-part-converter__option-label { + .edit-site-create-template-part-modal__option-label { padding-top: $grid-unit-05; white-space: normal; @@ -71,7 +71,7 @@ } } - .edit-site-template-part-converter__checkbox { + .edit-site-create-template-part-modal__checkbox { margin-left: auto; min-width: $grid-unit-30; } diff --git a/packages/edit-site/src/components/list/header.js b/packages/edit-site/src/components/list/header.js index e090dddfb33116..4f98ecf7843d5b 100644 --- a/packages/edit-site/src/components/list/header.js +++ b/packages/edit-site/src/components/list/header.js @@ -3,10 +3,12 @@ */ import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; -import { - __experimentalHeading as Heading, - Button, -} from '@wordpress/components'; +import { __experimentalHeading as Heading } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import AddNewTemplate from '../add-new-template'; export default function Header( { templateType } ) { const postType = useSelect( @@ -24,8 +26,8 @@ export default function Header( { templateType } ) { { postType.labels?.name } -
- +
+
); diff --git a/packages/edit-site/src/components/list/style.scss b/packages/edit-site/src/components/list/style.scss index 972bda61d6effb..e044aaf052f7f1 100644 --- a/packages/edit-site/src/components/list/style.scss +++ b/packages/edit-site/src/components/list/style.scss @@ -27,6 +27,11 @@ } } +.edit-site-list-header__right { + // Creating a stacking context so that it won't be covered by title. + position: relative; +} + .edit-site { .edit-site-list { .interface-interface-skeleton__editor { diff --git a/packages/edit-site/src/components/template-part-converter/convert-to-template-part.js b/packages/edit-site/src/components/template-part-converter/convert-to-template-part.js index 7274344816f1f0..d4cf5c8da842a1 100644 --- a/packages/edit-site/src/components/template-part-converter/convert-to-template-part.js +++ b/packages/edit-site/src/components/template-part-converter/convert-to-template-part.js @@ -6,61 +6,36 @@ import { kebabCase } from 'lodash'; /** * WordPress dependencies */ -import { useDispatch, useSelect } from '@wordpress/data'; +import { useDispatch } from '@wordpress/data'; import { BlockSettingsMenuControls, store as blockEditorStore, } from '@wordpress/block-editor'; -import { - MenuItem, - Icon, - BaseControl, - TextControl, - Flex, - FlexItem, - FlexBlock, - Button, - Modal, - __experimentalRadioGroup as RadioGroup, - __experimentalRadio as Radio, -} from '@wordpress/components'; -import { useInstanceId } from '@wordpress/compose'; +import { MenuItem } from '@wordpress/components'; import { createBlock, serialize } from '@wordpress/blocks'; import { __ } from '@wordpress/i18n'; import { useState } from '@wordpress/element'; import { store as coreStore } from '@wordpress/core-data'; import { store as noticesStore } from '@wordpress/notices'; -import { store as editorStore } from '@wordpress/editor'; -import { check } from '@wordpress/icons'; /** * Internal dependencies */ -import { TEMPLATE_PART_AREA_GENERAL } from '../../store/constants'; +import CreateTemplatePartModal from '../create-template-part-modal'; export default function ConvertToTemplatePart( { clientIds, blocks } ) { - const instanceId = useInstanceId( ConvertToTemplatePart ); const [ isModalOpen, setIsModalOpen ] = useState( false ); - const [ title, setTitle ] = useState( '' ); const { replaceBlocks } = useDispatch( blockEditorStore ); const { saveEntityRecord } = useDispatch( coreStore ); const { createSuccessNotice } = useDispatch( noticesStore ); - const [ area, setArea ] = useState( TEMPLATE_PART_AREA_GENERAL ); - - const templatePartAreas = useSelect( - ( select ) => - select( editorStore ).__experimentalGetDefaultTemplatePartAreas(), - [] - ); - const onConvert = async ( templatePartTitle ) => { - const defaultTitle = __( 'Untitled Template Part' ); + const onConvert = async ( { title, area } ) => { const templatePart = await saveEntityRecord( 'postType', 'wp_template_part', { - slug: kebabCase( templatePartTitle || defaultTitle ), - title: templatePartTitle || defaultTitle, + slug: kebabCase( title ), + title, content: serialize( blocks ), area, } @@ -84,113 +59,18 @@ export default function ConvertToTemplatePart( { clientIds, blocks } ) { { setIsModalOpen( true ); + onClose(); } } > { __( 'Make template part' ) } { isModalOpen && ( - { + { setIsModalOpen( false ); - setTitle( '' ); } } - overlayClassName="edit-site-template-part-converter__modal" - > -
{ - event.preventDefault(); - onConvert( title ); - setIsModalOpen( false ); - setTitle( '' ); - onClose(); - } } - > - - - - { templatePartAreas.map( - ( { - icon, - label, - area: value, - description, - } ) => ( - - - - - - - { label } -
- { description } -
-
- - - { area === - value && ( - - ) } - -
-
- ) - ) } -
-
- - - - - - - - - -
+ onCreate={ onConvert } + /> ) } ) } diff --git a/packages/edit-site/src/index.js b/packages/edit-site/src/index.js index 83f918dc63a941..9b9a00a7a3e54c 100644 --- a/packages/edit-site/src/index.js +++ b/packages/edit-site/src/index.js @@ -12,6 +12,7 @@ import { __experimentalFetchLinkSuggestions as fetchLinkSuggestions, __experimentalFetchUrlData as fetchUrlData, } from '@wordpress/core-data'; +import { store as editorStore } from '@wordpress/editor'; /** * Internal dependencies @@ -73,10 +74,16 @@ export function initializeEditor( id, settings ) { * * @param {string} id ID of the root element to render the screen in. * @param {string} templateType The type of the list. "wp_template" or "wp_template_part". + * @param {Object} settings Editor settings. */ -export function initializeList( id, templateType ) { +export function initializeList( id, templateType, settings ) { const target = document.getElementById( id ); + dispatch( editorStore ).updateEditorSettings( { + defaultTemplateTypes: settings.defaultTemplateTypes, + defaultTemplatePartAreas: settings.defaultTemplatePartAreas, + } ); + render( , target ); } diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss index 56dddd41499ee6..6502a0ae1dd51c 100644 --- a/packages/edit-site/src/style.scss +++ b/packages/edit-site/src/style.scss @@ -8,12 +8,13 @@ @import "./components/navigation-sidebar/navigation-toggle/style.scss"; @import "./components/navigation-sidebar/navigation-panel/style.scss"; @import "./components/list/style.scss"; +@import "./components/add-new-template/style.scss"; @import "./components/sidebar/style.scss"; @import "./components/sidebar/settings-header/style.scss"; @import "./components/sidebar/template-card/style.scss"; @import "./components/editor/style.scss"; @import "./components/template-details/style.scss"; -@import "./components/template-part-converter/style.scss"; +@import "./components/create-template-part-modal/style.scss"; @import "./components/secondary-sidebar/style.scss"; @import "./components/welcome-guide/style.scss"; From 4dc55a5ab6210bcbeaa552a8fffef37ea0cead10 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Thu, 18 Nov 2021 16:35:33 +0800 Subject: [PATCH 2/5] Fix e2e test --- packages/e2e-tests/specs/experiments/template-part.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e-tests/specs/experiments/template-part.test.js b/packages/e2e-tests/specs/experiments/template-part.test.js index 8f18da2b88006e..f670d9026c1447 100644 --- a/packages/e2e-tests/specs/experiments/template-part.test.js +++ b/packages/e2e-tests/specs/experiments/template-part.test.js @@ -19,7 +19,7 @@ import { import { siteEditor } from '../../experimental-features'; const templatePartNameInput = - '.edit-site-template-part-converter__modal .components-text-control__input'; + '.edit-site-create-template-part-modal .components-text-control__input'; describe( 'Template Part', () => { beforeAll( async () => { From f5565a5b2a94c8eb1ab9b6d571567f29cc1b3e4c Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Thu, 18 Nov 2021 19:12:46 +0800 Subject: [PATCH 3/5] Fix modal not opened when making template part --- .../convert-to-template-part.js | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/edit-site/src/components/template-part-converter/convert-to-template-part.js b/packages/edit-site/src/components/template-part-converter/convert-to-template-part.js index d4cf5c8da842a1..35f8428b60dac3 100644 --- a/packages/edit-site/src/components/template-part-converter/convert-to-template-part.js +++ b/packages/edit-site/src/components/template-part-converter/convert-to-template-part.js @@ -53,9 +53,9 @@ export default function ConvertToTemplatePart( { clientIds, blocks } ) { }; return ( - - { ( { onClose } ) => ( - <> + <> + + { ( { onClose } ) => ( { setIsModalOpen( true ); @@ -64,16 +64,16 @@ export default function ConvertToTemplatePart( { clientIds, blocks } ) { > { __( 'Make template part' ) } - { isModalOpen && ( - { - setIsModalOpen( false ); - } } - onCreate={ onConvert } - /> - ) } - + ) } + + { isModalOpen && ( + { + setIsModalOpen( false ); + } } + onCreate={ onConvert } + /> ) } - + ); } From cd5bfea2dca5c95d891c910cc87d97095a4bc87c Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Fri, 19 Nov 2021 11:21:26 +0800 Subject: [PATCH 4/5] Code review --- .../add-new-template/new-template-part.js | 21 +++++------ .../add-new-template/new-template.js | 35 +++++++++---------- .../create-template-part-modal/index.js | 9 +++-- packages/edit-site/src/store/actions.js | 3 +- 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/packages/edit-site/src/components/add-new-template/new-template-part.js b/packages/edit-site/src/components/add-new-template/new-template-part.js index cbe6f2e8b1e0c9..94b51a1a99c78a 100644 --- a/packages/edit-site/src/components/add-new-template/new-template-part.js +++ b/packages/edit-site/src/components/add-new-template/new-template-part.js @@ -8,9 +8,8 @@ import { kebabCase } from 'lodash'; */ import { useState } from '@wordpress/element'; import { Button } from '@wordpress/components'; -import { useDispatch } from '@wordpress/data'; -import { store as coreStore } from '@wordpress/core-data'; import { addQueryArgs } from '@wordpress/url'; +import apiFetch from '@wordpress/api-fetch'; /** * Internal dependencies @@ -19,23 +18,22 @@ import CreateTemplatePartModal from '../create-template-part-modal'; export default function NewTemplatePart( { postType } ) { const [ isModalOpen, setIsModalOpen ] = useState( false ); - const { saveEntityRecord } = useDispatch( coreStore ); async function createTemplatePart( { title, area } ) { - if ( ! title || ! area ) { + if ( ! title ) { return; } - const templatePart = await saveEntityRecord( - 'postType', - 'wp_template_part', - { + const templatePart = await apiFetch( { + path: '/wp/v2/template-parts', + method: 'POST', + data: { slug: kebabCase( title ), title, content: '', area, - } - ); + }, + } ); // Navigate to the created template part editor. window.location.search = addQueryArgs( '', { @@ -43,6 +41,9 @@ export default function NewTemplatePart( { postType } ) { postId: templatePart.id, postType: 'wp_template_part', } ); + + // Wait for async navigation to happen before closing the modal. + await new Promise( () => {} ); } return ( 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 022090351941c8..55719e6ec71bb7 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 @@ -12,15 +12,11 @@ import { MenuItem, NavigableMenu, } from '@wordpress/components'; -import { useDispatch, useSelect } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; import { store as editorStore } from '@wordpress/editor'; import { addQueryArgs } from '@wordpress/url'; - -/** - * Internal dependencies - */ -import { store as editSiteStore } from '../../store'; +import apiFetch from '@wordpress/api-fetch'; const DEFAULT_TEMPLATE_SLUGS = [ 'front-page', @@ -45,23 +41,26 @@ export default function NewTemplate( { postType } ) { } ), [] ); - const { addTemplate } = useDispatch( editSiteStore ); - async function createTemplate( slug ) { + async function createTemplate( { slug } ) { const { title, description } = find( defaultTemplateTypes, { slug } ); - const { templateId } = await addTemplate( { - excerpt: description, - // Slugs need to be strings, so this is for template `404` - slug: slug.toString(), - status: 'publish', - title, + const template = await apiFetch( { + path: '/wp/v2/templates', + method: 'POST', + data: { + excerpt: description, + // Slugs need to be strings, so this is for template `404` + slug: slug.toString(), + status: 'publish', + title, + }, } ); // Navigate to the created template editor. window.location.search = addQueryArgs( '', { page: 'gutenberg-edit-site', - postId: templateId, + postId: template.id, postType: 'wp_template', } ); } @@ -92,7 +91,7 @@ export default function NewTemplate( { postType } ) { variant: 'primary', } } > - { ( { onClose } ) => ( + { () => ( { map( @@ -102,8 +101,8 @@ export default function NewTemplate( { postType } ) { info={ description } key={ slug } onClick={ () => { - createTemplate( slug ); - onClose(); + createTemplate( { slug } ); + // We will be navigated way so no need to close the dropdown. } } > { title } diff --git a/packages/edit-site/src/components/create-template-part-modal/index.js b/packages/edit-site/src/components/create-template-part-modal/index.js index a0644fe7701ceb..bbdf7434a466b8 100644 --- a/packages/edit-site/src/components/create-template-part-modal/index.js +++ b/packages/edit-site/src/components/create-template-part-modal/index.js @@ -28,6 +28,7 @@ import { TEMPLATE_PART_AREA_GENERAL } from '../../store/constants'; export default function CreateTemplatePartModal( { closeModal, onCreate } ) { const [ title, setTitle ] = useState( '' ); const [ area, setArea ] = useState( TEMPLATE_PART_AREA_GENERAL ); + const [ isSubmitting, setIsSubmitting ] = useState( false ); const instanceId = useInstanceId( CreateTemplatePartModal ); const templatePartAreas = useSelect( @@ -46,10 +47,12 @@ export default function CreateTemplatePartModal( { closeModal, onCreate } ) {
{ event.preventDefault(); - if ( ! title || ! area ) { + if ( ! title ) { return; } + setIsSubmitting( true ); await onCreate( { title, area } ); + setIsSubmitting( false ); closeModal(); } } > @@ -70,7 +73,6 @@ export default function CreateTemplatePartModal( { closeModal, onCreate } ) { id={ `edit-site-create-template-part-modal__area-selection-${ instanceId }` } onChange={ setArea } checked={ area } - required > { templatePartAreas.map( ( { icon, label, area: value, description } ) => ( @@ -117,7 +119,8 @@ export default function CreateTemplatePartModal( { closeModal, onCreate } ) { diff --git a/packages/edit-site/src/store/actions.js b/packages/edit-site/src/store/actions.js index 3b46c91ed2ead6..4f9dc3f4184898 100644 --- a/packages/edit-site/src/store/actions.js +++ b/packages/edit-site/src/store/actions.js @@ -116,7 +116,8 @@ export function* removeTemplate( template ) { 'deleteEntityRecord', 'postType', template.type, - template.id + template.id, + { force: true } ); } From 6a07f633fd60058fac248825c5b3a5b34ca29eb4 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Fri, 19 Nov 2021 11:54:21 +0800 Subject: [PATCH 5/5] Fix unit test --- packages/edit-site/src/store/test/actions.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/edit-site/src/store/test/actions.js b/packages/edit-site/src/store/test/actions.js index 52532cbd612e1c..5d45a0f0556cad 100644 --- a/packages/edit-site/src/store/test/actions.js +++ b/packages/edit-site/src/store/test/actions.js @@ -86,7 +86,12 @@ describe( 'actions', () => { const it = removeTemplate( template ); expect( it.next().value ).toEqual( { actionName: 'deleteEntityRecord', - args: [ 'postType', 'wp_template_part', 'tt1-blocks//general' ], + args: [ + 'postType', + 'wp_template_part', + 'tt1-blocks//general', + { force: true }, + ], storeKey: 'core', type: '@@data/DISPATCH', } );