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 / stripe / helpers / FrmStrpLiteConnectHelper.php

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

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