PluginProbe
seQura / 4.1.3
seQura v4.1.3
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.1.3, at src/Controllers/Rest/class-onboarding-rest-controller.php

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