From c126e81edb8ae894bede8c836e38d0cb14723718 Mon Sep 17 00:00:00 2001 From: Tomasz Tunik Date: Tue, 5 Apr 2022 13:08:24 +0200 Subject: [PATCH 01/17] Product search as variation --- assets/js/blocks/product-search/index.js | 153 +++++++++--------- .../block.js | 0 .../edit.js | 0 .../editor.scss | 0 assets/js/blocks/product-search__/index.js | 108 +++++++++++++ .../style.scss | 0 6 files changed, 181 insertions(+), 80 deletions(-) rename assets/js/blocks/{product-search => product-search__}/block.js (100%) rename assets/js/blocks/{product-search => product-search__}/edit.js (100%) rename assets/js/blocks/{product-search => product-search__}/editor.scss (100%) create mode 100644 assets/js/blocks/product-search__/index.js rename assets/js/blocks/{product-search => product-search__}/style.scss (100%) diff --git a/assets/js/blocks/product-search/index.js b/assets/js/blocks/product-search/index.js index d230edccf20..7edf4361c24 100644 --- a/assets/js/blocks/product-search/index.js +++ b/assets/js/blocks/product-search/index.js @@ -1,52 +1,83 @@ /** * External dependencies */ +import { store as blockEditorStore } from '@wordpress/block-editor'; +import { useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; -import { createBlock, registerBlockType } from '@wordpress/blocks'; import { Icon, search } from '@wordpress/icons'; -/** - * Internal dependencies - */ -import './style.scss'; -import './editor.scss'; -import Block from './block.js'; -import edit from './edit.js'; +import { + // @ts-ignore-line + registerBlockVariation, + registerBlockType, + createBlock, +} from '@wordpress/blocks'; -const attributes = { - /** - * Whether to show the field label. - */ - hasLabel: { - type: 'boolean', - default: true, - }, +const PRODUCT_SEARCH_ATTRIBUTES = { + postType: 'product', + label: __( 'Search', 'woo-gutenberg-products-block' ), + buttonText: __( 'Search', 'woo-gutenberg-products-block' ), + placeholder: __( 'Search products…', 'woo-gutenberg-products-block' ), +}; - /** - * Search field label. - */ - label: { - type: 'string', - default: __( 'Search', 'woo-gutenberg-products-block' ), - }, +const DeprecatedEdit = ( { clientId } ) => { + const { replaceBlocks } = useDispatch( blockEditorStore ); + const updateBlock = () => { + replaceBlocks( + clientId, + createBlock( 'core/search', PRODUCT_SEARCH_ATTRIBUTES ) + ); + }; - /** - * Search field placeholder. - */ - placeholder: { - type: 'string', - default: __( 'Search products…', 'woo-gutenberg-products-block' ), - }, + // useEffect( () => { + // replaceBlocks( + // clientId, + // createBlock( 'core/search', PRODUCT_SEARCH_ATTRIBUTES ) + // ); + // }, [ clientId, replaceBlocks ] ); - /** - * Store the instance ID. - */ - formId: { - type: 'string', - default: '', - }, + // return null; + + return ( +
+ Old Product Search block is deprecated. +
+ + + . + +
+ ); }; registerBlockType( 'woocommerce/product-search', { + name: 'woocommerce/product-search', + title: __( 'Product Search', 'woo-gutenberg-products-block' ), + category: 'woocommerce', + attributes: {}, + supports: { + inserter: false, + }, + edit: DeprecatedEdit, + transforms: { + to: [ + { + type: 'block', + blocks: [ 'core/search' ], + transform: () => { + return createBlock( + 'core/search', + PRODUCT_SEARCH_ATTRIBUTES + ); + }, + }, + ], + }, +} ); + +registerBlockVariation( 'core/search', { + name: 'woocommerce/product-search', title: __( 'Product Search', 'woo-gutenberg-products-block' ), icon: { src: ( @@ -56,53 +87,15 @@ registerBlockType( 'woocommerce/product-search', { /> ), }, + // @ts-ignore + isActive: ( blockAttributes, variationAttributes ) => { + return blockAttributes.postType === variationAttributes.postType; + }, category: 'woocommerce', keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ], description: __( 'A search box to allow customers to search for products by keyword.', 'woo-gutenberg-products-block' ), - supports: { - align: [ 'wide', 'full' ], - }, - example: { - attributes: { - hasLabel: true, - }, - }, - attributes, - transforms: { - from: [ - { - type: 'block', - blocks: [ 'core/legacy-widget' ], - // We can't transform if raw instance isn't shown in the REST API. - isMatch: ( { idBase, instance } ) => - idBase === 'woocommerce_product_search' && !! instance?.raw, - transform: ( { instance } ) => - createBlock( 'woocommerce/product-search', { - label: - instance.raw.title === '' - ? __( 'Search', 'woo-gutenberg-products-block' ) - : instance.raw.title, - } ), - }, - ], - }, - deprecated: [ - { - attributes, - save( props ) { - return ( -
- -
- ); - }, - }, - ], - edit, - save() { - return null; - }, + attributes: PRODUCT_SEARCH_ATTRIBUTES, } ); diff --git a/assets/js/blocks/product-search/block.js b/assets/js/blocks/product-search__/block.js similarity index 100% rename from assets/js/blocks/product-search/block.js rename to assets/js/blocks/product-search__/block.js diff --git a/assets/js/blocks/product-search/edit.js b/assets/js/blocks/product-search__/edit.js similarity index 100% rename from assets/js/blocks/product-search/edit.js rename to assets/js/blocks/product-search__/edit.js diff --git a/assets/js/blocks/product-search/editor.scss b/assets/js/blocks/product-search__/editor.scss similarity index 100% rename from assets/js/blocks/product-search/editor.scss rename to assets/js/blocks/product-search__/editor.scss diff --git a/assets/js/blocks/product-search__/index.js b/assets/js/blocks/product-search__/index.js new file mode 100644 index 00000000000..4543dd4920b --- /dev/null +++ b/assets/js/blocks/product-search__/index.js @@ -0,0 +1,108 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { createBlock, registerBlockType } from '@wordpress/blocks'; +import { Icon, search } from '@wordpress/icons'; +/** + * Internal dependencies + */ +import './style.scss'; +import './editor.scss'; +import Block from './block.js'; +import edit from './edit.js'; + +const attributes = { + /** + * Whether to show the field label. + */ + hasLabel: { + type: 'boolean', + default: true, + }, + + /** + * Search field label. + */ + label: { + type: 'string', + default: __( 'Search', 'woo-gutenberg-products-block' ), + }, + + /** + * Search field placeholder. + */ + placeholder: { + type: 'string', + default: __( 'Search products…', 'woo-gutenberg-products-block' ), + }, + + /** + * Store the instance ID. + */ + formId: { + type: 'string', + default: '', + }, +}; + +registerBlockType( 'woocommerce/product-search-old', { + title: __( 'Product Search', 'woo-gutenberg-products-block' ), + icon: { + src: ( + + ), + }, + category: 'woocommerce', + keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ], + description: __( + 'A search box to allow customers to search for products by keyword.', + 'woo-gutenberg-products-block' + ), + supports: { + align: [ 'wide', 'full' ], + }, + example: { + attributes: { + hasLabel: true, + }, + }, + attributes, + transforms: { + from: [ + { + type: 'block', + blocks: [ 'core/legacy-widget' ], + // We can't transform if raw instance isn't shown in the REST API. + isMatch: ( { idBase, instance } ) => + idBase === 'woocommerce_product_search' && !! instance?.raw, + transform: ( { instance } ) => + createBlock( 'woocommerce/product-search', { + label: + instance.raw.title === '' + ? __( 'Search', 'woo-gutenberg-products-block' ) + : instance.raw.title, + } ), + }, + ], + }, + deprecated: [ + { + attributes, + save( props ) { + return ( +
+ +
+ ); + }, + }, + ], + edit, + save() { + return null; + }, +} ); diff --git a/assets/js/blocks/product-search/style.scss b/assets/js/blocks/product-search__/style.scss similarity index 100% rename from assets/js/blocks/product-search/style.scss rename to assets/js/blocks/product-search__/style.scss From d8ea416528b86908e23fb6de2377777b8cd909a7 Mon Sep 17 00:00:00 2001 From: Tomasz Tunik Date: Tue, 26 Apr 2022 12:47:18 +0200 Subject: [PATCH 02/17] remove old product search block --- assets/js/blocks/product-search/index.js | 12 +- assets/js/blocks/product-search__/block.js | 89 ---------- assets/js/blocks/product-search__/edit.js | 160 ------------------ assets/js/blocks/product-search__/editor.scss | 16 -- assets/js/blocks/product-search__/index.js | 108 ------------ assets/js/blocks/product-search__/style.scss | 38 ----- 6 files changed, 8 insertions(+), 415 deletions(-) delete mode 100644 assets/js/blocks/product-search__/block.js delete mode 100644 assets/js/blocks/product-search__/edit.js delete mode 100644 assets/js/blocks/product-search__/editor.scss delete mode 100644 assets/js/blocks/product-search__/index.js delete mode 100644 assets/js/blocks/product-search__/style.scss diff --git a/assets/js/blocks/product-search/index.js b/assets/js/blocks/product-search/index.js index 7edf4361c24..2d056bb8e4a 100644 --- a/assets/js/blocks/product-search/index.js +++ b/assets/js/blocks/product-search/index.js @@ -6,20 +6,22 @@ import { useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { Icon, search } from '@wordpress/icons'; import { - // @ts-ignore-line registerBlockVariation, registerBlockType, createBlock, } from '@wordpress/blocks'; const PRODUCT_SEARCH_ATTRIBUTES = { - postType: 'product', label: __( 'Search', 'woo-gutenberg-products-block' ), buttonText: __( 'Search', 'woo-gutenberg-products-block' ), placeholder: __( 'Search products…', 'woo-gutenberg-products-block' ), + query: { + post_type: 'product', + }, }; const DeprecatedEdit = ( { clientId } ) => { + // @ts-ignore const { replaceBlocks } = useDispatch( blockEditorStore ); const updateBlock = () => { replaceBlocks( @@ -87,9 +89,11 @@ registerBlockVariation( 'core/search', { /> ), }, - // @ts-ignore isActive: ( blockAttributes, variationAttributes ) => { - return blockAttributes.postType === variationAttributes.postType; + return ( + blockAttributes.query?.post_type === + variationAttributes.query.postType + ); }, category: 'woocommerce', keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ], diff --git a/assets/js/blocks/product-search__/block.js b/assets/js/blocks/product-search__/block.js deleted file mode 100644 index 1f6e10e74b1..00000000000 --- a/assets/js/blocks/product-search__/block.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import classnames from 'classnames'; -import PropTypes from 'prop-types'; -import { HOME_URL } from '@woocommerce/settings'; - -/** - * Internal dependencies - */ -import './editor.scss'; -import './style.scss'; - -/** - * Component displaying a product search form. - * - * @param {Object} props Incoming props for the component. - * @param {Object} props.attributes Incoming block attributes. - * @param {string} props.attributes.label - * @param {string} props.attributes.placeholder - * @param {string} props.attributes.formId - * @param {string} props.attributes.className - * @param {boolean} props.attributes.hasLabel - * @param {string} props.attributes.align - */ -const ProductSearchBlock = ( { - attributes: { label, placeholder, formId, className, hasLabel, align }, -} ) => { - const classes = classnames( - 'wc-block-product-search', - align ? 'align' + align : '', - className - ); - - return ( -
-
- -
- - - -
-
-
- ); -}; - -ProductSearchBlock.propTypes = { - /** - * The attributes for this block. - */ - attributes: PropTypes.object.isRequired, -}; - -export default ProductSearchBlock; diff --git a/assets/js/blocks/product-search__/edit.js b/assets/js/blocks/product-search__/edit.js deleted file mode 100644 index 8d22a426305..00000000000 --- a/assets/js/blocks/product-search__/edit.js +++ /dev/null @@ -1,160 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import classnames from 'classnames'; -import PropTypes from 'prop-types'; -import { InspectorControls, PlainText } from '@wordpress/block-editor'; -import { PanelBody, ToggleControl, TextControl } from '@wordpress/components'; -import { withInstanceId } from '@wordpress/compose'; -import { useEffect } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import './editor.scss'; -import './style.scss'; - -/** - * Component displaying a product search form. - * - * @param {Object} props Incoming props for the component. - * @param {Object} props.attributes Incoming block attributes. - * @param {string} props.attributes.label - * @param {string} props.attributes.placeholder - * @param {string} props.attributes.formId - * @param {string} props.attributes.className - * @param {boolean} props.attributes.hasLabel - * @param {string} props.attributes.align - * @param {string} props.instanceId - * @param {function(any):any} props.setAttributes Setter for block attributes. - */ -const Edit = ( { - attributes: { label, placeholder, formId, className, hasLabel, align }, - instanceId, - setAttributes, -} ) => { - const classes = classnames( - 'wc-block-product-search', - align ? 'align' + align : '', - className - ); - - useEffect( () => { - if ( ! formId ) { - setAttributes( { - formId: `wc-block-product-search-${ instanceId }`, - } ); - } - }, [ formId, setAttributes, instanceId ] ); - - return ( - <> - - - - setAttributes( { hasLabel: ! hasLabel } ) - } - /> - - -
- { !! hasLabel && ( - <> - - - setAttributes( { label: value } ) - } - /> - </> - ) } - <div className="wc-block-product-search__fields"> - <TextControl - className="wc-block-product-search__field input-control" - value={ placeholder } - placeholder={ __( - 'Enter search placeholder text', - 'woo-gutenberg-products-block' - ) } - onChange={ ( value ) => - setAttributes( { placeholder: value } ) - } - /> - <button - type="submit" - className="wc-block-product-search__button" - label={ __( 'Search', 'woo-gutenberg-products-block' ) } - onClick={ ( e ) => e.preventDefault() } - tabIndex="-1" - > - <svg - aria-hidden="true" - role="img" - focusable="false" - className="dashicon dashicons-arrow-right-alt2" - xmlns="http://www.w3.org/2000/svg" - width="20" - height="20" - viewBox="0 0 20 20" - > - <path d="M6 15l5-5-5-5 1-2 7 7-7 7z" /> - </svg> - </button> - </div> - </div> - </> - ); -}; - -Edit.propTypes = { - /** - * The attributes for this block. - */ - attributes: PropTypes.object.isRequired, - /** - * A unique ID for identifying the label for the select dropdown. - */ - instanceId: PropTypes.number, - /** - * Whether it's in the editor or frontend display. - */ - isEditor: PropTypes.bool, - /** - * A callback to update attributes. - */ - setAttributes: PropTypes.func, -}; - -export default withInstanceId( Edit ); diff --git a/assets/js/blocks/product-search__/editor.scss b/assets/js/blocks/product-search__/editor.scss deleted file mode 100644 index 224f0ce39e6..00000000000 --- a/assets/js/blocks/product-search__/editor.scss +++ /dev/null @@ -1,16 +0,0 @@ -.wc-block-product-search__field.input-control { - color: #828b96 !important; - padding: 0; - - .components-base-control__field { - margin-bottom: 0; - } -} - -.wc-block-product-search { - .wc-block-product-search__fields { - .block-editor-rich-text { - flex-grow: 1; - } - } -} diff --git a/assets/js/blocks/product-search__/index.js b/assets/js/blocks/product-search__/index.js deleted file mode 100644 index 4543dd4920b..00000000000 --- a/assets/js/blocks/product-search__/index.js +++ /dev/null @@ -1,108 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import { createBlock, registerBlockType } from '@wordpress/blocks'; -import { Icon, search } from '@wordpress/icons'; -/** - * Internal dependencies - */ -import './style.scss'; -import './editor.scss'; -import Block from './block.js'; -import edit from './edit.js'; - -const attributes = { - /** - * Whether to show the field label. - */ - hasLabel: { - type: 'boolean', - default: true, - }, - - /** - * Search field label. - */ - label: { - type: 'string', - default: __( 'Search', 'woo-gutenberg-products-block' ), - }, - - /** - * Search field placeholder. - */ - placeholder: { - type: 'string', - default: __( 'Search products…', 'woo-gutenberg-products-block' ), - }, - - /** - * Store the instance ID. - */ - formId: { - type: 'string', - default: '', - }, -}; - -registerBlockType( 'woocommerce/product-search-old', { - title: __( 'Product Search', 'woo-gutenberg-products-block' ), - icon: { - src: ( - <Icon - icon={ search } - className="wc-block-editor-components-block-icon" - /> - ), - }, - category: 'woocommerce', - keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ], - description: __( - 'A search box to allow customers to search for products by keyword.', - 'woo-gutenberg-products-block' - ), - supports: { - align: [ 'wide', 'full' ], - }, - example: { - attributes: { - hasLabel: true, - }, - }, - attributes, - transforms: { - from: [ - { - type: 'block', - blocks: [ 'core/legacy-widget' ], - // We can't transform if raw instance isn't shown in the REST API. - isMatch: ( { idBase, instance } ) => - idBase === 'woocommerce_product_search' && !! instance?.raw, - transform: ( { instance } ) => - createBlock( 'woocommerce/product-search', { - label: - instance.raw.title === '' - ? __( 'Search', 'woo-gutenberg-products-block' ) - : instance.raw.title, - } ), - }, - ], - }, - deprecated: [ - { - attributes, - save( props ) { - return ( - <div> - <Block { ...props } /> - </div> - ); - }, - }, - ], - edit, - save() { - return null; - }, -} ); diff --git a/assets/js/blocks/product-search__/style.scss b/assets/js/blocks/product-search__/style.scss deleted file mode 100644 index 56cc636f923..00000000000 --- a/assets/js/blocks/product-search__/style.scss +++ /dev/null @@ -1,38 +0,0 @@ -.wc-block-product-search { - .wc-block-product-search__fields { - display: flex; - } - .wc-block-product-search__field { - padding: 6px 8px; - line-height: 1.8; - flex-grow: 1; - } - .wc-block-product-search__button { - display: flex; - align-items: center; - margin: 0 0 0 6px; - cursor: pointer; - padding: 0 0.5em; - position: relative; - overflow: hidden; - svg { - fill: currentColor; - outline: none; - .rtl & { - transform: rotate(180deg); - } - } - &:active { - color: currentColor; - } - &:disabled, - &[aria-disabled="true"] { - cursor: default; - opacity: 0.3; - } - &[aria-disabled="true"]:focus, - &:disabled:focus { - box-shadow: none; - } - } -} From 7cd5267f57d4fd327a93a865231ea16475c0831d Mon Sep 17 00:00:00 2001 From: Tomasz Tunik <tomasztunik@gmail.com> Date: Fri, 6 May 2022 14:54:16 +0200 Subject: [PATCH 03/17] improvements - make old block deprecate more gracefully, - update to typescript - use Warning component to create cleaner experience of updating the block --- assets/js/blocks/product-search/editor.scss | 16 ++++++++ .../product-search/{index.js => index.tsx} | 19 +++++++--- assets/js/blocks/product-search/style.scss | 38 +++++++++++++++++++ 3 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 assets/js/blocks/product-search/editor.scss rename assets/js/blocks/product-search/{index.js => index.tsx} (80%) create mode 100644 assets/js/blocks/product-search/style.scss diff --git a/assets/js/blocks/product-search/editor.scss b/assets/js/blocks/product-search/editor.scss new file mode 100644 index 00000000000..224f0ce39e6 --- /dev/null +++ b/assets/js/blocks/product-search/editor.scss @@ -0,0 +1,16 @@ +.wc-block-product-search__field.input-control { + color: #828b96 !important; + padding: 0; + + .components-base-control__field { + margin-bottom: 0; + } +} + +.wc-block-product-search { + .wc-block-product-search__fields { + .block-editor-rich-text { + flex-grow: 1; + } + } +} diff --git a/assets/js/blocks/product-search/index.js b/assets/js/blocks/product-search/index.tsx similarity index 80% rename from assets/js/blocks/product-search/index.js rename to assets/js/blocks/product-search/index.tsx index 2d056bb8e4a..c12f5c03707 100644 --- a/assets/js/blocks/product-search/index.js +++ b/assets/js/blocks/product-search/index.tsx @@ -1,11 +1,13 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ /** * External dependencies */ -import { store as blockEditorStore } from '@wordpress/block-editor'; +import { store as blockEditorStore, Warning } from '@wordpress/block-editor'; import { useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { Icon, search } from '@wordpress/icons'; import { + // @ts-ignore waiting for @types/wordpress__blocks update registerBlockVariation, registerBlockType, createBlock, @@ -20,8 +22,12 @@ const PRODUCT_SEARCH_ATTRIBUTES = { }, }; -const DeprecatedEdit = ( { clientId } ) => { - // @ts-ignore +/** + * editor.scss and style.scss are required + * to gracefully handle old block deprecation + */ +const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { + // @ts-ignore @wordpress/block-editor/store types not provided const { replaceBlocks } = useDispatch( blockEditorStore ); const updateBlock = () => { replaceBlocks( @@ -40,7 +46,7 @@ const DeprecatedEdit = ( { clientId } ) => { // return null; return ( - <div> + <Warning> Old Product Search block is deprecated. <br /> <small> @@ -49,7 +55,7 @@ const DeprecatedEdit = ( { clientId } ) => { </button> . </small> - </div> + </Warning> ); }; @@ -61,7 +67,7 @@ registerBlockType( 'woocommerce/product-search', { supports: { inserter: false, }, - edit: DeprecatedEdit, + edit: DeprecatedBlockEdit, transforms: { to: [ { @@ -89,6 +95,7 @@ registerBlockVariation( 'core/search', { /> ), }, + // @ts-ignore waiting for @types/wordpress__blocks update isActive: ( blockAttributes, variationAttributes ) => { return ( blockAttributes.query?.post_type === diff --git a/assets/js/blocks/product-search/style.scss b/assets/js/blocks/product-search/style.scss new file mode 100644 index 00000000000..56cc636f923 --- /dev/null +++ b/assets/js/blocks/product-search/style.scss @@ -0,0 +1,38 @@ +.wc-block-product-search { + .wc-block-product-search__fields { + display: flex; + } + .wc-block-product-search__field { + padding: 6px 8px; + line-height: 1.8; + flex-grow: 1; + } + .wc-block-product-search__button { + display: flex; + align-items: center; + margin: 0 0 0 6px; + cursor: pointer; + padding: 0 0.5em; + position: relative; + overflow: hidden; + svg { + fill: currentColor; + outline: none; + .rtl & { + transform: rotate(180deg); + } + } + &:active { + color: currentColor; + } + &:disabled, + &[aria-disabled="true"] { + cursor: default; + opacity: 0.3; + } + &[aria-disabled="true"]:focus, + &:disabled:focus { + box-shadow: none; + } + } +} From 1dfc12252ced22227118a75e15b52c04cc2c7395 Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Thu, 28 Jul 2022 23:27:05 +0700 Subject: [PATCH 04/17] Add: editor version check (#6761) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Albert Juhé Lluveras <contact@albertjuhe.com> --- assets/js/blocks/product-search/block.js | 89 ++++++++++ assets/js/blocks/product-search/edit.js | 160 +++++++++++++++++ assets/js/blocks/product-search/index.tsx | 206 ++++++++++++++++------ src/BlockTypes/ProductSearch.php | 32 ++++ 4 files changed, 433 insertions(+), 54 deletions(-) create mode 100644 assets/js/blocks/product-search/block.js create mode 100644 assets/js/blocks/product-search/edit.js diff --git a/assets/js/blocks/product-search/block.js b/assets/js/blocks/product-search/block.js new file mode 100644 index 00000000000..1f6e10e74b1 --- /dev/null +++ b/assets/js/blocks/product-search/block.js @@ -0,0 +1,89 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import classnames from 'classnames'; +import PropTypes from 'prop-types'; +import { HOME_URL } from '@woocommerce/settings'; + +/** + * Internal dependencies + */ +import './editor.scss'; +import './style.scss'; + +/** + * Component displaying a product search form. + * + * @param {Object} props Incoming props for the component. + * @param {Object} props.attributes Incoming block attributes. + * @param {string} props.attributes.label + * @param {string} props.attributes.placeholder + * @param {string} props.attributes.formId + * @param {string} props.attributes.className + * @param {boolean} props.attributes.hasLabel + * @param {string} props.attributes.align + */ +const ProductSearchBlock = ( { + attributes: { label, placeholder, formId, className, hasLabel, align }, +} ) => { + const classes = classnames( + 'wc-block-product-search', + align ? 'align' + align : '', + className + ); + + return ( + <div className={ classes }> + <form role="search" method="get" action={ HOME_URL }> + <label + htmlFor={ formId } + className={ + hasLabel + ? 'wc-block-product-search__label' + : 'wc-block-product-search__label screen-reader-text' + } + > + { label } + </label> + <div className="wc-block-product-search__fields"> + <input + type="search" + id={ formId } + className="wc-block-product-search__field" + placeholder={ placeholder } + name="s" + /> + <input type="hidden" name="post_type" value="product" /> + <button + type="submit" + className="wc-block-product-search__button" + label={ __( 'Search', 'woo-gutenberg-products-block' ) } + > + <svg + aria-hidden="true" + role="img" + focusable="false" + className="dashicon dashicons-arrow-right-alt2" + xmlns="http://www.w3.org/2000/svg" + width="20" + height="20" + viewBox="0 0 20 20" + > + <path d="M6 15l5-5-5-5 1-2 7 7-7 7z" /> + </svg> + </button> + </div> + </form> + </div> + ); +}; + +ProductSearchBlock.propTypes = { + /** + * The attributes for this block. + */ + attributes: PropTypes.object.isRequired, +}; + +export default ProductSearchBlock; diff --git a/assets/js/blocks/product-search/edit.js b/assets/js/blocks/product-search/edit.js new file mode 100644 index 00000000000..8d22a426305 --- /dev/null +++ b/assets/js/blocks/product-search/edit.js @@ -0,0 +1,160 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import classnames from 'classnames'; +import PropTypes from 'prop-types'; +import { InspectorControls, PlainText } from '@wordpress/block-editor'; +import { PanelBody, ToggleControl, TextControl } from '@wordpress/components'; +import { withInstanceId } from '@wordpress/compose'; +import { useEffect } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import './editor.scss'; +import './style.scss'; + +/** + * Component displaying a product search form. + * + * @param {Object} props Incoming props for the component. + * @param {Object} props.attributes Incoming block attributes. + * @param {string} props.attributes.label + * @param {string} props.attributes.placeholder + * @param {string} props.attributes.formId + * @param {string} props.attributes.className + * @param {boolean} props.attributes.hasLabel + * @param {string} props.attributes.align + * @param {string} props.instanceId + * @param {function(any):any} props.setAttributes Setter for block attributes. + */ +const Edit = ( { + attributes: { label, placeholder, formId, className, hasLabel, align }, + instanceId, + setAttributes, +} ) => { + const classes = classnames( + 'wc-block-product-search', + align ? 'align' + align : '', + className + ); + + useEffect( () => { + if ( ! formId ) { + setAttributes( { + formId: `wc-block-product-search-${ instanceId }`, + } ); + } + }, [ formId, setAttributes, instanceId ] ); + + return ( + <> + <InspectorControls key="inspector"> + <PanelBody + title={ __( 'Content', 'woo-gutenberg-products-block' ) } + initialOpen + > + <ToggleControl + label={ __( + 'Show search field label', + 'woo-gutenberg-products-block' + ) } + help={ + hasLabel + ? __( + 'Label is visible.', + 'woo-gutenberg-products-block' + ) + : __( + 'Label is hidden.', + 'woo-gutenberg-products-block' + ) + } + checked={ hasLabel } + onChange={ () => + setAttributes( { hasLabel: ! hasLabel } ) + } + /> + </PanelBody> + </InspectorControls> + <div className={ classes }> + { !! hasLabel && ( + <> + <label + className="screen-reader-text" + htmlFor="wc-block-product-search__label" + > + { __( + 'Search Label', + 'woo-gutenberg-products-block' + ) } + </label> + <PlainText + className="wc-block-product-search__label" + id="wc-block-product-search__label" + value={ label } + onChange={ ( value ) => + setAttributes( { label: value } ) + } + /> + </> + ) } + <div className="wc-block-product-search__fields"> + <TextControl + className="wc-block-product-search__field input-control" + value={ placeholder } + placeholder={ __( + 'Enter search placeholder text', + 'woo-gutenberg-products-block' + ) } + onChange={ ( value ) => + setAttributes( { placeholder: value } ) + } + /> + <button + type="submit" + className="wc-block-product-search__button" + label={ __( 'Search', 'woo-gutenberg-products-block' ) } + onClick={ ( e ) => e.preventDefault() } + tabIndex="-1" + > + <svg + aria-hidden="true" + role="img" + focusable="false" + className="dashicon dashicons-arrow-right-alt2" + xmlns="http://www.w3.org/2000/svg" + width="20" + height="20" + viewBox="0 0 20 20" + > + <path d="M6 15l5-5-5-5 1-2 7 7-7 7z" /> + </svg> + </button> + </div> + </div> + </> + ); +}; + +Edit.propTypes = { + /** + * The attributes for this block. + */ + attributes: PropTypes.object.isRequired, + /** + * A unique ID for identifying the label for the select dropdown. + */ + instanceId: PropTypes.number, + /** + * Whether it's in the editor or frontend display. + */ + isEditor: PropTypes.bool, + /** + * A callback to update attributes. + */ + setAttributes: PropTypes.func, +}; + +export default withInstanceId( Edit ); diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx index c12f5c03707..3e668dc5164 100644 --- a/assets/js/blocks/product-search/index.tsx +++ b/assets/js/blocks/product-search/index.tsx @@ -6,6 +6,9 @@ import { store as blockEditorStore, Warning } from '@wordpress/block-editor'; import { useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { Icon, search } from '@wordpress/icons'; +import { getSettingWithCoercion } from '@woocommerce/settings'; +import { isBoolean } from '@woocommerce/types'; +import { Button } from '@wordpress/components'; import { // @ts-ignore waiting for @types/wordpress__blocks update registerBlockVariation, @@ -13,10 +16,58 @@ import { createBlock, } from '@wordpress/blocks'; +/** + * Internal dependencies + */ +import './style.scss'; +import './editor.scss'; +import Block from './block.js'; +import Edit from './edit.js'; + +const isBlockVariationAvailable = getSettingWithCoercion( + 'isBlockVariationAvailable', + false, + isBoolean +); + +const attributes = { + /** + * Whether to show the field label. + */ + hasLabel: { + type: 'boolean', + default: true, + }, + + /** + * Search field label. + */ + label: { + type: 'string', + default: __( 'Search', 'woo-gutenberg-products-block' ), + }, + + /** + * Search field placeholder. + */ + placeholder: { + type: 'string', + default: __( 'Search products…', 'woo-gutenberg-products-block' ), + }, + + /** + * Store the instance ID. + */ + formId: { + type: 'string', + default: '', + }, +}; + const PRODUCT_SEARCH_ATTRIBUTES = { - label: __( 'Search', 'woo-gutenberg-products-block' ), - buttonText: __( 'Search', 'woo-gutenberg-products-block' ), - placeholder: __( 'Search products…', 'woo-gutenberg-products-block' ), + label: attributes.label.default, + buttonText: attributes.label.default, + placeholder: attributes.placeholder.default, query: { post_type: 'product', }, @@ -35,57 +86,20 @@ const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { createBlock( 'core/search', PRODUCT_SEARCH_ATTRIBUTES ) ); }; - - // useEffect( () => { - // replaceBlocks( - // clientId, - // createBlock( 'core/search', PRODUCT_SEARCH_ATTRIBUTES ) - // ); - // }, [ clientId, replaceBlocks ] ); - - // return null; + const actions = [ + <Button key="update" onClick={ updateBlock } variant="primary"> + Update to Search Block variant + </Button>, + ]; return ( - <Warning> + <Warning actions={ actions }> Old Product Search block is deprecated. - <br /> - <small> - <button onClick={ updateBlock }> - Update to Search Block variant - </button> - . - </small> </Warning> ); }; registerBlockType( 'woocommerce/product-search', { - name: 'woocommerce/product-search', - title: __( 'Product Search', 'woo-gutenberg-products-block' ), - category: 'woocommerce', - attributes: {}, - supports: { - inserter: false, - }, - edit: DeprecatedBlockEdit, - transforms: { - to: [ - { - type: 'block', - blocks: [ 'core/search' ], - transform: () => { - return createBlock( - 'core/search', - PRODUCT_SEARCH_ATTRIBUTES - ); - }, - }, - ], - }, -} ); - -registerBlockVariation( 'core/search', { - name: 'woocommerce/product-search', title: __( 'Product Search', 'woo-gutenberg-products-block' ), icon: { src: ( @@ -95,18 +109,102 @@ registerBlockVariation( 'core/search', { /> ), }, - // @ts-ignore waiting for @types/wordpress__blocks update - isActive: ( blockAttributes, variationAttributes ) => { - return ( - blockAttributes.query?.post_type === - variationAttributes.query.postType - ); - }, category: 'woocommerce', keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ], description: __( 'A search box to allow customers to search for products by keyword.', 'woo-gutenberg-products-block' ), - attributes: PRODUCT_SEARCH_ATTRIBUTES, + supports: { + align: [ 'wide', 'full' ], + inserter: ! isBlockVariationAvailable, + }, + example: { + attributes: { + hasLabel: true, + }, + }, + attributes, + transforms: isBlockVariationAvailable + ? { + to: [ + { + type: 'block', + blocks: [ 'core/search' ], + transform: () => { + return createBlock( + 'core/search', + PRODUCT_SEARCH_ATTRIBUTES + ); + }, + }, + ], + } + : { + from: [ + { + type: 'block', + blocks: [ 'core/legacy-widget' ], + // We can't transform if raw instance isn't shown in the REST API. + isMatch: ( { idBase, instance } ) => + idBase === 'woocommerce_product_search' && + !! instance?.raw, + transform: ( { instance } ) => + createBlock( 'woocommerce/product-search', { + label: + instance.raw.title === '' + ? __( + 'Search', + 'woo-gutenberg-products-block' + ) + : instance.raw.title, + } ), + }, + ], + }, + deprecated: [ + { + attributes, + save( props ) { + return ( + <div> + <Block { ...props } /> + </div> + ); + }, + }, + ], + edit: isBlockVariationAvailable ? DeprecatedBlockEdit : Edit, + save() { + return null; + }, } ); + +if ( isBlockVariationAvailable ) { + registerBlockVariation( 'core/search', { + name: 'woocommerce/product-search', + title: __( 'Product Search', 'woo-gutenberg-products-block' ), + icon: { + src: ( + <Icon + icon={ search } + className="wc-block-editor-components-block-icon" + /> + ), + }, + // @ts-ignore waiting for @types/wordpress__blocks update + isActive: ( blockAttributes, variationAttributes ) => { + return ( + blockAttributes.query?.post_type === + variationAttributes.query.postType + ); + }, + category: 'woocommerce', + keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ], + description: __( + 'A search box to allow customers to search for products by keyword.', + 'woo-gutenberg-products-block' + ), + attributes: PRODUCT_SEARCH_ATTRIBUTES, + } ); +} diff --git a/src/BlockTypes/ProductSearch.php b/src/BlockTypes/ProductSearch.php index 613aa67d77d..2afa20ac5ec 100644 --- a/src/BlockTypes/ProductSearch.php +++ b/src/BlockTypes/ProductSearch.php @@ -124,4 +124,36 @@ protected function render( $attributes, $content ) { $label_markup . $field_markup ); } + + /** + * Extra data passed through from server to client for block. + * + * @param array $attributes Any attributes that currently are available from the block. + * Note, this will be empty in the editor context when the block is + * not in the post content on editor load. + */ + protected function enqueue_data( array $attributes = [] ) { + parent::enqueue_data( $attributes ); + + $gutenberg_version = ''; + + if ( is_plugin_active( 'gutenberg/gutenberg.php' ) ) { + if ( defined( 'GUTENBERG_VERSION' ) ) { + $gutenberg_version = GUTENBERG_VERSION; + } + + if ( ! $gutenberg_version ) { + $gutenberg_data = get_file_data( + WP_PLUGIN_DIR . '/gutenberg/gutenberg.php', + array( 'Version' => 'Version' ) + ); + $gutenberg_version = $gutenberg_data['Version']; + } + } + + $this->asset_data_registry->add( + 'isBlockVariationAvailable', + version_compare( get_bloginfo( 'version' ), '6.1', '>=' ) || version_compare( $gutenberg_version, '13.4', '>=' ) + ); + } } From 800c7411f7dc86d6359676af02485f77defa142c Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Fri, 29 Jul 2022 08:16:59 +0700 Subject: [PATCH 05/17] fix: add missing translation wrapper --- assets/js/blocks/product-search/index.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx index 3e668dc5164..fe982c51009 100644 --- a/assets/js/blocks/product-search/index.tsx +++ b/assets/js/blocks/product-search/index.tsx @@ -88,13 +88,19 @@ const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { }; const actions = [ <Button key="update" onClick={ updateBlock } variant="primary"> - Update to Search Block variant + { __( + 'Update to Search Block variant', + 'woo-gutenberg-products-block' + ) } </Button>, ]; return ( <Warning actions={ actions }> - Old Product Search block is deprecated. + { __( + 'Old Product Search block is deprecated.', + 'woo-gutenberg-products-block' + ) } </Warning> ); }; From 07cbdf4595bd3e14f75b46b29cda36664a35e8e4 Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Fri, 29 Jul 2022 08:57:39 +0700 Subject: [PATCH 06/17] match correct query key --- assets/js/blocks/product-search/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx index fe982c51009..f7ba24e9725 100644 --- a/assets/js/blocks/product-search/index.tsx +++ b/assets/js/blocks/product-search/index.tsx @@ -202,7 +202,7 @@ if ( isBlockVariationAvailable ) { isActive: ( blockAttributes, variationAttributes ) => { return ( blockAttributes.query?.post_type === - variationAttributes.query.postType + variationAttributes.query.post_type ); }, category: 'woocommerce', From 1794616c23621e074eba5025e8fee6c062a569c1 Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Fri, 29 Jul 2022 10:48:36 +0700 Subject: [PATCH 07/17] use the current label and placeholder for conversion --- assets/js/blocks/product-search/index.tsx | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx index f7ba24e9725..358d8cc8c6b 100644 --- a/assets/js/blocks/product-search/index.tsx +++ b/assets/js/blocks/product-search/index.tsx @@ -3,7 +3,7 @@ * External dependencies */ import { store as blockEditorStore, Warning } from '@wordpress/block-editor'; -import { useDispatch } from '@wordpress/data'; +import { useDispatch, useSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { Icon, search } from '@wordpress/icons'; import { getSettingWithCoercion } from '@woocommerce/settings'; @@ -80,12 +80,31 @@ const PRODUCT_SEARCH_ATTRIBUTES = { const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { // @ts-ignore @wordpress/block-editor/store types not provided const { replaceBlocks } = useDispatch( blockEditorStore ); + + const currentBlockAttributes = useSelect( + ( select ) => + select( 'core/block-editor' ).getBlockAttributes( clientId ), + [ clientId ] + ); + const updateBlock = () => { replaceBlocks( clientId, - createBlock( 'core/search', PRODUCT_SEARCH_ATTRIBUTES ) + createBlock( 'core/search', { + label: + currentBlockAttributes?.label || + PRODUCT_SEARCH_ATTRIBUTES.label, + buttonText: + currentBlockAttributes?.label || + PRODUCT_SEARCH_ATTRIBUTES.buttonText, + placeholder: + currentBlockAttributes?.placeholder || + PRODUCT_SEARCH_ATTRIBUTES.placeholder, + query: PRODUCT_SEARCH_ATTRIBUTES.query, + } ) ); }; + const actions = [ <Button key="update" onClick={ updateBlock } variant="primary"> { __( From 907193bb19032e6a7b98ffd4036bdc5a7da2de46 Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Fri, 29 Jul 2022 12:14:25 +0700 Subject: [PATCH 08/17] remove unnecessary transform --- assets/js/blocks/product-search/index.tsx | 57 ++++++++--------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx index 358d8cc8c6b..3f76ccb5dbf 100644 --- a/assets/js/blocks/product-search/index.tsx +++ b/assets/js/blocks/product-search/index.tsx @@ -98,7 +98,7 @@ const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { currentBlockAttributes?.label || PRODUCT_SEARCH_ATTRIBUTES.buttonText, placeholder: - currentBlockAttributes?.placeholder || + currentBlockAttributes?.label || PRODUCT_SEARCH_ATTRIBUTES.placeholder, query: PRODUCT_SEARCH_ATTRIBUTES.query, } ) @@ -150,43 +150,23 @@ registerBlockType( 'woocommerce/product-search', { }, }, attributes, - transforms: isBlockVariationAvailable - ? { - to: [ - { - type: 'block', - blocks: [ 'core/search' ], - transform: () => { - return createBlock( - 'core/search', - PRODUCT_SEARCH_ATTRIBUTES - ); - }, - }, - ], - } - : { - from: [ - { - type: 'block', - blocks: [ 'core/legacy-widget' ], - // We can't transform if raw instance isn't shown in the REST API. - isMatch: ( { idBase, instance } ) => - idBase === 'woocommerce_product_search' && - !! instance?.raw, - transform: ( { instance } ) => - createBlock( 'woocommerce/product-search', { - label: - instance.raw.title === '' - ? __( - 'Search', - 'woo-gutenberg-products-block' - ) - : instance.raw.title, - } ), - }, - ], - }, + transforms: { + from: [ + { + type: 'block', + blocks: [ 'core/legacy-widget' ], + // We can't transform if raw instance isn't shown in the REST API. + isMatch: ( { idBase, instance } ) => + idBase === 'woocommerce_product_search' && !! instance?.raw, + transform: ( { instance } ) => + createBlock( 'woocommerce/product-search', { + label: + instance.raw.title || + PRODUCT_SEARCH_ATTRIBUTES.label, + } ), + }, + ], + }, deprecated: [ { attributes, @@ -231,5 +211,6 @@ if ( isBlockVariationAvailable ) { 'woo-gutenberg-products-block' ), attributes: PRODUCT_SEARCH_ATTRIBUTES, + scope: [ 'block', 'inserter', 'transform' ], } ); } From 187ed2f0daf7030dacfdbc947006e016081794bd Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Fri, 29 Jul 2022 12:46:11 +0700 Subject: [PATCH 09/17] remove unnecessary scope --- assets/js/blocks/product-search/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx index 3f76ccb5dbf..8d205f2c420 100644 --- a/assets/js/blocks/product-search/index.tsx +++ b/assets/js/blocks/product-search/index.tsx @@ -211,6 +211,5 @@ if ( isBlockVariationAvailable ) { 'woo-gutenberg-products-block' ), attributes: PRODUCT_SEARCH_ATTRIBUTES, - scope: [ 'block', 'inserter', 'transform' ], } ); } From 95a17bdecdf79ddb04e324a7d3f64d43f05ac77b Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Fri, 29 Jul 2022 12:57:30 +0700 Subject: [PATCH 10/17] fix: placeholder value --- assets/js/blocks/product-search/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx index 8d205f2c420..1b9aa0ac808 100644 --- a/assets/js/blocks/product-search/index.tsx +++ b/assets/js/blocks/product-search/index.tsx @@ -98,7 +98,7 @@ const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { currentBlockAttributes?.label || PRODUCT_SEARCH_ATTRIBUTES.buttonText, placeholder: - currentBlockAttributes?.label || + currentBlockAttributes?.placeholder || PRODUCT_SEARCH_ATTRIBUTES.placeholder, query: PRODUCT_SEARCH_ATTRIBUTES.query, } ) From ff2369c6c4e9fd4577ec8a8761968b8cfa68dcd9 Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Fri, 29 Jul 2022 13:27:48 +0700 Subject: [PATCH 11/17] avoid expose technical term to end user --- assets/js/blocks/product-search/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx index 1b9aa0ac808..620d08da4d2 100644 --- a/assets/js/blocks/product-search/index.tsx +++ b/assets/js/blocks/product-search/index.tsx @@ -108,7 +108,7 @@ const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { const actions = [ <Button key="update" onClick={ updateBlock } variant="primary"> { __( - 'Update to Search Block variant', + 'Update to new Search Block', 'woo-gutenberg-products-block' ) } </Button>, @@ -117,7 +117,7 @@ const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { return ( <Warning actions={ actions }> { __( - 'Old Product Search block is deprecated.', + 'The old Product Search block has been deprecated.', 'woo-gutenberg-products-block' ) } </Warning> From 22955262f90b6ddc0a743faad393870bdd4c821c Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Mon, 1 Aug 2022 19:25:24 +0700 Subject: [PATCH 12/17] address code review --- assets/js/blocks/product-search/index.tsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx index 620d08da4d2..5a1b6d72f36 100644 --- a/assets/js/blocks/product-search/index.tsx +++ b/assets/js/blocks/product-search/index.tsx @@ -73,10 +73,6 @@ const PRODUCT_SEARCH_ATTRIBUTES = { }, }; -/** - * editor.scss and style.scss are required - * to gracefully handle old block deprecation - */ const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { // @ts-ignore @wordpress/block-editor/store types not provided const { replaceBlocks } = useDispatch( blockEditorStore ); @@ -94,9 +90,7 @@ const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { label: currentBlockAttributes?.label || PRODUCT_SEARCH_ATTRIBUTES.label, - buttonText: - currentBlockAttributes?.label || - PRODUCT_SEARCH_ATTRIBUTES.buttonText, + buttonText: PRODUCT_SEARCH_ATTRIBUTES.buttonText, placeholder: currentBlockAttributes?.placeholder || PRODUCT_SEARCH_ATTRIBUTES.placeholder, @@ -108,7 +102,7 @@ const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { const actions = [ <Button key="update" onClick={ updateBlock } variant="primary"> { __( - 'Update to new Search Block', + 'Update to new Search block', 'woo-gutenberg-products-block' ) } </Button>, From 6cb78b0031d02a9d2fa827bb5e30eb56102b719e Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Mon, 8 Aug 2022 13:00:58 +0700 Subject: [PATCH 13/17] only test against wp latest --- .../e2e/specs/backend/product-search.test.js | 84 ++++++++++--------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/tests/e2e/specs/backend/product-search.test.js b/tests/e2e/specs/backend/product-search.test.js index b4189ab1810..9ff12181774 100644 --- a/tests/e2e/specs/backend/product-search.test.js +++ b/tests/e2e/specs/backend/product-search.test.js @@ -10,6 +10,7 @@ import { clearAndFillInput } from '@woocommerce/e2e-utils'; import { findLabelWithText, visitBlockPage, + GUTENBERG_EDITOR_CONTEXT, } from '@woocommerce/blocks-test-utils'; const block = { @@ -18,46 +19,51 @@ const block = { class: '.wc-block-product-search', }; -describe( `${ block.name } Block`, () => { - beforeAll( async () => { - await switchUserToAdmin(); - await visitBlockPage( `${ block.name } Block` ); - } ); +if ( GUTENBERG_EDITOR_CONTEXT === 'gutenberg' ) { + // eslint-disable-next-line jest/no-focused-tests, jest/expect-expect + test.only( `Skipping ${ block.name } tests`, () => {} ); +} else { + describe( `${ block.name } Block`, () => { + beforeAll( async () => { + await switchUserToAdmin(); + await visitBlockPage( `${ block.name } Block` ); + } ); - it( 'renders without crashing', async () => { - await expect( page ).toRenderBlock( block ); - } ); + it( 'renders without crashing', async () => { + await expect( page ).toRenderBlock( block ); + } ); - it( 'can toggle field label', async () => { - await openDocumentSettingsSidebar(); - await page.click( block.class ); - const selector = `${ block.class } .wc-block-product-search__label`; - const toggleLabel = await findLabelWithText( - 'Show search field label' - ); - await expect( toggleLabel ).toToggleElement( selector ); - } ); + it( 'can toggle field label', async () => { + await openDocumentSettingsSidebar(); + await page.click( block.class ); + const selector = `${ block.class } .wc-block-product-search__label`; + const toggleLabel = await findLabelWithText( + 'Show search field label' + ); + await expect( toggleLabel ).toToggleElement( selector ); + } ); + + it( 'can change field labels in editor', async () => { + await expect( page ).toFill( + 'textarea.wc-block-product-search__label', + 'I am a new label' + ); + + await expect( page ).toFill( + '.wc-block-product-search__field input', + 'I am a new placeholder' + ); + + await clearAndFillInput( + 'textarea.wc-block-product-search__label', + 'The Label' + ); + await clearAndFillInput( + '.wc-block-product-search__field input', + 'The Placeholder' + ); - it( 'can change field labels in editor', async () => { - await expect( page ).toFill( - 'textarea.wc-block-product-search__label', - 'I am a new label' - ); - - await expect( page ).toFill( - '.wc-block-product-search__field input', - 'I am a new placeholder' - ); - - await clearAndFillInput( - 'textarea.wc-block-product-search__label', - 'The Label' - ); - await clearAndFillInput( - '.wc-block-product-search__field input', - 'The Placeholder' - ); - - expect( await getEditedPostContent() ).toMatchSnapshot(); + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); } ); -} ); +} From 6ab88fc4c7bc6e5bda18ce6745d4e28c118dd51d Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Mon, 8 Aug 2022 13:43:49 +0700 Subject: [PATCH 14/17] correct dependencies import --- tests/e2e/specs/backend/product-search.test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/e2e/specs/backend/product-search.test.js b/tests/e2e/specs/backend/product-search.test.js index 9ff12181774..884c67fb54a 100644 --- a/tests/e2e/specs/backend/product-search.test.js +++ b/tests/e2e/specs/backend/product-search.test.js @@ -10,9 +10,13 @@ import { clearAndFillInput } from '@woocommerce/e2e-utils'; import { findLabelWithText, visitBlockPage, - GUTENBERG_EDITOR_CONTEXT, } from '@woocommerce/blocks-test-utils'; +/** + * Internal dependencies + */ +import { GUTENBERG_EDITOR_CONTEXT } from '../../utils'; + const block = { name: 'Product Search', slug: 'woocommerce/product-search', From 4c2ae55cb569b340b95d3bbfdbf3712fb851074d Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Mon, 8 Aug 2022 15:33:35 +0700 Subject: [PATCH 15/17] avoid obsolate warning --- tests/e2e/specs/backend/product-search.test.js | 14 ++++++-------- tests/e2e/utils.js | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/e2e/specs/backend/product-search.test.js b/tests/e2e/specs/backend/product-search.test.js index 884c67fb54a..d7f99c391ff 100644 --- a/tests/e2e/specs/backend/product-search.test.js +++ b/tests/e2e/specs/backend/product-search.test.js @@ -15,7 +15,7 @@ import { /** * Internal dependencies */ -import { GUTENBERG_EDITOR_CONTEXT } from '../../utils'; +import { GUTENBERG_EDITOR_CONTEXT, describeOrSkip } from '../../utils'; const block = { name: 'Product Search', @@ -23,11 +23,9 @@ const block = { class: '.wc-block-product-search', }; -if ( GUTENBERG_EDITOR_CONTEXT === 'gutenberg' ) { - // eslint-disable-next-line jest/no-focused-tests, jest/expect-expect - test.only( `Skipping ${ block.name } tests`, () => {} ); -} else { - describe( `${ block.name } Block`, () => { +describeOrSkip( GUTENBERG_EDITOR_CONTEXT !== 'gutenberg' )( + `${ block.name } Block`, + () => { beforeAll( async () => { await switchUserToAdmin(); await visitBlockPage( `${ block.name } Block` ); @@ -69,5 +67,5 @@ if ( GUTENBERG_EDITOR_CONTEXT === 'gutenberg' ) { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); - } ); -} + } +); diff --git a/tests/e2e/utils.js b/tests/e2e/utils.js index 3a4f127c19f..b9fe0e20128 100644 --- a/tests/e2e/utils.js +++ b/tests/e2e/utils.js @@ -438,3 +438,18 @@ export const openBlockEditorSettings = async ( { isFSEEditor = false } ) => { export const waitForAllProductsBlockLoaded = async () => { await page.waitForSelector( SELECTORS.allProductsBlock.productsList ); }; + +/** + * Execute or skip the test suite base on the provided condition. + * + * @param {boolean} condition Condition to execute test suite. + */ +export const describeOrSkip = ( condition ) => + condition ? describe : describe.skip; + +/** + * Execute or skip the test base on the provided condition. + * + * @param {boolean} condition Condition to execute test. + */ +export const itOrSkip = ( condition ) => ( condition ? it : it.skip ); From c672048a46d4b85c38e11ddc3c70e34c069b855b Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Fri, 19 Aug 2022 14:44:39 +0700 Subject: [PATCH 16/17] update copy and spacing for the warning --- assets/js/blocks/product-search/editor.scss | 6 ++++++ assets/js/blocks/product-search/index.tsx | 9 +++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/assets/js/blocks/product-search/editor.scss b/assets/js/blocks/product-search/editor.scss index 224f0ce39e6..d47eb352c8b 100644 --- a/assets/js/blocks/product-search/editor.scss +++ b/assets/js/blocks/product-search/editor.scss @@ -14,3 +14,9 @@ } } } + +.wc-block-components-actions { + .block-editor-warning__actions { + margin-top: 0; + } +} diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx index 5a1b6d72f36..942c6f7d4b2 100644 --- a/assets/js/blocks/product-search/index.tsx +++ b/assets/js/blocks/product-search/index.tsx @@ -101,17 +101,14 @@ const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { const actions = [ <Button key="update" onClick={ updateBlock } variant="primary"> - { __( - 'Update to new Search block', - 'woo-gutenberg-products-block' - ) } + { __( 'Upgrade Block', 'woo-gutenberg-products-block' ) } </Button>, ]; return ( - <Warning actions={ actions }> + <Warning actions={ actions } className="wc-block-components-actions"> { __( - 'The old Product Search block has been deprecated.', + 'This version of the Product Search block is outdated.', 'woo-gutenberg-products-block' ) } </Warning> From c3e22b1b5da34245a036cf647b75f915022545a9 Mon Sep 17 00:00:00 2001 From: Tung Du <dinhtungdu@gmail.com> Date: Tue, 23 Aug 2022 15:49:04 +0700 Subject: [PATCH 17/17] update message copy --- assets/js/blocks/product-search/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx index 942c6f7d4b2..04e5c64d137 100644 --- a/assets/js/blocks/product-search/index.tsx +++ b/assets/js/blocks/product-search/index.tsx @@ -108,7 +108,7 @@ const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { return ( <Warning actions={ actions } className="wc-block-components-actions"> { __( - 'This version of the Product Search block is outdated.', + 'This version of the Product Search block is outdated. Upgrade to continue using.', 'woo-gutenberg-products-block' ) } </Warning>