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
← All changes | stripe/controllers/FrmStrpLiteActionsController.php +132 -32 6.25.1 → trunk View file →
@@ -14,8 +14,9 @@
14 14 * @since 6.22
15 15 *
16 16 * @param string $callback
17 17 * @param array|false|object $field
18 + *
18 19 * @return string
19 20 */
20 21 public static function maybe_show_card( $callback, $field = false ) {
21 22 if ( false === $field ) {
@@ -27,13 +28,10 @@
27 28 }
28 29
29 30 $form_id = is_object( $field ) ? $field->form_id : $field['form_id'];
30 31 $actions = self::get_actions_before_submit( $form_id );
31 - if ( empty( $actions ) ) {
32 - return $callback;
33 - }
34 32
35 - return self::class . '::show_card';
33 + return $actions ? self::class . '::show_card' : $callback;
36 34 }
37 35
38 36 /**
39 37 * Override the credit card field HTML if there is a Stripe action.
@@ -42,8 +40,9 @@
42 40 *
43 41 * @param array $field
44 42 * @param string $field_name
45 43 * @param array $atts
44 + *
46 45 * @return void
47 46 */
48 47 public static function show_card( $field, $field_name, $atts ) {
49 48 $actions = self::get_actions_before_submit( $field['form_id'] );
@@ -63,19 +62,23 @@
63 62 *
64 63 * @since 6.5, introduced in v2.0 of the Stripe add on.
65 64 *
66 65 * @param int|string $form_id
66 + *
67 67 * @return array
68 68 */
69 69 public static function get_actions_before_submit( $form_id ) {
70 70 $payment_actions = self::get_actions_for_form( $form_id );
71 +
71 72 foreach ( $payment_actions as $k => $payment_action ) {
72 73 $gateway = $payment_action->post_content['gateway'];
73 74 $is_stripe = $gateway === 'stripe' || ( is_array( $gateway ) && in_array( 'stripe', $gateway, true ) );
75 +
74 76 if ( ! $is_stripe || empty( $payment_action->post_content['amount'] ) ) {
75 77 unset( $payment_actions[ $k ] );
76 78 }
77 79 }
80 +
78 81 return $payment_actions;
79 82 }
80 83
81 84 /**
@@ -85,8 +88,9 @@
85 88 *
86 89 * @since 6.5, introduced in v3.0 of the Stripe add on.
87 90 *
88 91 * @param int|string $form_id
92 + *
89 93 * @return false|WP_Post
90 94 */
91 95 public static function get_stripe_link_action( $form_id ) {
92 96 $actions = self::get_actions_before_submit( $form_id );
@@ -100,8 +104,9 @@
100 104 *
101 105 * @param WP_Post $action
102 106 * @param stdClass $entry
103 107 * @param mixed $form
108 + *
104 109 * @return array
105 110 */
106 111 public static function trigger_gateway( $action, $entry, $form ) {
107 112 $response = array(
@@ -109,21 +114,23 @@
109 114 'run_triggers' => false,
110 115 'show_errors' => true,
111 116 );
112 117 $atts = compact( 'action', 'entry', 'form' );
118 + $amount = self::prepare_amount( $action->post_content['amount'], $atts );
113 119
114 - $amount = self::prepare_amount( $action->post_content['amount'], $atts );
115 - if ( empty( $amount ) || $amount == 000 ) {
120 + // phpcs:ignore Universal.Operators.StrictComparisons
121 + if ( ! $amount || $amount == 000 ) {
116 122 $response['error'] = __( 'Please specify an amount for the payment', 'formidable' );
117 123 return $response;
118 124 }
119 125
120 126 if ( ! self::stripe_is_configured() ) {
121 - $response['error'] = __( 'There was a problem communicating with Stripe. Please try again.', 'formidable' );
127 + $response['error'] = __( 'Stripe still needs to be configured.', 'formidable' );
122 128 return $response;
123 129 }
124 130
125 - $customer = self::set_customer_with_token( $atts );
131 + $customer = self::set_customer_with_token( $atts, self::get_customer_id_from_posted_setup_intents( $form->id ) );
132 +
126 133 if ( ! is_object( $customer ) ) {
127 134 $response['error'] = $customer;
128 135 return $response;
129 136 }
@@ -129,9 +136,13 @@
129 136 }
130 137
131 138 $one_time_payment_args = compact( 'customer', 'form', 'entry', 'action', 'amount' );
132 139
133 - FrmStrpLiteLinkController::create_pending_stripe_link_payment( $one_time_payment_args );
140 + if ( ! FrmStrpLiteLinkController::create_pending_stripe_link_payment( $one_time_payment_args ) ) {
141 + $response['error'] = __( 'There was something wrong with the payment data.', 'formidable' );
142 + return $response;
143 + }
144 +
134 145 $response['show_errors'] = false;
135 146 return $response;
136 147 }
137 148
@@ -144,14 +155,56 @@
144 155 return FrmStrpLiteAppHelper::call_stripe_helper_class( 'initialize_api' );
145 156 }
146 157
147 158 /**
159 + * Get the customer id from a setup intent that was created for this submission.
160 + * A Stripe Link subscription builds its subscription from the setup intent's customer,
161 + * so reusing that customer here avoids creating a duplicate customer for guests.
162 + *
163 + * @since 6.35
164 + *
165 + * @param int|string $form_id
166 + *
167 + * @return false|string The Stripe customer id, or false if it can't be found.
168 + */
169 + public static function get_customer_id_from_posted_setup_intents( $form_id ) {
170 + $posted_intents = FrmStrpLiteAuth::get_payment_intents( 'frmintent' . $form_id );
171 +
172 + if ( ! is_array( $posted_intents ) || ! $posted_intents ) {
173 + return false;
174 + }
175 +
176 + $setup_intent_ids = array_filter(
177 + $posted_intents,
178 + function ( $intent_id ) {
179 + return str_starts_with( $intent_id, 'seti_' );
180 + }
181 + );
182 +
183 + if ( ! $setup_intent_ids ) {
184 + return false;
185 + }
186 +
187 + $first_setup_intent_id = reset( $setup_intent_ids );
188 + $first_setup_intent_id = explode( '_secret_', $first_setup_intent_id )[0];
189 + $setup_intent = FrmStrpLiteAppHelper::call_stripe_helper_class( 'get_setup_intent', $first_setup_intent_id );
190 +
191 + if ( ! is_object( $setup_intent ) || empty( $setup_intent->customer ) ) {
192 + return false;
193 + }
194 +
195 + return $setup_intent->customer;
196 + }
197 +
198 + /**
148 199 * Set a customer object to $_POST['customer'] to use later.
149 200 *
150 - * @param array $atts
201 + * @param array $atts The action, entry, and form for the payment.
202 + * @param false|string $customer_id The Stripe customer id when it is already known.
203 + *
151 204 * @return object|string
152 205 */
153 - private static function set_customer_with_token( $atts ) {
206 + private static function set_customer_with_token( $atts, $customer_id = false ) {
154 207 if ( isset( self::$customer ) ) {
155 208 // It's an object if this isn't the first Stripe action running.
156 209 return self::$customer;
157 210 }
@@ -159,8 +212,12 @@
159 212 $payment_info = array(
160 213 'user_id' => FrmTransLiteAppHelper::get_user_id_for_current_payment(),
161 214 );
162 215
216 + if ( $customer_id ) {
217 + $payment_info['customer_id'] = $customer_id;
218 + }
219 +
163 220 if ( ! empty( $atts['action']->post_content['email'] ) ) {
164 221 $payment_info['email'] = apply_filters( 'frm_content', $atts['action']->post_content['email'], $atts['form'], $atts['entry'] );
165 222 $payment_info['email'] = self::replace_email_shortcode( $payment_info['email'] );
166 223 }
@@ -177,12 +234,13 @@
177 234 /**
178 235 * Replace an [email] shortcode with the current user email.
179 236 *
180 237 * @param string $email
238 + *
181 239 * @return string
182 240 */
183 241 private static function replace_email_shortcode( $email ) {
184 - if ( false === strpos( $email, '[email]' ) ) {
242 + if ( ! str_contains( $email, '[email]' ) ) {
185 243 return $email;
186 244 }
187 245
188 246 global $current_user;
@@ -199,8 +257,9 @@
199 257 * @since 6.5, introduced in v2.02 of the Stripe add on.
200 258 *
201 259 * @param array $atts
202 260 * @param array $payment_info
261 + *
203 262 * @return void
204 263 */
205 264 private static function add_customer_name( $atts, &$payment_info ) {
206 265 if ( empty( $atts['action']->post_content['billing_first_name'] ) ) {
@@ -207,8 +266,9 @@
207 266 return;
208 267 }
209 268
210 269 $name = '[' . $atts['action']->post_content['billing_first_name'] . ' show="first"]';
270 +
211 271 if ( ! empty( $atts['action']->post_content['billing_last_name'] ) ) {
212 272 $name .= ' [' . $atts['action']->post_content['billing_last_name'] . ' show="last"]';
213 273 }
214 274
@@ -220,17 +280,20 @@
220 280 *
221 281 * @since 6.5, introduced in v1.16 of the Stripe add on.
222 282 *
223 283 * @param array $atts Includes 'customer', 'entry', 'action', 'amount'.
284 + *
224 285 * @return int The timestamp when the trial should end. 0 for no trial
225 286 */
226 287 public static function get_trial_end_time( $atts ) {
227 288 $settings = $atts['action']->post_content;
289 +
228 290 if ( empty( $settings['trial_interval_count'] ) ) {
229 291 return 0;
230 292 }
231 293
232 294 $trial = $settings['trial_interval_count'];
295 +
233 296 if ( ! is_numeric( $trial ) ) {
234 297 $trial = FrmTransLiteAppHelper::process_shortcodes(
235 298 array(
236 299 'value' => $trial,
@@ -250,8 +313,9 @@
250 313 * Convert the amount from 10.00 to 1000.
251 314 *
252 315 * @param mixed $amount
253 316 * @param array $atts
317 + *
254 318 * @return string
255 319 */
256 320 public static function prepare_amount( $amount, $atts = array() ) {
257 321 $amount = parent::prepare_amount( $amount, $atts );
@@ -262,14 +326,21 @@
262 326 /**
263 327 * Add defaults for additional Stripe action options.
264 328 *
265 329 * @param array $defaults
330 + *
266 331 * @return array
267 332 */
268 333 public static function add_action_defaults( $defaults ) {
334 + // Stripe action options.
269 335 $defaults['plan_id'] = '';
270 336 $defaults['capture'] = '';
271 337 $defaults['stripe_link'] = '';
338 +
339 + // PayPal action options.
340 + $defaults['product_name'] = '';
341 + $defaults['pay_later'] = '';
342 +
272 343 return $defaults;
273 344 }
274 345
275 346 /**
@@ -275,8 +346,9 @@
275 346 /**
276 347 * Print additional options for Stripe action settings.
277 348 *
278 349 * @param array $atts
350 + *
279 351 * @return void
280 352 */
281 353 public static function add_action_options( $atts ) {
282 354 $form_action = $atts['form_action'];
@@ -288,8 +360,9 @@
288 360 * Filter Stripe action on save.
289 361 *
290 362 * @param array $settings
291 363 * @param array $action
364 + *
292 365 * @return array
293 366 */
294 367 public static function before_save_settings( $settings, $action ) {
295 368 $settings['currency'] = strtolower( $settings['currency'] );
@@ -294,12 +367,13 @@
294 367 public static function before_save_settings( $settings, $action ) {
295 368 $settings['currency'] = strtolower( $settings['currency'] );
296 369
297 370 // Gateway is a radio button but it should always be an array in the database for
298 - // compatibility with the payments submodule where it is a checkbox.
299 - $settings['gateway'] = ! empty( $settings['gateway'] ) ? (array) $settings['gateway'] : array( 'stripe' );
371 + // compatibility with the payments submodule where it is a checkbox (when Authorize.Net is active).
372 + $settings['gateway'] = ! empty( $settings['gateway'] ) ? (array) $settings['gateway'] : array( 'stripe' );
300 373
301 374 $is_stripe = in_array( 'stripe', $settings['gateway'], true );
375 +
302 376 if ( ! $is_stripe ) {
303 377 return $settings;
304 378 }
305 379
@@ -304,11 +378,10 @@
304 378 }
305 379
306 380 // In Lite Stripe link is always used.
307 381 $settings['stripe_link'] = 1;
308 - $settings = self::create_plans( $settings );
309 382
310 - return $settings;
383 + return self::create_plans( $settings );
311 384 }
312 385
313 386 /**
314 387 * Create any required Stripe plans, used for subscriptions.
@@ -313,8 +386,9 @@
313 386 /**
314 387 * Create any required Stripe plans, used for subscriptions.
315 388 *
316 389 * @param array $settings
390 + *
317 391 * @return array
318 392 */
319 393 public static function create_plans( $settings ) {
320 394 if ( $settings['type'] !== 'recurring' || strpos( $settings['amount'], ']' ) ) {
@@ -323,8 +397,10 @@
323 397 return $settings;
324 398 }
325 399
326 400 $plan_opts = FrmStrpLiteSubscriptionHelper::prepare_plan_options( $settings );
401 +
402 + // phpcs:ignore Universal.Operators.StrictComparisons
327 403 if ( $plan_opts['id'] != $settings['plan_id'] ) {
328 404 $settings['plan_id'] = FrmStrpLiteSubscriptionHelper::maybe_create_plan( $plan_opts );
329 405 }
330 406
@@ -334,14 +410,26 @@
334 410 /**
335 411 * Include settings in the plan description in order to make sure the correct plan is used.
336 412 *
337 413 * @param array $settings
414 + *
338 415 * @return string
339 416 */
340 417 public static function create_plan_id( $settings ) {
341 418 $amount = self::prepare_amount( $settings['amount'], $settings );
342 - $id = sanitize_title_with_dashes( $settings['description'] ) . '_' . $amount . '_' . $settings['interval_count'] . $settings['interval'] . '_' . $settings['currency'];
343 - return $id;
419 + $parts = array(
420 + sanitize_title_with_dashes( $settings['description'] ),
421 + $amount,
422 + $settings['interval_count'] . $settings['interval'],
423 + $settings['currency'],
424 + );
425 +
426 + if ( isset( $settings['trial_interval_count'] ) && '' !== $settings['trial_interval_count'] ) {
427 + // Include the trial so two actions that differ only by trial length don't share a plan.
428 + $parts[] = $settings['trial_interval_count'];
429 + }
430 +
431 + return implode( '_', $parts );
344 432 }
345 433
346 434 /**
347 435 * If this form submits with ajax, load the scripts on the first page.
@@ -346,11 +434,13 @@
346 434 /**
347 435 * If this form submits with ajax, load the scripts on the first page.
348 436 *
349 437 * @param array $params
438 + *
350 439 * @return void
351 440 */
352 441 public static function maybe_load_scripts( $params ) {
442 + // phpcs:ignore Universal.Operators.StrictComparisons
353 443 if ( $params['form_id'] == $params['posted_form_id'] ) {
354 444 // This form has already been posted, so we aren't on the first page.
355 445 return;
356 446 }
@@ -355,8 +445,9 @@
355 445 return;
356 446 }
357 447
358 448 $form = FrmForm::getOne( $params['form_id'] );
449 +
359 450 if ( ! $form ) {
360 451 return;
361 452 }
362 453
@@ -365,8 +456,9 @@
365 456 'fi.form_id' => $form->id,
366 457 'type' => 'credit_card',
367 458 )
368 459 );
460 +
369 461 if ( ! $credit_card_field ) {
370 462 return;
371 463 }
372 464
@@ -376,8 +468,9 @@
376 468 /**
377 469 * Load front end JavaScript for a Stripe form.
378 470 *
379 471 * @param int $form_id
472 + *
380 473 * @return void
381 474 */
382 475 public static function load_scripts( $form_id ) {
383 476 if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) ) {
@@ -388,8 +481,9 @@
388 481 return;
389 482 }
390 483
391 484 $stripe_connect_is_setup = FrmStrpLiteConnectHelper::stripe_connect_is_setup();
485 +
392 486 if ( ! $stripe_connect_is_setup ) {
393 487 return;
394 488 }
395 489
@@ -419,8 +513,9 @@
419 513 if ( ! $suffix && ! is_readable( FrmStrpLiteAppHelper::plugin_path() . 'js/frmstrp.js' ) ) {
420 514 // The unminified file is not included in releases so force the minified script.
421 515 $suffix = '.min';
422 516 }
517 +
423 518 $script_url = FrmStrpLiteAppHelper::plugin_url() . 'js/frmstrp' . $suffix . '.js';
424 519 }
425 520
426 521 if ( class_exists( 'FrmProStrpLiteController' ) && ( ! $suffix || ! FrmProAppController::has_combo_js_file() ) ) {
@@ -428,15 +523,21 @@
428 523 }
429 524
430 525 $action_settings = self::prepare_settings_for_js( $form_id );
431 526 $found_gateway = false;
432 - foreach ( $action_settings as $action ) {
527 +
528 + foreach ( $action_settings as &$action ) {
433 529 $gateways = $action['gateways'];
530 +
434 531 if ( ! $gateways || in_array( 'stripe', (array) $gateways, true ) ) {
435 532 $found_gateway = true;
436 - break;
437 533 }
534 +
535 + if ( ! empty( $action['layout'] ) && ! in_array( $action['layout'], array( 'accordion', 'tabs' ), true ) ) {
536 + $action['layout'] = '';
537 + }
438 538 }
539 + unset( $action );
439 540
440 541 if ( ! $found_gateway ) {
441 542 return;
442 543 }
@@ -470,8 +571,9 @@
470 571 *
471 572 * @since 6.5, introduced in v3.0 of the Stripe add on.
472 573 *
473 574 * @param mixed $form_id
575 + *
474 576 * @return array
475 577 */
476 578 private static function get_style_settings_for_form( $form_id ) {
477 579 if ( ! $form_id ) {
@@ -478,8 +580,9 @@
478 580 return array();
479 581 }
480 582
481 583 $style = FrmStylesController::get_form_style( $form_id );
584 +
482 585 if ( ! $style ) {
483 586 return array();
484 587 }
485 588
@@ -484,8 +587,9 @@
484 587 }
485 588
486 589 $settings = FrmStylesHelper::get_settings_for_output( $style );
487 590 $disallowed = array( ';', ':', '!important' );
591 +
488 592 foreach ( $settings as $k => $s ) {
489 593 if ( is_string( $s ) ) {
490 594 $settings[ $k ] = str_replace( $disallowed, '', $s );
491 595 }
@@ -502,8 +606,9 @@
502 606 *
503 607 * @since 6.5, introduced in v3.0 of the Stripe add on.
504 608 *
505 609 * @param array $settings
610 + *
506 611 * @return array
507 612 */
508 613 private static function get_appearance_rules( $settings ) {
509 614 $rules = array(
@@ -544,10 +649,9 @@
544 649 *
545 650 * @param array $rules
546 651 * @param array $settings
547 652 */
548 - $rules = apply_filters( 'frm_stripe_appearance_rules', $rules, $settings );
549 - return $rules;
653 + return apply_filters( 'frm_stripe_appearance_rules', $rules, $settings );
550 654 }
551 655
552 656 /**
553 657 * Get the border width for Stripe elements.
@@ -554,8 +658,9 @@
554 658 *
555 659 * @since 6.21
556 660 *
557 661 * @param array $settings
662 + *
558 663 * @return string
559 664 */
560 665 private static function get_border_width( $settings ) {
561 666 if ( ! empty( $settings['field_shape_type'] ) && 'underline' === $settings['field_shape_type'] ) {
@@ -569,8 +674,9 @@
569 674 *
570 675 * @since 6.21
571 676 *
572 677 * @param array $settings
678 + *
573 679 * @return string
574 680 */
575 681 private static function get_border_radius( $settings ) {
576 682 if ( ! empty( $settings['field_shape_type'] ) ) {
@@ -588,8 +694,9 @@
588 694 /**
589 695 * Get the language to use for Stripe elements.
590 696 *
591 697 * @since 6.5, introduced in v2.0 of the Stripe add on.
698 + *
592 699 * @return string
593 700 */
594 701 private static function get_locale() {
595 702 $allowed = array( 'ar', 'da', 'de', 'en', 'es', 'fi', 'fr', 'he', 'it', 'ja', 'nl', 'no', 'pl', 'ru', 'sv', 'zh' );
@@ -607,24 +714,17 @@
607 714 *
608 715 * @param array $errors
609 716 * @param stdClass $field
610 717 * @param array $values
718 + *
611 719 * @return array
612 720 */
613 721 public static function remove_cc_validation( $errors, $field, $values ) {
614 722 $has_processed = isset( $_POST[ 'frmintent' . $field->form_id ] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
723 +
615 724 if ( ! $has_processed ) {
616 725 return $errors;
617 726 }
618 727
619 - $field_id = $field->temp_id ?? $field->id;
620 -
621 - if ( isset( $errors[ 'field' . $field_id . '-cc' ] ) ) {
622 - unset( $errors[ 'field' . $field_id . '-cc' ] );
623 - }
624 - if ( isset( $errors[ 'field' . $field_id ] ) ) {
625 - unset( $errors[ 'field' . $field_id ] );
626 - }
627 -
628 - return $errors;
728 + return FrmTransLiteActionsController::remove_cc_errors( $errors, $field );
629 729 }
630 730 }