Skip to content

Commit

Permalink
[ Product Block Editor ] Create Variation options block (woocommerce#…
Browse files Browse the repository at this point in the history
…39256)

* Add support for variable products

* Add 'hello world' block to variations tab

* Add product-section block to template

* Add AttributeControl component to screen

* Add changelog

* Change labels

* Make a copy of AttributeControl to VariationOptionsControl to allow the fields to evolve separately in future

* Fix tests

* Add changelog to woocommerce

* Fix alert error

* Remove copied control and start adapting attribute control to handle both scenarios

* Add -field to block name

* Revert "Add -field to block name"

This reverts commit 50e1ee6.

* Revert "Revert "Add -field to block name""

This reverts commit eee0441.

* Extract more labels

* Hide drag handle in variation options
  • Loading branch information
nathanss authored Jul 28, 2023
1 parent bf97630 commit 403c8ba
Show file tree
Hide file tree
Showing 15 changed files with 190 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: add

Add variation options block
1 change: 1 addition & 0 deletions packages/js/product-editor/src/blocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export { init as initToggle } from './toggle';
export { init as attributesInit } from './attributes';
export { init as initVariations } from './variations';
export { init as initRequirePassword } from './password';
export { init as initVariationOptions } from './variation-options';
1 change: 1 addition & 0 deletions packages/js/product-editor/src/blocks/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
@import 'tab/editor.scss';
@import 'variations/editor.scss';
@import 'password/editor.scss';
@import 'variation-options/editor.scss';
26 changes: 26 additions & 0 deletions packages/js/product-editor/src/blocks/variation-options/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "woocommerce/product-variations-options-field",
"title": "Product variations options",
"category": "woocommerce",
"description": "The product variations options.",
"keywords": [ "products", "variations" ],
"textdomain": "default",
"attributes": {
"description": {
"type": "string",
"__experimentalRole": "content"
}
},
"supports": {
"align": false,
"html": false,
"multiple": false,
"reusable": false,
"inserter": false,
"lock": false,
"__experimentalToolbar": false
},
"editorStyle": "file:./editor.css"
}
58 changes: 58 additions & 0 deletions packages/js/product-editor/src/blocks/variation-options/edit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import { createElement } from '@wordpress/element';
import { ProductAttribute } from '@woocommerce/data';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore No types for this exist yet.
// eslint-disable-next-line @woocommerce/dependency-group
import { useEntityProp, useEntityId } from '@wordpress/core-data';

/**
* Internal dependencies
*/
import { useProductAttributes } from '../../hooks/use-product-attributes';
import { AttributeControl } from '../../components/attribute-control';

export function Edit() {
const blockProps = useBlockProps();

const [ entityAttributes, setEntityAttributes ] = useEntityProp<
ProductAttribute[]
>( 'postType', 'product', 'attributes' );

const { attributes, handleChange } = useProductAttributes( {
allAttributes: entityAttributes,
onChange: setEntityAttributes,
isVariationAttributes: true,
productId: useEntityId( 'postType', 'product' ),
} );

return (
<div { ...blockProps }>
<AttributeControl
value={ attributes }
onChange={ handleChange }
uiStrings={ {
globalAttributeHelperMessage: '',
customAttributeHelperMessage: '',
newAttributeModalNotice: '',
newAttributeModalTitle: __(
'Add variation options',
'woocommerce'
),
attributeRemoveLabel: __(
'Remove variation option',
'woocommerce'
),
attributeRemoveConfirmationMessage: __(
'Remove this variation option?',
'woocommerce'
),
} }
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.wp-block-woocommerce-product-variations-options-field {
.woocommerce-sortable {
padding: 0;
}

.woocommerce-list-item {
background: none;
border: none;
border-bottom: 1px solid $gray-200;
padding-left: 0;
grid-template-columns: 26% auto 90px;
}

.woocommerce-sortable__handle {
display: none;
}
}
29 changes: 29 additions & 0 deletions packages/js/product-editor/src/blocks/variation-options/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
import { BlockConfiguration } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { initBlock } from '../../utils/init-blocks';
import blockConfiguration from './block.json';
import { Edit } from './edit';
import { VariationOptionsBlockAttributes } from './types';

const { name, ...metadata } =
blockConfiguration as BlockConfiguration< VariationOptionsBlockAttributes >;

export { metadata, name };

export const settings: Partial<
BlockConfiguration< VariationOptionsBlockAttributes >
> = {
example: {},
edit: Edit,
};

export function init() {
return initBlock( { name, metadata, settings } );
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* External dependencies
*/
import { BlockAttributes } from '@wordpress/blocks';

export interface VariationOptionsBlockAttributes extends BlockAttributes {
description: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ type AttributeControlProps = {
emptyStateSubtitle?: string;
newAttributeListItemLabel?: string;
newAttributeModalTitle?: string;
newAttributeModalNotice?: string;
customAttributeHelperMessage?: string;
attributeRemoveLabel?: string;
attributeRemoveConfirmationMessage?: string;
globalAttributeHelperMessage: string;
};
};
Expand All @@ -65,16 +69,24 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
onEditModalOpen = () => {},
onRemove = () => {},
onRemoveCancel = () => {},
uiStrings,
} ) => {
uiStrings = {
newAttributeModalTitle: undefined,
emptyStateSubtitle: undefined,
newAttributeListItemLabel: __( 'Add attributes', 'woocommerce' ),
newAttributeListItemLabel: __( 'Add new', 'woocommerce' ),
globalAttributeHelperMessage: __(
`You can change the attribute's name in <link>Attributes</link>.`,
'woocommerce'
),
},
} ) => {
newAttributeModalNotice: __(
'By default, attributes are filterable and visible on the product page. You can change these settings for each attribute separately later.',
'woocommerce'
),
attributeRemoveConfirmationMessage: __(
'Remove this attribute?',
'woocommerce'
),
...uiStrings,
};
const [ isNewModalVisible, setIsNewModalVisible ] = useState( false );
const [ currentAttributeId, setCurrentAttributeId ] = useState<
null | string
Expand All @@ -97,7 +109,7 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {

const handleRemove = ( attribute: ProductAttribute ) => {
// eslint-disable-next-line no-alert
if ( window.confirm( __( 'Remove this attribute?', 'woocommerce' ) ) ) {
if ( window.confirm( uiStrings?.attributeRemoveConfirmationMessage ) ) {
handleChange(
value.filter(
( attr ) =>
Expand Down Expand Up @@ -213,6 +225,7 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
{ sortedAttributes.map( ( attr ) => (
<AttributeListItem
attribute={ attr }
removeLabel={ uiStrings?.attributeRemoveLabel }
key={ getAttributeId( attr ) }
onEditClick={ () => openEditModal( attr ) }
onRemoveClick={ () => handleRemove( attr ) }
Expand All @@ -224,6 +237,7 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
{ isNewModalVisible && (
<NewAttributeModal
title={ uiStrings.newAttributeModalTitle }
notice={ uiStrings.newAttributeModalNotice }
onCancel={ () => {
closeNewModal();
onNewModalCancel();
Expand All @@ -240,6 +254,9 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
__( 'Edit %s', 'woocommerce' ),
currentAttribute.name
) }
customAttributeHelperMessage={
uiStrings.customAttributeHelperMessage
}
globalAttributeHelperMessage={ createInterpolateElement(
uiStrings.globalAttributeHelperMessage,
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.woocommerce-new-attribute-modal {
min-width: 50%;
.components-notice.is-info {
margin-left: 0;
margin-right: 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,11 @@ export const NewAttributeModal: React.FC< NewAttributeModalProps > = ( {
} }
className="woocommerce-new-attribute-modal"
>
<Notice isDismissible={ false }>
<p>{ notice }</p>
</Notice>
{ notice && (
<Notice isDismissible={ false }>
<p>{ notice }</p>
</Notice>
) }

<div className="woocommerce-new-attribute-modal__body">
<table className="woocommerce-new-attribute-modal__table">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,11 @@ describe( 'AttributeControl', () => {
} );

describe( 'empty state', () => {
it( 'should show subtitle and "Add attributes" button', () => {
it( 'should show subtitle and "Add new" button', () => {
const { queryByText } = render(
<AttributeControl value={ [] } onChange={ () => {} } />
);
expect( queryByText( 'Add attributes' ) ).toBeInTheDocument();
expect( queryByText( 'Add new' ) ).toBeInTheDocument();
} );
} );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type AttributeListItemProps = {

export const AttributeListItem: React.FC< AttributeListItemProps > = ( {
attribute,
editLabel = __( 'edit', 'woocommerce' ),
editLabel = __( 'Edit', 'woocommerce' ),
removeLabel = __( 'Remove attribute', 'woocommerce' ),
onDragStart,
onDragEnd,
Expand Down
4 changes: 4 additions & 0 deletions plugins/woocommerce/changelog/add-variation-options-block
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: update

Add 'variable' to supported post types for product block editor
12 changes: 10 additions & 2 deletions plugins/woocommerce/src/Admin/Features/ProductBlockEditor/Init.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Init {
*
* @var array
*/
private $supported_post_types = array( 'simple' );
private $supported_post_types = array( 'simple', 'variable' );

/**
* Redirection controller.
Expand Down Expand Up @@ -727,7 +727,15 @@ public function add_product_template( $args ) {
'</strong>'
),
),
array(),
array(
array(
'woocommerce/product-section',
array(
'title' => __( 'Variation options', 'woocommerce' ),
),
array( array( 'woocommerce/product-variations-options-field' ) ),
),
),
),
),
)
Expand Down

0 comments on commit 403c8ba

Please sign in to comment.