PluginProbe
seQura / 4.0.0
seQura v4.0.0
4.3.4 4.3.3 4.3.2 4.3.1 trunk 2.0.0 2.0.10 2.0.11 2.0.12 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 3.0.0 3.0.2 3.0.5 3.0.6 3.0.7 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 4.0.0 All 30 releases
sequra / src / Controllers / Rest / class-onboarding-rest-controller.php

class-onboarding-rest-controller.php in seQura 4.0.0, at src/Controllers/Rest/class-onboarding-rest-controller.php

664 lines 23.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * REST Onboarding Controller
4 *
5 * @package SeQura/WC
6 * @subpackage SeQura/WC/Controllers/Rest
7 */
8
9 namespace SeQura\WC\Controllers\Rest;
10
11 use SeQura\Core\BusinessLogic\AdminAPI\AdminAPI;
12 use SeQura\Core\BusinessLogic\AdminAPI\Connection\Requests\ConnectionRequest;
13 use SeQura\Core\BusinessLogic\AdminAPI\Connection\Requests\OnboardingRequest;
14 use SeQura\Core\BusinessLogic\AdminAPI\CountryConfiguration\Requests\CountryConfigurationRequest;
15 use SeQura\Core\BusinessLogic\AdminAPI\Disconnect\Requests\DisconnectRequest;
16 use SeQura\Core\BusinessLogic\AdminAPI\PromotionalWidgets\Requests\WidgetSettingsRequest;
17 use SeQura\WC\Services\Log\Interface_Logger_Service;
18 use SeQura\Core\Infrastructure\Utility\RegexProvider;
19 use WP_Error;
20 use WP_REST_Request;
21 use WP_REST_Response;
22
23 /**
24 * REST Onboarding Controller
25 */
26 class Onboarding_REST_Controller extends REST_Controller {
27
28 private const PARAM_ENVIRONMENT = 'environment';
29 private const PARAM_USERNAME = 'username';
30 private const PARAM_PASSWORD = 'password';
31 private const PARAM_DEPLOYMENT_ID = 'deploymentId';
32 private const PARAM_DEPLOYMENT = 'deployment';
33 private const PARAM_CONNECTION_DATA = 'connectionData';
34 private const PARAM_SEND_STATISTICAL_DATA = 'sendStatisticalData';
35 private const PARAM_DISPLAY_WIDGET_ON_PRODUCT_PAGE = 'displayWidgetOnProductPage';
36 private const PARAM_SHOW_INSTALLMENT_AMOUNT_IN_PRODUCT_LISTING = 'showInstallmentAmountInProductListing';
37 private const PARAM_SHOW_INSTALLMENT_AMOUNT_IN_CART_PAGE = 'showInstallmentAmountInCartPage';
38 private const PARAM_WIDGET_STYLES = 'widgetStyles';
39 private const PARAM_CUSTOM_LOCATIONS = 'customLocations';
40 private const PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET = 'selForTarget';
41 private const PARAM_CUSTOM_LOCATION_WIDGET_STYLES = self::PARAM_WIDGET_STYLES;
42 private const PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET = 'displayWidget';
43 private const PARAM_CUSTOM_LOCATION_PRODUCT = 'product';
44 private const PARAM_CUSTOM_LOCATION_CAMPAIGN = 'campaign';
45
46 private const PARAM_SEL_FOR_PRICE = 'productPriceSelector';
47 private const PARAM_SEL_FOR_ALT_PRICE = 'altProductPriceSelector';
48 private const PARAM_SEL_FOR_ALT_PRICE_TRIGGER = 'altProductPriceTriggerSelector';
49 private const PARAM_SEL_FOR_DEFAULT_LOCATION = 'defaultProductLocationSelector';
50 // Cart widget config.
51 private const PARAM_CART_SEL_FOR_PRICE = 'cartPriceSelector';
52 private const PARAM_CART_SEL_FOR_DEFAULT_LOCATION = 'cartLocationSelector';
53 private const PARAM_CART_WIDGET_ON_PAGE = 'widgetOnCartPage';
54 // Product listing widget config.
55 private const PARAM_LISTING_SEL_FOR_PRICE = 'listingPriceSelector';
56 private const PARAM_LISTING_SEL_FOR_LOCATION = 'listingLocationSelector';
57 private const PARAM_LISTING_WIDGET_ON_PAGE = 'widgetOnListingPage';
58
59 private const PARAM_IS_FULL_DISCONNECT = 'isFullDisconnect';
60
61 /**
62 * Constructor.
63 *
64 * @param string $rest_namespace The namespace.
65 * @param Interface_Logger_Service $logger The logger service.
66 * @param RegexProvider $regex The regex provider.
67 */
68 public function __construct(
69 $rest_namespace,
70 Interface_Logger_Service $logger,
71 RegexProvider $regex
72 ) {
73 parent::__construct( $logger, $regex );
74 $this->namespace = $rest_namespace;
75 $this->rest_base = '/onboarding';
76 }
77
78 /**
79 * Register the API endpoints.
80 *
81 * @return void
82 */
83 public function register_routes() {
84 $this->logger->log_debug( 'Hook executed', __FUNCTION__, __CLASS__ );
85 $store_id_args = array( self::PARAM_STORE_ID => $this->get_arg_string() );
86
87 $data_args = array_merge(
88 $store_id_args,
89 array(
90 self::PARAM_ENVIRONMENT => array_merge(
91 $this->get_arg_string(),
92 array( 'enum' => array( 'sandbox', 'production' ) )
93 ),
94 self::PARAM_USERNAME => $this->get_arg_string(),
95 self::PARAM_PASSWORD => $this->get_arg_string(),
96 self::PARAM_SEND_STATISTICAL_DATA => $this->get_arg_bool(),
97 )
98 );
99
100 $disconnect_args = array_merge(
101 $store_id_args,
102 array(
103 self::PARAM_IS_FULL_DISCONNECT => $this->get_arg_bool(),
104 self::PARAM_DEPLOYMENT_ID => $this->get_arg_string(),
105 )
106 );
107
108 $validate_data_args = array_merge(
109 $data_args,
110 array(
111 self::PARAM_MERCHANT_ID => $this->get_arg_string( false ),
112 )
113 );
114
115 $widget_args = array_merge(
116 $store_id_args,
117 array(
118 self::PARAM_DISPLAY_WIDGET_ON_PRODUCT_PAGE => $this->get_arg_bool(),
119 self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_PRODUCT_LISTING => $this->get_arg_bool(),
120 self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_CART_PAGE => $this->get_arg_bool(),
121 self::PARAM_WIDGET_STYLES => $this->get_arg_string(),
122 self::PARAM_SEL_FOR_PRICE => $this->get_arg_string( true, '', array( $this, 'validate_required_widget_selector' ) ),
123 self::PARAM_SEL_FOR_ALT_PRICE => $this->get_arg_string( true, '', array( $this, 'validate_optional_widget_selector' ) ),
124 self::PARAM_SEL_FOR_ALT_PRICE_TRIGGER => $this->get_arg_string( true, '', array( $this, 'validate_optional_widget_selector' ) ),
125 self::PARAM_SEL_FOR_DEFAULT_LOCATION => $this->get_arg_string( true, '', array( $this, 'validate_required_widget_selector' ) ),
126
127 self::PARAM_CUSTOM_LOCATIONS => $this->get_arg_widget_location_list(),
128
129 self::PARAM_CART_SEL_FOR_PRICE => $this->get_arg_string( true, '', array( $this, 'validate_required_cart_widget_selector' ) ),
130 self::PARAM_CART_SEL_FOR_DEFAULT_LOCATION => $this->get_arg_string( true, '', array( $this, 'validate_required_cart_widget_selector' ) ),
131 self::PARAM_CART_WIDGET_ON_PAGE => $this->get_arg_string( true, '', array( $this, 'validate_required_cart_widget_selector' ) ),
132
133 self::PARAM_LISTING_SEL_FOR_PRICE => $this->get_arg_string( true, '', array( $this, 'validate_required_listing_widget_selector' ) ),
134 self::PARAM_LISTING_SEL_FOR_LOCATION => $this->get_arg_string( true, '', array( $this, 'validate_required_listing_widget_selector' ) ),
135 self::PARAM_LISTING_WIDGET_ON_PAGE => $this->get_arg_string( true, '', array( $this, 'validate_required_listing_widget_selector' ) ),
136 )
137 );
138
139 $store_id = $this->url_param_pattern( self::PARAM_STORE_ID );
140
141 $this->register_get( "data/{$store_id}", 'get_connection_data', $store_id_args );
142 $this->register_post( "data/validate/{$store_id}", 'validate_connection_data', $validate_data_args );
143 $this->register_post( "data/disconnect/{$store_id}", 'disconnect', $disconnect_args );
144 $this->register_post( "data/connect/{$store_id}", 'connect', $store_id_args );
145
146 $this->register_get( "widgets/{$store_id}", 'get_widgets', $store_id_args );
147 $this->register_post( "widgets/{$store_id}", 'save_widgets', $widget_args );
148
149 $this->register_get( "countries/selling/{$store_id}", 'get_selling_countries', $store_id_args );
150 $this->register_get( "countries/{$store_id}", 'get_countries', $store_id_args );
151 $this->register_post( "countries/{$store_id}", 'save_countries', $store_id_args );
152
153 $this->register_get( "deployments/{$store_id}", 'get_deployments', $store_id_args );
154 $this->register_get( "deployments/not-connected/{$store_id}", 'get_not_connected_deployments', $store_id_args );
155 }
156
157 /**
158 * Get connection data.
159 *
160 * @param WP_REST_Request $request The request.
161 *
162 * @return WP_REST_Response|WP_Error
163 */
164 public function get_connection_data( WP_REST_Request $request ) {
165 $response = null;
166 try {
167 $response = AdminAPI::get()
168 ->connection( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
169 ->getOnboardingData()
170 ->toArray();
171 } catch ( \Throwable $e ) {
172 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
173 $response = new WP_Error( 'error', $e->getMessage() );
174 }
175 return \rest_ensure_response( $response );
176 }
177
178 /**
179 * Get deployments.
180 *
181 * @param WP_REST_Request $request The request.
182 *
183 * @return WP_REST_Response|WP_Error
184 */
185 public function get_deployments( WP_REST_Request $request ) {
186 $response = null;
187 try {
188 $response = AdminAPI::get()
189 ->deployments( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
190 ->getAllDeployments()
191 ->toArray();
192 } catch ( \Throwable $e ) {
193 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
194 $response = new WP_Error( 'error', $e->getMessage() );
195 }
196 return \rest_ensure_response( $response );
197 }
198
199 /**
200 * Get deployments.
201 *
202 * @param WP_REST_Request $request The request.
203 *
204 * @return WP_REST_Response|WP_Error
205 */
206 public function get_not_connected_deployments( WP_REST_Request $request ) {
207 $response = null;
208 try {
209 $response = AdminAPI::get()
210 ->deployments( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
211 ->getNotConnectedDeployments()
212 ->toArray();
213 } catch ( \Throwable $e ) {
214 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
215 $response = new WP_Error( 'error', $e->getMessage() );
216 }
217 return \rest_ensure_response( $response );
218 }
219
220 /**
221 * Validate connection data before saving.
222 *
223 * @param WP_REST_Request $request The request.
224 *
225 * @return WP_REST_Response|WP_Error
226 */
227 public function validate_connection_data( WP_REST_Request $request ) {
228 $response = null;
229 try {
230 $response = AdminAPI::get()
231 ->connection( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
232 ->isConnectionDataValid(
233 new ConnectionRequest(
234 strval( $request->get_param( self::PARAM_ENVIRONMENT ) ),
235 strval( $request->get_param( self::PARAM_MERCHANT_ID ) ),
236 strval( $request->get_param( self::PARAM_USERNAME ) ),
237 strval( $request->get_param( self::PARAM_PASSWORD ) ),
238 strval( $request->get_param( self::PARAM_DEPLOYMENT_ID ) )
239 )
240 )
241 ->toArray();
242 } catch ( \Throwable $e ) {
243 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
244 $response = new WP_Error( 'error', $e->getMessage() );
245 }
246 return \rest_ensure_response( $response );
247 }
248
249 /**
250 * Disconnects integration from the shop.
251 *
252 * @param WP_REST_Request $request The request.
253 *
254 * @return WP_REST_Response|WP_Error
255 */
256 public function disconnect( WP_REST_Request $request ) {
257 $response = null;
258 try {
259 $response = AdminAPI::get()
260 ->disconnect( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
261 ->disconnect(
262 new DisconnectRequest(
263 strval( $request->get_param( self::PARAM_DEPLOYMENT_ID ) ),
264 (bool) $request->get_param( self::PARAM_IS_FULL_DISCONNECT )
265 )
266 )
267 ->toArray();
268 } catch ( \Throwable $e ) {
269 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
270 $response = new WP_Error( 'error', $e->getMessage() );
271 }
272 return \rest_ensure_response( $response );
273 }
274
275 /**
276 * Disconnects integration from the shop.
277 *
278 * @param WP_REST_Request $request The request.
279 *
280 * @return WP_REST_Response|WP_Error
281 */
282 public function connect( WP_REST_Request $request ) {
283 $response = null;
284 try {
285 /**
286 * Connection Data
287 *
288 * @var array<array{merchantId?: string,
289 * username?: string,
290 * password?: string,
291 * deployment?: string}> $connection_data_array
292 */
293 $connection_data_array = $request->get_param( self::PARAM_CONNECTION_DATA ) ?? array();
294
295 $connection_requests = array();
296 foreach ( $connection_data_array as $conn_data ) {
297 $connection_requests[] = new ConnectionRequest(
298 strval( $request->get_param( self::PARAM_ENVIRONMENT ) ),
299 strval( $conn_data[ self::PARAM_MERCHANT_ID ] ?? '' ),
300 strval( $conn_data[ self::PARAM_USERNAME ] ?? '' ),
301 strval( $conn_data[ self::PARAM_PASSWORD ] ?? '' ),
302 strval( $conn_data[ self::PARAM_DEPLOYMENT ] ?? '' )
303 );
304 }
305
306 $response = AdminAPI::get()
307 ->connection( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
308 ->connect(
309 new OnboardingRequest(
310 $connection_requests,
311 (bool) $request->get_param( self::PARAM_SEND_STATISTICAL_DATA ),
312 )
313 )
314 ->toArray();
315 } catch ( \Throwable $e ) {
316 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
317 $response = new WP_Error( 'error', $e->getMessage() );
318 }
319 return \rest_ensure_response( $response );
320 }
321
322 /**
323 * GET selling countries.
324 *
325 * @param WP_REST_Request $request The request.
326 *
327 * @return WP_REST_Response|WP_Error
328 */
329 public function get_selling_countries( WP_REST_Request $request ) {
330 $response = null;
331 try {
332 $response = AdminAPI::get()
333 ->countryConfiguration( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
334 ->getSellingCountries()
335 ->toArray();
336 } catch ( \Throwable $e ) {
337 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
338 $response = new WP_Error( 'error', $e->getMessage() );
339 }
340 return \rest_ensure_response( $response );
341 }
342
343 /**
344 * GET countries.
345 *
346 * @param WP_REST_Request $request The request.
347 *
348 * @return WP_REST_Response|WP_Error
349 */
350 public function get_countries( WP_REST_Request $request ) {
351 $response = null;
352 try {
353 $response = AdminAPI::get()
354 ->countryConfiguration( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
355 ->getCountryConfigurations()
356 ->toArray();
357 } catch ( \Throwable $e ) {
358 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
359 $response = new WP_Error( 'error', $e->getMessage() );
360 }
361 return \rest_ensure_response( $response );
362 }
363
364 /**
365 * Save countries.
366 *
367 * @throws \Exception
368 * @param WP_REST_Request $request The request.
369 *
370 * @return WP_REST_Response|WP_Error
371 */
372 public function save_countries( WP_REST_Request $request ) {
373 if ( ! $this->validate_countries( $request ) ) {
374 return new WP_REST_Response( 'Invalid data', 400 );
375 }
376
377 $response = null;
378 try {
379 /**
380 * Data
381 *
382 * @var array<int, array<string, string>> $data The data.
383 */
384 $data = (array) json_decode( $request->get_body(), true );
385
386 $response = AdminAPI::get()
387 ->countryConfiguration( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
388 ->saveCountryConfigurations( new CountryConfigurationRequest( $data ) )
389 ->toArray();
390 } catch ( \Throwable $e ) {
391 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
392 $response = new WP_Error( 'error', $e->getMessage() );
393 }
394 return \rest_ensure_response( $response );
395 }
396
397 /**
398 * GET widgets.
399 *
400 * @param WP_REST_Request $request The request.
401 *
402 * @return WP_REST_Response|WP_Error
403 */
404 public function get_widgets( WP_REST_Request $request ) {
405 $response = null;
406 try {
407 $response = AdminAPI::get()
408 ->widgetConfiguration( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
409 ->getWidgetSettings()
410 ->toArray();
411
412 if ( ! empty( $response ) ) {
413 $response[ self::PARAM_WIDGET_STYLES ] = $response['widgetConfiguration'];
414 unset( $response['widgetConfiguration'] );
415 }
416 } catch ( \Throwable $e ) {
417 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
418 $response = new WP_Error( 'error', $e->getMessage() );
419 }
420 return \rest_ensure_response( $response );
421 }
422
423 /**
424 * Save countries.
425 *
426 * @throws \Exception
427 * @param WP_REST_Request $request The request.
428 *
429 * @return WP_REST_Response|WP_Error
430 */
431 public function save_widgets( WP_REST_Request $request ) {
432 $response = null;
433 try {
434 $store_id = strval( $request->get_param( self::PARAM_STORE_ID ) );
435 $response = AdminAPI::get()
436 ->widgetConfiguration( $store_id )
437 ->setWidgetSettings(
438 new WidgetSettingsRequest(
439 (bool) $request->get_param( self::PARAM_DISPLAY_WIDGET_ON_PRODUCT_PAGE ),
440 (bool) $request->get_param( self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_PRODUCT_LISTING ),
441 (bool) $request->get_param( self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_CART_PAGE ),
442 strval( $request->get_param( self::PARAM_WIDGET_STYLES ) ),
443 strval( $request->get_param( self::PARAM_SEL_FOR_PRICE ) ),
444 strval( $request->get_param( self::PARAM_SEL_FOR_DEFAULT_LOCATION ) ),
445 strval( $request->get_param( self::PARAM_CART_SEL_FOR_PRICE ) ),
446 strval( $request->get_param( self::PARAM_CART_SEL_FOR_DEFAULT_LOCATION ) ),
447 strval( $request->get_param( self::PARAM_CART_WIDGET_ON_PAGE ) ),
448 strval( $request->get_param( self::PARAM_LISTING_WIDGET_ON_PAGE ) ),
449 strval( $request->get_param( self::PARAM_LISTING_SEL_FOR_PRICE ) ),
450 strval( $request->get_param( self::PARAM_LISTING_SEL_FOR_LOCATION ) ),
451 strval( $request->get_param( self::PARAM_SEL_FOR_ALT_PRICE ) ),
452 strval( $request->get_param( self::PARAM_SEL_FOR_ALT_PRICE_TRIGGER ) ),
453 (array) $request->get_param( self::PARAM_CUSTOM_LOCATIONS )
454 )
455 );
456 $response = $response->toArray();
457 } catch ( \Throwable $e ) {
458 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
459 $response = new WP_Error( 'error', $e->getMessage() );
460 }
461 return \rest_ensure_response( $response );
462 }
463
464 /**
465 * Validate if countries payload is valid.
466 *
467 * @param WP_REST_Request $request The request.
468 */
469 public function validate_countries( WP_REST_Request $request ): bool {
470 try {
471 $data = json_decode( $request->get_body(), true );
472 if ( ! is_array( $data ) ) {
473 return false;
474 }
475 $allowed_countries = AdminAPI::get()
476 ->countryConfiguration( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
477 ->getSellingCountries()
478 ->toArray();
479
480 $allowed_countries = array_column( $allowed_countries, 'code' );
481
482 foreach ( $data as $country ) {
483 if ( ! isset( $country['countryCode'] )
484 || ! isset( $country['merchantId'] )
485 || ! is_string( $country['countryCode'] )
486 || ! is_string( $country['merchantId'] )
487 || ! in_array( $country['countryCode'], $allowed_countries, true )
488 ) {
489 return false;
490 }
491 }
492 } catch ( \Throwable $e ) {
493 return false;
494 }
495 return true;
496 }
497
498 /**
499 * Validate if widget label is valid.
500 *
501 * @param mixed $param The parameter.
502 * @param WP_REST_Request $request The request.
503 * @param string $key The key.
504 */
505 public function validate_widget_labels( $param, $request, $key ): bool {
506 return is_array( $param )
507 && isset( $param['message'] )
508 && is_string( $param['message'] )
509 && isset( $param['messageBelowLimit'] )
510 && is_string( $param['messageBelowLimit'] );
511 }
512
513 /**
514 * Validate if required selector is valid.
515 *
516 * @param mixed $param The parameter.
517 */
518 private function validate_required_selector( string $dependant_param_key, $param, WP_REST_Request $request, string $key ): bool {
519
520 $use_widgets = (bool) $request->get_param( $dependant_param_key );
521 if ( ! $use_widgets ) {
522 return null === $param || is_string( $param );
523 }
524
525 return null !== $param
526 && is_string( $param )
527 && '' !== trim( $param );
528 }
529
530 /**
531 * Validate if required widget selector is valid.
532 *
533 * @param mixed $param The param.
534 */
535 public function validate_required_widget_selector( $param, WP_REST_Request $request, string $key ): bool {
536 return $this->validate_required_selector( self::PARAM_DISPLAY_WIDGET_ON_PRODUCT_PAGE, $param, $request, $key );
537 }
538
539 /**
540 * Validate if required cart widget selector is valid.
541 *
542 * @param mixed $param The param.
543 */
544 public function validate_required_cart_widget_selector( $param, WP_REST_Request $request, string $key ): bool {
545 return $this->validate_required_selector( self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_CART_PAGE, $param, $request, $key );
546 }
547
548 /**
549 * Validate if required listing widget selector is valid.
550 *
551 * @param mixed $param The param.
552 */
553 public function validate_required_listing_widget_selector( $param, WP_REST_Request $request, string $key ): bool {
554 return $this->validate_required_selector( self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_PRODUCT_LISTING, $param, $request, $key );
555 }
556
557 /**
558 * Validate if optional widget selector is valid.
559 *
560 * @param mixed $param The parameter.
561 * @param WP_REST_Request $request The request.
562 * @param string $key The key.
563 */
564 public function validate_optional_widget_selector( $param, $request, $key ): bool {
565 return null === $param || is_string( $param );
566 }
567
568 /**
569 * Sanitize widget label.
570 *
571 * @param mixed[] $param The parameter.
572 * @return mixed[]
573 */
574 public function sanitize_widget_labels( $param ): array {
575 return array(
576 'message' => \sanitize_text_field( strval( $param['message'] ) ),
577 'messageBelowLimit' => \sanitize_text_field( strval( $param['messageBelowLimit'] ) ),
578 );
579 }
580
581 /**
582 * Get argument structure for the widget location list.
583 *
584 * @param bool $required If the argument is required.
585 * @param mixed $default_value The default value. Null will be ignored.
586 * @param callable $validate The validate callback. Leave null to use the default.
587 * @param callable $sanitize The sanitize callback. Leave null to use the default.
588 * @return mixed[]
589 */
590 protected function get_arg_widget_location_list( $required = true, $default_value = array(), $validate = null, $sanitize = null ): array {
591 return array_merge(
592 $this->get_arg( $required, $default_value ),
593 array(
594 'validate_callback' => null === $validate ? array( $this, 'validate_widget_location_list' ) : $validate,
595 'sanitize_callback' => null === $sanitize ? array( $this, 'sanitize_widget_location_list' ) : $sanitize,
596 )
597 );
598 }
599
600 /**
601 * Validate if widget location list is valid.
602 *
603 * @param mixed $param The parameter.
604 * @param WP_REST_Request $request The request.
605 * @param string $key The key.
606 */
607 public function validate_widget_location_list( $param, $request, $key ): bool {
608 if ( ! is_array( $param ) ) {
609 return false;
610 }
611 foreach ( $param as $location ) {
612 if ( ! isset(
613 $location[ self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET ],
614 $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ],
615 $location[ self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES ],
616 $location[ self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET ]
617 )
618 || ! is_string( $location[ self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET ] )
619 || ! is_string( $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] )
620 || ! is_string( $location[ self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES ] )
621 || ! is_bool( $location[ self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET ] )
622 || empty( $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] )
623 ) {
624 return false;
625 }
626
627 // check if exists another location with the same title and product.
628 $product = $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ];
629 $campaign = $location[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ?? null;
630 $found = \array_filter(
631 $param,
632 function ( $loc ) use ( $product, $campaign ) {
633 return isset( $loc[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] )
634 && $loc[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] === $product
635 && ( $loc[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ?? null ) === $campaign;
636 }
637 );
638 if ( count( $found ) > 1 ) {
639 return false;
640 }
641 }
642 return true;
643 }
644
645 /**
646 * Sanitize widget location list.
647 *
648 * @param array<int, array<string, string>> $param The parameter.
649 * @return array<int, array<string, string>>
650 */
651 public function sanitize_widget_location_list( $param ): array {
652 foreach ( $param as &$location ) {
653 $location = array(
654 self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET => \sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET ] ) ),
655 self::PARAM_CUSTOM_LOCATION_PRODUCT => \sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] ) ),
656 self::PARAM_CUSTOM_LOCATION_CAMPAIGN => isset( $location[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ) ? \sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ) ) : null,
657 self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES => \sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES ] ) ),
658 self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET => (bool) $location[ self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET ],
659 );
660 }
661 return $param;
662 }
663 }
664