1<?php
2/**
3 * Blocks API: WP_Block_Type_Registry class
4 *
5 * @package WordPress
6 * @subpackage Blocks
7 * @since 5.0.0
8 */
9
10/**
11 * Core class used for interacting with block types.
12 *
13 * @since 5.0.0
14 */
15#[AllowDynamicProperties]
16final class WP_Block_Type_Registry {
17 /**
18 * Registered block types, as `$name => $instance` pairs.
19 *
20 * @since 5.0.0
21 * @var WP_Block_Type[]
22 */
23 private $registered_block_types = array();
24
25 /**
26 * Container for the main instance of the class.
27 *
28 * @since 5.0.0
29 * @var WP_Block_Type_Registry|null
30 */
31 private static $instance = null;
32
33 /**
34 * Registers a block type.
35 *
36 * @since 5.0.0
37 *
38 * @see WP_Block_Type::__construct()
39 *
40 * @param string|WP_Block_Type $name Block type name including namespace, or alternatively
41 * a complete WP_Block_Type instance. In case a WP_Block_Type
42 * is provided, the $args parameter will be ignored.
43 * @param array $args Optional. Array of block type arguments. Accepts any public property
44 * of `WP_Block_Type`. See WP_Block_Type::__construct() for information
45 * on accepted arguments. Default empty array.
46 * @return WP_Block_Type|false The registered block type on success, or false on failure.
47 */
48 public function register( $name, $args = array() ) {
49 $block_type = null;
50 if ( $name instanceof WP_Block_Type ) {
51 $block_type = $name;
52 $name = $block_type->name;
53 }
54
55 if ( ! is_string( $name ) ) {
56 _doing_it_wrong(
57 __METHOD__,
58 __( 'Block type names must be strings.' ),
59 '5.0.0'
60 );
61 return false;
62 }
63
64 if ( preg_match( '/[A-Z]+/', $name ) ) {
65 _doing_it_wrong(
66 __METHOD__,
67 __( 'Block type names must not contain uppercase characters.' ),
68 '5.0.0'
69 );
70 return false;
71 }
72
73 $name_matcher = '/^[a-z0-9-]+\/[a-z0-9-]+$/';
74 if ( ! preg_match( $name_matcher, $name ) ) {
75 _doing_it_wrong(
76 __METHOD__,
77 __( 'Block type names must contain a namespace prefix. Example: my-plugin/my-custom-block-type' ),
78 '5.0.0'
79 );
80 return false;
81 }
82
83 if ( $this->is_registered( $name ) ) {
84 _doing_it_wrong(
85 __METHOD__,
86 /* translators: %s: Block name. */
87 sprintf( __( 'Block type "%s" is already registered.' ), $name ),
88 '5.0.0'
89 );
90 return false;
91 }
92
93 if ( ! $block_type ) {
94 $block_type = new WP_Block_Type( $name, $args );
95 }
96
97 $this->registered_block_types[ $name ] = $block_type;
98
99 return $block_type;
100 }
101
102 /**
103 * Unregisters a block type.
104 *
105 * @since 5.0.0
106 *
107 * @param string|WP_Block_Type $name Block type name including namespace, or alternatively
108 * a complete WP_Block_Type instance.
109 * @return WP_Block_Type|false The unregistered block type on success, or false on failure.
110 */
111 public function unregister( $name ) {
112 if ( $name instanceof WP_Block_Type ) {
113 $name = $name->name;
114 }
115
116 if ( ! $this->is_registered( $name ) ) {
117 _doing_it_wrong(
118 __METHOD__,
119 /* translators: %s: Block name. */
120 sprintf( __( 'Block type "%s" is not registered.' ), $name ),
121 '5.0.0'
122 );
123 return false;
124 }
125
126 $unregistered_block_type = $this->registered_block_types[ $name ];
127 unset( $this->registered_block_types[ $name ] );
128
129 return $unregistered_block_type;
130 }
131
132 /**
133 * Retrieves a registered block type.
134 *
135 * @since 5.0.0
136 *
137 * @param string|null $name Block type name including namespace.
138 * @return WP_Block_Type|null The registered block type, or null if it is not registered.
139 */
140 public function get_registered( $name ) {
141 if ( ! $this->is_registered( $name ) ) {
142 return null;
143 }
144
145 return $this->registered_block_types[ $name ];
146 }
147
148 /**
149 * Retrieves all registered block types.
150 *
151 * @since 5.0.0
152 *
153 * @return WP_Block_Type[] Associative array of `$block_type_name => $block_type` pairs.
154 */
155 public function get_all_registered() {
156 return $this->registered_block_types;
157 }
158
159 /**
160 * Checks if a block type is registered.
161 *
162 * @since 5.0.0
163 *
164 * @param string|null $name Block type name including namespace.
165 * @return bool True if the block type is registered, false otherwise.
166 */
167 public function is_registered( $name ) {
168 return isset( $name, $this->registered_block_types[ $name ] );
169 }
170
171 public function __wakeup() {
172 if ( ! $this->registered_block_types ) {
173 return;
174 }
175 if ( ! is_array( $this->registered_block_types ) ) {
176 throw new UnexpectedValueException();
177 }
178 foreach ( $this->registered_block_types as $value ) {
179 if ( ! $value instanceof WP_Block_Type ) {
180 throw new UnexpectedValueException();
181 }
182 }
183 }
184
185 /**
186 * Utility method to retrieve the main instance of the class.
187 *
188 * The instance will be created if it does not exist yet.
189 *
190 * @since 5.0.0
191 *
192 * @return WP_Block_Type_Registry The main instance.
193 */
194 public static function get_instance() {
195 if ( null === self::$instance ) {
196 self::$instance = new self();
197 }
198
199 return self::$instance;
200 }
201}
202