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

655 lines 25.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\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 private function validate_required_selector( string $dependant_param_key, mixed $param, WP_REST_Request $request, string $key ): bool {
510
511 $use_widgets = (bool) $request->get_param( $dependant_param_key );
512 if ( ! $use_widgets ) {
513 return null === $param || is_string( $param );
514 }
515
516 return null !== $param
517 && is_string( $param )
518 && '' !== trim( $param );
519 }
520
521 /**
522 * Validate if required widget selector is valid.
523 */
524 public function validate_required_widget_selector( mixed $param, WP_REST_Request $request, string $key ): bool {
525 return $this->validate_required_selector( self::PARAM_USE_WIDGETS, $param, $request, $key );
526 }
527
528 /**
529 * Validate if required cart widget selector is valid.
530 */
531 public function validate_required_cart_widget_selector( mixed $param, WP_REST_Request $request, string $key ): bool {
532 return $this->validate_required_selector( self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_CART_PAGE, $param, $request, $key );
533 }
534
535 /**
536 * Validate if required listing widget selector is valid.
537 */
538 public function validate_required_listing_widget_selector( mixed $param, WP_REST_Request $request, string $key ): bool {
539 return $this->validate_required_selector( self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_PRODUCT_LISTING, $param, $request, $key );
540 }
541
542 /**
543 * Validate if optional widget selector is valid.
544 *
545 * @param mixed $param The parameter.
546 * @param WP_REST_Request $request The request.
547 * @param string $key The key.
548 */
549 public function validate_optional_widget_selector( $param, $request, $key ): bool {
550 return null === $param || is_string( $param );
551 }
552
553 /**
554 * Sanitize widget label.
555 *
556 * @param mixed[] $param The parameter.
557 * @return mixed[]
558 */
559 public function sanitize_widget_labels( $param ): array {
560 return array(
561 'message' => sanitize_text_field( strval( $param['message'] ) ),
562 'messageBelowLimit' => sanitize_text_field( strval( $param['messageBelowLimit'] ) ),
563 );
564 }
565
566 /**
567 * Get argument structure for the widget location list.
568 *
569 * @param bool $required If the argument is required.
570 * @param mixed $default_value The default value. Null will be ignored.
571 * @param callable $validate The validate callback. Leave null to use the default.
572 * @param callable $sanitize The sanitize callback. Leave null to use the default.
573 * @return mixed[]
574 */
575 protected function get_arg_widget_location_list( $required = true, $default_value = array(), $validate = null, $sanitize = null ): array {
576 return array_merge(
577 $this->get_arg( $required, $default_value ),
578 array(
579 'validate_callback' => null === $validate ? array( $this, 'validate_widget_location_list' ) : $validate,
580 'sanitize_callback' => null === $sanitize ? array( $this, 'sanitize_widget_location_list' ) : $sanitize,
581 )
582 );
583 }
584
585 /**
586 * Validate if widget location list is valid.
587 *
588 * @param mixed $param The parameter.
589 * @param WP_REST_Request $request The request.
590 * @param string $key The key.
591 */
592 public function validate_widget_location_list( $param, $request, $key ): bool {
593 if ( ! is_array( $param ) ) {
594 return false;
595 }
596 foreach ( $param as $location ) {
597 if ( ! isset(
598 $location[ self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET ],
599 $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ],
600 $location[ self::PARAM_CUSTOM_LOCATION_COUNTRY ],
601 $location[ self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES ],
602 $location[ self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET ]
603 )
604 || ! is_string( $location[ self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET ] )
605 || ! is_string( $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] )
606 || ! is_string( $location[ self::PARAM_CUSTOM_LOCATION_COUNTRY ] )
607 || ! is_string( $location[ self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES ] )
608 || ! is_bool( $location[ self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET ] )
609 || empty( $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] )
610 || empty( $location[ self::PARAM_CUSTOM_LOCATION_COUNTRY ] )
611 ) {
612 return false;
613 }
614
615 // check if exists another location with the same country title and product.
616 $country = $location[ self::PARAM_CUSTOM_LOCATION_COUNTRY ];
617 $product = $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ];
618 $campaign = $location[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ?? null;
619 $found = array_filter(
620 $param,
621 function ( $loc ) use ( $country, $product, $campaign ) {
622 return isset( $loc[ self::PARAM_CUSTOM_LOCATION_PRODUCT ], $loc[ self::PARAM_CUSTOM_LOCATION_COUNTRY ] )
623 && $loc[ self::PARAM_CUSTOM_LOCATION_COUNTRY ] === $country
624 && $loc[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] === $product
625 && ( $loc[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ?? null ) === $campaign;
626 }
627 );
628 if ( count( $found ) > 1 ) {
629 return false;
630 }
631 }
632 return true;
633 }
634
635 /**
636 * Sanitize widget location list.
637 *
638 * @param array<int, array<string, string>> $param The parameter.
639 * @return array<int, array<string, string>>
640 */
641 public function sanitize_widget_location_list( $param ): array {
642 foreach ( $param as &$location ) {
643 $location = array(
644 self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET => sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET ] ) ),
645 self::PARAM_CUSTOM_LOCATION_PRODUCT => sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] ) ),
646 self::PARAM_CUSTOM_LOCATION_COUNTRY => sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_COUNTRY ] ) ),
647 self::PARAM_CUSTOM_LOCATION_CAMPAIGN => isset( $location[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ) ? sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ) ) : null,
648 self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES => sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES ] ) ),
649 self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET => (bool) $location[ self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET ],
650 );
651 }
652 return $param;
653 }
654 }
655