From 829d078a68f5f03b282bf8b33db6c3977d9b665f Mon Sep 17 00:00:00 2001 From: tjcafferkey Date: Wed, 31 Aug 2022 16:31:01 +0100 Subject: [PATCH 1/3] If user has created a template for a specific product, find the closest matching template details --- assets/js/blocks/classic-template/index.tsx | 51 +++++++++++++++------ 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/assets/js/blocks/classic-template/index.tsx b/assets/js/blocks/classic-template/index.tsx index 2bbf623b1c8..265209b05f0 100644 --- a/assets/js/blocks/classic-template/index.tsx +++ b/assets/js/blocks/classic-template/index.tsx @@ -27,6 +27,20 @@ import './editor.scss'; import './style.scss'; import { BLOCK_SLUG, TEMPLATES } from './constants'; +const templates = Object.keys( TEMPLATES ); + +const getTemplateDetailsBySlug = ( parsedTemplate: string ) => { + let templateSlug = null; + for ( let i = 0; templates.length > i; i++ ) { + if ( parsedTemplate.includes( templates[ i ] ) ) { + templateSlug = templates[ i ]; + break; + } + } + + return templateSlug ? TEMPLATES[ templateSlug ] : null; +}; + type Attributes = { template: string; align: string; @@ -40,10 +54,9 @@ const Edit = ( { const { replaceBlock } = useDispatch( 'core/block-editor' ); const blockProps = useBlockProps(); - const templateTitle = - TEMPLATES[ attributes.template ]?.title ?? attributes.template; - const templatePlaceholder = - TEMPLATES[ attributes.template ]?.placeholder ?? 'fallback'; + const templateDetails = getTemplateDetailsBySlug( attributes.template ); + const templateTitle = templateDetails?.title ?? attributes.template; + const templatePlaceholder = templateDetails?.placeholder ?? 'fallback'; useEffect( () => @@ -118,8 +131,6 @@ const Edit = ( { ); }; -const templates = Object.keys( TEMPLATES ); - const registerClassicTemplateBlock = ( { template, inserter, @@ -136,12 +147,13 @@ const registerClassicTemplateBlock = ( { * See https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues/5861 for more context */ registerBlockType( BLOCK_SLUG, { - title: template - ? TEMPLATES[ template ].title - : __( - 'WooCommerce Classic Template', - 'woo-gutenberg-products-block' - ), + title: + template && TEMPLATES[ template ] + ? TEMPLATES[ template ].title + : __( + 'WooCommerce Classic Template', + 'woo-gutenberg-products-block' + ), icon: ( block?.title !== TEMPLATES[ parsedTemplate ].title; -const hasTemplateSupportForClassicTemplateBlock = ( parsedTemplate: string ) => - templates.includes( parsedTemplate ); +const hasTemplateSupportForClassicTemplateBlock = ( + parsedTemplate: string +) => { + let hasSupport = false; + for ( let i = 0; templates.length > i; i++ ) { + if ( parsedTemplate.includes( templates[ i ] ) ) { + hasSupport = true; + break; + } + } + + return hasSupport; +}; // @todo Refactor when there will be possible to show a block according on a template/post with a Gutenberg API. https://github.com/WordPress/gutenberg/pull/41718 From c83d4eedcbf6e5164c86e40146ebe607a4a04533 Mon Sep 17 00:00:00 2001 From: tjcafferkey Date: Thu, 1 Sep 2022 09:56:44 +0100 Subject: [PATCH 2/3] Move Classic Template functions into Utils file and refactor function for specific template names --- assets/js/blocks/classic-template/index.tsx | 40 +++-------------- assets/js/blocks/classic-template/utils.ts | 50 +++++++++++++++++++++ 2 files changed, 55 insertions(+), 35 deletions(-) create mode 100644 assets/js/blocks/classic-template/utils.ts diff --git a/assets/js/blocks/classic-template/index.tsx b/assets/js/blocks/classic-template/index.tsx index 265209b05f0..2506c3f2383 100644 --- a/assets/js/blocks/classic-template/index.tsx +++ b/assets/js/blocks/classic-template/index.tsx @@ -2,7 +2,6 @@ * External dependencies */ import { - Block, BlockEditProps, createBlock, getBlockType, @@ -26,20 +25,11 @@ import { useEffect } from '@wordpress/element'; import './editor.scss'; import './style.scss'; import { BLOCK_SLUG, TEMPLATES } from './constants'; - -const templates = Object.keys( TEMPLATES ); - -const getTemplateDetailsBySlug = ( parsedTemplate: string ) => { - let templateSlug = null; - for ( let i = 0; templates.length > i; i++ ) { - if ( parsedTemplate.includes( templates[ i ] ) ) { - templateSlug = templates[ i ]; - break; - } - } - - return templateSlug ? TEMPLATES[ templateSlug ] : null; -}; +import { + isClassicTemplateBlockRegisteredWithAnotherTitle, + hasTemplateSupportForClassicTemplateBlock, + getTemplateDetailsBySlug, +} from './utils'; type Attributes = { template: string; @@ -214,26 +204,6 @@ const registerClassicTemplateBlock = ( { } ); }; -const isClassicTemplateBlockRegisteredWithAnotherTitle = ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - block: Block< any > | undefined, - parsedTemplate: string -) => block?.title !== TEMPLATES[ parsedTemplate ].title; - -const hasTemplateSupportForClassicTemplateBlock = ( - parsedTemplate: string -) => { - let hasSupport = false; - for ( let i = 0; templates.length > i; i++ ) { - if ( parsedTemplate.includes( templates[ i ] ) ) { - hasSupport = true; - break; - } - } - - return hasSupport; -}; - // @todo Refactor when there will be possible to show a block according on a template/post with a Gutenberg API. https://github.com/WordPress/gutenberg/pull/41718 let currentTemplateId: string | undefined; diff --git a/assets/js/blocks/classic-template/utils.ts b/assets/js/blocks/classic-template/utils.ts new file mode 100644 index 00000000000..f8c43ebb4db --- /dev/null +++ b/assets/js/blocks/classic-template/utils.ts @@ -0,0 +1,50 @@ +/** + * External dependencies + */ +import { Block } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { TEMPLATES } from './constants'; + +const templateKeys = Object.keys( TEMPLATES ); + +// Finds the most appropriate template details object for specific template keys such as single-product-hoodie. +export function getTemplateDetailsBySlug( parsedTemplate: string ) { + let templateDetails = null; + + for ( let i = 0; templateKeys.length > i; i++ ) { + const keyToMatch = parsedTemplate.substr( 0, templateKeys[ i ].length ); + const maybeTemplate = TEMPLATES[ keyToMatch ]; + if ( maybeTemplate ) { + templateDetails = maybeTemplate; + break; + } + } + + return templateDetails; +} + +export function isClassicTemplateBlockRegisteredWithAnotherTitle( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + block: Block< any > | undefined, + parsedTemplate: string +) { + const templateDetails = getTemplateDetailsBySlug( parsedTemplate ); + return block?.title !== templateDetails?.title; +} + +export function hasTemplateSupportForClassicTemplateBlock( + parsedTemplate: string +) { + let hasSupport = false; + for ( let i = 0; templateKeys.length > i; i++ ) { + if ( parsedTemplate.includes( templateKeys[ i ] ) ) { + hasSupport = true; + break; + } + } + + return hasSupport; +} From b3b9e40e4d794224bc5832dea712cedb501e9d1c Mon Sep 17 00:00:00 2001 From: tjcafferkey Date: Thu, 1 Sep 2022 10:31:46 +0100 Subject: [PATCH 3/3] Classic Template utils refactor and unit tests --- .../js/blocks/classic-template/constants.ts | 8 +++- assets/js/blocks/classic-template/index.tsx | 15 ++++-- .../js/blocks/classic-template/test/utils.ts | 47 +++++++++++++++++++ assets/js/blocks/classic-template/types.ts | 1 + assets/js/blocks/classic-template/utils.ts | 31 ++++++------ 5 files changed, 81 insertions(+), 21 deletions(-) create mode 100644 assets/js/blocks/classic-template/test/utils.ts create mode 100644 assets/js/blocks/classic-template/types.ts diff --git a/assets/js/blocks/classic-template/constants.ts b/assets/js/blocks/classic-template/constants.ts index f75f9f78b82..dfeb37b3308 100644 --- a/assets/js/blocks/classic-template/constants.ts +++ b/assets/js/blocks/classic-template/constants.ts @@ -2,10 +2,14 @@ * External dependencies */ import { __ } from '@wordpress/i18n'; - export const BLOCK_SLUG = 'woocommerce/legacy-template'; -export const TEMPLATES: Record< string, Record< string, string > > = { +/** + * Internal dependencies + */ +import { TemplateDetails } from './types'; + +export const TEMPLATES: TemplateDetails = { 'single-product': { title: __( 'WooCommerce Single Product Block', diff --git a/assets/js/blocks/classic-template/index.tsx b/assets/js/blocks/classic-template/index.tsx index 2506c3f2383..18bf8237ed2 100644 --- a/assets/js/blocks/classic-template/index.tsx +++ b/assets/js/blocks/classic-template/index.tsx @@ -44,7 +44,10 @@ const Edit = ( { const { replaceBlock } = useDispatch( 'core/block-editor' ); const blockProps = useBlockProps(); - const templateDetails = getTemplateDetailsBySlug( attributes.template ); + const templateDetails = getTemplateDetailsBySlug( + attributes.template, + TEMPLATES + ); const templateTitle = templateDetails?.title ?? attributes.template; const templatePlaceholder = templateDetails?.placeholder ?? 'fallback'; @@ -228,7 +231,10 @@ if ( isExperimentalBuild() ) { if ( block !== undefined && - ( ! hasTemplateSupportForClassicTemplateBlock( parsedTemplate ) || + ( ! hasTemplateSupportForClassicTemplateBlock( + parsedTemplate, + TEMPLATES + ) || isClassicTemplateBlockRegisteredWithAnotherTitle( block, parsedTemplate @@ -241,7 +247,10 @@ if ( isExperimentalBuild() ) { if ( block === undefined && - hasTemplateSupportForClassicTemplateBlock( parsedTemplate ) + hasTemplateSupportForClassicTemplateBlock( + parsedTemplate, + TEMPLATES + ) ) { registerClassicTemplateBlock( { template: parsedTemplate, diff --git a/assets/js/blocks/classic-template/test/utils.ts b/assets/js/blocks/classic-template/test/utils.ts new file mode 100644 index 00000000000..8f413c21ab0 --- /dev/null +++ b/assets/js/blocks/classic-template/test/utils.ts @@ -0,0 +1,47 @@ +/** + * Internal dependencies + */ +import { getTemplateDetailsBySlug } from '../utils'; + +const TEMPLATES = { + 'single-product': { + title: 'Single Product Title', + placeholder: 'Single Product Placeholder', + }, + 'archive-product': { + title: 'Product Archive Title', + placeholder: 'Product Archive Placeholder', + }, + 'archive-product': { + title: 'Product Archive Title', + placeholder: 'Product Archive Placeholder', + }, + 'taxonomy-product_cat': { + title: 'Product Taxonomy Title', + placeholder: 'Product Taxonomy Placeholder', + }, +}; + +describe( 'getTemplateDetailsBySlug', function () { + it( 'should return single-product object when given an exact match', () => { + expect( + getTemplateDetailsBySlug( 'single-product', TEMPLATES ) + ).toBeTruthy(); + expect( + getTemplateDetailsBySlug( 'single-product', TEMPLATES ) + ).toStrictEqual( TEMPLATES[ 'single-product' ] ); + } ); + + it( 'should return single-product object when given a partial match', () => { + expect( + getTemplateDetailsBySlug( 'single-product-hoodie', TEMPLATES ) + ).toBeTruthy(); + expect( + getTemplateDetailsBySlug( 'single-product-hoodie', TEMPLATES ) + ).toStrictEqual( TEMPLATES[ 'single-product' ] ); + } ); + + it( 'should return null object when given an incorrect match', () => { + expect( getTemplateDetailsBySlug( 'void', TEMPLATES ) ).toBeNull(); + } ); +} ); diff --git a/assets/js/blocks/classic-template/types.ts b/assets/js/blocks/classic-template/types.ts new file mode 100644 index 00000000000..3e28296b652 --- /dev/null +++ b/assets/js/blocks/classic-template/types.ts @@ -0,0 +1 @@ +export type TemplateDetails = Record< string, Record< string, string > >; diff --git a/assets/js/blocks/classic-template/utils.ts b/assets/js/blocks/classic-template/utils.ts index f8c43ebb4db..76a31299be4 100644 --- a/assets/js/blocks/classic-template/utils.ts +++ b/assets/js/blocks/classic-template/utils.ts @@ -7,16 +7,19 @@ import { Block } from '@wordpress/blocks'; * Internal dependencies */ import { TEMPLATES } from './constants'; - -const templateKeys = Object.keys( TEMPLATES ); +import { TemplateDetails } from './types'; // Finds the most appropriate template details object for specific template keys such as single-product-hoodie. -export function getTemplateDetailsBySlug( parsedTemplate: string ) { +export function getTemplateDetailsBySlug( + parsedTemplate: string, + templates: TemplateDetails +) { + const templateKeys = Object.keys( templates ); let templateDetails = null; for ( let i = 0; templateKeys.length > i; i++ ) { const keyToMatch = parsedTemplate.substr( 0, templateKeys[ i ].length ); - const maybeTemplate = TEMPLATES[ keyToMatch ]; + const maybeTemplate = templates[ keyToMatch ]; if ( maybeTemplate ) { templateDetails = maybeTemplate; break; @@ -31,20 +34,16 @@ export function isClassicTemplateBlockRegisteredWithAnotherTitle( block: Block< any > | undefined, parsedTemplate: string ) { - const templateDetails = getTemplateDetailsBySlug( parsedTemplate ); + const templateDetails = getTemplateDetailsBySlug( + parsedTemplate, + TEMPLATES + ); return block?.title !== templateDetails?.title; } export function hasTemplateSupportForClassicTemplateBlock( - parsedTemplate: string -) { - let hasSupport = false; - for ( let i = 0; templateKeys.length > i; i++ ) { - if ( parsedTemplate.includes( templateKeys[ i ] ) ) { - hasSupport = true; - break; - } - } - - return hasSupport; + parsedTemplate: string, + templates: TemplateDetails +): boolean { + return getTemplateDetailsBySlug( parsedTemplate, templates ) ? true : false; }