Layout templates REST API (#43067)
* Endpoint shell * Single layout template route * Add area query arg * Fix BlockTemplateRegistry::get_registered() return type * Check if templates are registered before registering * Use json format for layout templates response * Remove unused use * Use json format for layout templates response for get_items * Consolidate processing for get_items and get_item * LayoutTemplateRegistry * Fix matching by id * Get templates from LayoutTemplateRegistry * Remove unused method * Fix typo in code doc * Move template instantiation to registry * Return template instance, not json when instantiating * Use LayoutTemplateRegistry instead of BlockTemplateRegistry * Add code docs for rest controller * Fix code doc in BlockTemplateRegistry * Code docs for LayoutTemplateRegistry * Changelog * Add code doc for LayoutTemplatesServiceProvider * Unit test for registering a layout template * Unit tests for invalid params when registering layout template * Unit test for layout template instantiation * Unit test for instantiating layout templates with query params * Unit test for layout template instance caching * Cache layout template instances * Refactor layout template info querying * Add unit test for layout template instantiation actions * Add before and after layout template instantiation actions * Use layout template ID for array key * REST API unit test to get all items * Unit test for unregister_all * Method to unregister all layout templates * REST API unit test to get all items for a specific area * Fix to_json() in TestLayoutTemplate * REST API unit test to get single item * Fix get_item * REST API unit test for single item with invalid id * REST API unit test for get all items for invalid area * Fix test_cached_instances - array access * Test that old register hook is called * Call old register hook * Remove before hook (will put in separate PR)
This commit is contained in:
parent
280fe7cd51
commit
a8dab20997
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Template layout REST API endpoints.
|
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
/**
|
||||
* REST API Layout Templates controller
|
||||
*
|
||||
* Handles requests to /layout-templates.
|
||||
*
|
||||
* @package WooCommerce\RestApi
|
||||
* @since 8.6.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\LayoutTemplates\LayoutTemplateRegistry;
|
||||
|
||||
/**
|
||||
* REST API Layout Templates controller class.
|
||||
*/
|
||||
class WC_REST_Layout_Templates_Controller extends WC_REST_Controller {
|
||||
|
||||
/**
|
||||
* Endpoint namespace.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace = 'wc/v3';
|
||||
|
||||
/**
|
||||
* Route base.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rest_base = 'layout-templates';
|
||||
|
||||
/**
|
||||
* Register the routes for template layouts.
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base,
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => array(
|
||||
'area' => array(
|
||||
'description' => __( 'Area to get templates for.', 'woocommerce' ),
|
||||
'type' => 'string',
|
||||
'default' => '',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/(?P<id>\w[\w\s\-]*)',
|
||||
array(
|
||||
'args' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => array(),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to read template layouts.
|
||||
*
|
||||
* @param WP_REST_Request $request The request.
|
||||
*/
|
||||
public function get_items_permissions_check( $request ): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to read a template layout.
|
||||
*
|
||||
* @param WP_REST_Request $request The request.
|
||||
*/
|
||||
public function get_item_permissions_check( $request ): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request for template layouts.
|
||||
*
|
||||
* @param WP_REST_Request $request The request.
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
$layout_templates = $this->get_layout_templates(
|
||||
array(
|
||||
'area' => $request['area'],
|
||||
)
|
||||
);
|
||||
|
||||
$response = rest_ensure_response( $layout_templates );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request for a single template layout.
|
||||
*
|
||||
* @param WP_REST_Request $request The request.
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
$layout_templates = $this->get_layout_templates(
|
||||
array(
|
||||
'id' => $request['id'],
|
||||
)
|
||||
);
|
||||
|
||||
if ( count( $layout_templates ) !== 1 ) {
|
||||
return new WP_Error( 'woocommerce_rest_layout_template_invalid_id', __( 'Invalid layout template ID.', 'woocommerce' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$response = rest_ensure_response( current( $layout_templates ) );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get layout templates.
|
||||
*
|
||||
* @param array $query_params Query params.
|
||||
*/
|
||||
private function get_layout_templates( array $query_params ): array {
|
||||
$layout_template_registry = wc_get_container()->get( LayoutTemplateRegistry::class );
|
||||
|
||||
return array_map(
|
||||
function( $layout_template ) {
|
||||
return $layout_template->to_json();
|
||||
},
|
||||
$layout_template_registry->instantiate_layout_templates( $query_params )
|
||||
);
|
||||
}
|
||||
}
|
|
@ -143,6 +143,7 @@ class Server {
|
|||
'coupons' => 'WC_REST_Coupons_Controller',
|
||||
'customer-downloads' => 'WC_REST_Customer_Downloads_Controller',
|
||||
'customers' => 'WC_REST_Customers_Controller',
|
||||
'layout-templates' => 'WC_REST_Layout_Templates_Controller',
|
||||
'network-orders' => 'WC_REST_Network_Orders_Controller',
|
||||
'order-notes' => 'WC_REST_Order_Notes_Controller',
|
||||
'order-refunds' => 'WC_REST_Order_Refunds_Controller',
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor;
|
||||
|
||||
use Automattic\WooCommerce\Admin\Features\Features;
|
||||
use Automattic\WooCommerce\Internal\Admin\Features\ProductBlockEditor\ProductTemplates\SimpleProductTemplate;
|
||||
use Automattic\WooCommerce\Internal\Admin\Features\ProductBlockEditor\ProductTemplates\ProductVariationTemplate;
|
||||
use Automattic\WooCommerce\Admin\Features\ProductBlockEditor\ProductTemplate;
|
||||
use Automattic\WooCommerce\Admin\PageController;
|
||||
use Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry\BlockTemplateRegistry;
|
||||
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\Block;
|
||||
use Automattic\WooCommerce\LayoutTemplates\LayoutTemplateRegistry;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\BlockTemplateLogger;
|
||||
use Automattic\WooCommerce\Internal\Admin\Features\ProductBlockEditor\ProductTemplates\SimpleProductTemplate;
|
||||
use Automattic\WooCommerce\Internal\Admin\Features\ProductBlockEditor\ProductTemplates\ProductVariationTemplate;
|
||||
|
||||
use WP_Block_Editor_Context;
|
||||
|
||||
/**
|
||||
|
@ -68,6 +69,8 @@ class Init {
|
|||
|
||||
add_action( 'current_screen', array( $this, 'set_current_screen_to_block_editor_if_wc_admin' ) );
|
||||
|
||||
add_action( 'rest_api_init', array( $this, 'register_product_editor_templates' ) );
|
||||
|
||||
// Make sure the block registry is initialized so that core blocks are registered.
|
||||
BlockRegistry::get_instance();
|
||||
|
||||
|
@ -211,12 +214,12 @@ class Init {
|
|||
* Get the product editor settings.
|
||||
*/
|
||||
private function get_product_editor_settings() {
|
||||
$layout_template_registry = wc_get_container()->get( BlockTemplateRegistry::class );
|
||||
$layout_template_registry = wc_get_container()->get( LayoutTemplateRegistry::class );
|
||||
$layout_template_logger = BlockTemplateLogger::get_instance();
|
||||
|
||||
$editor_settings = array();
|
||||
|
||||
foreach ( $layout_template_registry->get_all_registered() as $layout_template ) {
|
||||
foreach ( $layout_template_registry->instantiate_layout_templates() as $layout_template ) {
|
||||
$editor_settings['layoutTemplates'][] = $layout_template->to_json();
|
||||
|
||||
$layout_template_logger->log_template_events_to_file( $layout_template->get_id() );
|
||||
|
@ -370,9 +373,23 @@ class Init {
|
|||
/**
|
||||
* Register product editor templates.
|
||||
*/
|
||||
private function register_product_editor_templates() {
|
||||
$template_registry = wc_get_container()->get( BlockTemplateRegistry::class );
|
||||
$template_registry->register( new SimpleProductTemplate() );
|
||||
$template_registry->register( new ProductVariationTemplate() );
|
||||
public function register_product_editor_templates() {
|
||||
$layout_template_registry = wc_get_container()->get( LayoutTemplateRegistry::class );
|
||||
|
||||
if ( ! $layout_template_registry->is_registered( 'simple-product' ) ) {
|
||||
$layout_template_registry->register(
|
||||
'simple-product',
|
||||
'product-form',
|
||||
SimpleProductTemplate::class
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! $layout_template_registry->is_registered( 'product-variation' ) ) {
|
||||
$layout_template_registry->register(
|
||||
'product-variation',
|
||||
'product-form',
|
||||
ProductVariationTemplate::class
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\Restoc
|
|||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\UtilsClassesServiceProvider;
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\BatchProcessingServiceProvider;
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\BlockTemplatesServiceProvider;
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\LayoutTemplatesServiceProvider;
|
||||
|
||||
/**
|
||||
* PSR11 compliant dependency injection container for WooCommerce.
|
||||
|
@ -77,6 +78,7 @@ final class Container {
|
|||
MarketingServiceProvider::class,
|
||||
MarketplaceServiceProvider::class,
|
||||
BlockTemplatesServiceProvider::class,
|
||||
LayoutTemplatesServiceProvider::class,
|
||||
LoggingServiceProvider::class,
|
||||
EnginesServiceProvider::class,
|
||||
);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders;
|
||||
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\AbstractServiceProvider;
|
||||
use Automattic\WooCommerce\LayoutTemplates\LayoutTemplateRegistry;
|
||||
|
||||
/**
|
||||
* Service provider for layout templates.
|
||||
*/
|
||||
class LayoutTemplatesServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The classes/interfaces that are serviced by this service provider.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = array(
|
||||
LayoutTemplateRegistry::class,
|
||||
);
|
||||
|
||||
/**
|
||||
* Register the classes.
|
||||
*/
|
||||
public function register() {
|
||||
$this->share( LayoutTemplateRegistry::class );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\LayoutTemplates;
|
||||
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||
|
||||
/**
|
||||
* Layout template registry.
|
||||
*/
|
||||
final class LayoutTemplateRegistry {
|
||||
|
||||
/**
|
||||
* Class instance.
|
||||
*
|
||||
* @var LayoutTemplateRegistry|null
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Layout templates info.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $layout_templates_info = array();
|
||||
|
||||
/**
|
||||
* Layout template instances.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $layout_template_instances = array();
|
||||
|
||||
/**
|
||||
* Get the instance of the class.
|
||||
*/
|
||||
public static function get_instance(): LayoutTemplateRegistry {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister all layout templates.
|
||||
*/
|
||||
public function unregister_all() {
|
||||
$this->layout_templates_info = array();
|
||||
$this->layout_template_instances = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a layout template is registered.
|
||||
*
|
||||
* @param string $layout_template_id Layout template ID.
|
||||
*/
|
||||
public function is_registered( $layout_template_id ): bool {
|
||||
return isset( $this->layout_templates_info[ $layout_template_id ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a single layout template.
|
||||
*
|
||||
* @param string $layout_template_id Layout template ID.
|
||||
* @param string $layout_template_area Layout template area.
|
||||
* @param string $layout_template_class_name Layout template class to register.
|
||||
*
|
||||
* @throws \ValueError If a layout template with the same ID already exists.
|
||||
* @throws \ValueError If the specified layout template area is empty.
|
||||
* @throws \ValueError If the specified layout template class does not exist.
|
||||
* @throws \ValueError If the specified layout template class does not implement the BlockTemplateInterface.
|
||||
*/
|
||||
public function register( $layout_template_id, $layout_template_area, $layout_template_class_name ) {
|
||||
if ( $this->is_registered( $layout_template_id ) ) {
|
||||
throw new \ValueError( 'A layout template with the specified ID already exists in the registry.' );
|
||||
}
|
||||
|
||||
if ( empty( $layout_template_area ) ) {
|
||||
throw new \ValueError( 'The specified layout template area is empty.' );
|
||||
}
|
||||
|
||||
if ( ! class_exists( $layout_template_class_name ) ) {
|
||||
throw new \ValueError( 'The specified layout template class does not exist.' );
|
||||
}
|
||||
|
||||
if ( ! is_subclass_of( $layout_template_class_name, BlockTemplateInterface::class ) ) {
|
||||
throw new \ValueError( 'The specified layout template class does not implement the BlockTemplateInterface.' );
|
||||
}
|
||||
|
||||
$this->layout_templates_info[ $layout_template_id ] = array(
|
||||
'id' => $layout_template_id,
|
||||
'area' => $layout_template_area,
|
||||
'class_name' => $layout_template_class_name,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the matching layout templates and return them.
|
||||
*
|
||||
* @param array $query_params Query params.
|
||||
*/
|
||||
public function instantiate_layout_templates( array $query_params = array() ): array {
|
||||
$layout_templates = array();
|
||||
|
||||
$layout_templates_info = $this->get_matching_layout_templates_info( $query_params );
|
||||
foreach ( $layout_templates_info as $layout_template_info ) {
|
||||
$layout_template = $this->get_layout_template_instance( $layout_template_info );
|
||||
|
||||
$layout_templates[ $layout_template->get_id() ] = $layout_template;
|
||||
}
|
||||
|
||||
return $layout_templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a single layout template and return it.
|
||||
*
|
||||
* @param array $layout_template_info Layout template info.
|
||||
*/
|
||||
private function get_layout_template_instance( $layout_template_info ): BlockTemplateInterface {
|
||||
$class_name = $layout_template_info['class_name'];
|
||||
|
||||
// Return the instance if it already exists.
|
||||
|
||||
$layout_template_instance = isset( $this->layout_template_instances[ $class_name ] )
|
||||
? $this->layout_template_instances[ $class_name ]
|
||||
: null;
|
||||
|
||||
if ( ! empty( $layout_template_instance ) ) {
|
||||
return $layout_template_instance;
|
||||
}
|
||||
|
||||
// Instantiate the layout template.
|
||||
|
||||
$layout_template_instance = new $class_name();
|
||||
$this->layout_template_instances[ $class_name ] = $layout_template_instance;
|
||||
|
||||
// Call the after instantiation hooks.
|
||||
|
||||
/**
|
||||
* Fires after a layout template is instantiated.
|
||||
*
|
||||
* @param string $layout_template_id Layout template ID.
|
||||
* @param string $layout_template_area Layout template area.
|
||||
* @param BlockTemplateInterface $layout_template Layout template instance.
|
||||
*
|
||||
* @since 8.6.0
|
||||
*/
|
||||
do_action( 'woocommerce_layout_template_after_instantiation', $layout_template_info['id'], $layout_template_info['area'], $layout_template_instance );
|
||||
|
||||
// Call the old, soon-to-be-deprecated, register hook.
|
||||
|
||||
/**
|
||||
* Fires when a template is registered.
|
||||
*
|
||||
* @param BlockTemplateInterface $template Template that was registered.
|
||||
*
|
||||
* @since 8.2.0
|
||||
*/
|
||||
do_action( 'woocommerce_block_template_register', $layout_template_instance );
|
||||
|
||||
return $layout_template_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get matching layout templates info.
|
||||
*
|
||||
* @param array $query_params Query params.
|
||||
*/
|
||||
private function get_matching_layout_templates_info( array $query_params = array() ): array {
|
||||
$area_to_match = isset( $query_params['area'] ) ? $query_params['area'] : null;
|
||||
$id_to_match = isset( $query_params['id'] ) ? $query_params['id'] : null;
|
||||
|
||||
$matching_layout_templates_info = array();
|
||||
|
||||
foreach ( $this->layout_templates_info as $layout_template_info ) {
|
||||
if ( ! empty( $area_to_match ) && $layout_template_info['area'] !== $area_to_match ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! empty( $id_to_match ) && $layout_template_info['id'] !== $id_to_match ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$matching_layout_templates_info[] = $layout_template_info;
|
||||
}
|
||||
|
||||
return $matching_layout_templates_info;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
use Automattic\WooCommerce\LayoutTemplates\LayoutTemplateRegistry;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Admin\Features\ProductBlockEditor\ProductTemplates\SimpleProductTemplate;
|
||||
use Automattic\WooCommerce\Internal\Admin\Features\ProductBlockEditor\ProductTemplates\ProductVariationTemplate;
|
||||
|
||||
use Automattic\WooCommerce\Tests\LayoutTemplates\TestLayoutTemplate;
|
||||
|
||||
/**
|
||||
* class WC_REST_Layout_Templates_Controller_Tests.
|
||||
* Layout Templates Controller tests for V3 REST API.
|
||||
*/
|
||||
class WC_REST_Layout_Templates_Controller_Tests extends WC_REST_Unit_Test_Case {
|
||||
/**
|
||||
* Runs before each test.
|
||||
*/
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$layout_template_registry = wc_get_container()->get( LayoutTemplateRegistry::class );
|
||||
|
||||
$layout_template_registry->unregister_all();
|
||||
|
||||
$layout_template_registry->register( 'test-layout-template', 'test', TestLayoutTemplate::class );
|
||||
$layout_template_registry->register( 'simple-product', 'product-form', SimpleProductTemplate::class );
|
||||
$layout_template_registry->register( 'product-variation', 'product-form', ProductVariationTemplate::class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting all layout templates.
|
||||
*/
|
||||
public function test_get_all_items() {
|
||||
$response = $this->do_rest_get_request( 'layout-templates' );
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertNotEmpty( $data );
|
||||
|
||||
$this->assertCount( 3, $data );
|
||||
|
||||
$this->assertArrayHasKey( 'test-layout-template', $data );
|
||||
$this->assertArrayHasKey( 'simple-product', $data );
|
||||
$this->assertArrayHasKey( 'product-variation', $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting all layout templates for a specific area.
|
||||
*/
|
||||
public function test_get_all_items_for_area() {
|
||||
$response = $this->do_rest_get_request( 'layout-templates', array( 'area' => 'product-form' ) );
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertNotEmpty( $data );
|
||||
|
||||
$this->assertCount( 2, $data );
|
||||
|
||||
$this->assertArrayHasKey( 'simple-product', $data );
|
||||
$this->assertArrayHasKey( 'product-variation', $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting all layout templates for an invalid area.
|
||||
*/
|
||||
public function test_get_all_items_for_invalid_area() {
|
||||
$response = $this->do_rest_get_request( 'layout-templates', array( 'area' => 'invalid-area' ) );
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertEmpty( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting a single layout template.
|
||||
*/
|
||||
public function test_get_single_item() {
|
||||
$response = $this->do_rest_get_request( 'layout-templates/test-layout-template' );
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertNotEmpty( $data );
|
||||
|
||||
$this->assertEquals( 'test-layout-template', $data['id'] );
|
||||
$this->assertEquals( 'test', $data['area'] );
|
||||
|
||||
$this->assertArrayHasKey( 'title', $data );
|
||||
$this->assertArrayHasKey( 'description', $data );
|
||||
$this->assertArrayHasKey( 'blockTemplates', $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting a single layout template with invalid id.
|
||||
*/
|
||||
public function test_get_single_item_with_invalid_id() {
|
||||
$response = $this->do_rest_get_request( 'layout-templates/invalid-layout-template' );
|
||||
|
||||
$this->assertEquals( 404, $response->get_status() );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Tests\LayoutTemplates;
|
||||
|
||||
use Automattic\WooCommerce\LayoutTemplates\LayoutTemplateRegistry;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Admin\Features\ProductBlockEditor\ProductTemplates\SimpleProductTemplate;
|
||||
use Automattic\WooCommerce\Internal\Admin\Features\ProductBlockEditor\ProductTemplates\ProductVariationTemplate;
|
||||
|
||||
use WC_Unit_Test_Case;
|
||||
|
||||
/**
|
||||
* Tests for the LayoutTemplateRegistry class.
|
||||
*/
|
||||
class LayoutTemplateRegistryTest extends WC_Unit_Test_Case {
|
||||
/**
|
||||
* Layout template registry.
|
||||
*
|
||||
* @var LayoutTemplateRegistry
|
||||
*/
|
||||
protected $layout_template_registry;
|
||||
|
||||
/**
|
||||
* Layout templates to register.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $layout_templates_to_register;
|
||||
|
||||
/**
|
||||
* Runs before each test.
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->layout_template_registry = new LayoutTemplateRegistry();
|
||||
|
||||
$this->layout_templates_to_register = array(
|
||||
'test-layout-template' => array(
|
||||
'area' => 'test',
|
||||
'class_name' => TestLayoutTemplate::class,
|
||||
),
|
||||
'simple-product' => array(
|
||||
'area' => 'product-form',
|
||||
'class_name' => SimpleProductTemplate::class,
|
||||
),
|
||||
'product-variation' => array(
|
||||
'area' => 'product-form',
|
||||
'class_name' => ProductVariationTemplate::class,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test registering a layout template.
|
||||
*/
|
||||
public function test_register() {
|
||||
$this->assertFalse( $this->layout_template_registry->is_registered( 'test-layout-template' ) );
|
||||
|
||||
$this->layout_template_registry->register( 'test-layout-template', 'test', TestLayoutTemplate::class );
|
||||
|
||||
$this->assertTrue( $this->layout_template_registry->is_registered( 'test-layout-template' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test registering a layout template with an existing ID.
|
||||
*/
|
||||
public function test_register_duplicate_id() {
|
||||
$this->expectException( \ValueError::class );
|
||||
$this->layout_template_registry->register( 'test-layout-template', 'test', TestLayoutTemplate::class );
|
||||
$this->layout_template_registry->register( 'test-layout-template', 'test', TestLayoutTemplate::class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test registering a layout template with an empty area.
|
||||
*/
|
||||
public function test_register_empty_area() {
|
||||
$this->expectException( \ValueError::class );
|
||||
$this->layout_template_registry->register( 'test-layout-template', '', TestLayoutTemplate::class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test registering a layout template with a non-existing class.
|
||||
*/
|
||||
public function test_register_non_existing_class() {
|
||||
$this->expectException( \ValueError::class );
|
||||
$this->layout_template_registry->register( 'test-layout-template', 'test', 'NonExistingClass' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test registering a layout template with a class that does not implement the BlockTemplateInterface.
|
||||
*/
|
||||
public function test_register_non_block_template_class() {
|
||||
$this->expectException( \ValueError::class );
|
||||
$this->layout_template_registry->register( 'test-layout-template', 'test', \stdClass::class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test unregistering a layout template.
|
||||
*/
|
||||
public function test_unregister() {
|
||||
$this->layout_template_registry->register( 'test-layout-template', 'test', TestLayoutTemplate::class );
|
||||
|
||||
$this->assertTrue( $this->layout_template_registry->is_registered( 'test-layout-template' ) );
|
||||
|
||||
$this->layout_template_registry->unregister_all( 'test-layout-template' );
|
||||
|
||||
$this->assertFalse( $this->layout_template_registry->is_registered( 'test-layout-template' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test instantiating layout templates.
|
||||
*/
|
||||
public function test_instantiate() {
|
||||
foreach ( $this->layout_templates_to_register as $template_id => $template_info ) {
|
||||
$this->layout_template_registry->register( $template_id, $template_info['area'], $template_info['class_name'] );
|
||||
}
|
||||
|
||||
$layout_templates = $this->layout_template_registry->instantiate_layout_templates();
|
||||
|
||||
$this->assertCount( 3, $layout_templates );
|
||||
|
||||
foreach ( $layout_templates as $layout_template ) {
|
||||
$template_info = $this->layout_templates_to_register[ $layout_template->get_id() ];
|
||||
$this->assertInstanceOf( $template_info['class_name'], $layout_template );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test instantiating layout templates with area query param.
|
||||
*/
|
||||
public function test_instantiate_with_area_query_param() {
|
||||
foreach ( $this->layout_templates_to_register as $template_id => $template_info ) {
|
||||
$this->layout_template_registry->register( $template_id, $template_info['area'], $template_info['class_name'] );
|
||||
}
|
||||
|
||||
$layout_templates = $this->layout_template_registry->instantiate_layout_templates(
|
||||
array( 'area' => 'product-form' )
|
||||
);
|
||||
|
||||
$this->assertCount( 2, $layout_templates );
|
||||
|
||||
foreach ( $layout_templates as $layout_template ) {
|
||||
$template_info = $this->layout_templates_to_register[ $layout_template->get_id() ];
|
||||
$this->assertInstanceOf( $template_info['class_name'], $layout_template );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test instantiating layout templates with id query param.
|
||||
*/
|
||||
public function test_instantiate_with_id_query_param() {
|
||||
foreach ( $this->layout_templates_to_register as $template_id => $template_info ) {
|
||||
$this->layout_template_registry->register( $template_id, $template_info['area'], $template_info['class_name'] );
|
||||
}
|
||||
|
||||
$layout_templates = $this->layout_template_registry->instantiate_layout_templates(
|
||||
array( 'id' => 'simple-product' )
|
||||
);
|
||||
|
||||
$this->assertCount( 1, $layout_templates );
|
||||
|
||||
foreach ( $layout_templates as $layout_template ) {
|
||||
$template_info = $this->layout_templates_to_register[ $layout_template->get_id() ];
|
||||
$this->assertInstanceOf( $template_info['class_name'], $layout_template );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test layout templates are only instantiated once.
|
||||
*/
|
||||
public function test_cached_instances() {
|
||||
$this->layout_template_registry->register( 'test-layout-template', 'test', TestLayoutTemplate::class );
|
||||
|
||||
$layout_templates = $this->layout_template_registry->instantiate_layout_templates(
|
||||
array( 'id' => 'test-layout-template' )
|
||||
);
|
||||
|
||||
$layout_templates_again = $this->layout_template_registry->instantiate_layout_templates(
|
||||
array( 'id' => 'test-layout-template' )
|
||||
);
|
||||
|
||||
$this->assertCount( 1, $layout_templates );
|
||||
$this->assertCount( 1, $layout_templates_again );
|
||||
|
||||
$this->assertSame( current( $layout_templates_again ), current( $layout_templates ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test layout template instantiation actions are fired.
|
||||
*/
|
||||
public function test_instantiation_actions() {
|
||||
$after_instantiation_hook_called = false;
|
||||
|
||||
$after_instantiation_hook = function( string $layout_template_id, string $area, $layout_template ) use ( &$after_instantiation_hook_called ) {
|
||||
$after_instantiation_hook_called = true;
|
||||
|
||||
$this->assertEquals( 'test-layout-template', $layout_template_id );
|
||||
$this->assertEquals( 'test', $area );
|
||||
|
||||
$this->assertInstanceOf( TestLayoutTemplate::class, $layout_template );
|
||||
};
|
||||
|
||||
$deprecated_register_hook_called = false;
|
||||
|
||||
$deprecated_register_hook = function( $layout_template ) use ( &$deprecated_register_hook_called ) {
|
||||
$deprecated_register_hook_called = true;
|
||||
|
||||
$this->assertInstanceOf( TestLayoutTemplate::class, $layout_template );
|
||||
|
||||
$this->assertEquals( 'test-layout-template', $layout_template->get_id() );
|
||||
$this->assertEquals( 'test', $layout_template->get_area() );
|
||||
|
||||
};
|
||||
|
||||
try {
|
||||
add_action( 'woocommerce_layout_template_after_instantiation', $after_instantiation_hook, 10, 3 );
|
||||
|
||||
add_action( 'woocommerce_block_template_register', $deprecated_register_hook );
|
||||
|
||||
$this->layout_template_registry->register( 'test-layout-template', 'test', TestLayoutTemplate::class );
|
||||
|
||||
$this->layout_template_registry->instantiate_layout_templates(
|
||||
array( 'id' => 'test-layout-template' )
|
||||
);
|
||||
|
||||
$this->assertTrue(
|
||||
$after_instantiation_hook_called,
|
||||
'woocommerce_layout_template_after_instantiation hook was not called.'
|
||||
);
|
||||
|
||||
$this->assertTrue(
|
||||
$deprecated_register_hook_called,
|
||||
'woocommerce_block_template_register hook was not called.'
|
||||
);
|
||||
} finally {
|
||||
remove_action( 'woocommerce_layout_template_after_instantiation', $after_instantiation_hook );
|
||||
|
||||
remove_action( 'woocommerce_block_template_register', $deprecated_register_hook );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Tests\LayoutTemplates;
|
||||
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||
|
||||
/**
|
||||
* Test layout template.
|
||||
*/
|
||||
class TestLayoutTemplate implements BlockTemplateInterface {
|
||||
/**
|
||||
* Get the layout template ID.
|
||||
*/
|
||||
public function get_id(): string {
|
||||
return 'test-layout-template';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layout template title.
|
||||
*/
|
||||
public function get_title(): string {
|
||||
return 'Test layout template';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layout template description.
|
||||
*/
|
||||
public function get_description(): string {
|
||||
return 'A test layout template';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layout template area.
|
||||
*/
|
||||
public function get_area(): string {
|
||||
return 'test';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layout template blocks.
|
||||
*
|
||||
* @param string $id_base Block ID base.
|
||||
*/
|
||||
public function generate_block_id( string $id_base ): string {
|
||||
return $id_base . '-test';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layout template blocks.
|
||||
*/
|
||||
public function &get_root_template(): BlockTemplateInterface {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layout template blocks.
|
||||
*
|
||||
* @param string $block_id Block ID.
|
||||
*/
|
||||
public function get_block( string $block_id ): ?BlockInterface {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layout template blocks.
|
||||
*
|
||||
* @param string $block_id Block ID.
|
||||
*/
|
||||
public function remove_block( string $block_id ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layout template blocks.
|
||||
*/
|
||||
public function remove_blocks() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layout template blocks.
|
||||
*/
|
||||
public function get_formatted_template(): array {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layout template blocks.
|
||||
*/
|
||||
public function to_json(): array {
|
||||
return array(
|
||||
'id' => $this->get_id(),
|
||||
'title' => $this->get_title(),
|
||||
'description' => $this->get_description(),
|
||||
'area' => $this->get_area(),
|
||||
'blockTemplates' => array(),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue