Core block-based template PHP API (adding blocks to templates) (#39470)
* Initial BlockTemplate implementation * Initial BlockTemplate tests * FIx undefined array key errors * Fix linter errors (except for missing docs ones) * Get as simple array * Unit test updates for get_as_simple_array() * Remove inner content (not used currently) * Rename attrs to attributes * Move name out of data array * Move id out of data array * Move order out of data array * Move attributes out of data array; remove data array * Add doc comments to Block * Add doc comments to BlockTemplate * Add doc comments to BlockContainerInterface and BlockContainerTrait * Doc comment updates. * Add doc comments to BlockTest * Add doc comments to BlockTemplateTest * Add BlockInterface * Remove key consts from Block * Move implementations to internal * Clean up interfaces * Do not have BlockInterface extend BlockContainerInterface * FIx case in namespace declaration * Add exceptions to add_block doc * Rename BlockTemplate to BlockBasedTemplate * Rename block-based template vars in tests * Fix missing get_parent on block containers * Changelog * Add get_block_by_id to BlockBasedTemplateInterface * Rename get_block_by_id to get_block * Rename get_as_simple_array to get_as_formatted_template * Rename child blocks to inner blocks * Rename BlockBasedTemplate to BlockTemplate * Move validation to separate method * Move namespace to be non-product editor specific * Rename get_as_formatted_ methods to get_formatted_ * Rename BlockBasedTemplateTest to BlockTemplateTest * Add ability to use a custom block generator with add_block * Add check that block belongs to root template in internal_add_block_to_template * Fix up code docs related to $block_creator * Fix code doc linting errors in tests * Add test for a buggy block creator implementation * Add test for an invalid block creator * Rename internal_add_block_to_template to cache_block * Add add_block_container() method * Fix linting issue. * Fix minor issues in ContainerInterface with get_root_template() and get_parent() * Add block template with abstract blocks and templates (#39630) * Make block template abstract and protected add block methods * Create block abstraction and generic block * Remove add_block from container interface * Update tests for generic and custom blocks * Add tests around custom block templates * Fix up lint errors * Fix errant comment for add_block --------- Co-authored-by: Joshua T Flowers <joshuatf@gmail.com>
This commit is contained in:
parent
91fadfd8fe
commit
e805b6b075
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
API for block-based templates.
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for block containers.
|
||||||
|
*/
|
||||||
|
interface BlockContainerInterface extends BlockInterface, ContainerInterface {}
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for block configuration used to specify blocks in BlockTemplate.
|
||||||
|
*/
|
||||||
|
interface BlockInterface {
|
||||||
|
/**
|
||||||
|
* Key for the block name in the block configuration.
|
||||||
|
*/
|
||||||
|
public const NAME_KEY = 'blockName';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key for the block ID in the block configuration.
|
||||||
|
*/
|
||||||
|
public const ID_KEY = 'id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key for the internal order in the block configuration.
|
||||||
|
*/
|
||||||
|
public const ORDER_KEY = 'order';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key for the block attributes in the block configuration.
|
||||||
|
*/
|
||||||
|
public const ATTRIBUTES_KEY = 'attributes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block name.
|
||||||
|
*/
|
||||||
|
public function get_name(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block ID.
|
||||||
|
*/
|
||||||
|
public function get_id(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block order.
|
||||||
|
*/
|
||||||
|
public function get_order(): int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the block order.
|
||||||
|
*
|
||||||
|
* @param int $order The block order.
|
||||||
|
*/
|
||||||
|
public function set_order( int $order );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block attributes.
|
||||||
|
*/
|
||||||
|
public function get_attributes(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the block attributes.
|
||||||
|
*
|
||||||
|
* @param array $attributes The block attributes.
|
||||||
|
*/
|
||||||
|
public function set_attributes( array $attributes );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the parent container that the block belongs to.
|
||||||
|
*/
|
||||||
|
public function &get_parent(): ?ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the root template that the block belongs to.
|
||||||
|
*/
|
||||||
|
public function &get_root_template(): BlockTemplateInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block configuration as a formatted template.
|
||||||
|
*
|
||||||
|
* @return array The block configuration as a formatted template.
|
||||||
|
*/
|
||||||
|
public function get_formatted_template(): array;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for block-based template.
|
||||||
|
*/
|
||||||
|
interface BlockTemplateInterface extends ContainerInterface {
|
||||||
|
/**
|
||||||
|
* Get a block by ID.
|
||||||
|
*
|
||||||
|
* @param string $block_id The block ID.
|
||||||
|
*/
|
||||||
|
public function get_block( string $block_id ): ?BlockInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a block ID based on a base.
|
||||||
|
*
|
||||||
|
* @param string $id_base The base to use when generating an ID.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function generate_block_id( string $id_base ): string;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for block containers.
|
||||||
|
*/
|
||||||
|
interface ContainerInterface {
|
||||||
|
/**
|
||||||
|
* Get the root template that the block belongs to.
|
||||||
|
*/
|
||||||
|
public function &get_root_template(): BlockTemplateInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block configuration as a formatted template.
|
||||||
|
*/
|
||||||
|
public function get_formatted_template(): array;
|
||||||
|
}
|
|
@ -0,0 +1,189 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block configuration used to specify blocks in BlockTemplate.
|
||||||
|
*/
|
||||||
|
class AbstractBlock implements BlockInterface {
|
||||||
|
/**
|
||||||
|
* The block name.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The block ID.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The block order.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $order = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The block attributes.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $attributes = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The block template that this block belongs to.
|
||||||
|
*
|
||||||
|
* @var BlockTemplate
|
||||||
|
*/
|
||||||
|
private $root_template;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent container.
|
||||||
|
*
|
||||||
|
* @var ContainerInterface
|
||||||
|
*/
|
||||||
|
private $parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block constructor.
|
||||||
|
*
|
||||||
|
* @param array $config The block configuration.
|
||||||
|
* @param BlockTemplateInterface $root_template The block template that this block belongs to.
|
||||||
|
* @param BlockContainerInterface|null $parent The parent block container.
|
||||||
|
*
|
||||||
|
* @throws \ValueError If the block configuration is invalid.
|
||||||
|
* @throws \ValueError If the parent block container does not belong to the same template as the block.
|
||||||
|
*/
|
||||||
|
public function __construct( array $config, BlockTemplateInterface &$root_template, ContainerInterface &$parent = null ) {
|
||||||
|
$this->validate( $config, $root_template, $parent );
|
||||||
|
|
||||||
|
$this->root_template = $root_template;
|
||||||
|
$this->parent = is_null( $parent ) ? $root_template : $parent;
|
||||||
|
|
||||||
|
$this->name = $config[ self::NAME_KEY ];
|
||||||
|
|
||||||
|
if ( ! isset( $config[ self::ID_KEY ] ) ) {
|
||||||
|
$this->id = $this->root_template->generate_block_id( $this->get_name() );
|
||||||
|
} else {
|
||||||
|
$this->id = $config[ self::ID_KEY ];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset( $config[ self::ORDER_KEY ] ) ) {
|
||||||
|
$this->order = $config[ self::ORDER_KEY ];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset( $config[ self::ATTRIBUTES_KEY ] ) ) {
|
||||||
|
$this->attributes = $config[ self::ATTRIBUTES_KEY ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate block configuration.
|
||||||
|
*
|
||||||
|
* @param array $config The block configuration.
|
||||||
|
* @param BlockTemplateInterface $root_template The block template that this block belongs to.
|
||||||
|
* @param ContainerInterface|null $parent The parent block container.
|
||||||
|
*
|
||||||
|
* @throws \ValueError If the block configuration is invalid.
|
||||||
|
* @throws \ValueError If the parent block container does not belong to the same template as the block.
|
||||||
|
*/
|
||||||
|
protected function validate( array $config, BlockTemplateInterface &$root_template, ContainerInterface &$parent = null ) {
|
||||||
|
if ( isset( $parent ) && ( $parent->get_root_template() !== $root_template ) ) {
|
||||||
|
throw new \ValueError( 'The parent block must belong to the same template as the block.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! isset( $config[ self::NAME_KEY ] ) || ! is_string( $config[ self::NAME_KEY ] ) ) {
|
||||||
|
throw new \ValueError( 'The block name must be specified.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset( $config[ self::ORDER_KEY ] ) && ! is_int( $config[ self::ORDER_KEY ] ) ) {
|
||||||
|
throw new \ValueError( 'The block order must be an integer.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset( $config[ self::ATTRIBUTES_KEY ] ) && ! is_array( $config[ self::ATTRIBUTES_KEY ] ) ) {
|
||||||
|
throw new \ValueError( 'The block attributes must be an array.' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block name.
|
||||||
|
*/
|
||||||
|
public function get_name(): string {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block ID.
|
||||||
|
*/
|
||||||
|
public function get_id(): string {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block order.
|
||||||
|
*/
|
||||||
|
public function get_order(): int {
|
||||||
|
return $this->order;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the block order.
|
||||||
|
*
|
||||||
|
* @param int $order The block order.
|
||||||
|
*/
|
||||||
|
public function set_order( int $order ) {
|
||||||
|
$this->order = $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block attributes.
|
||||||
|
*/
|
||||||
|
public function get_attributes(): array {
|
||||||
|
return $this->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the block attributes.
|
||||||
|
*
|
||||||
|
* @param array $attributes The block attributes.
|
||||||
|
*/
|
||||||
|
public function set_attributes( array $attributes ) {
|
||||||
|
$this->attributes = $attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template that this block belongs to.
|
||||||
|
*/
|
||||||
|
public function &get_root_template(): BlockTemplateInterface {
|
||||||
|
return $this->root_template;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the parent block container.
|
||||||
|
*/
|
||||||
|
public function &get_parent(): ContainerInterface {
|
||||||
|
return $this->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block configuration as a formatted template.
|
||||||
|
*
|
||||||
|
* @return array The block configuration as a formatted template.
|
||||||
|
*/
|
||||||
|
public function get_formatted_template(): array {
|
||||||
|
$arr = [
|
||||||
|
$this->get_name(),
|
||||||
|
$this->get_attributes(),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $arr;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\ContainerInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block template class.
|
||||||
|
*/
|
||||||
|
abstract class AbstractBlockTemplate implements BlockTemplateInterface {
|
||||||
|
use BlockContainerTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The block cache.
|
||||||
|
*
|
||||||
|
* @var BlockInterface[]
|
||||||
|
*/
|
||||||
|
private $block_cache = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a block by ID.
|
||||||
|
*
|
||||||
|
* @param string $block_id The block ID.
|
||||||
|
*/
|
||||||
|
public function get_block( string $block_id ): ?BlockInterface {
|
||||||
|
return $this->block_cache[ $block_id ] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caches a block in the template. This is an internal method and should not be called directly
|
||||||
|
* except for classes that implement BlockContainerInterface, in their add_block() method.
|
||||||
|
*
|
||||||
|
* @param BlockInterface $block The block to cache.
|
||||||
|
*
|
||||||
|
* @throws \ValueError If a block with the specified ID already exists in the template.
|
||||||
|
* @throws \ValueError If the block template that the block belongs to is not this template.
|
||||||
|
*
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function cache_block( BlockInterface &$block ) {
|
||||||
|
$id = $block->get_id();
|
||||||
|
|
||||||
|
if ( isset( $this->block_cache[ $id ] ) ) {
|
||||||
|
throw new \ValueError( 'A block with the specified ID already exists in the template.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $block->get_root_template() !== $this ) {
|
||||||
|
throw new \ValueError( 'The block template that the block belongs to must be the same as this template.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->block_cache[ $id ] = $block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a block ID based on a base.
|
||||||
|
*
|
||||||
|
* @param string $id_base The base to use when generating an ID.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function generate_block_id( string $id_base ): string {
|
||||||
|
$instance_count = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
$instance_count++;
|
||||||
|
$block_id = $id_base . '-' . $instance_count;
|
||||||
|
} while ( isset( $this->block_cache[ $block_id ] ) );
|
||||||
|
|
||||||
|
return $block_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the root template.
|
||||||
|
*/
|
||||||
|
public function &get_root_template(): BlockTemplateInterface {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the inner blocks as a formatted template.
|
||||||
|
*/
|
||||||
|
public function get_formatted_template(): array {
|
||||||
|
$inner_blocks = $this->get_inner_blocks_sorted_by_order();
|
||||||
|
|
||||||
|
$inner_blocks_formatted_template = array_map(
|
||||||
|
function( Block $block ) {
|
||||||
|
return $block->get_formatted_template();
|
||||||
|
},
|
||||||
|
$inner_blocks
|
||||||
|
);
|
||||||
|
|
||||||
|
return $inner_blocks_formatted_template;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockContainerInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic block with container properties to be used in BlockTemplate.
|
||||||
|
*/
|
||||||
|
class Block extends AbstractBlock implements BlockContainerInterface {
|
||||||
|
use BlockContainerTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the block configuration as a formatted template.
|
||||||
|
*
|
||||||
|
* @return array The block configuration as a formatted template.
|
||||||
|
*/
|
||||||
|
public function get_formatted_template(): array {
|
||||||
|
$arr = [
|
||||||
|
$this->get_name(),
|
||||||
|
$this->get_attributes(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$inner_blocks = $this->get_inner_blocks_sorted_by_order();
|
||||||
|
|
||||||
|
if ( ! empty( $inner_blocks ) ) {
|
||||||
|
$arr[] = array_map(
|
||||||
|
function( BlockInterface $block ) {
|
||||||
|
return $block->get_formatted_template();
|
||||||
|
},
|
||||||
|
$inner_blocks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an inner block to this block.
|
||||||
|
*
|
||||||
|
* @param array $block_config The block data.
|
||||||
|
*/
|
||||||
|
public function &add_block( array $block_config ): BlockInterface {
|
||||||
|
$block = new Block( $block_config, $this->get_root_template(), $this );
|
||||||
|
return $this->add_inner_block( $block );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait for block containers.
|
||||||
|
*/
|
||||||
|
trait BlockContainerTrait {
|
||||||
|
/**
|
||||||
|
* The inner blocks.
|
||||||
|
*
|
||||||
|
* @var BlockInterface[]
|
||||||
|
*/
|
||||||
|
private $inner_blocks = [];
|
||||||
|
|
||||||
|
// phpcs doesn't take into account exceptions thrown by called methods.
|
||||||
|
// phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a block to the block container.
|
||||||
|
*
|
||||||
|
* @param BlockInterface $block The block.
|
||||||
|
*
|
||||||
|
* @throws \ValueError If the block configuration is invalid.
|
||||||
|
* @throws \ValueError If a block with the specified ID already exists in the template.
|
||||||
|
* @throws \UnexpectedValueException If the block container is not the parent of the block.
|
||||||
|
*/
|
||||||
|
protected function &add_inner_block( BlockInterface $block ): BlockInterface {
|
||||||
|
if ( ! $block instanceof BlockInterface ) {
|
||||||
|
throw new \UnexpectedValueException( 'The block must return an instance of BlockInterface.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $block->get_parent() !== $this ) {
|
||||||
|
throw new \UnexpectedValueException( 'The block container is not the parent of the block.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$root_template = $block->get_root_template();
|
||||||
|
$root_template->cache_block( $block );
|
||||||
|
$this->inner_blocks[] = &$block;
|
||||||
|
return $block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// phpcs:enable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the inner blocks sorted by order.
|
||||||
|
*/
|
||||||
|
private function get_inner_blocks_sorted_by_order(): array {
|
||||||
|
$sorted_inner_blocks = $this->inner_blocks;
|
||||||
|
|
||||||
|
usort(
|
||||||
|
$sorted_inner_blocks,
|
||||||
|
function( Block $a, Block $b ) {
|
||||||
|
return $a->get_order() <=> $b->get_order();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $sorted_inner_blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the inner blocks as a formatted template.
|
||||||
|
*/
|
||||||
|
public function get_formatted_template(): array {
|
||||||
|
$arr = [
|
||||||
|
$this->get_name(),
|
||||||
|
$this->get_attributes(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$inner_blocks = $this->get_inner_blocks_sorted_by_order();
|
||||||
|
|
||||||
|
if ( ! empty( $inner_blocks ) ) {
|
||||||
|
$arr[] = array_map(
|
||||||
|
function( BlockInterface $block ) {
|
||||||
|
return $block->get_formatted_template();
|
||||||
|
},
|
||||||
|
$inner_blocks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $arr;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\ContainerInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block template class.
|
||||||
|
*/
|
||||||
|
class BlockTemplate extends AbstractBlockTemplate {
|
||||||
|
/**
|
||||||
|
* Generate a block ID based on a base.
|
||||||
|
*
|
||||||
|
* @param array $block_config The block data.
|
||||||
|
*/
|
||||||
|
public function add_block( array $block_config ): BlockInterface {
|
||||||
|
$block = new Block( $block_config, $this->get_root_template(), $this );
|
||||||
|
return $this->add_inner_block( $block );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,367 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Tests\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\BlockTemplate;
|
||||||
|
|
||||||
|
use WC_Unit_Test_Case;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the BlockTemplate class.
|
||||||
|
*/
|
||||||
|
class BlockTemplateTest extends WC_Unit_Test_Case {
|
||||||
|
/**
|
||||||
|
* Test generating a block ID.
|
||||||
|
*/
|
||||||
|
public function test_generate_block_id() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$this->assertSame( 'test-block-id-1', $template->generate_block_id( 'test-block-id' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test adding a block.
|
||||||
|
*/
|
||||||
|
public function test_add_block() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$block = $template->add_block(
|
||||||
|
[
|
||||||
|
'id' => 'test-block-id',
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame( $block, $template->get_block( 'test-block-id' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test adding a block throws an exception if a block with the same ID already exists.
|
||||||
|
*/
|
||||||
|
public function test_add_block_throws_exception_if_block_with_same_id_already_exists() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$template->add_block(
|
||||||
|
[
|
||||||
|
'id' => 'test-block-id',
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->expectException( \ValueError::class );
|
||||||
|
|
||||||
|
$template->add_block(
|
||||||
|
[
|
||||||
|
'id' => 'test-block-id',
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test adding a block generates an ID if one is not provided.
|
||||||
|
*/
|
||||||
|
public function test_add_block_generates_id_if_not_provided() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$block = $template->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame( 'test-block-name-1', $block->get_id() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test getting a block by ID returns null if the block does not exist.
|
||||||
|
*/
|
||||||
|
public function test_get_block_returns_null_if_block_does_not_exist() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$this->assertNull( $template->get_block( 'test-block-id' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test getting a block by ID returns a reference to the block.
|
||||||
|
*/
|
||||||
|
public function test_get_block_returns_reference() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$template->add_block(
|
||||||
|
[
|
||||||
|
'id' => 'test-block-id',
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block = $template->get_block( 'test-block-id' );
|
||||||
|
|
||||||
|
$block->set_order( 23 );
|
||||||
|
|
||||||
|
$this->assertSame( 23, $template->get_block( 'test-block-id' )->get_order() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that the formatted template representation of a block template is correct.
|
||||||
|
*/
|
||||||
|
public function test_get_formatted_template() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$template->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name-c',
|
||||||
|
'order' => 100,
|
||||||
|
'attributes' => [
|
||||||
|
'attr-c1' => 'value-c1',
|
||||||
|
'attr-c2' => 'value-c2',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block_b = $template->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name-b',
|
||||||
|
'order' => 50,
|
||||||
|
'attributes' => [
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$template->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name-a',
|
||||||
|
'order' => 10,
|
||||||
|
'attributes' => [
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block_b->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name-2',
|
||||||
|
'order' => 20,
|
||||||
|
'attributes' => [
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block_b->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name-1',
|
||||||
|
'order' => 10,
|
||||||
|
'attributes' => [
|
||||||
|
'attr-3' => 'value-3',
|
||||||
|
'attr-4' => 'value-4',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block_b->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name-3',
|
||||||
|
'order' => 30,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'test-block-name-a',
|
||||||
|
[
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'test-block-name-b',
|
||||||
|
[
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'test-block-name-1',
|
||||||
|
[
|
||||||
|
'attr-3' => 'value-3',
|
||||||
|
'attr-4' => 'value-4',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'test-block-name-2',
|
||||||
|
[
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'test-block-name-3',
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'test-block-name-c',
|
||||||
|
[
|
||||||
|
'attr-c1' => 'value-c1',
|
||||||
|
'attr-c2' => 'value-c2',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
$template->get_formatted_template(),
|
||||||
|
'Failed asserting that the block is converted to a simple array correctly.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that inserting a block to a parent in the template works.
|
||||||
|
*/
|
||||||
|
public function test_inserting_block_by_parent_id() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$template->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name-c',
|
||||||
|
'order' => 100,
|
||||||
|
'attributes' => [
|
||||||
|
'attr-c1' => 'value-c1',
|
||||||
|
'attr-c2' => 'value-c2',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block_b = $template->add_block(
|
||||||
|
[
|
||||||
|
'id' => 'b',
|
||||||
|
'blockName' => 'test-block-name-b',
|
||||||
|
'order' => 50,
|
||||||
|
'attributes' => [
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$template->add_block(
|
||||||
|
[
|
||||||
|
'id' => 'a',
|
||||||
|
'blockName' => 'test-block-name-a',
|
||||||
|
'order' => 10,
|
||||||
|
'attributes' => [
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block_b->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name-2',
|
||||||
|
'order' => 20,
|
||||||
|
'attributes' => [
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block_b->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name-1',
|
||||||
|
'order' => 10,
|
||||||
|
'attributes' => [
|
||||||
|
'attr-3' => 'value-3',
|
||||||
|
'attr-4' => 'value-4',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block_b->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name-3',
|
||||||
|
'order' => 30,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block_to_insert_in = $template->get_block( 'a' );
|
||||||
|
|
||||||
|
$block_to_insert_in->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'inserted-block',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$another_block_to_insert_in = $template->get_block( 'b' );
|
||||||
|
|
||||||
|
$another_block_to_insert_in->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'another-inserted-block',
|
||||||
|
'order' => 15,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'test-block-name-a',
|
||||||
|
[
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'inserted-block',
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'test-block-name-b',
|
||||||
|
[
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'test-block-name-1',
|
||||||
|
[
|
||||||
|
'attr-3' => 'value-3',
|
||||||
|
'attr-4' => 'value-4',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'another-inserted-block',
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'test-block-name-2',
|
||||||
|
[
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'test-block-name-3',
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'test-block-name-c',
|
||||||
|
[
|
||||||
|
'attr-c1' => 'value-c1',
|
||||||
|
'attr-c2' => 'value-c2',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
$template->get_formatted_template(),
|
||||||
|
'Failed asserting that the template is converted to a formatted template correctly.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,306 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Tests\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockContainerInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\Block;
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\BlockTemplate;
|
||||||
|
|
||||||
|
use WC_Unit_Test_Case;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the Block class.
|
||||||
|
*/
|
||||||
|
class BlockTest extends WC_Unit_Test_Case {
|
||||||
|
/**
|
||||||
|
* Test that the block name is required when creating a block.
|
||||||
|
*/
|
||||||
|
public function test_name_is_required() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$this->expectException( \ValueError::class );
|
||||||
|
|
||||||
|
new Block( [], $template );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an ID is generated if not provided when creating a block.
|
||||||
|
*/
|
||||||
|
public function test_id_is_generated_if_not_provided() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$block = new Block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
],
|
||||||
|
$template
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame( 'test-block-name-1', $block->get_id() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that setting a parent from a different template is prevented.
|
||||||
|
*/
|
||||||
|
public function test_parent_from_different_template_throws_exception() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
$template_2 = new BlockTemplate();
|
||||||
|
|
||||||
|
$parent = new Block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-parent-name',
|
||||||
|
],
|
||||||
|
$template_2
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->expectException( \ValueError::class );
|
||||||
|
|
||||||
|
new Block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
],
|
||||||
|
$template,
|
||||||
|
$parent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that adding a block to a block sets the parent and root template correctly
|
||||||
|
* and that the block is added to the root template.
|
||||||
|
*/
|
||||||
|
public function test_add_block() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$block = $template->add_block(
|
||||||
|
[
|
||||||
|
'id' => 'test-block-id',
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$child_block = $block->add_block(
|
||||||
|
[
|
||||||
|
'id' => 'test-block-id-2',
|
||||||
|
'blockName' => 'test-block-name-2',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
$child_block->get_root_template(),
|
||||||
|
$block->get_root_template(),
|
||||||
|
'Failed asserting that the child block has the same root template as the parent block.'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
$block,
|
||||||
|
$child_block->get_parent(),
|
||||||
|
'Failed asserting that the child block\'s parent is the block it was added to.'
|
||||||
|
);
|
||||||
|
$this->assertSame(
|
||||||
|
$child_block,
|
||||||
|
$template->get_block( 'test-block-id-2' ),
|
||||||
|
'Failed asserting that the child block is in the root template.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that adding nested blocks sets the parent and root template correctly.
|
||||||
|
*/
|
||||||
|
public function test_nested_add_block() {
|
||||||
|
$block_template = new BlockTemplate();
|
||||||
|
|
||||||
|
$block = $block_template->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$child_block_1 = $block->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$grandchild_block = $child_block_1->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
$block_template,
|
||||||
|
$grandchild_block->get_root_template(),
|
||||||
|
'Failed asserting that the grandchild block has the same root template.'
|
||||||
|
);
|
||||||
|
|
||||||
|
$grandchild_parent = $grandchild_block->get_parent();
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
$child_block_1,
|
||||||
|
$grandchild_parent,
|
||||||
|
'Failed asserting that the grandchild block\'s parent is the block it was added to.'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(
|
||||||
|
BlockContainerInterface::class,
|
||||||
|
$grandchild_parent,
|
||||||
|
'Failed asserting that the grandchild block\'s parent is a BlockContainerInterface instance.'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
$block,
|
||||||
|
$grandchild_parent->get_parent(),
|
||||||
|
'Failed asserting that the grandchild block\'s grandparent is correct.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that getting the block as a formatted template is structured correctly.
|
||||||
|
*/
|
||||||
|
public function test_get_formatted_template() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$block = $template->add_block(
|
||||||
|
[
|
||||||
|
'id' => 'test-block-id',
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
'attributes' => [
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block->add_block(
|
||||||
|
[
|
||||||
|
'id' => 'test-block-id-2',
|
||||||
|
'blockName' => 'test-block-name-2',
|
||||||
|
'attributes' => [
|
||||||
|
'attr-3' => 'value-3',
|
||||||
|
'attr-4' => 'value-4',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block->add_block(
|
||||||
|
[
|
||||||
|
'id' => 'test-block-id-3',
|
||||||
|
'blockName' => 'test-block-name-3',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$formatted_template = $block->get_formatted_template();
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
[
|
||||||
|
'test-block-name',
|
||||||
|
[
|
||||||
|
'attr-1' => 'value-1',
|
||||||
|
'attr-2' => 'value-2',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'test-block-name-2',
|
||||||
|
[
|
||||||
|
'attr-3' => 'value-3',
|
||||||
|
'attr-4' => 'value-4',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'test-block-name-3',
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
$formatted_template,
|
||||||
|
'Failed asserting that the block is converted to a formatted template correctly.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that getting the inner blocks as a sorted formatted template is ordered correctly.
|
||||||
|
*/
|
||||||
|
public function test_get_formatted_template_with_sorting() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
|
||||||
|
$block = $template->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'five',
|
||||||
|
'order' => 5,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'three',
|
||||||
|
'order' => 3,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'one',
|
||||||
|
'order' => 1,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'four',
|
||||||
|
'order' => 4,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block->add_block(
|
||||||
|
[
|
||||||
|
'blockName' => 'two',
|
||||||
|
'order' => 2,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
[
|
||||||
|
'test-block-name',
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'one',
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'two',
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'three',
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'four',
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'five',
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
$block->get_formatted_template(),
|
||||||
|
'Failed asserting that the inner blocks are sorted by order.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Tests\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockContainerInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\AbstractBlock;
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\Block;
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\BlockContainerTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom block class for testing.
|
||||||
|
*/
|
||||||
|
class CustomBlock extends AbstractBlock implements CustomBlockInterface {
|
||||||
|
use BlockContainerTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom method.
|
||||||
|
*/
|
||||||
|
public function add_custom_inner_block(): BlockInterface {
|
||||||
|
$block = new Block(
|
||||||
|
[
|
||||||
|
'blockName' => 'custom-inner-block',
|
||||||
|
],
|
||||||
|
$this->get_root_template(),
|
||||||
|
$this
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->add_inner_block( $block );
|
||||||
|
|
||||||
|
return $block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Tests\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockContainerInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||||
|
|
||||||
|
interface CustomBlockInterface extends BlockContainerInterface {
|
||||||
|
/**
|
||||||
|
* Adds a method to insert a specific custom inner block.
|
||||||
|
*/
|
||||||
|
public function add_custom_inner_block(): BlockInterface;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Tests\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\AbstractBlockTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom block template class.
|
||||||
|
*/
|
||||||
|
class CustomBlockTemplate extends AbstractBlockTemplate {
|
||||||
|
/**
|
||||||
|
* Add a custom block type to this template.
|
||||||
|
*
|
||||||
|
* @param array $block_config The block data.
|
||||||
|
*/
|
||||||
|
public function add_custom_block( array $block_config ): BlockInterface {
|
||||||
|
$block = new CustomBlock( $block_config, $this->get_root_template(), $this );
|
||||||
|
return $this->add_inner_block( $block );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Tests\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockContainerInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\Block;
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\BlockTemplate;
|
||||||
|
|
||||||
|
use WC_Unit_Test_Case;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the CustomBlockTemplate class.
|
||||||
|
*/
|
||||||
|
class CustomBlockTemplateTest extends WC_Unit_Test_Case {
|
||||||
|
/**
|
||||||
|
* Test that the add_block method does not exist by default on templates.
|
||||||
|
*/
|
||||||
|
public function test_add_block_does_not_exist() {
|
||||||
|
$template = new CustomBlockTemplate();
|
||||||
|
$this->assertFalse( method_exists( $template, 'add_block' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a custom block inserter method inserts as expected.
|
||||||
|
*/
|
||||||
|
public function test_add_custom_block() {
|
||||||
|
$template = new CustomBlockTemplate();
|
||||||
|
|
||||||
|
$template->add_custom_block(
|
||||||
|
[
|
||||||
|
'id' => 'test-block-name',
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$block = $template->get_block( 'test-block-name' );
|
||||||
|
$this->assertInstanceOf( CustomBlock::class, $block );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Tests\Internal\Admin\BlockTemplates;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockContainerInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\Block;
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\BlockTemplate;
|
||||||
|
|
||||||
|
use WC_Unit_Test_Case;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the CustomBlock class.
|
||||||
|
*/
|
||||||
|
class CustomBlockTest extends WC_Unit_Test_Case {
|
||||||
|
/**
|
||||||
|
* Test that the add_block method does not exist by default on blocks.
|
||||||
|
*/
|
||||||
|
public function test_add_block_does_not_exist() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
$block = new CustomBlock(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
],
|
||||||
|
$template
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse( method_exists( $block, 'add_block' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a custom block inserter method inserts as expected.
|
||||||
|
*/
|
||||||
|
public function test_add_custom_inner_block() {
|
||||||
|
$template = new BlockTemplate();
|
||||||
|
$block = new CustomBlock(
|
||||||
|
[
|
||||||
|
'blockName' => 'test-block-name',
|
||||||
|
],
|
||||||
|
$template
|
||||||
|
);
|
||||||
|
|
||||||
|
$block->add_custom_inner_block();
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
[
|
||||||
|
'test-block-name',
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'custom-inner-block',
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
$block->get_formatted_template(),
|
||||||
|
'Failed asserting that the inner block was added'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue