Template API: Conditional disabling support (#41307)
* Add disable conditions functionality to back-end * Evaluate _templateBlockDisableConditions in registerWooBlockType * Add 'disabled' support for number, pricing, and text * Add disabled support for checkbox * Add disabled for taxonomy block * Add changelogs * Update documentation * Add unit tests * Augment attribute with disabled in back-end * Fix disabled styling * Remove disabled from toggle since it's being added for all blocks * Improve CSS for disabled fields * Only add disabled attribute when it's not added on the block json and refactor * Allow adding disable conditions in the constructor * Fix lint issue * Fix test * Add disableConditions to dependencies
This commit is contained in:
parent
7ec5a88573
commit
55766ac140
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Use _templateBlockDisableConditions attribute to evaluate disabled attribute
|
|
@ -46,31 +46,46 @@ function getEdit<
|
|||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore context is added to the block props by the block editor.
|
||||
const { context } = props;
|
||||
const { _templateBlockHideConditions: hideConditions } =
|
||||
props.attributes;
|
||||
const {
|
||||
_templateBlockHideConditions: hideConditions,
|
||||
_templateBlockDisableConditions: disableConditions,
|
||||
} = props.attributes;
|
||||
|
||||
const { getEvaluationContext } = useEvaluationContext( context );
|
||||
|
||||
const shouldHide = useSelect(
|
||||
const { shouldHide, shouldDisable } = useSelect(
|
||||
( select: typeof WPSelect ) => {
|
||||
if ( ! hideConditions || ! Array.isArray( hideConditions ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const evaluationContext = getEvaluationContext( select );
|
||||
|
||||
return hideConditions.some( ( condition ) =>
|
||||
evaluate( condition.expression, evaluationContext )
|
||||
);
|
||||
return {
|
||||
shouldHide:
|
||||
hideConditions &&
|
||||
Array.isArray( hideConditions ) &&
|
||||
hideConditions.some( ( condition ) =>
|
||||
evaluate( condition.expression, evaluationContext )
|
||||
),
|
||||
shouldDisable:
|
||||
disableConditions &&
|
||||
Array.isArray( disableConditions ) &&
|
||||
disableConditions.some( ( condition ) =>
|
||||
evaluate( condition.expression, evaluationContext )
|
||||
),
|
||||
};
|
||||
},
|
||||
[ getEvaluationContext, hideConditions ]
|
||||
[ getEvaluationContext, hideConditions, disableConditions ]
|
||||
);
|
||||
|
||||
if ( ! edit || shouldHide ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createElement( edit, props );
|
||||
return createElement( edit, {
|
||||
...props,
|
||||
attributes: {
|
||||
...props.attributes,
|
||||
disabled: props.attributes.disabled || shouldDisable,
|
||||
},
|
||||
} );
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -95,6 +110,14 @@ function augmentAttributes<
|
|||
type: 'array',
|
||||
__experimentalRole: 'content',
|
||||
},
|
||||
_templateBlockDisableConditions: {
|
||||
type: 'array',
|
||||
__experimentalRole: 'content',
|
||||
},
|
||||
disabled: attributes.disabled || {
|
||||
type: 'boolean',
|
||||
__experimentalRole: 'content',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -54,6 +54,14 @@ describe( 'registerWooBlockType', () => {
|
|||
type: 'array',
|
||||
__experimentalRole: 'content',
|
||||
},
|
||||
_templateBlockDisableConditions: {
|
||||
__experimentalRole: 'content',
|
||||
type: 'array',
|
||||
},
|
||||
disabled: {
|
||||
__experimentalRole: 'content',
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add support for disabled state in SelectTree
|
|
@ -11,7 +11,17 @@
|
|||
box-sizing: border-box;
|
||||
|
||||
&--disabled {
|
||||
opacity: 0.5;
|
||||
background-color: $gray-100;
|
||||
border-color: $gray-400;
|
||||
opacity: 1.0;
|
||||
.woocommerce-experimental-select-control {
|
||||
&__items-wrapper {
|
||||
opacity: 0.5;
|
||||
}
|
||||
&__suffix {
|
||||
fill: $gray-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.woocommerce-experimental-select-control {
|
||||
&__input:disabled {
|
||||
background-color: $gray-100;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-experimental-select-tree-control__dropdown {
|
||||
display: block;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ interface SelectTreeProps extends TreeControlProps {
|
|||
treeRef?: React.ForwardedRef< HTMLOListElement >;
|
||||
suffix?: JSX.Element | null;
|
||||
isLoading?: boolean;
|
||||
disabled?: boolean;
|
||||
label: string | JSX.Element;
|
||||
onInputChange?: ( value: string | undefined ) => void;
|
||||
initialInputValue?: string | undefined;
|
||||
|
@ -36,6 +37,7 @@ export const SelectTree = function SelectTree( {
|
|||
suffix = <SuffixIcon icon={ chevronDown } />,
|
||||
placeholder,
|
||||
isLoading,
|
||||
disabled,
|
||||
initialInputValue,
|
||||
onInputChange,
|
||||
shouldShowCreateButton,
|
||||
|
@ -98,6 +100,7 @@ export const SelectTree = function SelectTree( {
|
|||
'aria-autocomplete': 'list',
|
||||
'aria-controls': `${ props.id }-menu`,
|
||||
autoComplete: 'off',
|
||||
disabled,
|
||||
onFocus: ( event ) => {
|
||||
if ( ! isOpen ) {
|
||||
setIsOpen( true );
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add support for disabled state for checkbox, number, pricing, taxonomy, and text blocks
|
|
@ -16,8 +16,15 @@ export function Edit( {
|
|||
attributes,
|
||||
context: { postType },
|
||||
}: ProductEditorBlockEditProps< CheckboxBlockAttributes > ) {
|
||||
const { property, title, label, tooltip, checkedValue, uncheckedValue } =
|
||||
attributes;
|
||||
const {
|
||||
property,
|
||||
title,
|
||||
label,
|
||||
tooltip,
|
||||
checkedValue,
|
||||
uncheckedValue,
|
||||
disabled,
|
||||
} = attributes;
|
||||
|
||||
const blockProps = useWooBlockProps( attributes );
|
||||
|
||||
|
@ -39,6 +46,7 @@ export function Edit( {
|
|||
tooltip={ tooltip }
|
||||
checkedValue={ checkedValue }
|
||||
uncheckedValue={ uncheckedValue }
|
||||
disabled={ disabled }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -30,6 +30,7 @@ export function Edit( {
|
|||
max,
|
||||
required,
|
||||
tooltip,
|
||||
disabled,
|
||||
} = attributes;
|
||||
const [ value, setValue ] = useProductEntityProp( property, {
|
||||
postType,
|
||||
|
@ -91,6 +92,7 @@ export function Edit( {
|
|||
} }
|
||||
required={ required }
|
||||
tooltip={ tooltip }
|
||||
disabled={ disabled }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -27,7 +27,7 @@ export function Edit( {
|
|||
context: { postType },
|
||||
}: ProductEditorBlockEditProps< PricingBlockAttributes > ) {
|
||||
const blockProps = useWooBlockProps( attributes );
|
||||
const { property, label, help } = attributes;
|
||||
const { property, label, help, disabled } = attributes;
|
||||
const [ price, setPrice ] = useProductEntityProp< string >( property, {
|
||||
postType,
|
||||
fallbackValue: '',
|
||||
|
@ -60,6 +60,7 @@ export function Edit( {
|
|||
<BaseControl id={ priceId } help={ interpolatedHelp }>
|
||||
<InputControl
|
||||
{ ...inputProps }
|
||||
disabled={ disabled }
|
||||
id={ priceId }
|
||||
name={ property }
|
||||
label={ label || __( 'Price', 'woocommerce' ) }
|
||||
|
|
|
@ -51,6 +51,7 @@ export function Edit( {
|
|||
createTitle,
|
||||
dialogNameHelpText,
|
||||
parentTaxonomyText,
|
||||
disabled,
|
||||
} = attributes;
|
||||
const [ searchValue, setSearchValue ] = useState( '' );
|
||||
const [ allEntries, setAllEntries ] = useState< Taxonomy[] >( [] );
|
||||
|
@ -105,6 +106,7 @@ export function Edit( {
|
|||
}
|
||||
label={ label }
|
||||
isLoading={ isResolving }
|
||||
disabled={ disabled }
|
||||
multiple
|
||||
createValue={ searchValue }
|
||||
onInputChange={ searchDelayed }
|
||||
|
|
|
@ -32,6 +32,7 @@ export function Edit( {
|
|||
maxLength,
|
||||
help,
|
||||
tooltip,
|
||||
disabled,
|
||||
} = attributes;
|
||||
const [ value, setValue ] = useProductEntityProp< string >( property, {
|
||||
postType,
|
||||
|
@ -87,6 +88,7 @@ export function Edit( {
|
|||
<div { ...blockProps }>
|
||||
<TextControl
|
||||
value={ value }
|
||||
disabled={ disabled }
|
||||
label={ label }
|
||||
onChange={ setValue }
|
||||
onBlur={ () => {
|
||||
|
|
|
@ -17,6 +17,7 @@ export type CheckboxProps = {
|
|||
onChange: ( selected: boolean | string | null ) => void;
|
||||
checkedValue?: string | null;
|
||||
uncheckedValue?: string | null;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export const Checkbox: React.FC< CheckboxProps > = ( {
|
||||
|
@ -27,6 +28,7 @@ export const Checkbox: React.FC< CheckboxProps > = ( {
|
|||
title,
|
||||
checkedValue,
|
||||
uncheckedValue,
|
||||
disabled,
|
||||
}: CheckboxProps ) => {
|
||||
function isChecked() {
|
||||
if ( checkedValue !== undefined ) {
|
||||
|
@ -50,6 +52,7 @@ export const Checkbox: React.FC< CheckboxProps > = ( {
|
|||
label={ label }
|
||||
checked={ isChecked() }
|
||||
onChange={ handleChange }
|
||||
disabled={ disabled }
|
||||
/>
|
||||
{ tooltip && (
|
||||
<Tooltip
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
.woocommerce-product-form__checkbox {
|
||||
.components-checkbox-control__input:disabled {
|
||||
opacity: 1;
|
||||
background-color: $gray-100;
|
||||
border-color: $gray-400;
|
||||
}
|
||||
.components-checkbox-control__input:disabled + svg {
|
||||
fill: $gray-400;
|
||||
}
|
||||
.components-base-control__field,
|
||||
.components-checkbox-control__label,
|
||||
&-wrapper,
|
||||
|
|
|
@ -27,6 +27,7 @@ export type NumberProps = {
|
|||
onBlur?: () => void;
|
||||
required?: boolean;
|
||||
tooltip?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export const NumberControl: React.FC< NumberProps > = ( {
|
||||
|
@ -40,6 +41,7 @@ export const NumberControl: React.FC< NumberProps > = ( {
|
|||
required,
|
||||
tooltip,
|
||||
placeholder,
|
||||
disabled,
|
||||
}: NumberProps ) => {
|
||||
const inputProps = useNumberInputProps( {
|
||||
value: value || '',
|
||||
|
@ -65,6 +67,7 @@ export const NumberControl: React.FC< NumberProps > = ( {
|
|||
>
|
||||
<InputControl
|
||||
{ ...inputProps }
|
||||
disabled={ disabled }
|
||||
id={ id }
|
||||
suffix={ suffix }
|
||||
placeholder={ placeholder }
|
||||
|
|
|
@ -25,6 +25,7 @@ export type TextProps = {
|
|||
required?: boolean;
|
||||
onBlur?: () => void;
|
||||
tooltip?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export const TextControl: React.FC< TextProps > = ( {
|
||||
|
@ -37,6 +38,7 @@ export const TextControl: React.FC< TextProps > = ( {
|
|||
placeholder,
|
||||
required,
|
||||
tooltip,
|
||||
disabled,
|
||||
}: TextProps ) => {
|
||||
const textControlId = useInstanceId(
|
||||
BaseControl,
|
||||
|
@ -59,6 +61,7 @@ export const TextControl: React.FC< TextProps > = ( {
|
|||
>
|
||||
<InputControl
|
||||
id={ textControlId }
|
||||
disabled={ disabled }
|
||||
placeholder={ placeholder }
|
||||
value={ value }
|
||||
onChange={ onChange }
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
@import "components/product-page-skeleton/styles.scss";
|
||||
@import "components/modal-editor-welcome-guide/style.scss";
|
||||
@import "components/attribute-control/attribute-skeleton.scss";
|
||||
@import "components/checkbox-control/style.scss";
|
||||
|
||||
/* Field Blocks */
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add API to allow adding disable conditions
|
|
@ -31,6 +31,11 @@ interface BlockInterface {
|
|||
*/
|
||||
public const HIDE_CONDITIONS_KEY = 'hideConditions';
|
||||
|
||||
/**
|
||||
* Key for the block disable conditions in the block configuration.
|
||||
*/
|
||||
public const DISABLE_CONDITIONS_KEY = 'disableConditions';
|
||||
|
||||
/**
|
||||
* Get the block name.
|
||||
*/
|
||||
|
@ -110,6 +115,29 @@ interface BlockInterface {
|
|||
*/
|
||||
public function get_hide_conditions(): array;
|
||||
|
||||
/**
|
||||
* Add a disable condition to the block.
|
||||
*
|
||||
* The disable condition is a JavaScript-like expression that will be evaluated on the client to determine if the block should be disabled.
|
||||
* See [@woocommerce/expression-evaluation](https://github.com/woocommerce/woocommerce/blob/trunk/packages/js/expression-evaluation/README.md) for more details.
|
||||
*
|
||||
* @param string $expression An expression, which if true, will disable the block.
|
||||
* @return string The key of the disable condition, which can be used to remove the disable condition.
|
||||
*/
|
||||
public function add_disable_condition( string $expression ): string;
|
||||
|
||||
/**
|
||||
* Remove a disable condition from the block.
|
||||
*
|
||||
* @param string $key The key of the disable condition to remove.
|
||||
*/
|
||||
public function remove_disable_condition( string $key );
|
||||
|
||||
/**
|
||||
* Get the disable conditions of the block.
|
||||
*/
|
||||
public function get_disable_conditions(): array;
|
||||
|
||||
/**
|
||||
* Get the block configuration as a formatted template.
|
||||
*
|
||||
|
|
|
@ -217,6 +217,18 @@ Removes a hide condition from the block, referenced by the key returned from `ad
|
|||
|
||||
Get the hide conditions for the block.
|
||||
|
||||
##### `add_disable_condition( string $expression ): string`
|
||||
|
||||
Adds a disable condition to the block. Similar to `add_hide_condition()`, but the block is shown as disabled instead of hidden.
|
||||
|
||||
##### `remove_disable_condition( string $key )`
|
||||
|
||||
Removes a disable condition from the block, referenced by the key returned from `add_disable_condition()`.
|
||||
|
||||
##### `get_disable_conditions(): array`
|
||||
|
||||
Get the disable conditions for the block.
|
||||
|
||||
##### `get_formatted_template(): array`
|
||||
|
||||
Get the block configuration as a formatted template.
|
||||
|
|
|
@ -23,7 +23,7 @@ class BlockRegistry {
|
|||
/**
|
||||
* Array of all available generic blocks.
|
||||
*/
|
||||
const GENERIC_BLOCKS = [
|
||||
const GENERIC_BLOCKS = array(
|
||||
'woocommerce/conditional',
|
||||
'woocommerce/product-checkbox-field',
|
||||
'woocommerce/product-collapsible',
|
||||
|
@ -35,12 +35,12 @@ class BlockRegistry {
|
|||
'woocommerce/product-taxonomy-field',
|
||||
'woocommerce/product-text-field',
|
||||
'woocommerce/product-number-field',
|
||||
];
|
||||
);
|
||||
|
||||
/**
|
||||
* Array of all available product fields blocks.
|
||||
*/
|
||||
const PRODUCT_FIELDS_BLOCKS = [
|
||||
const PRODUCT_FIELDS_BLOCKS = array(
|
||||
'woocommerce/product-catalog-visibility-field',
|
||||
'woocommerce/product-description-field',
|
||||
'woocommerce/product-downloads-field',
|
||||
|
@ -61,7 +61,7 @@ class BlockRegistry {
|
|||
'woocommerce/product-password-field',
|
||||
'woocommerce/product-has-variations-notice',
|
||||
'woocommerce/product-single-variation-notice',
|
||||
];
|
||||
);
|
||||
|
||||
/**
|
||||
* Get a file path for a given block file.
|
||||
|
@ -136,20 +136,28 @@ class BlockRegistry {
|
|||
// registerWooBlockType function in @woocommerce/block-templates.
|
||||
return array_merge(
|
||||
$attributes,
|
||||
[
|
||||
'_templateBlockId' => [
|
||||
array(
|
||||
'_templateBlockId' => array(
|
||||
'type' => 'string',
|
||||
'__experimentalRole' => 'content',
|
||||
],
|
||||
'_templateBlockOrder' => [
|
||||
),
|
||||
'_templateBlockOrder' => array(
|
||||
'type' => 'integer',
|
||||
'__experimentalRole' => 'content',
|
||||
],
|
||||
'_templateBlockHideConditions' => [
|
||||
),
|
||||
'_templateBlockHideConditions' => array(
|
||||
'type' => 'array',
|
||||
'__experimentalRole' => 'content',
|
||||
],
|
||||
]
|
||||
),
|
||||
'_templateBlockDisableConditions' => array(
|
||||
'type' => 'array',
|
||||
'__experimentalRole' => 'content',
|
||||
),
|
||||
'disabled' => isset( $attributes['disabled'] ) ? $attributes['disabled'] : array(
|
||||
'type' => 'boolean',
|
||||
'__experimentalRole' => 'content',
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -162,10 +170,10 @@ class BlockRegistry {
|
|||
// Note: If you modify this function, also update the client-side
|
||||
// registerProductEditorBlockType function in @woocommerce/product-editor.
|
||||
return array_merge(
|
||||
isset( $uses_context ) ? $uses_context : [],
|
||||
[
|
||||
isset( $uses_context ) ? $uses_context : array(),
|
||||
array(
|
||||
'postType',
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -199,10 +207,10 @@ class BlockRegistry {
|
|||
|
||||
return register_block_type_from_metadata(
|
||||
$block_json_file,
|
||||
[
|
||||
'attributes' => $this->augment_attributes( isset( $metadata['attributes'] ) ? $metadata['attributes'] : [] ),
|
||||
'uses_context' => $this->augment_uses_context( isset( $metadata['usesContext'] ) ? $metadata['usesContext'] : [] ),
|
||||
]
|
||||
array(
|
||||
'attributes' => $this->augment_attributes( isset( $metadata['attributes'] ) ? $metadata['attributes'] : array() ),
|
||||
'uses_context' => $this->augment_uses_context( isset( $metadata['usesContext'] ) ? $metadata['usesContext'] : array() ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ add_action( 'woocommerce_block_template_area_product-form_after_remove_block_sal
|
|||
```php
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||
|
||||
// hide sale price block if regular_price is less than 10
|
||||
function YOUR_PREFIX_hide_block( BlockInterface $sale_price_block ) {
|
||||
$sale_price_block->add_hide_condition( 'editedProduct.regular_price < 10' );
|
||||
}
|
||||
|
@ -78,6 +79,21 @@ function YOUR_PREFIX_hide_block( BlockInterface $sale_price_block ) {
|
|||
add_action( 'woocommerce_block_template_area_product-form_after_add_block_sale-price', 'YOUR_PREFIX_hide_block' );
|
||||
```
|
||||
|
||||
### Conditionally disabling a block in product editor templates
|
||||
|
||||
```php
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||
|
||||
// disable sale price block if regular_price is not set
|
||||
function YOUR_PREFIX_hide_block( BlockInterface $sale_price_block ) {
|
||||
$sale_price_block->add_disable_condition( '!editedProduct.regular_price' );
|
||||
}
|
||||
|
||||
add_action( 'woocommerce_block_template_area_product-form_after_add_block_sale-price', 'YOUR_PREFIX_hide_block' );
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Interfaces
|
||||
|
||||
### GroupInterface
|
||||
|
|
|
@ -38,14 +38,14 @@ class AbstractBlock implements BlockInterface {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
private $attributes = [];
|
||||
private $attributes = array();
|
||||
|
||||
/**
|
||||
* The block hide conditions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $hide_conditions = [];
|
||||
private $hide_conditions = array();
|
||||
|
||||
/**
|
||||
* The block hide conditions counter.
|
||||
|
@ -54,6 +54,20 @@ class AbstractBlock implements BlockInterface {
|
|||
*/
|
||||
private $hide_conditions_counter = 0;
|
||||
|
||||
/**
|
||||
* The block disable conditions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $disable_conditions = array();
|
||||
|
||||
/**
|
||||
* The block disable conditions counter.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $disable_conditions_counter = 0;
|
||||
|
||||
/**
|
||||
* The block template that this block belongs to.
|
||||
*
|
||||
|
@ -105,6 +119,12 @@ class AbstractBlock implements BlockInterface {
|
|||
$this->add_hide_condition( $hide_condition['expression'] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $config[ self::DISABLE_CONDITIONS_KEY ] ) ) {
|
||||
foreach ( $config[ self::DISABLE_CONDITIONS_KEY ] as $disable_condition ) {
|
||||
$this->add_disable_condition( $disable_condition['expression'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,9 +248,9 @@ class AbstractBlock implements BlockInterface {
|
|||
|
||||
// Storing the expression in an array to allow for future expansion
|
||||
// (such as adding the plugin that added the condition).
|
||||
$this->hide_conditions[ $key ] = [
|
||||
$this->hide_conditions[ $key ] = array(
|
||||
'expression' => $expression,
|
||||
];
|
||||
);
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
@ -250,4 +270,41 @@ class AbstractBlock implements BlockInterface {
|
|||
public function get_hide_conditions(): array {
|
||||
return $this->hide_conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a disable condition to the block.
|
||||
*
|
||||
* The disable condition is a JavaScript-like expression that will be evaluated on the client to determine if the block should be hidden.
|
||||
* See [@woocommerce/expression-evaluation](https://github.com/woocommerce/woocommerce/blob/trunk/packages/js/expression-evaluation/README.md) for more details.
|
||||
*
|
||||
* @param string $expression An expression, which if true, will disable the block.
|
||||
*/
|
||||
public function add_disable_condition( string $expression ): string {
|
||||
$key = 'k' . $this->disable_conditions_counter;
|
||||
$this->disable_conditions_counter++;
|
||||
|
||||
// Storing the expression in an array to allow for future expansion
|
||||
// (such as adding the plugin that added the condition).
|
||||
$this->disable_conditions[ $key ] = array(
|
||||
'expression' => $expression,
|
||||
);
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a disable condition from the block.
|
||||
*
|
||||
* @param string $key The key of the disable condition to remove.
|
||||
*/
|
||||
public function remove_disable_condition( string $key ) {
|
||||
unset( $this->disable_conditions[ $key ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the disable conditions of the block.
|
||||
*/
|
||||
public function get_disable_conditions(): array {
|
||||
return $this->disable_conditions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,19 +12,22 @@ trait BlockFormattedTemplateTrait {
|
|||
* @return array The block configuration as a formatted template.
|
||||
*/
|
||||
public function get_formatted_template(): array {
|
||||
$arr = [
|
||||
$arr = array(
|
||||
$this->get_name(),
|
||||
array_merge(
|
||||
$this->get_attributes(),
|
||||
[
|
||||
array(
|
||||
'_templateBlockId' => $this->get_id(),
|
||||
'_templateBlockOrder' => $this->get_order(),
|
||||
],
|
||||
! empty( $this->get_hide_conditions() ) ? [
|
||||
),
|
||||
! empty( $this->get_hide_conditions() ) ? array(
|
||||
'_templateBlockHideConditions' => $this->get_formatted_hide_conditions(),
|
||||
] : []
|
||||
) : array(),
|
||||
! empty( $this->get_disable_conditions() ) ? array(
|
||||
'_templateBlockDisableConditions' => $this->get_formatted_disable_conditions(),
|
||||
) : array(),
|
||||
),
|
||||
];
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
@ -33,15 +36,31 @@ trait BlockFormattedTemplateTrait {
|
|||
* Get the block hide conditions formatted for inclusion in a formatted template.
|
||||
*/
|
||||
private function get_formatted_hide_conditions(): array {
|
||||
$formatted_hide_conditions = array_map(
|
||||
function( $hide_condition ) {
|
||||
return [
|
||||
'expression' => $hide_condition['expression'],
|
||||
];
|
||||
return $this->format_conditions( $this->get_hide_conditions() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block disable conditions formatted for inclusion in a formatted template.
|
||||
*/
|
||||
private function get_formatted_disable_conditions(): array {
|
||||
return $this->format_conditions( $this->get_disable_conditions() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats conditions in the expected format to include in the template.
|
||||
*
|
||||
* @param array $conditions The conditions to format.
|
||||
*/
|
||||
private function format_conditions( $conditions ): array {
|
||||
$formatted_expressions = array_map(
|
||||
function( $condition ) {
|
||||
return array(
|
||||
'expression' => $condition['expression'],
|
||||
);
|
||||
},
|
||||
array_values( $this->get_hide_conditions() )
|
||||
array_values( $conditions )
|
||||
);
|
||||
|
||||
return $formatted_hide_conditions;
|
||||
return $formatted_expressions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
|
||||
$this->expectException( \ValueError::class );
|
||||
|
||||
new Block( [], $template );
|
||||
new Block( array(), $template );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,9 +32,9 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template = new BlockTemplate();
|
||||
|
||||
$block = new Block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'test-block-name',
|
||||
],
|
||||
),
|
||||
$template
|
||||
);
|
||||
|
||||
|
@ -49,18 +49,18 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template_2 = new BlockTemplate();
|
||||
|
||||
$parent = new Block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'test-block-parent-name',
|
||||
],
|
||||
),
|
||||
$template_2
|
||||
);
|
||||
|
||||
$this->expectException( \ValueError::class );
|
||||
|
||||
new Block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'test-block-name',
|
||||
],
|
||||
),
|
||||
$template,
|
||||
$parent
|
||||
);
|
||||
|
@ -74,17 +74,17 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id',
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$child_block = $block->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id-2',
|
||||
'blockName' => 'test-block-name-2',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
|
@ -113,17 +113,17 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id',
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$child_block = $block->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id-2',
|
||||
'blockName' => 'test-block-name-2',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$block->remove_block( 'test-block-id-2' );
|
||||
|
@ -152,17 +152,17 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id',
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$child_block = $block->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id-2',
|
||||
'blockName' => 'test-block-name-2',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$template->remove_block( 'test-block-id-2' );
|
||||
|
@ -191,17 +191,17 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id',
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$child_block = $block->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id-2',
|
||||
'blockName' => 'test-block-name-2',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$template->remove_block( 'test-block-id' );
|
||||
|
@ -239,10 +239,10 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id',
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$block->remove();
|
||||
|
@ -260,27 +260,27 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$block_template = new BlockTemplate();
|
||||
|
||||
$block = $block_template->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$child_block_1 = $block->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$block->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$grandchild_block = $child_block_1->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
|
@ -317,19 +317,19 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id',
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$template->remove_block( 'test-block-id' );
|
||||
|
||||
$child_block = $block->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id-2',
|
||||
'blockName' => 'test-block-name-2',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertNull(
|
||||
|
@ -360,27 +360,55 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'test-block-name',
|
||||
'hideConditions' => [
|
||||
[
|
||||
'hideConditions' => array(
|
||||
array(
|
||||
'expression' => 'foo === bar',
|
||||
],
|
||||
],
|
||||
]
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
[
|
||||
'k0' => [
|
||||
array(
|
||||
'k0' => array(
|
||||
'expression' => 'foo === bar',
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
$block->get_hide_conditions(),
|
||||
'Failed asserting that the hide conditions are set correctly in the constructor.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that disable conditions can be passed in when creating a block.
|
||||
*/
|
||||
public function test_disable_conditions_in_constructor() {
|
||||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
array(
|
||||
'blockName' => 'test-block-name',
|
||||
'disableConditions' => array(
|
||||
array(
|
||||
'expression' => 'foo === bar',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
array(
|
||||
'k0' => array(
|
||||
'expression' => 'foo === bar',
|
||||
),
|
||||
),
|
||||
$block->get_disable_conditions(),
|
||||
'Failed asserting that the disable conditions are set correctly in the constructor.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that hide conditions can be added to a block.
|
||||
*/
|
||||
|
@ -388,9 +416,9 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$condition_1_key = $block->add_hide_condition( 'editedProduct.manage_stock === true' );
|
||||
|
@ -402,19 +430,53 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$block->remove_hide_condition( $condition_2_key );
|
||||
|
||||
$this->assertSame(
|
||||
[
|
||||
$condition_1_key => [
|
||||
array(
|
||||
$condition_1_key => array(
|
||||
'expression' => 'editedProduct.manage_stock === true',
|
||||
],
|
||||
$condition_3_key => [
|
||||
),
|
||||
$condition_3_key => array(
|
||||
'expression' => 'foo > 10',
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
$block->get_hide_conditions(),
|
||||
'Failed asserting that the hide conditions are added correctly.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that hide conditions can be added to a block.
|
||||
*/
|
||||
public function test_add_disable_condition() {
|
||||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
array(
|
||||
'blockName' => 'test-block-name',
|
||||
)
|
||||
);
|
||||
|
||||
$condition_1_key = $block->add_disable_condition( 'editedProduct.manage_stock === true' );
|
||||
|
||||
$condition_2_key = $block->add_disable_condition( 'true' );
|
||||
|
||||
$condition_3_key = $block->add_disable_condition( 'foo > 10' );
|
||||
|
||||
$block->remove_disable_condition( $condition_2_key );
|
||||
|
||||
$this->assertSame(
|
||||
array(
|
||||
$condition_1_key => array(
|
||||
'expression' => 'editedProduct.manage_stock === true',
|
||||
),
|
||||
$condition_3_key => array(
|
||||
'expression' => 'foo > 10',
|
||||
),
|
||||
),
|
||||
$block->get_disable_conditions(),
|
||||
'Failed asserting that the hide conditions are added correctly.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that getting the block as a formatted template is structured correctly.
|
||||
*/
|
||||
|
@ -422,71 +484,78 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id',
|
||||
'blockName' => 'test-block-name',
|
||||
'attributes' => [
|
||||
'attributes' => array(
|
||||
'attr-1' => 'value-1',
|
||||
'attr-2' => 'value-2',
|
||||
],
|
||||
]
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$block->add_hide_condition( 'foo === bar' );
|
||||
|
||||
$block->add_disable_condition( 'test > 100' );
|
||||
|
||||
$block->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id-2',
|
||||
'blockName' => 'test-block-name-2',
|
||||
'attributes' => [
|
||||
'attributes' => array(
|
||||
'attr-3' => 'value-3',
|
||||
'attr-4' => 'value-4',
|
||||
],
|
||||
]
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$block->add_block(
|
||||
[
|
||||
array(
|
||||
'id' => 'test-block-id-3',
|
||||
'blockName' => 'test-block-name-3',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$formatted_template = $block->get_formatted_template();
|
||||
|
||||
$this->assertSame(
|
||||
[
|
||||
array(
|
||||
'test-block-name',
|
||||
[
|
||||
'attr-1' => 'value-1',
|
||||
'attr-2' => 'value-2',
|
||||
'_templateBlockId' => 'test-block-id',
|
||||
'_templateBlockOrder' => 10000,
|
||||
'_templateBlockHideConditions' => [
|
||||
[
|
||||
array(
|
||||
'attr-1' => 'value-1',
|
||||
'attr-2' => 'value-2',
|
||||
'_templateBlockId' => 'test-block-id',
|
||||
'_templateBlockOrder' => 10000,
|
||||
'_templateBlockHideConditions' => array(
|
||||
array(
|
||||
'expression' => 'foo === bar',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
),
|
||||
),
|
||||
'_templateBlockDisableConditions' => array(
|
||||
array(
|
||||
'expression' => 'test > 100',
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'test-block-name-2',
|
||||
[
|
||||
array(
|
||||
'attr-3' => 'value-3',
|
||||
'attr-4' => 'value-4',
|
||||
'_templateBlockId' => 'test-block-id-2',
|
||||
'_templateBlockOrder' => 10000,
|
||||
],
|
||||
],
|
||||
[
|
||||
),
|
||||
),
|
||||
array(
|
||||
'test-block-name-3',
|
||||
[
|
||||
array(
|
||||
'_templateBlockId' => 'test-block-id-3',
|
||||
'_templateBlockOrder' => 10000,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
$formatted_template,
|
||||
'Failed asserting that the block is converted to a formatted template correctly.'
|
||||
);
|
||||
|
@ -499,91 +568,91 @@ class BlockTest extends WC_Unit_Test_Case {
|
|||
$template = new BlockTemplate();
|
||||
|
||||
$block = $template->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'test-block-name',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$block->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'five',
|
||||
'order' => 5,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$block->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'three',
|
||||
'order' => 3,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$block->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'one',
|
||||
'order' => 1,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$block->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'four',
|
||||
'order' => 4,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$block->add_block(
|
||||
[
|
||||
array(
|
||||
'blockName' => 'two',
|
||||
'order' => 2,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
[
|
||||
array(
|
||||
'test-block-name',
|
||||
[
|
||||
array(
|
||||
'_templateBlockId' => 'test-block-name-1',
|
||||
'_templateBlockOrder' => 10000,
|
||||
],
|
||||
[
|
||||
[
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'one',
|
||||
[
|
||||
array(
|
||||
'_templateBlockId' => 'one-1',
|
||||
'_templateBlockOrder' => 1,
|
||||
],
|
||||
],
|
||||
[
|
||||
),
|
||||
),
|
||||
array(
|
||||
'two',
|
||||
[
|
||||
array(
|
||||
'_templateBlockId' => 'two-1',
|
||||
'_templateBlockOrder' => 2,
|
||||
],
|
||||
],
|
||||
[
|
||||
),
|
||||
),
|
||||
array(
|
||||
'three',
|
||||
[
|
||||
array(
|
||||
'_templateBlockId' => 'three-1',
|
||||
'_templateBlockOrder' => 3,
|
||||
],
|
||||
],
|
||||
[
|
||||
),
|
||||
),
|
||||
array(
|
||||
'four',
|
||||
[
|
||||
array(
|
||||
'_templateBlockId' => 'four-1',
|
||||
'_templateBlockOrder' => 4,
|
||||
],
|
||||
],
|
||||
[
|
||||
),
|
||||
),
|
||||
array(
|
||||
'five',
|
||||
[
|
||||
array(
|
||||
'_templateBlockId' => 'five-1',
|
||||
'_templateBlockOrder' => 5,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
$block->get_formatted_template(),
|
||||
'Failed asserting that the inner blocks are sorted by order.'
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue