From 10f631b05c4cf4736100ba9643cf0ef8d0f0e2fd Mon Sep 17 00:00:00 2001 From: Andy Peatling Date: Thu, 12 Jan 2023 10:19:22 -0800 Subject: [PATCH] Move slug and title functions to shared utils file. Make sure the title is unique on conversion. (#47082) --- .../add-new-template/new-template-part.js | 43 ++++--------- .../src/components/add-new-template/utils.js | 14 ----- .../convert-to-template-part.js | 22 ++++--- .../src/utils/template-part-create.js | 62 +++++++++++++++++++ 4 files changed, 85 insertions(+), 56 deletions(-) create mode 100644 packages/edit-site/src/utils/template-part-create.js 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 377a5c56f7fe5..eb46c3e497bbc 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 @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import { kebabCase } from 'lodash'; - /** * WordPress dependencies */ @@ -20,7 +15,11 @@ import { plus } from '@wordpress/icons'; import { useHistory } from '../routes'; import { store as editSiteStore } from '../../store'; import CreateTemplatePartModal from '../create-template-part-modal'; -import { useExistingTemplateParts } from './utils'; +import { + useExistingTemplateParts, + getUniqueTemplatePartTitle, + getCleanTemplatePartSlug, +} from '../../utils/template-part-create'; export default function NewTemplatePart( { postType, @@ -42,39 +41,19 @@ export default function NewTemplatePart( { return; } - const uniqueTitle = () => { - const lowercaseTitle = title.toLowerCase(); - const existingTitles = existingTemplateParts.map( - ( templatePart ) => templatePart.title.rendered.toLowerCase() - ); - - if ( ! existingTitles.includes( lowercaseTitle ) ) { - return title; - } - - let suffix = 2; - while ( - existingTitles.includes( `${ lowercaseTitle } ${ suffix }` ) - ) { - suffix++; - } - - return `${ title } ${ suffix }`; - }; - try { - // Currently template parts only allow latin chars. - // Fallback slug will receive suffix by default. - const cleanSlug = - kebabCase( title ).replace( /[^\w-]+/g, '' ) || - 'wp-custom-part'; + const cleanSlug = getCleanTemplatePartSlug( title ); + const uniqueTitle = getUniqueTemplatePartTitle( + title, + existingTemplateParts + ); const templatePart = await saveEntityRecord( 'postType', 'wp_template_part', { slug: cleanSlug, - title: uniqueTitle(), + title: uniqueTitle, content: '', area, }, diff --git a/packages/edit-site/src/components/add-new-template/utils.js b/packages/edit-site/src/components/add-new-template/utils.js index 03bd184a8af60..7309f2ff711ca 100644 --- a/packages/edit-site/src/components/add-new-template/utils.js +++ b/packages/edit-site/src/components/add-new-template/utils.js @@ -52,20 +52,6 @@ export const useExistingTemplates = () => { ); }; -export const useExistingTemplateParts = () => { - return useSelect( - ( select ) => - select( coreStore ).getEntityRecords( - 'postType', - 'wp_template_part', - { - per_page: -1, - } - ), - [] - ); -}; - export const useDefaultTemplateTypes = () => { return useSelect( ( select ) => 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 e518614044015..bfe9f2f46337c 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 @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import { kebabCase } from 'lodash'; - /** * WordPress dependencies */ @@ -24,12 +19,18 @@ import { symbolFilled } from '@wordpress/icons'; */ import CreateTemplatePartModal from '../create-template-part-modal'; import { store as editSiteStore } from '../../store'; +import { + useExistingTemplateParts, + getUniqueTemplatePartTitle, + getCleanTemplatePartSlug, +} from '../../utils/template-part-create'; export default function ConvertToTemplatePart( { clientIds, blocks } ) { const [ isModalOpen, setIsModalOpen ] = useState( false ); const { replaceBlocks } = useDispatch( blockEditorStore ); const { saveEntityRecord } = useDispatch( coreStore ); const { createSuccessNotice } = useDispatch( noticesStore ); + const existingTemplateParts = useExistingTemplateParts(); const { canCreate } = useSelect( ( select ) => { const { supportsTemplatePartsMode } = @@ -44,17 +45,18 @@ export default function ConvertToTemplatePart( { clientIds, blocks } ) { } const onConvert = async ( { title, area } ) => { - // Currently template parts only allow latin chars. - // Fallback slug will receive suffix by default. - const cleanSlug = - kebabCase( title ).replace( /[^\w-]+/g, '' ) || 'wp-custom-part'; + const cleanSlug = getCleanTemplatePartSlug( title ); + const uniqueTitle = getUniqueTemplatePartTitle( + title, + existingTemplateParts + ); const templatePart = await saveEntityRecord( 'postType', 'wp_template_part', { slug: cleanSlug, - title, + title: uniqueTitle, content: serialize( blocks ), area, } diff --git a/packages/edit-site/src/utils/template-part-create.js b/packages/edit-site/src/utils/template-part-create.js new file mode 100644 index 0000000000000..3c0fa14cbf7ad --- /dev/null +++ b/packages/edit-site/src/utils/template-part-create.js @@ -0,0 +1,62 @@ +/** + * External dependencies + */ +import { kebabCase } from 'lodash'; + +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; + +export const useExistingTemplateParts = () => { + return useSelect( + ( select ) => + select( coreStore ).getEntityRecords( + 'postType', + 'wp_template_part', + { + per_page: -1, + } + ), + [] + ); +}; + +/** + * Return a unique template part title based on + * the given title and existing template parts. + * + * @param {string} title The original template part title. + * @param {Object} templateParts The array of template part entities. + * @return {string} A unique template part title. + */ +export const getUniqueTemplatePartTitle = ( title, templateParts ) => { + const lowercaseTitle = title.toLowerCase(); + const existingTitles = templateParts.map( ( templatePart ) => + templatePart.title.rendered.toLowerCase() + ); + + if ( ! existingTitles.includes( lowercaseTitle ) ) { + return title; + } + + let suffix = 2; + while ( existingTitles.includes( `${ lowercaseTitle } ${ suffix }` ) ) { + suffix++; + } + + return `${ title } ${ suffix }`; +}; + +/** + * Get a valid slug for a template part. + * Currently template parts only allow latin chars. + * The fallback slug will receive suffix by default. + * + * @param {string} title The template part title. + * @return {string} A valid template part slug. + */ +export const getCleanTemplatePartSlug = ( title ) => { + return kebabCase( title ).replace( /[^\w-]+/g, '' ) || 'wp-custom-part'; +};