Skip to content

Commit

Permalink
Core block-based template PHP API (adding blocks to templates) (wooco…
Browse files Browse the repository at this point in the history
…mmerce#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 (woocommerce#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>
  • Loading branch information
Matt Sherman and joshuatf authored Aug 10, 2023
1 parent 91fadfd commit e805b6b
Show file tree
Hide file tree
Showing 17 changed files with 1,417 additions and 0 deletions.
4 changes: 4 additions & 0 deletions plugins/woocommerce/changelog/add-add-block-to-block-template
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: add

API for block-based templates.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Automattic\WooCommerce\Admin\BlockTemplates;

/**
* Interface for block containers.
*/
interface BlockContainerInterface extends BlockInterface, ContainerInterface {}
79 changes: 79 additions & 0 deletions plugins/woocommerce/src/Admin/BlockTemplates/BlockInterface.php
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading

0 comments on commit e805b6b

Please sign in to comment.