PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / square / helpers / FrmSquareLiteConnectHelper.php

FrmSquareLiteConnectHelper.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More trunk, at square/helpers/FrmSquareLiteConnectHelper.php

834 lines 22.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 class FrmSquareLiteConnectHelper {
7
8 /**
9 * Track the latest error when calling the Square API.
10 *
11 * @since 6.22
12 *
13 * @var string|null
14 */
15 public static $latest_error_from_square_api;
16
17 /**
18 * @return void
19 */
20 public static function render_settings_container() {
21 $settings = FrmSquareLiteAppHelper::get_settings();
22
23 self::register_settings_scripts();
24
25 FrmSquareLiteAppHelper::fee_education( 'square-global-settings-tip' );
26
27 // phpcs:disable Generic.WhiteSpace.ScopeIndent
28 ?>
29 <table class="form-table" style="width: 400px;">
30 <tr class="form-field">
31 <td>
32 <?php esc_html_e( 'Test Mode', 'formidable' ); ?>
33 </td>
34 <td>
35 <label>
36 <input type="checkbox" name="frm_square_test_mode" id="frm_square_test_mode" value="1" <?php checked( $settings->settings->test_mode, 1 ); ?> />
37 <?php esc_html_e( 'Use the Square test mode', 'formidable' ); ?>
38 </label>
39 </td>
40 </tr>
41 </table>
42
43 <div>
44 <div class="frm_grid_container">
45 <?php
46
47 $modes = array( 'live', 'test' );
48
49 foreach ( $modes as $mode ) {
50 self::render_settings_for_mode( $mode );
51 }
52 ?>
53 </div>
54 </div>
55 <?php if ( ! is_ssl() ) { ?>
56 <div>
57 <em>
58 <?php esc_html_e( 'Your site is not using SSL. Before using Square to collect payments, you will need to install an SSL certificate on your site.', 'formidable' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong ?>
59 </em>
60 </div>
61 <?php } ?>
62 <?php
63 // phpcs:enable Generic.WhiteSpace.ScopeIndent
64 }
65
66 /**
67 * @param string $mode
68 *
69 * @return void
70 */
71 private static function render_settings_for_mode( $mode ) {
72 // phpcs:disable Generic.WhiteSpace.ScopeIndent
73 ?>
74 <div class="frm-card-item frm4">
75 <div class="frm-flex-col" style="width: 100%;">
76 <div>
77 <span style="font-size: var(--text-lg); font-weight: 500; margin-right: 5px;">
78 <?php
79 echo $mode === 'test' ? esc_html__( 'Test', 'formidable' ) : esc_html__( 'Live', 'formidable' );
80 ?>
81 </span>
82 <?php
83
84 $connected = (bool) self::get_merchant_id( $mode );
85 $tag_classes = $connected ? 'frm-lt-green-tag' : 'frm-grey-tag';
86 ?>
87 <div class="frm-meta-tag <?php echo esc_attr( $tag_classes ); ?>" style="font-size: var(--text-sm); font-weight: 600;">
88 <?php
89 if ( $connected ) {
90 FrmAppHelper::icon_by_class( 'frmfont frm_checkmark_icon', array( 'style' => 'width: 10px; position: relative; top: 2px; margin-right: 5px;' ) );
91 echo 'Connected';
92 } else {
93 echo 'Not configured';
94 }
95 ?>
96 </div>
97 </div>
98 <div style="margin-top: 5px; flex: 1;">
99 <?php
100 if ( 'live' === $mode ) {
101 esc_html_e( 'Live version to process real customer transactions', 'formidable' );
102 } else {
103 esc_html_e( 'Simulate payments and ensure everything works smoothly before going live.', 'formidable' );
104 }
105 ?>
106 </div>
107 <div class="frm-card-bottom">
108 <?php if ( $connected ) { ?>
109 <a id="frm_disconnect_square_<?php echo esc_attr( $mode ); ?>" class="button-secondary frm-button-secondary" href="#">
110 <?php esc_html_e( 'Disconnect', 'formidable' ); ?>
111 </a>
112 <?php } else { ?>
113 <a class="frm-connect-square-with-oauth button-secondary frm-button-secondary" data-mode="<?php echo esc_attr( $mode ); ?>" href="#">
114 <?php esc_html_e( 'Connect', 'formidable' ); ?>
115 </a>
116 <?php } ?>
117 </div>
118 </div>
119 </div>
120 <?php
121 // phpcs:enable Generic.WhiteSpace.ScopeIndent
122 }
123
124 /**
125 * @return void
126 */
127 private static function register_settings_scripts() {
128 $script_url = FrmSquareLiteAppHelper::plugin_url() . '/js/settings.js';
129 $dependencies = array( 'formidable_dom' );
130 wp_register_script( 'formidable_square_settings', $script_url, $dependencies, FrmAppHelper::plugin_version(), true );
131 wp_enqueue_script( 'formidable_square_settings' );
132 }
133
134 /**
135 * @return false|string
136 */
137 public static function get_oauth_redirect_url() {
138 $mode = self::get_mode_value_from_post();
139
140 if ( self::get_merchant_id( $mode ) ) {
141 // Do not allow for initialize if there is already a configured account id.
142 return false;
143 }
144
145 $additional_body = array(
146 'password' => self::generate_client_password( $mode ),
147 'user_id' => get_current_user_id(),
148 'frm_square_api_mode' => $mode,
149 );
150
151 // Clear the transient so it doesn't fail.
152 delete_option( 'frm_square_lite_last_verify_attempt' );
153 $data = self::post_to_connect_server( 'oauth_request', $additional_body );
154
155 if ( is_string( $data ) ) {
156 return false;
157 }
158
159 if ( ! empty( $data->password ) ) {
160 update_option( self::get_server_side_token_option_name( $mode ), $data->password, false );
161 }
162
163 if ( ! is_object( $data ) || empty( $data->redirect_url ) ) {
164 return false;
165 }
166
167 return $data->redirect_url;
168 }
169
170 /**
171 * @param string $action
172 * @param array $additional_body
173 *
174 * @return object|string
175 */
176 private static function post_to_connect_server( $action, $additional_body = array() ) {
177 $body = array(
178 'frm_square_api_action' => $action,
179 'frm_square_api_mode' => FrmSquareLiteAppHelper::active_mode(),
180 );
181 $body = array_merge( $body, $additional_body );
182 $url = self::get_url_to_connect_server();
183 $headers = self::build_headers_for_post();
184
185 // (Seconds) default timeout is 5. we want a bit more time to work with.
186 $timeout = 45;
187
188 self::try_to_extend_server_timeout( $timeout );
189
190 $args = compact( 'body', 'headers', 'timeout' );
191 $response = wp_remote_post( $url, $args );
192
193 if ( ! self::validate_response( $response ) ) {
194 return 'Response from server is invalid';
195 }
196
197 $body = self::pull_response_body( $response );
198
199 if ( empty( $body->success ) ) {
200 if ( ! empty( $body->data ) && is_string( $body->data ) ) {
201 return $body->data;
202 }
203
204 return 'Response from server was not successful';
205 }
206
207 return $body->data ?? array();
208 }
209
210 /**
211 * @param array $response
212 *
213 * @return mixed
214 */
215 private static function pull_response_body( $response ) {
216 $http_response = $response['http_response'];
217 $response_object = $http_response->get_response_object();
218 return json_decode( $response_object->body );
219 }
220
221 /**
222 * @param mixed $response
223 *
224 * @return bool
225 */
226 private static function validate_response( $response ) {
227 return ! is_wp_error( $response ) && is_array( $response ) && isset( $response['http_response'] );
228 }
229
230 /**
231 * @return string
232 */
233 private static function get_url_to_connect_server() {
234 return 'https://api.strategy11.com/';
235 }
236
237 /**
238 * @return array
239 */
240 private static function build_headers_for_post() {
241 $password = self::maybe_get_pro_license();
242
243 if ( false === $password ) {
244 $password = 'lite_' . self::get_uuid();
245 }
246
247 $site_url = home_url();
248 $site_url = self::maybe_fix_wpml_url( $site_url );
249 // Remove protocol from url (our url cannot include the colon).
250 $site_url = preg_replace( '#^https?://#', '', $site_url );
251 // Remove port from url (mostly helpful in development).
252 $site_url = preg_replace( '/:[0-9]+/', '', $site_url );
253 $site_url = self::strip_lang_from_url( $site_url );
254
255 // $password is either a Pro license or a uuid (See FrmUsage::uuid).
256 return array(
257 'Authorization' => 'Basic ' . base64_encode( $site_url . ':' . $password ),
258 );
259 }
260
261 /**
262 * Get a unique ID to use for connecting Lite users.
263 *
264 * @return string
265 */
266 private static function get_uuid() {
267 $usage = new FrmUsage();
268 return $usage->uuid();
269 }
270
271 /**
272 * WPML might add a language to the url. Don't send that to the server.
273 *
274 * @param string $url URL to strip language from.
275 *
276 * @return string
277 */
278 private static function strip_lang_from_url( $url ) {
279 $split_on_language = explode( '/?lang=', $url );
280 return 2 === count( $split_on_language ) ? $split_on_language[0] : $url;
281 }
282
283 /**
284 * WPML alters the output of home_url.
285 * If it is active, use the WPML "absolute home" URL which is not modified.
286 *
287 * @param string $url URL to maybe fix.
288 *
289 * @return string
290 */
291 private static function maybe_fix_wpml_url( $url ) {
292 if ( defined( 'ICL_SITEPRESS_VERSION' ) && ! ICL_PLUGIN_INACTIVE && class_exists( 'SitePress' ) ) {
293 global $wpml_url_converter;
294 $url = $wpml_url_converter->get_abs_home();
295 }
296 return $url;
297 }
298
299 /**
300 * Get a Pro license when Pro is active.
301 * Otherwise we'll use a uuid to support Lite.
302 *
303 * @return false|string
304 */
305 private static function maybe_get_pro_license() {
306 if ( FrmAppHelper::pro_is_installed() ) {
307 $pro_license = FrmAddonsController::get_pro_license();
308
309 if ( $pro_license ) {
310 $password = $pro_license;
311 }
312 }
313
314 return ! empty( $password ) ? $password : false;
315 }
316
317 /**
318 * Try to make sure the server time limit exceeds the request time limit.
319 *
320 * @param int $timeout seconds.
321 *
322 * @return void
323 */
324 private static function try_to_extend_server_timeout( $timeout ) {
325 if ( function_exists( 'set_time_limit' ) ) {
326 set_time_limit( $timeout + 10 );
327 }
328 }
329
330 /**
331 * @param string $mode either 'auto', 'live', or 'test'.
332 *
333 * @return string
334 */
335 private static function get_server_side_token_option_name( $mode = 'auto' ) {
336 return self::get_square_connect_option_name( 'server_password', $mode );
337 }
338
339 /**
340 * Generate a new client password for authenticating with Connect Service and save it locally as an option.
341 *
342 * @param string $mode 'live' or 'test'.
343 *
344 * @return string the client password.
345 */
346 private static function generate_client_password( $mode ) {
347 $client_password = wp_generate_password();
348 update_option( self::get_client_side_token_option_name( $mode ), $client_password, false );
349 return $client_password;
350 }
351
352 /**
353 * @param string $mode either 'auto', 'live', or 'test'.
354 *
355 * @return string
356 */
357 private static function get_client_side_token_option_name( $mode = 'auto' ) {
358 return self::get_square_connect_option_name( 'client_password', $mode );
359 }
360
361 /**
362 * @return string
363 */
364 private static function get_mode_value() {
365 $settings = FrmSquareLiteAppHelper::get_settings();
366 return $settings->settings->test_mode ? 'test' : 'live';
367 }
368
369 /**
370 * @param string $mode either 'auto', 'live', or 'test'.
371 *
372 * @return bool|string
373 */
374 public static function get_merchant_id( $mode = 'auto' ) {
375 if ( 'auto' === $mode ) {
376 $mode = self::get_mode_value();
377 }
378 return get_option( self::get_merchant_id_option_name( $mode ) );
379 }
380
381 /**
382 * @param string $mode either 'auto', 'live', or 'test'.
383 *
384 * @return string
385 */
386 private static function get_merchant_id_option_name( $mode = 'auto' ) {
387 return self::get_square_connect_option_name( 'merchant_id', $mode );
388 }
389
390 /**
391 * @param string $mode either 'auto', 'live', or 'test'.
392 *
393 * @return string
394 */
395 private static function get_location_id_option_name( $mode = 'auto' ) {
396 return self::get_square_connect_option_name( 'merchant_location_id', $mode );
397 }
398
399 /**
400 * @param string $mode either 'auto', 'live', or 'test'.
401 *
402 * @return string
403 */
404 private static function get_merchant_currency_option_name( $mode = 'auto' ) {
405 return self::get_square_connect_option_name( 'merchant_currency', $mode );
406 }
407
408 /**
409 * @param string $key 'merchant_id', 'client_password', 'server_password'.
410 * @param string $mode either 'auto', 'live', or 'test'.
411 *
412 * @return string
413 */
414 private static function get_square_connect_option_name( $key, $mode = 'auto' ) {
415 return 'frm_square_connect_' . $key . self::get_active_mode_option_name_suffix( $mode );
416 }
417
418 /**
419 * @param string $mode either 'auto', 'live', or 'test'.
420 *
421 * @return string either _test or _live.
422 */
423 private static function get_active_mode_option_name_suffix( $mode = 'auto' ) {
424 if ( 'auto' !== $mode ) {
425 return '_' . $mode;
426 }
427 return '_' . FrmSquareLiteAppHelper::active_mode();
428 }
429
430 public static function check_for_redirects() {
431 if ( self::user_landed_on_the_oauth_return_url() ) {
432 self::redirect_oauth();
433 }
434 }
435
436 /**
437 * @return bool
438 */
439 private static function user_landed_on_the_oauth_return_url() {
440 return isset( $_GET['frm_square_api_return_oauth'] );
441 }
442
443 private static function redirect_oauth() {
444 $connected = self::check_server_for_oauth_merchant_id();
445 wp_safe_redirect( self::get_url_for_square_settings( $connected ) );
446 exit;
447 }
448
449 /**
450 * @param bool $connected
451 *
452 * @return string
453 */
454 private static function get_url_for_square_settings( $connected ) {
455 return admin_url( 'admin.php?page=formidable-settings&t=square_settings&connected=' . intval( $connected ) );
456 }
457
458 /**
459 * @return bool
460 */
461 private static function check_server_for_oauth_merchant_id() {
462 $mode = 'test' === FrmAppHelper::simple_get( 'mode' ) ? 'test' : 'live';
463
464 if ( self::get_merchant_id( $mode ) ) {
465 // Do not allow for initialize if there is already a configured merchant id.
466 return false;
467 }
468
469 $body = array(
470 'server_password' => get_option( self::get_server_side_token_option_name( $mode ) ),
471 'client_password' => get_option( self::get_client_side_token_option_name( $mode ) ),
472 'frm_square_api_mode' => $mode,
473 );
474 $data = self::post_to_connect_server( 'oauth_merchant_status', $body );
475
476 if ( is_object( $data ) && ! empty( $data->merchant_id ) ) {
477 update_option( self::get_merchant_id_option_name( $mode ), $data->merchant_id, false );
478
479 $currency = self::get_merchant_currency( true, $mode );
480 $location_id = self::get_location_id( true, $mode );
481
482 if ( $currency ) {
483 update_option( self::get_merchant_currency_option_name( $mode ), $currency, false );
484 }
485
486 if ( $location_id ) {
487 update_option( self::get_location_id_option_name( $mode ), $location_id, false );
488 }
489
490 FrmTransLiteAppController::install();
491
492 return true;
493 }
494
495 return false;
496 }
497
498 /**
499 * @param string $amount
500 * @param string $currency
501 * @param string $square_token
502 * @param string $verification_token
503 * @param string $description
504 *
505 * @return false|object
506 */
507 public static function create_payment( $amount, $currency, $square_token, $verification_token, $description ) {
508 return self::post_with_authenticated_body(
509 'create_payment',
510 array(
511 'amount' => $amount,
512 'currency' => $currency,
513 'square_token' => $square_token,
514 'verification_token' => $verification_token,
515 'description' => $description,
516 )
517 );
518 }
519
520 /**
521 * @param string $action
522 * @param array $additional_body
523 *
524 * @return false|object
525 */
526 private static function post_with_authenticated_body( $action, $additional_body = array() ) {
527 $body = array_merge( self::get_standard_authenticated_body(), $additional_body );
528 $response = self::post_to_connect_server( $action, $body );
529
530 if ( is_object( $response ) ) {
531 return $response;
532 }
533
534 if ( is_array( $response ) ) {
535 // Reformat empty arrays as empty objects
536 // If the response is an array, it's because it's empty. Everything with data is already an object.
537 return new stdClass();
538 }
539
540 if ( is_string( $response ) ) {
541 self::$latest_error_from_square_api = $response;
542 FrmTransLiteLog::log_message( 'Square API Error', $response );
543 } else {
544 self::$latest_error_from_square_api = '';
545 }
546
547 return false;
548 }
549
550 /**
551 * @return array
552 */
553 private static function get_standard_authenticated_body() {
554 return self::get_body_for_mode( FrmSquareLiteAppHelper::active_mode() );
555 }
556
557 /**
558 * Check $_POST for live or test mode value as it can be updated in real time from Square Settings and can be configured before the update is saved.
559 * The connect request sends a 'mode' string, and the disconnect request sends a 'testMode' flag, so check for both.
560 *
561 * @return string 'test' or 'live'
562 */
563 private static function get_mode_value_from_post() {
564 // phpcs:ignore WordPress.Security.NonceVerification.Missing
565 if ( array_key_exists( 'mode', $_POST ) ) {
566 $mode = FrmAppHelper::get_post_param( 'mode', '', 'sanitize_text_field' );
567 return 'test' === $mode ? 'test' : 'live';
568 }
569
570 // phpcs:ignore WordPress.Security.NonceVerification.Missing
571 if ( array_key_exists( 'testMode', $_POST ) ) {
572 $test_mode = FrmAppHelper::get_post_param( 'testMode', '', 'absint' );
573 return $test_mode ? 'test' : 'live';
574 }
575
576 return FrmSquareLiteAppHelper::active_mode();
577 }
578
579 /**
580 * Get the standard body with account id, mode, and passwords to send to the connect server.
581 *
582 * @since 6.32.1
583 *
584 * @param string $mode 'live' or 'test'.
585 *
586 * @return array
587 */
588 private static function get_body_for_mode( $mode ) {
589 return array(
590 'merchant_id' => get_option( self::get_merchant_id_option_name( $mode ) ),
591 'server_password' => get_option( self::get_server_side_token_option_name( $mode ) ),
592 'client_password' => get_option( self::get_client_side_token_option_name( $mode ) ),
593 'frm_square_api_mode' => $mode,
594 );
595 }
596
597 /**
598 * @return string|null
599 */
600 public static function get_latest_error_from_square_api() {
601 return self::$latest_error_from_square_api;
602 }
603
604 /**
605 * @param string $receipt_id
606 *
607 * @return bool
608 */
609 public static function refund_payment( $receipt_id ) {
610 $data = self::post_with_authenticated_body( 'refund_payment', array( 'receipt_id' => $receipt_id ) );
611 return is_object( $data );
612 }
613
614 /**
615 * @param array $info
616 *
617 * @return false|object
618 */
619 public static function create_subscription( $info ) {
620 return self::post_with_authenticated_body( 'create_subscription', compact( 'info' ) );
621 }
622
623 /**
624 * @param bool $force Whether to force refreshing the location id.
625 * @param string $mode Either 'auto', 'live', or 'test'.
626 *
627 * @return false|string
628 */
629 public static function get_location_id( $force = false, $mode = 'auto' ) {
630 if ( ! $force ) {
631 $location_id = get_option( self::get_location_id_option_name( $mode ) );
632
633 if ( $location_id ) {
634 return $location_id;
635 }
636 }
637
638 $request_body = array();
639
640 if ( 'auto' !== $mode ) {
641 $request_body = self::get_body_for_mode( $mode );
642 }
643
644 $response = self::post_with_authenticated_body( 'get_location_id', $request_body );
645
646 if ( is_object( $response ) ) {
647 update_option( self::get_location_id_option_name( $mode ), $response->id, false );
648 return $response->id;
649 }
650
651 return false;
652 }
653
654 /**
655 * @return array
656 */
657 public static function get_unprocessed_event_ids() {
658 $data = self::post_with_authenticated_body( 'get_unprocessed_event_ids' );
659
660 if ( false === $data || empty( $data->event_ids ) ) {
661 return array();
662 }
663
664 return $data->event_ids;
665 }
666
667 /**
668 * @param string $event_id
669 *
670 * @return false|object
671 */
672 public static function get_event( $event_id ) {
673 $event = wp_cache_get( $event_id, 'frm_square' );
674
675 if ( is_object( $event ) ) {
676 return $event;
677 }
678
679 $event = self::post_with_authenticated_body( 'get_event', compact( 'event_id' ) );
680
681 if ( false === $event || empty( $event->event ) ) {
682 return false;
683 }
684
685 wp_cache_set( $event_id, $event->event, 'frm_square' );
686
687 return $event->event;
688 }
689
690 /**
691 * @param string $event_id
692 *
693 * @return false|object
694 */
695 public static function process_event( $event_id ) {
696 return self::post_with_authenticated_body( 'process_event', compact( 'event_id' ) );
697 }
698
699 /**
700 * @param string $payment_id
701 *
702 * @return false|object
703 */
704 public static function get_payment( $payment_id ) {
705 return self::post_with_authenticated_body( 'get_payment', compact( 'payment_id' ) );
706 }
707
708 /**
709 * @param string $payment_id
710 *
711 * @return false|object
712 */
713 public static function get_subscription_id_for_payment( $payment_id ) {
714 return self::post_with_authenticated_body( 'get_subscription_id_for_payment', compact( 'payment_id' ) );
715 }
716
717 /**
718 * @param string $subscription_id
719 *
720 * @return bool
721 */
722 public static function cancel_subscription( $subscription_id ) {
723 return false !== self::post_with_authenticated_body( 'cancel_subscription', compact( 'subscription_id' ) );
724 }
725
726 public static function handle_disconnect() {
727 self::disconnect();
728 self::reset_square_api_integration();
729 FrmTransLiteAppHelper::trigger_gateway_disconnected_hook( 'square', self::get_mode_value_from_post() );
730 wp_send_json_success();
731 }
732
733 /**
734 * @return false|object
735 */
736 private static function disconnect() {
737 $mode = self::get_mode_value_from_post();
738 $additional_body = self::get_body_for_mode( $mode );
739 return self::post_with_authenticated_body( 'disconnect', $additional_body );
740 }
741
742 /**
743 * Delete every Square API option, calling when disconnecting.
744 *
745 * @return void
746 */
747 public static function reset_square_api_integration() {
748 $mode = self::get_mode_value_from_post();
749 delete_option( self::get_merchant_id_option_name( $mode ) );
750 delete_option( self::get_server_side_token_option_name( $mode ) );
751 delete_option( self::get_client_side_token_option_name( $mode ) );
752 delete_option( self::get_merchant_currency_option_name( $mode ) );
753 delete_option( self::get_location_id_option_name( $mode ) );
754 }
755
756 /**
757 * @param bool $force
758 * @param string $mode
759 *
760 * @return false|string
761 */
762 public static function get_merchant_currency( $force = false, $mode = 'auto' ) {
763 if ( ! $force ) {
764 $currency = get_option( self::get_merchant_currency_option_name( $mode ) );
765
766 if ( $currency ) {
767 return $currency;
768 }
769 }
770
771 $request_body = array();
772
773 if ( 'auto' !== $mode ) {
774 $request_body = self::get_body_for_mode( $mode );
775 }
776
777 $response = self::post_with_authenticated_body( 'get_merchant_currency', $request_body );
778
779 if ( is_object( $response ) && ! empty( $response->currency ) ) {
780 update_option( self::get_merchant_currency_option_name( $mode ), $response->currency, false );
781 return $response->currency;
782 }
783
784 return false;
785 }
786
787 /**
788 * @since 6.22
789 *
790 * @return bool
791 */
792 public static function at_least_one_mode_is_setup() {
793 return self::get_merchant_id( 'test' ) || self::get_merchant_id( 'live' );
794 }
795
796 /**
797 * Verify a site identifier is a match.
798 */
799 public static function verify() {
800 $option_name = 'frm_square_lite_last_verify_attempt';
801 $last_request = get_option( $option_name );
802
803 if ( $last_request && $last_request > strtotime( '-1 day' ) ) {
804 wp_send_json_error( 'Too many requests' );
805 }
806
807 $site_identifier = FrmAppHelper::get_post_param( 'site_identifier' );
808 $usage = new FrmUsage();
809
810 update_option( $option_name, time() );
811
812 if ( $site_identifier === $usage->uuid() ) {
813 wp_send_json_success();
814 }
815
816 wp_send_json_error();
817 }
818
819 /**
820 * @param string $subscription_id
821 *
822 * @return false|object
823 */
824 public static function get_subscription( $subscription_id ) {
825 $response = self::post_with_authenticated_body( 'get_subscription', array( 'subscription_id' => $subscription_id ) );
826
827 if ( is_object( $response ) && is_object( $response->subscription ) ) {
828 return $response->subscription;
829 }
830
831 return false;
832 }
833 }
834