Product search block as core/search variation (https://github.com/woocommerce/woocommerce-blocks/pull/6191)
Co-authored-by: Albert Juhé Lluveras <contact@albertjuhe.com> Co-authored-by: Tung Du <dinhtungdu@gmail.com>
This commit is contained in:
parent
aae8c5d357
commit
b295689571
|
@ -14,3 +14,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wc-block-components-actions {
|
||||
.block-editor-warning__actions {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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', {
|
||||
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;
|
||||
},
|
||||
} );
|
|
@ -0,0 +1,206 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { store as blockEditorStore, Warning } from '@wordpress/block-editor';
|
||||
import { useDispatch, useSelect } 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,
|
||||
registerBlockType,
|
||||
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: attributes.label.default,
|
||||
buttonText: attributes.label.default,
|
||||
placeholder: attributes.placeholder.default,
|
||||
query: {
|
||||
post_type: 'product',
|
||||
},
|
||||
};
|
||||
|
||||
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', {
|
||||
label:
|
||||
currentBlockAttributes?.label ||
|
||||
PRODUCT_SEARCH_ATTRIBUTES.label,
|
||||
buttonText: 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">
|
||||
{ __( 'Upgrade Block', 'woo-gutenberg-products-block' ) }
|
||||
</Button>,
|
||||
];
|
||||
|
||||
return (
|
||||
<Warning actions={ actions } className="wc-block-components-actions">
|
||||
{ __(
|
||||
'This version of the Product Search block is outdated. Upgrade to continue using.',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
</Warning>
|
||||
);
|
||||
};
|
||||
|
||||
registerBlockType( 'woocommerce/product-search', {
|
||||
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' ],
|
||||
inserter: ! isBlockVariationAvailable,
|
||||
},
|
||||
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 ||
|
||||
PRODUCT_SEARCH_ATTRIBUTES.label,
|
||||
} ),
|
||||
},
|
||||
],
|
||||
},
|
||||
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.post_type
|
||||
);
|
||||
},
|
||||
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,
|
||||
} );
|
||||
}
|
|
@ -124,4 +124,36 @@ class ProductSearch extends AbstractBlock {
|
|||
$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', '>=' )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,52 +12,60 @@ import {
|
|||
visitBlockPage,
|
||||
} from '@woocommerce/blocks-test-utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { GUTENBERG_EDITOR_CONTEXT, describeOrSkip } from '../../utils';
|
||||
|
||||
const block = {
|
||||
name: 'Product Search',
|
||||
slug: 'woocommerce/product-search',
|
||||
class: '.wc-block-product-search',
|
||||
};
|
||||
|
||||
describe( `${ block.name } Block`, () => {
|
||||
beforeAll( async () => {
|
||||
await switchUserToAdmin();
|
||||
await visitBlockPage( `${ block.name } Block` );
|
||||
} );
|
||||
describeOrSkip( GUTENBERG_EDITOR_CONTEXT !== 'gutenberg' )(
|
||||
`${ 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'
|
||||
);
|
||||
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 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'
|
||||
);
|
||||
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();
|
||||
} );
|
||||
}
|
||||
);
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in New Issue