PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.1
WooCommerce v10.9.1
10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / src / StoreApi / Schemas / ExtendSchema.php
woocommerce / src / StoreApi / Schemas Last commit date
V1 4 weeks ago ExtendSchema.php 2 years ago
ExtendSchema.php
350 lines
1 <?php
2 namespace Automattic\WooCommerce\StoreApi\Schemas;
3
4 use Automattic\WooCommerce\StoreApi\Schemas\V1\CartItemSchema;
5 use Automattic\WooCommerce\StoreApi\Schemas\V1\CartSchema;
6 use Automattic\WooCommerce\StoreApi\Schemas\V1\CheckoutSchema;
7 use Automattic\WooCommerce\StoreApi\Schemas\V1\ProductSchema;
8 use Automattic\WooCommerce\StoreApi\Formatters;
9
10 /**
11 * Provides utility functions to extend Store API schemas.
12 *
13 * Note there are also helpers that map to these methods.
14 *
15 * @see woocommerce_store_api_register_endpoint_data()
16 * @see woocommerce_store_api_register_update_callback()
17 * @see woocommerce_store_api_register_payment_requirements()
18 * @see woocommerce_store_api_get_formatter()
19 */
20 final class ExtendSchema {
21 /**
22 * List of Store API schema that is allowed to be extended by extensions.
23 *
24 * @var string[]
25 */
26 private $endpoints = [
27 CartItemSchema::IDENTIFIER,
28 CartSchema::IDENTIFIER,
29 CheckoutSchema::IDENTIFIER,
30 ProductSchema::IDENTIFIER,
31 ];
32
33 /**
34 * Holds the formatters class instance.
35 *
36 * @var Formatters
37 */
38 private $formatters;
39
40 /**
41 * Data to be extended
42 *
43 * @var array
44 */
45 private $extend_data = [];
46
47 /**
48 * Data to be extended
49 *
50 * @var array
51 */
52 private $callback_methods = [];
53
54 /**
55 * Array of payment requirements
56 *
57 * @var array
58 */
59 private $payment_requirements = [];
60
61 /**
62 * Constructor
63 *
64 * @param Formatters $formatters An instance of the formatters class.
65 */
66 public function __construct( Formatters $formatters ) {
67 $this->formatters = $formatters;
68 }
69
70 /**
71 * Register endpoint data under a specified namespace
72 *
73 * @param array $args {
74 * An array of elements that make up a post to update or insert.
75 *
76 * @type string $endpoint Required. The endpoint to extend.
77 * @type string $namespace Required. Plugin namespace.
78 * @type callable $schema_callback Callback executed to add schema data.
79 * @type callable $data_callback Callback executed to add endpoint data.
80 * @type string $schema_type The type of data, object or array.
81 * }
82 *
83 * @throws \Exception On failure to register.
84 */
85 public function register_endpoint_data( $args ) {
86 $args = wp_parse_args(
87 $args,
88 [
89 'endpoint' => '',
90 'namespace' => '',
91 'schema_callback' => null,
92 'data_callback' => null,
93 'schema_type' => ARRAY_A,
94 ]
95 );
96
97 if ( ! is_string( $args['namespace'] ) || empty( $args['namespace'] ) ) {
98 $this->throw_exception( 'You must provide a plugin namespace when extending a Store REST endpoint.' );
99 }
100
101 if ( ! in_array( $args['endpoint'], $this->endpoints, true ) ) {
102 $this->throw_exception(
103 sprintf( 'You must provide a valid Store REST endpoint to extend, valid endpoints are: %1$s. You provided %2$s.', implode( ', ', $this->endpoints ), $args['endpoint'] )
104 );
105 }
106
107 if ( ! is_null( $args['schema_callback'] ) && ! is_callable( $args['schema_callback'] ) ) {
108 $this->throw_exception( '$schema_callback must be a callable function.' );
109 }
110
111 if ( ! is_null( $args['data_callback'] ) && ! is_callable( $args['data_callback'] ) ) {
112 $this->throw_exception( '$data_callback must be a callable function.' );
113 }
114
115 if ( ! in_array( $args['schema_type'], [ ARRAY_N, ARRAY_A ], true ) ) {
116 $this->throw_exception(
117 sprintf( 'Data type must be either ARRAY_N for a numeric array or ARRAY_A for an object like array. You provided %1$s.', $args['schema_type'] )
118 );
119 }
120
121 $this->extend_data[ $args['endpoint'] ][ $args['namespace'] ] = [
122 'schema_callback' => $args['schema_callback'],
123 'data_callback' => $args['data_callback'],
124 'schema_type' => $args['schema_type'],
125 ];
126 }
127
128 /**
129 * Add callback functions that can be executed by the cart/extensions endpoint.
130 *
131 * @param array $args {
132 * An array of elements that make up the callback configuration.
133 *
134 * @type string $namespace Required. Plugin namespace.
135 * @type callable $callback Required. The function/callable to execute.
136 * }
137 *
138 * @throws \Exception On failure to register.
139 */
140 public function register_update_callback( $args ) {
141 $args = wp_parse_args(
142 $args,
143 [
144 'namespace' => '',
145 'callback' => null,
146 ]
147 );
148
149 if ( ! is_string( $args['namespace'] ) || empty( $args['namespace'] ) ) {
150 throw new \Exception( 'You must provide a plugin namespace when extending a Store REST endpoint.' );
151 }
152
153 if ( ! is_callable( $args['callback'] ) ) {
154 throw new \Exception( 'There is no valid callback supplied to register_update_callback.' );
155 }
156
157 $this->callback_methods[ $args['namespace'] ] = $args;
158 }
159
160 /**
161 * Registers and validates payment requirements callbacks.
162 *
163 * @param array $args {
164 * Array of registration data.
165 *
166 * @type callable $data_callback Required. Callback executed to add payment requirements data.
167 * }
168 *
169 * @throws \Exception On failure to register.
170 */
171 public function register_payment_requirements( $args ) {
172 if ( empty( $args['data_callback'] ) || ! is_callable( $args['data_callback'] ) ) {
173 $this->throw_exception( '$data_callback must be a callable function.' );
174 }
175 $this->payment_requirements[] = $args['data_callback'];
176 }
177
178 /**
179 * Returns a formatter instance.
180 *
181 * @param string $name Formatter name.
182 * @return FormatterInterface
183 */
184 public function get_formatter( $name ) {
185 return $this->formatters->$name;
186 }
187
188 /**
189 * Get callback for a specific endpoint and namespace.
190 *
191 * @param string $namespace The namespace to get callbacks for.
192 *
193 * @return callable The callback registered by the extension.
194 * @throws \Exception When callback is not callable or parameters are incorrect.
195 */
196 public function get_update_callback( $namespace ) {
197 if ( ! is_string( $namespace ) ) {
198 throw new \Exception( 'You must provide a plugin namespace when extending a Store REST endpoint.' );
199 }
200
201 if ( ! array_key_exists( $namespace, $this->callback_methods ) ) {
202 throw new \Exception( sprintf( 'There is no such namespace registered: %1$s.', $namespace ) );
203 }
204
205 if ( ! array_key_exists( 'callback', $this->callback_methods[ $namespace ] ) || ! is_callable( $this->callback_methods[ $namespace ]['callback'] ) ) {
206 throw new \Exception( sprintf( 'There is no valid callback registered for: %1$s.', $namespace ) );
207 }
208
209 return $this->callback_methods[ $namespace ]['callback'];
210 }
211
212 /**
213 * Returns the registered endpoint data
214 *
215 * @param string $endpoint A valid identifier.
216 * @param array $passed_args Passed arguments from the Schema class.
217 * @return object Returns an casted object with registered endpoint data.
218 * @throws \Exception If a registered callback throws an error, or silently logs it.
219 */
220 public function get_endpoint_data( $endpoint, array $passed_args = [] ) {
221 $registered_data = [];
222
223 if ( isset( $this->extend_data[ $endpoint ] ) ) {
224 foreach ( $this->extend_data[ $endpoint ] as $namespace => $callbacks ) {
225 if ( is_null( $callbacks['data_callback'] ) ) {
226 continue;
227 }
228 try {
229 $data = $callbacks['data_callback']( ...$passed_args );
230
231 if ( ! is_array( $data ) ) {
232 $data = [];
233 throw new \Exception( '$data_callback must return an array.' );
234 }
235 } catch ( \Throwable $e ) {
236 $this->throw_exception( $e );
237 }
238
239 $registered_data[ $namespace ] = $data;
240 }
241 }
242
243 return (object) $registered_data;
244 }
245
246 /**
247 * Returns the registered endpoint schema
248 *
249 * @param string $endpoint A valid identifier.
250 * @param array $passed_args Passed arguments from the Schema class.
251 * @return object Returns an array with registered schema data.
252 * @throws \Exception If a registered callback throws an error, or silently logs it.
253 */
254 public function get_endpoint_schema( $endpoint, array $passed_args = [] ) {
255 $registered_schema = [];
256
257 if ( isset( $this->extend_data[ $endpoint ] ) ) {
258 foreach ( $this->extend_data[ $endpoint ] as $namespace => $callbacks ) {
259 if ( is_null( $callbacks['schema_callback'] ) ) {
260 continue;
261 }
262 try {
263 $schema = $callbacks['schema_callback']( ...$passed_args );
264
265 if ( ! is_array( $schema ) ) {
266 $schema = [];
267 throw new \Exception( '$schema_callback must return an array.' );
268 }
269 } catch ( \Throwable $e ) {
270 $this->throw_exception( $e );
271 }
272
273 $registered_schema[ $namespace ] = $this->format_extensions_properties( $namespace, $schema, $callbacks['schema_type'] );
274 }
275 }
276
277 return (object) $registered_schema;
278 }
279
280 /**
281 * Returns the additional payment requirements for the cart which are required to make payments. Values listed here
282 * are compared against each Payment Gateways "supports" flag.
283 *
284 * @param array $requirements list of requirements that should be added to the collected requirements.
285 * @return array Returns a list of payment requirements.
286 * @throws \Exception If a registered callback throws an error, or silently logs it.
287 */
288 public function get_payment_requirements( array $requirements = [ 'products' ] ) {
289 if ( ! empty( $this->payment_requirements ) ) {
290 foreach ( $this->payment_requirements as $callback ) {
291 try {
292 $data = $callback();
293
294 if ( ! is_array( $data ) ) {
295 throw new \Exception( '$data_callback must return an array.' );
296 }
297
298 $requirements = array_unique( array_merge( $requirements, $data ) );
299 } catch ( \Throwable $e ) {
300 $this->throw_exception( $e );
301 }
302 }
303 }
304 return $requirements;
305 }
306
307 /**
308 * Throws error and/or silently logs it.
309 *
310 * @param string|\Throwable $exception_or_error Error message or \Exception.
311 * @throws \Exception An error to throw if we have debug enabled and user is admin.
312 */
313 private function throw_exception( $exception_or_error ) {
314 $exception = is_string( $exception_or_error ) ? new \Exception( $exception_or_error ) : $exception_or_error;
315
316 wc_caught_exception( $exception );
317
318 if ( defined( 'WP_DEBUG' ) && WP_DEBUG && current_user_can( 'manage_woocommerce' ) ) {
319 throw $exception;
320 }
321 }
322
323 /**
324 * Format schema for an extension.
325 *
326 * @param string $namespace Error message or \Exception.
327 * @param array $schema An error to throw if we have debug enabled and user is admin.
328 * @param string $schema_type How should data be shaped.
329 * @return array Formatted schema.
330 */
331 private function format_extensions_properties( $namespace, $schema, $schema_type ) {
332 if ( ARRAY_N === $schema_type ) {
333 return [
334 /* translators: %s: extension namespace */
335 'description' => sprintf( __( 'Extension data registered by %s', 'woocommerce' ), $namespace ),
336 'type' => [ 'array', 'null' ],
337 'context' => [ 'view', 'edit' ],
338 'items' => $schema,
339 ];
340 }
341 return [
342 /* translators: %s: extension namespace */
343 'description' => sprintf( __( 'Extension data registered by %s', 'woocommerce' ), $namespace ),
344 'type' => [ 'object', 'null' ],
345 'context' => [ 'view', 'edit' ],
346 'properties' => $schema,
347 ];
348 }
349 }
350