PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.28
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.28
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 / stripe / helpers / FrmStrpLiteConnectHelper.php

FrmStrpLiteConnectHelper.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.28, at stripe/helpers/FrmStrpLiteConnectHelper.php

966 lines 25.5 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 FrmStrpLiteConnectHelper {
7
8 /**
9 * Track the latest error when calling stripe connect.
10 *
11 * @since 6.5
12 *
13 * @var string|null
14 */
15 public static $latest_error_from_stripe_connect;
16
17 /**
18 * @return void
19 */
20 public static function check_for_stripe_connect_webhooks() {
21 if ( wp_doing_ajax() ) {
22 self::check_for_stripe_connect_ajax_actions();
23 } elseif ( self::user_landed_on_the_return_url() ) {
24 self::redirect();
25 } elseif ( self::user_landed_on_the_oauth_return_url() ) {
26 self::redirect_oauth();
27 }
28 }
29
30 /**
31 * @return void
32 */
33 private static function check_for_stripe_connect_ajax_actions() {
34 $action = FrmAppHelper::get_param( 'action', '', 'post', 'sanitize_text_field' );
35 $prefix = 'frm_stripe_connect_';
36
37 if ( ! $action || ! str_starts_with( $action, $prefix ) ) {
38 if ( 'frm_strp_connect_get_settings_button' === $action ) {
39 FrmAppHelper::permission_check( 'frm_change_settings' );
40 self::render_settings();
41 }
42
43 return;
44 }
45
46 FrmAppHelper::permission_check( 'frm_change_settings' );
47
48 $action = str_replace( $prefix, '', $action );
49 $function = 'handle_' . $action;
50
51 if ( ! is_callable( self::class . '::' . $function ) || ! check_admin_referer( 'frm_ajax', 'nonce' ) ) {
52 wp_send_json_error();
53 }
54
55 self::$function();
56 }
57
58 /**
59 * @return bool
60 */
61 private static function user_landed_on_the_return_url() {
62 return isset( $_GET['frm_stripe_connect_return'] );
63 }
64
65 /**
66 * @return bool
67 */
68 private static function user_landed_on_the_oauth_return_url() {
69 return isset( $_GET['frm_stripe_connect_return_oauth'] );
70 }
71
72 /**
73 * Handle the request to initialize with Stripe Connect
74 *
75 * @return void
76 */
77 private static function handle_initialize() {
78 $data = self::initialize();
79
80 if ( is_string( $data ) ) {
81 wp_send_json_error( $data );
82 }
83
84 if ( false === $data || empty( $data->password ) || empty( $data->account_id ) || empty( $data->connect_url ) ) {
85 wp_send_json_error();
86 }
87
88 $response_data = array(
89 'connect_url' => $data->connect_url,
90 );
91 wp_send_json_success( $response_data );
92 }
93
94 /**
95 * Initialize a Stripe Connect integration with the connect server
96 *
97 * @return object|string
98 */
99 private static function initialize() {
100 $mode = self::get_mode_value_from_post();
101
102 if ( self::get_account_id( $mode ) ) {
103 // Do not allow for initialize if there is already a configured account id.
104 return 'Cannot initialize another account';
105 }
106
107 $additional_body = array(
108 'password' => self::generate_client_password( $mode ),
109 'user_id' => get_current_user_id(),
110 'frm_strp_connect_mode' => $mode,
111 );
112 $data = self::post_to_connect_server( 'initialize', $additional_body );
113
114 if ( is_string( $data ) ) {
115 return $data;
116 }
117
118 if ( ! empty( $data->password ) ) {
119 update_option( self::get_server_side_token_option_name( $mode ), $data->password, false );
120 }
121
122 if ( ! empty( $data->account_id ) ) {
123 update_option( self::get_account_id_option_name( $mode ), $data->account_id, false );
124 }
125
126 return $data;
127 }
128
129 /**
130 * Generate a new client password for authenticating with Connect Service and save it locally as an option.
131 *
132 * @param string $mode 'live' or 'test'.
133 *
134 * @return string the client password.
135 */
136 private static function generate_client_password( $mode ) {
137 $client_password = wp_generate_password();
138 update_option( self::get_client_side_token_option_name( $mode ), $client_password, false );
139 return $client_password;
140 }
141
142 /**
143 * @param string $action
144 * @param array $additional_body
145 *
146 * @return object|string
147 */
148 private static function post_to_connect_server( $action, $additional_body = array() ) {
149 $body = array(
150 'frm_strp_connect_action' => $action,
151 'frm_strp_connect_mode' => FrmStrpLiteAppHelper::active_mode(),
152 );
153 $body = array_merge( $body, $additional_body );
154 $url = self::get_url_to_connect_server();
155 $headers = self::build_headers_for_post();
156
157 if ( ! $headers ) {
158 return 'Unable to build headers for post. Is your pro license configured properly?';
159 }
160
161 // (Seconds) default timeout is 5. we want a bit more time to work with.
162 $timeout = 45;
163
164 self::try_to_extend_server_timeout( $timeout );
165
166 $args = compact( 'body', 'headers', 'timeout' );
167 $response = wp_remote_post( $url, $args );
168
169 if ( ! self::validate_response( $response ) ) {
170 return 'Response from server is invalid';
171 }
172
173 $body = self::pull_response_body( $response );
174
175 if ( empty( $body->success ) ) {
176 if ( ! empty( $body->data ) && is_string( $body->data ) ) {
177 return $body->data;
178 }
179
180 return 'Response from server was not successful';
181 }
182
183 return $body->data ?? array();
184 }
185
186 /**
187 * Try to make sure the server time limit exceeds the request time limit.
188 *
189 * @param int $timeout seconds.
190 *
191 * @return void
192 */
193 private static function try_to_extend_server_timeout( $timeout ) {
194 if ( function_exists( 'set_time_limit' ) ) {
195 set_time_limit( $timeout + 10 );
196 }
197 }
198
199 /**
200 * @param string $mode either 'auto', 'live', or 'test'.
201 *
202 * @return string either _test or _live.
203 */
204 private static function get_active_mode_option_name_suffix( $mode = 'auto' ) {
205 if ( 'auto' !== $mode ) {
206 return '_' . $mode;
207 }
208 return '_' . FrmStrpLiteAppHelper::active_mode();
209 }
210
211 /**
212 * @param string $key 'account_id', 'client_password', 'server_password', 'details_submitted'.
213 * @param string $mode either 'auto', 'live', or 'test'.
214 *
215 * @return string
216 */
217 private static function get_strp_connect_option_name( $key, $mode = 'auto' ) {
218 return 'frm_strp_connect_' . $key . self::get_active_mode_option_name_suffix( $mode );
219 }
220
221 /**
222 * @param string $mode either 'auto', 'live', or 'test'.
223 *
224 * @return string
225 */
226 private static function get_account_id_option_name( $mode = 'auto' ) {
227 return self::get_strp_connect_option_name( 'account_id', $mode );
228 }
229
230 /**
231 * @param string $mode either 'auto', 'live', or 'test'.
232 *
233 * @return string
234 */
235 private static function get_client_side_token_option_name( $mode = 'auto' ) {
236 return self::get_strp_connect_option_name( 'client_password', $mode );
237 }
238
239 /**
240 * @param string $mode either 'auto', 'live', or 'test'.
241 *
242 * @return string
243 */
244 private static function get_server_side_token_option_name( $mode = 'auto' ) {
245 return self::get_strp_connect_option_name( 'server_password', $mode );
246 }
247
248 /**
249 * @param string $mode either 'auto', 'live', or 'test'.
250 *
251 * @return string
252 */
253 private static function get_stripe_details_submitted_option_name( $mode = 'auto' ) {
254 return self::get_strp_connect_option_name( 'details_submitted', $mode );
255 }
256
257 /**
258 * @return string
259 */
260 private static function get_url_to_connect_server() {
261 return 'https://api.strategy11.com/';
262 }
263
264 /**
265 * @return void
266 */
267 private static function handle_disconnect() {
268 self::disconnect();
269 self::reset_stripe_connect_integration();
270 self::maybe_unschedule_crons();
271 wp_send_json_success();
272 }
273
274 /**
275 * Delete every Stripe connect option, calling when disconnecting.
276 *
277 * @return void
278 */
279 public static function reset_stripe_connect_integration() {
280 $mode = self::get_mode_value_from_post();
281 delete_option( self::get_account_id_option_name( $mode ) );
282 delete_option( self::get_server_side_token_option_name( $mode ) );
283 delete_option( self::get_client_side_token_option_name( $mode ) );
284 delete_option( self::get_stripe_details_submitted_option_name( $mode ) );
285 }
286
287 /**
288 * @return false|object
289 */
290 private static function disconnect() {
291 $additional_body = array(
292 'frm_strp_connect_mode' => self::get_mode_value_from_post(),
293 );
294 return self::post_with_authenticated_body( 'disconnect', $additional_body );
295 }
296
297 /**
298 * Stop the payment cron once all Stripe connections have been disconnected.
299 *
300 * @since 6.5
301 *
302 * @return void
303 */
304 private static function maybe_unschedule_crons() {
305 if ( self::at_least_one_mode_is_setup() ) {
306 // Don't unschedule if a mode is still on.
307 return;
308 }
309
310 $event = 'frm_payment_cron';
311 $timestamp = wp_next_scheduled( $event );
312
313 if ( false !== $timestamp ) {
314 wp_unschedule_event( $timestamp, $event );
315 }
316 }
317
318 /**
319 * @since 6.5
320 *
321 * @return bool
322 */
323 public static function at_least_one_mode_is_setup() {
324 return self::stripe_connect_is_setup( 'test' ) || self::stripe_connect_is_setup( 'live' );
325 }
326
327 /**
328 * @return void
329 */
330 private static function handle_reauth() {
331 $additional_body = array(
332 'frm_strp_connect_mode' => self::get_mode_value_from_post(),
333 );
334 $data = self::post_with_authenticated_body( 'reauth', $additional_body );
335
336 if ( false === $data ) {
337 // Check account status.
338 if ( self::check_server_for_connected_account_status() ) {
339 wp_send_json_success();
340 }
341
342 wp_send_json_error();
343 }
344
345 $response_data = array(
346 'connect_url' => $data->connect_url,
347 );
348 wp_send_json_success( $response_data );
349 }
350
351 /**
352 * @return array
353 */
354 private static function get_standard_authenticated_body() {
355 $mode = self::get_mode_value_from_post();
356 return array(
357 'account_id' => get_option( self::get_account_id_option_name( $mode ) ),
358 'server_password' => get_option( self::get_server_side_token_option_name( $mode ) ),
359 'client_password' => get_option( self::get_client_side_token_option_name( $mode ) ),
360 );
361 }
362
363 private static function redirect() {
364 $connected = self::check_server_for_connected_account_status();
365 wp_safe_redirect( self::get_url_for_stripe_settings( $connected ) );
366 exit;
367 }
368
369 private static function redirect_oauth() {
370 $connected = self::check_server_for_oauth_account_id();
371 wp_safe_redirect( self::get_url_for_stripe_settings( $connected ) );
372 exit;
373 }
374
375 /**
376 * @return bool
377 */
378 private static function check_server_for_oauth_account_id() {
379 $mode = FrmAppHelper::get_param( 'mode', '', 'get', 'sanitize_text_field' );
380
381 if ( 'live' !== $mode ) {
382 $mode = 'test';
383 }
384
385 if ( self::get_account_id( $mode ) ) {
386 // Do not allow for initialize if there is already a configured account id.
387 return false;
388 }
389
390 $body = array(
391 'server_password' => get_option( self::get_server_side_token_option_name( $mode ) ),
392 'client_password' => get_option( self::get_client_side_token_option_name( $mode ) ),
393 'frm_strp_connect_mode' => $mode,
394 );
395 $data = self::post_to_connect_server( 'oauth_account_status', $body );
396
397 if ( is_object( $data ) && ! empty( $data->account_id ) ) {
398 update_option( self::get_account_id_option_name( $mode ), $data->account_id, false );
399
400 if ( ! empty( $data->details_submitted ) ) {
401 self::set_stripe_details_as_submitted( $mode );
402 }
403
404 return true;
405 }
406
407 return false;
408 }
409
410 /**
411 * On a successful account status check, set details_submitted option.
412 *
413 * @param string $mode 'live' or 'test'.
414 *
415 * @return void
416 */
417 private static function set_stripe_details_as_submitted( $mode ) {
418 update_option( self::get_stripe_details_submitted_option_name( $mode ), true, false );
419 FrmTransLiteAppController::install();
420 }
421
422 /**
423 * @return void
424 */
425 private static function handle_oauth() {
426 $response_data = array(
427 'redirect_url' => self::get_oauth_redirect_url(),
428 );
429 wp_send_json_success( $response_data );
430 }
431
432 /**
433 * @return false|string
434 */
435 private static function get_oauth_redirect_url() {
436 $mode = self::get_mode_value_from_post();
437
438 if ( self::get_account_id( $mode ) ) {
439 // Do not allow for initialize if there is already a configured account id.
440 return false;
441 }
442
443 $additional_body = array(
444 'password' => self::generate_client_password( $mode ),
445 'user_id' => get_current_user_id(),
446 'frm_strp_connect_mode' => $mode,
447 );
448
449 // Clear the transient so it doesn't fail.
450 delete_option( 'frm_stripe_lite_last_verify_attempt' );
451 $data = self::post_to_connect_server( 'oauth_request', $additional_body );
452
453 if ( is_string( $data ) ) {
454 return false;
455 }
456
457 if ( ! empty( $data->password ) ) {
458 update_option( self::get_server_side_token_option_name( $mode ), $data->password, false );
459 }
460
461 if ( ! is_object( $data ) || empty( $data->redirect_url ) ) {
462 return false;
463 }
464
465 return $data->redirect_url;
466 }
467
468 /**
469 * @return bool true if our account is onboarded
470 */
471 public static function check_server_for_connected_account_status() {
472 $mode = FrmAppHelper::get_param( 'mode', '', 'get', 'sanitize_text_field' );
473
474 if ( 'live' !== $mode ) {
475 $mode = 'test';
476 }
477
478 $additional_body = array(
479 'frm_strp_connect_mode' => $mode,
480 );
481 $data = self::post_with_authenticated_body( 'account_status', $additional_body );
482 $success = false !== $data && ! empty( $data->details_submitted );
483
484 if ( $success ) {
485 self::set_stripe_details_as_submitted( $mode );
486 }
487
488 return $success;
489 }
490
491 /**
492 * @param string $mode
493 *
494 * @return bool
495 */
496 public static function stripe_connect_is_setup( $mode = 'auto' ) {
497 return get_option( self::get_stripe_details_submitted_option_name( $mode ) );
498 }
499
500 /**
501 * @param mixed $response
502 *
503 * @return bool
504 */
505 private static function validate_response( $response ) {
506 return ! is_wp_error( $response ) && is_array( $response ) && isset( $response['http_response'] );
507 }
508
509 /**
510 * @param array $response
511 *
512 * @return object|null
513 */
514 private static function pull_response_body( $response ) {
515 $http_response = $response['http_response'];
516 $response_object = $http_response->get_response_object();
517 return json_decode( $response_object->body );
518 }
519
520 /**
521 * @return array
522 */
523 private static function build_headers_for_post() {
524 $password = self::maybe_get_pro_license();
525
526 if ( false === $password ) {
527 $password = 'lite_' . self::get_uuid();
528 }
529
530 $site_url = home_url();
531 $site_url = self::maybe_fix_wpml_url( $site_url );
532 // Remove protocol from url (our url cannot include the colon).
533 $site_url = preg_replace( '#^https?://#', '', $site_url );
534 // Remove port from url (mostly helpful in development).
535 $site_url = preg_replace( '/:[0-9]+/', '', $site_url );
536 $site_url = self::strip_lang_from_url( $site_url );
537
538 // $password is either a Pro license or a uuid (See FrmUsage::uuid).
539 return array(
540 'Authorization' => 'Basic ' . base64_encode( $site_url . ':' . $password ),
541 );
542 }
543
544 /**
545 * WPML alters the output of home_url.
546 * If it is active, use the WPML "absolute home" URL which is not modified.
547 *
548 * @param string $url
549 *
550 * @return string
551 */
552 private static function maybe_fix_wpml_url( $url ) {
553 if ( defined( 'ICL_SITEPRESS_VERSION' ) && ! ICL_PLUGIN_INACTIVE && class_exists( 'SitePress' ) ) {
554 global $wpml_url_converter;
555 $url = $wpml_url_converter->get_abs_home();
556 }
557 return $url;
558 }
559
560 /**
561 * WPML might add a language to the url. Don't send that to the server.
562 *
563 * @param string $url URL.
564 *
565 * @return string
566 */
567 private static function strip_lang_from_url( $url ) {
568 $split_on_language = explode( '/?lang=', $url );
569 return 2 === count( $split_on_language ) ? $split_on_language[0] : $url;
570 }
571
572 /**
573 * Get a Pro license when Pro is active.
574 * Otherwise we'll use a uuid to support Lite.
575 *
576 * @return false|string
577 */
578 private static function maybe_get_pro_license() {
579 if ( FrmAppHelper::pro_is_installed() ) {
580 $pro_license = FrmAddonsController::get_pro_license();
581
582 if ( $pro_license ) {
583 $password = $pro_license;
584 }
585 }
586
587 return ! empty( $password ) ? $password : false;
588 }
589
590 /**
591 * Get a unique ID to use for connecting Lite users.
592 *
593 * @return string
594 */
595 private static function get_uuid() {
596 $usage = new FrmUsage();
597 return $usage->uuid();
598 }
599
600 /**
601 * @param bool $connected
602 *
603 * @return string
604 */
605 private static function get_url_for_stripe_settings( $connected ) {
606 return admin_url( 'admin.php?page=formidable-settings&t=stripe_settings&connected=' . intval( $connected ) );
607 }
608
609 /**
610 * @return void
611 */
612 public static function render_stripe_connect_settings_container() {
613 self::register_settings_scripts();
614 // phpcs:disable Generic.WhiteSpace.ScopeIndent
615 ?>
616 <tr>
617 <td>
618 <?php esc_html_e( 'Connection Status', 'formidable' ); ?>
619 </td>
620 <td>
621 <div id="frm_strp_settings_container"></div>
622 </td>
623 </tr>
624 <?php
625 // phpcs:enable Generic.WhiteSpace.ScopeIndent
626 }
627
628 /**
629 * @return void
630 */
631 private static function render_settings() {
632 $modes = array( 'test', 'live' );
633 $html = '';
634
635 foreach ( $modes as $mode ) {
636 $account_id = self::get_account_id( $mode );
637 $connected = self::stripe_connect_is_setup( $mode );
638 $test = 'test' === $mode;
639 $title = $test ? __( 'TEST', 'formidable' ) : __( 'LIVE', 'formidable' );
640
641 ob_start();
642 require FrmStrpLiteAppHelper::plugin_path() . '/views/settings/connect.php';
643 $html .= ob_get_clean();
644 }
645
646 $response_data = array(
647 'html' => $html,
648 );
649 wp_send_json_success( $response_data );
650 }
651
652 /**
653 * @return void
654 */
655 public static function stripe_icon() {
656 // phpcs:disable Generic.WhiteSpace.ScopeIndent
657 ?>
658 <svg height="16" aria-hidden="true" style="vertical-align:text-bottom" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M155.3 154.6c0-22.3 18.6-30.9 48.4-30.9a320 320 0 01141.9 36.7V26.1A376.2 376.2 0 00203.8 0C88.1 0 11 60.4 11 161.4c0 157.9 216.8 132.3 216.8 200.4 0 26.4-22.9 34.9-54.7 34.9-47.2 0-108.2-19.5-156.1-45.5v128.5a396 396 0 00156 32.4c118.6 0 200.3-51 200.3-153.6 0-170.2-218-139.7-218-203.9z"/></svg><?php // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong ?>
659 <?php
660 // phpcs:enable Generic.WhiteSpace.ScopeIndent
661 }
662
663 /**
664 * Check $_POST for live or test mode value as it can be updated in real time from Stripe Settings and can be configured before the update is saved.
665 *
666 * @return string 'test' or 'live'
667 */
668 private static function get_mode_value_from_post() {
669 // phpcs:ignore WordPress.Security.NonceVerification.Missing
670 if ( empty( $_POST ) || ! array_key_exists( 'testMode', $_POST ) ) {
671 return FrmStrpLiteAppHelper::active_mode();
672 }
673
674 $test_mode = FrmAppHelper::get_param( 'testMode', '', 'post', 'absint' );
675 return $test_mode ? 'test' : 'live';
676 }
677
678 /**
679 * @return void
680 */
681 private static function register_settings_scripts() {
682 wp_register_script( 'formidable_stripe_settings', FrmStrpLiteAppHelper::plugin_url() . '/js/connect_settings.js', array( 'formidable_dom' ), FrmAppHelper::plugin_version(), true ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
683 wp_enqueue_script( 'formidable_stripe_settings' );
684 }
685
686 /**
687 * @param string $mode
688 *
689 * @return bool|string
690 */
691 public static function get_account_id( $mode = 'auto' ) {
692 return get_option( self::get_account_id_option_name( $mode ) );
693 }
694
695 /**
696 * @param array $options
697 *
698 * @return false|string
699 */
700 public static function get_customer_id( $options ) {
701 $data = self::post_with_authenticated_body( 'get_customer', compact( 'options' ) );
702 $success = false !== $data;
703
704 if ( ! $success ) {
705 return ! empty( self::$latest_error_from_stripe_connect ) ? self::$latest_error_from_stripe_connect : false;
706 }
707
708 return ! empty( $data->customer_id ) ? $data->customer_id : false;
709 }
710
711 /**
712 * @param string $customer_id
713 *
714 * @return bool
715 */
716 public static function validate_customer( $customer_id ) {
717 $data = self::post_with_authenticated_body( 'validate_customer', compact( 'customer_id' ) );
718 return is_object( $data ) && ! empty( $data->valid );
719 }
720
721 /**
722 * @param string $action
723 * @param array $additional_body
724 *
725 * @return false|object
726 */
727 private static function post_with_authenticated_body( $action, $additional_body = array() ) {
728 $body = array_merge( self::get_standard_authenticated_body(), $additional_body );
729 $response = self::post_to_connect_server( $action, $body );
730
731 if ( is_object( $response ) ) {
732 return $response;
733 }
734
735 if ( is_array( $response ) ) {
736 // Reformat empty arrays as empty objects
737 // If the response is an array, it's because it's empty. Everything with data is already an object.
738 return new stdClass();
739 }
740
741 if ( is_string( $response ) ) {
742 self::$latest_error_from_stripe_connect = $response;
743 FrmTransLiteLog::log_message( 'Stripe Connect Error', $response );
744 } else {
745 self::$latest_error_from_stripe_connect = '';
746 }
747
748 return false;
749 }
750
751 /**
752 * @param array $new_charge
753 *
754 * @return mixed
755 */
756 public static function create_intent( $new_charge ) {
757 $data = self::post_with_authenticated_body( 'create_intent', compact( 'new_charge' ) );
758 $success = false !== $data;
759
760 return $success ? $data : false;
761 }
762
763 /**
764 * @param string $payment_id
765 *
766 * @return bool
767 */
768 public static function refund_payment( $payment_id ) {
769 $data = self::post_with_authenticated_body( 'refund_payment', compact( 'payment_id' ) );
770 return is_object( $data );
771 }
772
773 /**
774 * @param array $new_charge
775 *
776 * @return mixed
777 */
778 public static function create_subscription( $new_charge ) {
779 $data = self::post_with_authenticated_body( 'create_subscription', compact( 'new_charge' ) );
780
781 if ( is_object( $data ) ) {
782 return $data;
783 }
784
785 if ( isset( self::$latest_error_from_stripe_connect ) && str_starts_with( self::$latest_error_from_stripe_connect, 'No such plan: ' ) ) {
786 return self::$latest_error_from_stripe_connect;
787 }
788
789 return false;
790 }
791
792 /**
793 * @param string $sub_id
794 * @param false|string $customer_id if specified, this will enforce a customer id match (bypassed for users with administrator permission).
795 *
796 * @return bool
797 */
798 public static function cancel_subscription( $sub_id, $customer_id = false ) {
799 $cancel_at_period_end = FrmStrpLiteSubscriptionHelper::should_cancel_at_period_end();
800 $data = self::post_with_authenticated_body( 'cancel_subscription', compact( 'sub_id', 'customer_id', 'cancel_at_period_end' ) );
801 return false !== $data;
802 }
803
804 /**
805 * @param string $payment_id
806 *
807 * @return mixed
808 */
809 public static function get_intent( $payment_id ) {
810 return self::post_with_authenticated_body( 'get_intent', compact( 'payment_id' ) );
811 }
812
813 /**
814 * @return false|object
815 */
816 public static function get_customer_subscriptions() {
817 $user_id = get_current_user_id();
818 $meta_name = FrmStrpLiteAppHelper::get_customer_id_meta_name();
819 $customer_id = get_user_meta( $user_id, $meta_name, true );
820 $data = self::post_with_authenticated_body( 'get_customer_subscriptions', compact( 'customer_id' ) );
821
822 return false === $data ? false : $data->subscriptions;
823 }
824
825 /**
826 * @param string $event_id
827 *
828 * @return false|object
829 */
830 public static function get_event( $event_id ) {
831 $event = wp_cache_get( $event_id, 'frm_strp' );
832
833 if ( is_object( $event ) ) {
834 return $event;
835 }
836
837 $event = self::post_with_authenticated_body( 'get_event', compact( 'event_id' ) );
838
839 if ( false === $event || empty( $event->event ) ) {
840 return false;
841 }
842
843 wp_cache_set( $event_id, $event->event, 'frm_strp' );
844 return $event->event;
845 }
846
847 /**
848 * @param string $event_id
849 *
850 * @return mixed
851 */
852 public static function process_event( $event_id ) {
853 return self::post_with_authenticated_body( 'process_event', compact( 'event_id' ) );
854 }
855
856 /**
857 * @param array $plan
858 *
859 * @return false|string
860 */
861 public static function maybe_create_plan( $plan ) {
862 $data = self::post_with_authenticated_body( 'maybe_create_plan', compact( 'plan' ) );
863
864 if ( false === $data || empty( $data->plan_id ) ) {
865 return false;
866 }
867
868 return $data->plan_id;
869 }
870
871 /**
872 * @param array $plan
873 *
874 * @return mixed
875 */
876 public static function create_plan( $plan ) {
877 return self::post_with_authenticated_body( 'create_plan', compact( 'plan' ) );
878 }
879
880 /**
881 * @param string $intent_id
882 * @param array $data
883 *
884 * @return bool
885 */
886 public static function update_intent( $intent_id, $data ) {
887 $data = self::post_with_authenticated_body( 'update_intent', compact( 'intent_id', 'data' ) );
888 return false !== $data;
889 }
890
891 /**
892 * @return array
893 */
894 public static function get_unprocessed_event_ids() {
895 $data = self::post_with_authenticated_body( 'get_unprocessed_event_ids' );
896
897 if ( false === $data || empty( $data->event_ids ) ) {
898 return array();
899 }
900
901 return $data->event_ids;
902 }
903
904 /**
905 * Create a setup intent for a Stripe link recurring payment.
906 * This is called when a form is loaded.
907 *
908 * @since 6.5, introduced in v3.0 of the Stripe add on.
909 *
910 * @param string $customer_id
911 * @param array|false $payment_method_types
912 *
913 * @return false|object|string
914 */
915 public static function create_setup_intent( $customer_id, $payment_method_types = false ) {
916 $charge_data = array( 'customer' => $customer_id );
917
918 if ( $payment_method_types ) {
919 $charge_data['payment_method_types'] = $payment_method_types;
920 } elseif ( false === $payment_method_types ) {
921 $charge_data['payment_method_types'] = array( 'card', 'link' );
922 } else {
923 $charge_data['automatic_payment_methods'] = array( 'enabled' => true );
924 }
925
926 return self::post_with_authenticated_body( 'create_setup_intent', compact( 'charge_data' ) );
927 }
928
929 /**
930 * Get a setup intent (used for Stripe link recurring payments).
931 *
932 * @since 6.5, introduced in v3.0 of the Stripe add on.
933 *
934 * @param string $setup_id
935 *
936 * @return false|object|string
937 */
938 public static function get_setup_intent( $setup_id ) {
939 return self::post_with_authenticated_body( 'get_setup_intent', compact( 'setup_id' ) );
940 }
941
942 /**
943 * Verify a site identifier is a match.
944 */
945 public static function verify() {
946 $option_name = 'frm_stripe_lite_last_verify_attempt';
947 $last_request = get_option( $option_name );
948
949 if ( $last_request && $last_request > strtotime( '-1 day' ) ) {
950 wp_send_json_error( 'Too many requests' );
951 }
952
953 $site_identifier = FrmAppHelper::get_post_param( 'site_identifier' );
954 $usage = new FrmUsage();
955 $uuid = $usage->uuid();
956
957 update_option( $option_name, time() );
958
959 if ( $site_identifier === $uuid ) {
960 wp_send_json_success();
961 }
962
963 wp_send_json_error();
964 }
965 }
966