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

674 lines 25.7 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_debug( '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 /**
323 * Data
324 *
325 * @var array<int, array<string, string>> $data The data.
326 */
327 $data = (array) json_decode( $request->get_body(), true );
328
329 $response = AdminAPI::get()
330 ->countryConfiguration( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
331 ->saveCountryConfigurations( new CountryConfigurationRequest( $data ) )
332 ->toArray();
333 } catch ( \Throwable $e ) {
334 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
335 $response = new WP_Error( 'error', $e->getMessage() );
336 }
337 return \rest_ensure_response( $response );
338 }
339
340 /**
341 * GET widgets.
342 *
343 * @param WP_REST_Request $request The request.
344 *
345 * @return WP_REST_Response|WP_Error
346 */
347 public function get_widgets( WP_REST_Request $request ) {
348 $response = null;
349 try {
350 $response = AdminAPI::get()
351 ->widgetConfiguration( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
352 ->getWidgetSettings()
353 ->toArray();
354
355 if ( ! empty( $response ) ) {
356 $response[ self::PARAM_WIDGET_LABELS ]['message'] = ! empty( $response[ self::PARAM_WIDGET_LABELS ]['messages'] ) ?
357 reset( $response[ self::PARAM_WIDGET_LABELS ]['messages'] ) : '';
358 $response[ self::PARAM_WIDGET_LABELS ]['messageBelowLimit'] = ! empty( $response[ self::PARAM_WIDGET_LABELS ]['messagesBelowLimit'] ) ?
359 reset( $response[ self::PARAM_WIDGET_LABELS ]['messagesBelowLimit'] ) : '';
360 $response[ self::PARAM_WIDGET_STYLES ] = $response['widgetConfiguration'];
361 unset( $response[ self::PARAM_WIDGET_LABELS ]['messages'], $response[ self::PARAM_WIDGET_LABELS ]['messagesBelowLimit'] );
362 unset( $response['widgetConfiguration'] );
363 }
364 } catch ( \Throwable $e ) {
365 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
366 $response = new WP_Error( 'error', $e->getMessage() );
367 }
368 return \rest_ensure_response( $response );
369 }
370
371 /**
372 * Save countries.
373 *
374 * @throws \Exception
375 * @param WP_REST_Request $request The request.
376 *
377 * @return WP_REST_Response|WP_Error
378 */
379 public function save_widgets( WP_REST_Request $request ) {
380 $response = null;
381 try {
382 //phpcs:disable Squiz.Commenting.InlineComment.InvalidEndChar
383 // $labels = $request->get_param( 'widgetLabels' );
384 // $messages = $labels['message'] ? array( $storeConfig->getLocale() => $labels['message'] ) : array();
385 // $messages_below_limit = $labels['messageBelowLimit'] ? array( $storeConfig->getLocale() => $labels['messageBelowLimit'] ) : array();
386 //phpcs:enable
387 $messages = array();
388 $messages_below_limit = array();
389
390 $store_id = strval( $request->get_param( self::PARAM_STORE_ID ) );
391
392 /**
393 * Filter the cart mini widgets.
394 * This field is not used in the UI and is not documented.
395 * The filter is intended for future use.
396 *
397 * @since 3.0.0
398 * @var Mini_Widget[] $cart_mini_widgets The cart mini widgets.
399 */
400 $cart_mini_widgets = \apply_filters( 'sequra_widget_settings_cart_mini_widgets', array(), $store_id );
401 if ( ! is_array( $cart_mini_widgets ) ) {
402 $this->logger->log_debug( 'Invalid cart mini widgets. ' . Mini_Widget::class . '[] is expected', __FUNCTION__, __CLASS__ );
403 $cart_mini_widgets = array();
404 }
405 foreach ( $cart_mini_widgets as $mini_widget ) {
406 if ( ! $mini_widget instanceof Mini_Widget ) {
407 $this->logger->log_debug( 'Invalid cart mini widgets. ' . Mini_Widget::class . '[] is expected', __FUNCTION__, __CLASS__ );
408 $cart_mini_widgets = array();
409 break;
410 }
411 }
412
413 /**
414 * Filter the product listing mini widgets.
415 * This field is not used in the UI and is not documented.
416 * The filter is intended for future use.
417 *
418 * @since 3.0.0
419 * @var Mini_Widget[] $listing_mini_widgets The product listing mini widgets.
420 */
421 $listing_mini_widgets = \apply_filters( 'sequra_widget_settings_product_listing_mini_widgets', array(), $store_id );
422 if ( ! is_array( $listing_mini_widgets ) ) {
423 $this->logger->log_debug( 'Invalid product listing mini widgets. ' . Mini_Widget::class . '[] is expected', __FUNCTION__, __CLASS__ );
424 $listing_mini_widgets = array();
425 }
426 foreach ( $listing_mini_widgets as $mini_widget ) {
427 if ( ! $mini_widget instanceof Mini_Widget ) {
428 $this->logger->log_debug( 'Invalid product listing mini widgets. ' . Mini_Widget::class . '[] is expected', __FUNCTION__, __CLASS__ );
429 $listing_mini_widgets = array();
430 break;
431 }
432 }
433
434 $response = AdminAPI::get()
435 ->widgetConfiguration( $store_id )
436 ->setWidgetSettings(
437 new Widget_Settings_Request(
438 (bool) $request->get_param( self::PARAM_USE_WIDGETS ),
439 null === $request->get_param( self::PARAM_ASSETS_KEY ) ? null : strval( $request->get_param( self::PARAM_ASSETS_KEY ) ),
440 (bool) $request->get_param( self::PARAM_DISPLAY_WIDGET_ON_PRODUCT_PAGE ),
441 (bool) $request->get_param( self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_PRODUCT_LISTING ),
442 (bool) $request->get_param( self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_CART_PAGE ),
443 strval( $request->get_param( self::PARAM_MINI_WIDGET_SELECTOR ) ),
444 strval( $request->get_param( self::PARAM_WIDGET_STYLES ) ),
445 (array) $messages,
446 (array) $messages_below_limit,
447 strval( $request->get_param( self::PARAM_SEL_FOR_PRICE ) ),
448 strval( $request->get_param( self::PARAM_SEL_FOR_ALT_PRICE ) ),
449 strval( $request->get_param( self::PARAM_SEL_FOR_ALT_PRICE_TRIGGER ) ),
450 strval( $request->get_param( self::PARAM_SEL_FOR_DEFAULT_LOCATION ) ),
451 (array) $request->get_param( self::PARAM_CUSTOM_LOCATIONS ),
452 strval( $request->get_param( self::PARAM_CART_SEL_FOR_PRICE ) ),
453 strval( $request->get_param( self::PARAM_CART_SEL_FOR_DEFAULT_LOCATION ) ),
454 $cart_mini_widgets,
455 strval( $request->get_param( self::PARAM_LISTING_SEL_FOR_PRICE ) ),
456 strval( $request->get_param( self::PARAM_LISTING_SEL_FOR_LOCATION ) ),
457 $listing_mini_widgets
458 )
459 )
460 ->toArray();
461 } catch ( \Throwable $e ) {
462 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
463 $response = new WP_Error( 'error', $e->getMessage() );
464 }
465 return \rest_ensure_response( $response );
466 }
467
468 /**
469 * Validate if countries payload is valid.
470 *
471 * @param WP_REST_Request $request The request.
472 */
473 public function validate_countries( WP_REST_Request $request ): bool {
474 try {
475 $data = json_decode( $request->get_body(), true );
476 if ( ! is_array( $data ) ) {
477 return false;
478 }
479 $allowed_countries = AdminAPI::get()
480 ->countryConfiguration( strval( $request->get_param( self::PARAM_STORE_ID ) ) )
481 ->getSellingCountries()
482 ->toArray();
483
484 $allowed_countries = array_column( $allowed_countries, 'code' );
485
486 foreach ( $data as $country ) {
487 if ( ! isset( $country['countryCode'] )
488 || ! isset( $country['merchantId'] )
489 || ! is_string( $country['countryCode'] )
490 || ! is_string( $country['merchantId'] )
491 || ! in_array( $country['countryCode'], $allowed_countries, true )
492 ) {
493 return false;
494 }
495 }
496 } catch ( \Throwable $e ) {
497 return false;
498 }
499 return true;
500 }
501
502 /**
503 * Validate if widget label is valid.
504 *
505 * @param mixed $param The parameter.
506 * @param WP_REST_Request $request The request.
507 * @param string $key The key.
508 */
509 public function validate_widget_labels( $param, $request, $key ): bool {
510 return is_array( $param )
511 && isset( $param['message'] )
512 && is_string( $param['message'] )
513 && isset( $param['messageBelowLimit'] )
514 && is_string( $param['messageBelowLimit'] );
515 }
516
517 /**
518 * Validate if required selector is valid.
519 *
520 * @param mixed $param The parameter.
521 */
522 private function validate_required_selector( string $dependant_param_key, $param, WP_REST_Request $request, string $key ): bool {
523
524 $use_widgets = (bool) $request->get_param( $dependant_param_key );
525 if ( ! $use_widgets ) {
526 return null === $param || is_string( $param );
527 }
528
529 return null !== $param
530 && is_string( $param )
531 && '' !== trim( $param );
532 }
533
534 /**
535 * Validate if required widget selector is valid.
536 *
537 * @param mixed $param The param.
538 */
539 public function validate_required_widget_selector( $param, WP_REST_Request $request, string $key ): bool {
540 return $this->validate_required_selector( self::PARAM_USE_WIDGETS, $param, $request, $key );
541 }
542
543 /**
544 * Validate if required cart widget selector is valid.
545 *
546 * @param mixed $param The param.
547 */
548 public function validate_required_cart_widget_selector( $param, WP_REST_Request $request, string $key ): bool {
549 return $this->validate_required_selector( self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_CART_PAGE, $param, $request, $key );
550 }
551
552 /**
553 * Validate if required listing widget selector is valid.
554 *
555 * @param mixed $param The param.
556 */
557 public function validate_required_listing_widget_selector( $param, WP_REST_Request $request, string $key ): bool {
558 return $this->validate_required_selector( self::PARAM_SHOW_INSTALLMENT_AMOUNT_IN_PRODUCT_LISTING, $param, $request, $key );
559 }
560
561 /**
562 * Validate if optional widget selector is valid.
563 *
564 * @param mixed $param The parameter.
565 * @param WP_REST_Request $request The request.
566 * @param string $key The key.
567 */
568 public function validate_optional_widget_selector( $param, $request, $key ): bool {
569 return null === $param || is_string( $param );
570 }
571
572 /**
573 * Sanitize widget label.
574 *
575 * @param mixed[] $param The parameter.
576 * @return mixed[]
577 */
578 public function sanitize_widget_labels( $param ): array {
579 return array(
580 'message' => \sanitize_text_field( strval( $param['message'] ) ),
581 'messageBelowLimit' => \sanitize_text_field( strval( $param['messageBelowLimit'] ) ),
582 );
583 }
584
585 /**
586 * Get argument structure for the widget location list.
587 *
588 * @param bool $required If the argument is required.
589 * @param mixed $default_value The default value. Null will be ignored.
590 * @param callable $validate The validate callback. Leave null to use the default.
591 * @param callable $sanitize The sanitize callback. Leave null to use the default.
592 * @return mixed[]
593 */
594 protected function get_arg_widget_location_list( $required = true, $default_value = array(), $validate = null, $sanitize = null ): array {
595 return array_merge(
596 $this->get_arg( $required, $default_value ),
597 array(
598 'validate_callback' => null === $validate ? array( $this, 'validate_widget_location_list' ) : $validate,
599 'sanitize_callback' => null === $sanitize ? array( $this, 'sanitize_widget_location_list' ) : $sanitize,
600 )
601 );
602 }
603
604 /**
605 * Validate if widget location list is valid.
606 *
607 * @param mixed $param The parameter.
608 * @param WP_REST_Request $request The request.
609 * @param string $key The key.
610 */
611 public function validate_widget_location_list( $param, $request, $key ): bool {
612 if ( ! is_array( $param ) ) {
613 return false;
614 }
615 foreach ( $param as $location ) {
616 if ( ! isset(
617 $location[ self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET ],
618 $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ],
619 $location[ self::PARAM_CUSTOM_LOCATION_COUNTRY ],
620 $location[ self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES ],
621 $location[ self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET ]
622 )
623 || ! is_string( $location[ self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET ] )
624 || ! is_string( $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] )
625 || ! is_string( $location[ self::PARAM_CUSTOM_LOCATION_COUNTRY ] )
626 || ! is_string( $location[ self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES ] )
627 || ! is_bool( $location[ self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET ] )
628 || empty( $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] )
629 || empty( $location[ self::PARAM_CUSTOM_LOCATION_COUNTRY ] )
630 ) {
631 return false;
632 }
633
634 // check if exists another location with the same country title and product.
635 $country = $location[ self::PARAM_CUSTOM_LOCATION_COUNTRY ];
636 $product = $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ];
637 $campaign = $location[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ?? null;
638 $found = \array_filter(
639 $param,
640 function ( $loc ) use ( $country, $product, $campaign ) {
641 return isset( $loc[ self::PARAM_CUSTOM_LOCATION_PRODUCT ], $loc[ self::PARAM_CUSTOM_LOCATION_COUNTRY ] )
642 && $loc[ self::PARAM_CUSTOM_LOCATION_COUNTRY ] === $country
643 && $loc[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] === $product
644 && ( $loc[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ?? null ) === $campaign;
645 }
646 );
647 if ( count( $found ) > 1 ) {
648 return false;
649 }
650 }
651 return true;
652 }
653
654 /**
655 * Sanitize widget location list.
656 *
657 * @param array<int, array<string, string>> $param The parameter.
658 * @return array<int, array<string, string>>
659 */
660 public function sanitize_widget_location_list( $param ): array {
661 foreach ( $param as &$location ) {
662 $location = array(
663 self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET => \sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_SEL_FOR_TARGET ] ) ),
664 self::PARAM_CUSTOM_LOCATION_PRODUCT => \sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_PRODUCT ] ) ),
665 self::PARAM_CUSTOM_LOCATION_COUNTRY => \sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_COUNTRY ] ) ),
666 self::PARAM_CUSTOM_LOCATION_CAMPAIGN => isset( $location[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ) ? \sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_CAMPAIGN ] ) ) : null,
667 self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES => \sanitize_text_field( strval( $location[ self::PARAM_CUSTOM_LOCATION_WIDGET_STYLES ] ) ),
668 self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET => (bool) $location[ self::PARAM_CUSTOM_LOCATION_DISPLAY_WIDGET ],
669 );
670 }
671 return $param;
672 }
673 }
674