PluginProbe
seQura / 3.0.2
seQura v3.0.2
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 3.0.2, at src/Controllers/Rest/class-onboarding-rest-controller.php

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