Allow LegacyTemplate block to be reinserted, only on WooCommerce block templates. (https://github.com/woocommerce/woocommerce-blocks/pull/5545)
* Set attribute of legacy template block when block is inserted * Allow inserter on Woo templates only * Allow correct legacy block straight from the inserter * Use WP Data store outside component to register block * Pass in all attribute data when registering block * Accommodate templates targetted at specific products or taxonomies * Replace beginsWith with startsWith * Replace test data with production data * Conditionally use stores selector if it exists * Unsubscribe if the store does not exist Co-authored-by: Lucio Giannotta <lucio.giannotta@a8c.com>
This commit is contained in:
parent
37bf7a8067
commit
cf9c82e02e
|
@ -3,7 +3,12 @@
|
|||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
export const TEMPLATES: Record< string, Record< string, string > > = {
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { TemplateAttributes } from './types';
|
||||
|
||||
export const TEMPLATES: Record< string, TemplateAttributes > = {
|
||||
'single-product': {
|
||||
title: __(
|
||||
'WooCommerce Single Product Block',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { select, subscribe } from '@wordpress/data';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
import { WC_BLOCKS_IMAGE_URL } from '@woocommerce/block-settings';
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
|
@ -13,24 +14,25 @@ import { box, Icon } from '@wordpress/icons';
|
|||
*/
|
||||
import './editor.scss';
|
||||
import { TEMPLATES } from './constants';
|
||||
import { getMatchingTemplateData } from './utils';
|
||||
|
||||
interface Props {
|
||||
attributes: {
|
||||
template: string;
|
||||
title: string;
|
||||
placeholder: string;
|
||||
};
|
||||
}
|
||||
|
||||
const Edit = ( { attributes }: Props ) => {
|
||||
const blockProps = useBlockProps();
|
||||
const templateTitle =
|
||||
TEMPLATES[ attributes.template ]?.title ?? attributes.template;
|
||||
const templatePlaceholder =
|
||||
TEMPLATES[ attributes.template ]?.placeholder ?? 'fallback';
|
||||
const { title, placeholder } = attributes;
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<Placeholder
|
||||
icon={ box }
|
||||
label={ templateTitle }
|
||||
label={ title }
|
||||
className="wp-block-woocommerce-legacy-template__placeholder"
|
||||
>
|
||||
<div className="wp-block-woocommerce-legacy-template__placeholder-copy">
|
||||
|
@ -53,15 +55,15 @@ const Edit = ( { attributes }: Props ) => {
|
|||
'This is an editor placeholder for the %s. On your store this will be replaced by the template and display with your product image(s), title, price, etc. You can move this placeholder around and add further blocks around it to extend the template.',
|
||||
'woo-gutenberg-products-block'
|
||||
),
|
||||
templateTitle
|
||||
title
|
||||
) }
|
||||
</p>
|
||||
</div>
|
||||
<div className="wp-block-woocommerce-legacy-template__placeholder-wireframe">
|
||||
<img
|
||||
className="wp-block-woocommerce-legacy-template__placeholder-image"
|
||||
src={ `${ WC_BLOCKS_IMAGE_URL }template-placeholders/${ templatePlaceholder }.svg` }
|
||||
alt={ templateTitle }
|
||||
src={ `${ WC_BLOCKS_IMAGE_URL }template-placeholders/${ placeholder }.svg` }
|
||||
alt={ title }
|
||||
/>
|
||||
</div>
|
||||
</Placeholder>
|
||||
|
@ -69,39 +71,77 @@ const Edit = ( { attributes }: Props ) => {
|
|||
);
|
||||
};
|
||||
|
||||
registerBlockType( 'woocommerce/legacy-template', {
|
||||
title: __( 'WooCommerce Legacy Template', 'woo-gutenberg-products-block' ),
|
||||
icon: (
|
||||
<Icon icon={ box } className="wc-block-editor-components-block-icon" />
|
||||
),
|
||||
category: 'woocommerce',
|
||||
apiVersion: 2,
|
||||
keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ],
|
||||
description: __(
|
||||
'Renders legacy WooCommerce PHP templates.',
|
||||
'woo-gutenberg-products-block'
|
||||
),
|
||||
supports: {
|
||||
align: [ 'wide', 'full' ],
|
||||
html: false,
|
||||
multiple: false,
|
||||
reusable: false,
|
||||
inserter: false,
|
||||
},
|
||||
example: {
|
||||
attributes: {
|
||||
isPreview: true,
|
||||
},
|
||||
},
|
||||
attributes: {
|
||||
/**
|
||||
* Template attribute is used to determine which core PHP template gets rendered.
|
||||
*/
|
||||
template: {
|
||||
type: 'string',
|
||||
default: 'any',
|
||||
},
|
||||
},
|
||||
edit: Edit,
|
||||
save: () => null,
|
||||
let templateId: string | undefined;
|
||||
|
||||
const unsubscribe = subscribe( () => {
|
||||
const store = select( 'core/edit-site' );
|
||||
|
||||
if ( ! store ) {
|
||||
// The store will only exist in the Site Editor so we need to unsubscribe and early return for Posts / Pages.
|
||||
unsubscribe();
|
||||
return;
|
||||
}
|
||||
|
||||
templateId = store?.getEditedPostId();
|
||||
|
||||
if ( templateId ) {
|
||||
unsubscribe();
|
||||
const currentTemplateSlug = templateId?.split( '//' )[ 1 ];
|
||||
const templateData = getMatchingTemplateData(
|
||||
TEMPLATES,
|
||||
currentTemplateSlug
|
||||
);
|
||||
// We only want this block to be available for use in specified WooCommerce templates.
|
||||
const eligibleForInserter = templateData !== null;
|
||||
const title = templateData?.title ?? currentTemplateSlug;
|
||||
const placeholder = templateData?.placeholder ?? 'fallback';
|
||||
|
||||
registerBlockType( 'woocommerce/legacy-template', {
|
||||
title,
|
||||
icon: (
|
||||
<Icon
|
||||
icon={ box }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
category: 'woocommerce',
|
||||
apiVersion: 2,
|
||||
keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ],
|
||||
description: __(
|
||||
'Renders legacy WooCommerce PHP templates.',
|
||||
'woo-gutenberg-products-block'
|
||||
),
|
||||
supports: {
|
||||
align: [ 'wide', 'full' ],
|
||||
html: false,
|
||||
multiple: false,
|
||||
reusable: false,
|
||||
inserter: eligibleForInserter,
|
||||
},
|
||||
example: {
|
||||
attributes: {
|
||||
isPreview: true,
|
||||
},
|
||||
},
|
||||
attributes: {
|
||||
/**
|
||||
* Template attribute is used to determine which core PHP template gets rendered.
|
||||
*/
|
||||
template: {
|
||||
type: 'string',
|
||||
default: currentTemplateSlug,
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
default: title,
|
||||
},
|
||||
placeholder: {
|
||||
type: 'string',
|
||||
default: placeholder,
|
||||
},
|
||||
},
|
||||
edit: Edit,
|
||||
save: () => null,
|
||||
} );
|
||||
}
|
||||
} );
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { getMatchingTemplateData } from '../utils';
|
||||
import { TEMPLATES } from '../constants';
|
||||
|
||||
describe( 'getMatchingTemplateData', () => {
|
||||
it( 'should return template data if a correct match has been found', () => {
|
||||
expect(
|
||||
getMatchingTemplateData(
|
||||
TEMPLATES,
|
||||
'taxonomy-product_cat-winter-collection'
|
||||
)
|
||||
).toBe( TEMPLATES[ 'taxonomy-product_cat' ] );
|
||||
|
||||
expect( getMatchingTemplateData( TEMPLATES, 'single-product' ) ).toBe(
|
||||
TEMPLATES[ 'single-product' ]
|
||||
);
|
||||
|
||||
expect(
|
||||
getMatchingTemplateData( TEMPLATES, 'taxonomy-product_tag' )
|
||||
).toBe( TEMPLATES[ 'taxonomy-product_tag' ] );
|
||||
} );
|
||||
|
||||
it( 'should return null if given template slug does not match any of the expected options', () => {
|
||||
expect(
|
||||
getMatchingTemplateData( TEMPLATES, 'slug-does-not-match' )
|
||||
).toBe( null );
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,4 @@
|
|||
export type TemplateAttributes = {
|
||||
title: string;
|
||||
placeholder: string;
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { TemplateAttributes } from './types';
|
||||
|
||||
export function beginsWith( needle: string, haystack: string ): boolean {
|
||||
return haystack.substr( 0, needle.length ) === needle;
|
||||
}
|
||||
|
||||
export function getMatchingTemplateData(
|
||||
templates: Record< string, TemplateAttributes >,
|
||||
slug: string
|
||||
): TemplateAttributes | null {
|
||||
const templateSlugs = Object.keys( templates );
|
||||
const matchingSlugs = templateSlugs.filter( ( templateSlug ) =>
|
||||
slug.startsWith( templateSlug )
|
||||
);
|
||||
|
||||
if ( matchingSlugs.length === 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return templates[ matchingSlugs[ 0 ] ];
|
||||
}
|
Loading…
Reference in New Issue