2021-10-29 07:31:50 +00:00
/ * *
* External dependencies
* /
2022-06-29 07:42:02 +00:00
import {
2023-05-10 11:02:33 +00:00
BlockInstance ,
createBlock ,
2022-06-29 07:42:02 +00:00
getBlockType ,
registerBlockType ,
unregisterBlockType ,
} from '@wordpress/blocks' ;
2022-11-02 16:46:14 +00:00
import type { BlockEditProps } from '@wordpress/blocks' ;
2022-06-06 14:49:19 +00:00
import {
isExperimentalBuild ,
WC_BLOCKS_IMAGE_URL ,
} from '@woocommerce/block-settings' ;
2023-05-10 11:02:33 +00:00
import {
useBlockProps ,
BlockPreview ,
store as blockEditorStore ,
} from '@wordpress/block-editor' ;
import { Button , Placeholder , Popover } from '@wordpress/components' ;
2023-02-27 14:34:18 +00:00
import { __ } from '@wordpress/i18n' ;
2021-12-10 10:07:10 +00:00
import { box , Icon } from '@wordpress/icons' ;
2023-05-10 11:02:33 +00:00
import { useDispatch , subscribe , useSelect , select } from '@wordpress/data' ;
2023-05-17 13:25:02 +00:00
import { useEffect , useState } from '@wordpress/element' ;
2023-05-10 11:02:33 +00:00
import { store as noticesStore } from '@wordpress/notices' ;
import { useEntityRecord } from '@wordpress/core-data' ;
2021-11-02 14:42:07 +00:00
/ * *
* Internal dependencies
* /
import './editor.scss' ;
2022-05-04 11:02:42 +00:00
import './style.scss' ;
2023-02-27 14:34:18 +00:00
import { BLOCK_SLUG , TEMPLATES , TYPES } from './constants' ;
2022-09-06 09:52:33 +00:00
import {
isClassicTemplateBlockRegisteredWithAnotherTitle ,
hasTemplateSupportForClassicTemplateBlock ,
getTemplateDetailsBySlug ,
} from './utils' ;
2023-02-27 14:34:18 +00:00
import {
blockifiedProductCatalogConfig ,
blockifiedProductTaxonomyConfig ,
} from './archive-product' ;
import * as blockifiedSingleProduct from './single-product' ;
import * as blockifiedProductSearchResults from './product-search-results' ;
import type { BlockifiedTemplateConfig } from './types' ;
2022-06-29 07:42:02 +00:00
type Attributes = {
template : string ;
align : string ;
} ;
2021-10-29 07:31:50 +00:00
2023-02-27 14:34:18 +00:00
const blockifiedFallbackConfig = {
isConversionPossible : ( ) = > false ,
getBlockifiedTemplate : ( ) = > [ ] ,
getDescription : ( ) = > '' ,
getButtonLabel : ( ) = > '' ,
2023-05-10 11:02:33 +00:00
onClickCallback : ( ) = > void 0 ,
2023-02-27 14:34:18 +00:00
} ;
const conversionConfig : { [ key : string ] : BlockifiedTemplateConfig } = {
[ TYPES . productCatalog ] : blockifiedProductCatalogConfig ,
[ TYPES . productTaxonomy ] : blockifiedProductTaxonomyConfig ,
[ TYPES . singleProduct ] : blockifiedSingleProduct ,
[ TYPES . productSearchResults ] : blockifiedProductSearchResults ,
fallback : blockifiedFallbackConfig ,
} ;
2023-05-10 11:02:33 +00:00
const pickBlockClientIds = ( blocks : Array < BlockInstance > ) = >
blocks . reduce < Array < string > > ( ( acc , block ) = > {
if ( block . name === 'core/template-part' ) {
return acc ;
}
return [ . . . acc , block . clientId ] ;
} , [ ] ) ;
2022-06-29 07:42:02 +00:00
const Edit = ( {
clientId ,
attributes ,
setAttributes ,
} : BlockEditProps < Attributes > ) = > {
2023-05-10 11:02:33 +00:00
const { replaceBlock , selectBlock , replaceBlocks } =
useDispatch ( blockEditorStore ) ;
const { getBlocks , editedPostId } = useSelect ( ( sel ) = > {
return {
getBlocks : sel ( blockEditorStore ) . getBlocks ,
editedPostId : sel ( 'core/edit-site' ) . getEditedPostId ( ) ,
} ;
} , [ ] ) ;
const template = useEntityRecord < {
slug : string ;
title : {
rendered? : string ;
row : string ;
} ;
} > ( 'postType' , 'wp_template' , editedPostId ) ;
const { createInfoNotice } = useDispatch ( noticesStore ) ;
2021-10-29 07:31:50 +00:00
const blockProps = useBlockProps ( ) ;
2022-09-06 09:52:33 +00:00
const templateDetails = getTemplateDetailsBySlug (
attributes . template ,
TEMPLATES
) ;
2023-05-10 11:02:33 +00:00
const templateTitle =
template . record ? . title . rendered ? . toLowerCase ( ) ? ? attributes . template ;
2022-09-06 09:52:33 +00:00
const templatePlaceholder = templateDetails ? . placeholder ? ? 'fallback' ;
2023-02-27 14:34:18 +00:00
const templateType = templateDetails ? . type ? ? 'fallback' ;
2022-06-29 07:42:02 +00:00
useEffect (
( ) = >
setAttributes ( {
template : attributes.template ,
align : attributes.align ? ? 'wide' ,
} ) ,
[ attributes . align , attributes . template , setAttributes ]
) ;
2023-02-27 14:34:18 +00:00
const {
isConversionPossible ,
getDescription ,
getButtonLabel ,
2023-05-10 11:02:33 +00:00
onClickCallback ,
getBlockifiedTemplate ,
2023-02-27 14:34:18 +00:00
} = conversionConfig [ templateType ] ;
2023-03-30 12:47:02 +00:00
const canConvert = isConversionPossible ( ) ;
2023-02-27 14:34:18 +00:00
const placeholderDescription = getDescription ( templateTitle , canConvert ) ;
2023-05-10 11:02:33 +00:00
const [ isPopoverOpen , setIsPopoverOpen ] = useState ( false ) ;
2023-02-27 14:34:18 +00:00
2021-10-29 07:31:50 +00:00
return (
< div { ...blockProps } >
2023-05-10 11:02:33 +00:00
< Placeholder className = "wp-block-woocommerce-classic-template__placeholder" >
2022-03-22 22:34:43 +00:00
< div className = "wp-block-woocommerce-classic-template__placeholder-wireframe" >
2023-05-10 11:02:33 +00:00
< div className = "wp-block-woocommerce-classic-template__placeholder-copy" >
< div className = "wp-block-woocommerce-classic-template__placeholder-copy__icon-container" >
< Icon icon = { box } / >
< span >
{ __ (
'Classic Product Template' ,
'woo-gutenberg-products-block'
) }
< / span >
2022-06-06 14:49:19 +00:00
< / div >
2023-05-10 11:02:33 +00:00
< p > { placeholderDescription } < / p >
{ canConvert && (
< div className = "wp-block-woocommerce-classic-template__placeholder-migration-button-container" >
< Button
isPrimary
onClick = { ( ) = > {
onClickCallback ( {
clientId ,
getBlocks ,
attributes ,
replaceBlock ,
selectBlock ,
} ) ;
createInfoNotice (
__ (
'Template transformed into blocks!' ,
'woo-gutenberg-products-block'
) ,
{
actions : [
{
label : __ (
'Undo' ,
'woo-gutenberg-products-block'
) ,
onClick : ( ) = > {
2023-05-17 13:25:02 +00:00
const clientIds =
pickBlockClientIds (
getBlocks ( )
) ;
2023-05-10 11:02:33 +00:00
replaceBlocks (
clientIds ,
createBlock (
'core/group' ,
{
layout : {
inherit :
true ,
type : 'constrained' ,
} ,
} ,
[
createBlock (
'woocommerce/legacy-template' ,
{
template :
attributes . template ,
}
) ,
]
)
) ;
} ,
} ,
] ,
type : 'snackbar' ,
}
) ;
} }
onMouseEnter = { ( ) = >
setIsPopoverOpen ( true )
}
onMouseLeave = { ( ) = >
setIsPopoverOpen ( false )
}
text = { getButtonLabel ( ) }
>
{ isPopoverOpen && (
< Popover
resize = { false }
placement = "right-end"
>
< div
style = { {
minWidth : '250px' ,
width : '250px' ,
maxWidth : '250px' ,
minHeight : '300px' ,
height : '300px' ,
maxHeight : '300px' ,
cursor : 'pointer' ,
} }
>
< BlockPreview
blocks = { getBlockifiedTemplate (
attributes
) }
viewportWidth = { 1200 }
additionalStyles = { [
{
css : 'body { padding: 20px !important; height: fit-content !important; overflow:hidden}' ,
} ,
] }
/ >
< / div >
< / Popover >
) }
< / Button >
< / div >
) }
< / div >
2021-11-02 14:42:07 +00:00
< img
2022-03-22 22:34:43 +00:00
className = "wp-block-woocommerce-classic-template__placeholder-image"
2022-01-27 09:45:00 +00:00
src = { ` ${ WC_BLOCKS_IMAGE_URL } template-placeholders/ ${ templatePlaceholder } .svg ` }
alt = { templateTitle }
2021-11-02 14:42:07 +00:00
/ >
< / div >
< / Placeholder >
2021-10-29 07:31:50 +00:00
< / div >
) ;
} ;
2022-06-29 07:42:02 +00:00
const registerClassicTemplateBlock = ( {
template ,
inserter ,
} : {
template? : string ;
inserter : boolean ;
} ) = > {
/ * *
* The 'WooCommerce Legacy Template' block was renamed to 'WooCommerce Classic Template' , however , the internal block
* name 'woocommerce/legacy-template' needs to remain the same . Otherwise , it would result in a corrupt block when
* loaded for users who have customized templates using the legacy - template ( since the internal block name is
* stored in the database ) .
*
* See https : //github.com/woocommerce/woocommerce-gutenberg-products-block/issues/5861 for more context
* /
registerBlockType ( BLOCK_SLUG , {
2022-09-06 09:52:33 +00:00
title :
template && TEMPLATES [ template ]
? TEMPLATES [ template ] . title
: __ (
'WooCommerce Classic Template' ,
'woo-gutenberg-products-block'
) ,
2022-06-29 07:42:02 +00:00
icon : (
< Icon
icon = { box }
className = "wc-block-editor-components-block-icon"
/ >
) ,
category : 'woocommerce' ,
apiVersion : 2 ,
keywords : [ __ ( 'WooCommerce' , 'woo-gutenberg-products-block' ) ] ,
description : __ (
'Renders classic WooCommerce PHP templates.' ,
'woo-gutenberg-products-block'
) ,
supports : {
align : [ 'wide' , 'full' ] ,
html : false ,
multiple : false ,
reusable : false ,
inserter ,
} ,
attributes : {
/ * *
* Template attribute is used to determine which core PHP template gets rendered .
* /
template : {
type : 'string' ,
default : 'any' ,
} ,
align : {
type : 'string' ,
default : 'wide' ,
} ,
2022-01-27 09:45:00 +00:00
} ,
2022-06-29 07:42:02 +00:00
edit : ( {
attributes ,
clientId ,
setAttributes ,
} : BlockEditProps < Attributes > ) = > {
const newTemplate = template ? ? attributes . template ;
return (
< Edit
attributes = { {
. . . attributes ,
template : newTemplate ,
} }
setAttributes = { setAttributes }
clientId = { clientId }
/ >
) ;
2022-05-04 11:02:42 +00:00
} ,
2022-06-29 07:42:02 +00:00
save : ( ) = > null ,
} ) ;
} ;
// @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 ;
if ( isExperimentalBuild ( ) ) {
subscribe ( ( ) = > {
const previousTemplateId = currentTemplateId ;
const store = select ( 'core/edit-site' ) ;
currentTemplateId = store ? . getEditedPostId ( ) as string | undefined ;
if ( previousTemplateId === currentTemplateId ) {
return ;
}
const parsedTemplate = currentTemplateId ? . split ( '//' ) [ 1 ] ;
if ( parsedTemplate === null || parsedTemplate === undefined ) {
return ;
}
const block = getBlockType ( BLOCK_SLUG ) ;
if (
block !== undefined &&
2022-09-06 09:52:33 +00:00
( ! hasTemplateSupportForClassicTemplateBlock (
parsedTemplate ,
TEMPLATES
) ||
2022-06-29 07:42:02 +00:00
isClassicTemplateBlockRegisteredWithAnotherTitle (
block ,
parsedTemplate
) )
) {
unregisterBlockType ( BLOCK_SLUG ) ;
currentTemplateId = undefined ;
return ;
}
if (
block === undefined &&
2022-09-06 09:52:33 +00:00
hasTemplateSupportForClassicTemplateBlock (
parsedTemplate ,
TEMPLATES
)
2022-06-29 07:42:02 +00:00
) {
registerClassicTemplateBlock ( {
template : parsedTemplate ,
inserter : true ,
} ) ;
}
} ) ;
} else {
registerClassicTemplateBlock ( {
inserter : false ,
} ) ;
}