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

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