<?php namespace Automattic\WooCommerce\LayoutTemplates; use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface; use Automattic\WooCommerce\Internal\Admin\BlockTemplates\BlockTemplateLogger; /** * 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 { // Make sure the block template logger is initialized before the templates are created, // so that the logger will collect the template events. $logger = BlockTemplateLogger::get_instance(); $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_template_id = $layout_template->get_id(); $layout_templates[ $layout_template_id ] = $layout_template; $logger->log_template_events_to_file( $layout_template_id ); } 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, deprecated, register hook. wc_do_deprecated_action( 'woocommerce_block_template_register', array( $layout_template_instance ), '8.6.0', 'woocommerce_layout_template_after_instantiation' ); 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; } }