PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.34
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.34
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 / controllers / FrmStrpLiteActionsController.php

FrmStrpLiteActionsController.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.34, at stripe/controllers/FrmStrpLiteActionsController.php

674 lines 18.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 FrmStrpLiteActionsController extends FrmTransLiteActionsController {
7
8 /**
9 * @var object|string|null A memoized value for the current Stripe customer object.
10 */
11 private static $customer;
12
13 /**
14 * @since 6.22
15 *
16 * @param string $callback
17 * @param array|false|object $field
18 *
19 * @return string
20 */
21 public static function maybe_show_card( $callback, $field = false ) {
22 if ( false === $field ) {
23 // Pro isn't up to date.
24 // Fallback to Stripe Lite if we do not know the form.
25 // This way we do not display the default credit card field
26 // when Pro is not up to version 6.21.
27 return self::class . '::show_card';
28 }
29
30 $form_id = is_object( $field ) ? $field->form_id : $field['form_id'];
31 $actions = self::get_actions_before_submit( $form_id );
32
33 return $actions ? self::class . '::show_card' : $callback;
34 }
35
36 /**
37 * Override the credit card field HTML if there is a Stripe action.
38 *
39 * @since 6.5, introduced in v2.0 of the Stripe add on.
40 *
41 * @param array $field
42 * @param string $field_name
43 * @param array $atts
44 *
45 * @return void
46 */
47 public static function show_card( $field, $field_name, $atts ) {
48 $actions = self::get_actions_before_submit( $field['form_id'] );
49
50 // Use the Pro function when there are no Stripe actions.
51 // This is required for other gateways like Authorize.Net.
52 if ( ! $actions && is_callable( 'FrmProCreditCardsController::show_in_form' ) ) {
53 FrmProCreditCardsController::show_in_form( $field, $field_name, $atts );
54 }
55
56 $html_id = $atts['html_id'];
57 include FrmStrpLiteAppHelper::plugin_path() . '/views/payments/card-field.php';
58 }
59
60 /**
61 * Get all published payment actions with the Stripe gateway that have an amount set.
62 *
63 * @since 6.5, introduced in v2.0 of the Stripe add on.
64 *
65 * @param int|string $form_id
66 *
67 * @return array
68 */
69 public static function get_actions_before_submit( $form_id ) {
70 $payment_actions = self::get_actions_for_form( $form_id );
71
72 foreach ( $payment_actions as $k => $payment_action ) {
73 $gateway = $payment_action->post_content['gateway'];
74 $is_stripe = $gateway === 'stripe' || ( is_array( $gateway ) && in_array( 'stripe', $gateway, true ) );
75
76 if ( ! $is_stripe || empty( $payment_action->post_content['amount'] ) ) {
77 unset( $payment_actions[ $k ] );
78 }
79 }
80
81 return $payment_actions;
82 }
83
84 /**
85 * Check the Stripe link action for a form. There should only be one.
86 * We want to ignore $action->post_content['stripe_link'].
87 * This way any Stripe action will fall back to Stripe link when the Stripe add on is unavailable.
88 *
89 * @since 6.5, introduced in v3.0 of the Stripe add on.
90 *
91 * @param int|string $form_id
92 *
93 * @return false|WP_Post
94 */
95 public static function get_stripe_link_action( $form_id ) {
96 $actions = self::get_actions_before_submit( $form_id );
97 return reset( $actions );
98 }
99
100 /**
101 * Trigger a Stripe payment after a form is submitted.
102 * This is called for both one time and recurring payments.
103 * It is also called when Stripe link is active but the Stripe payment is triggered instead with JavaScript.
104 *
105 * @param WP_Post $action
106 * @param stdClass $entry
107 * @param mixed $form
108 *
109 * @return array
110 */
111 public static function trigger_gateway( $action, $entry, $form ) {
112 $response = array(
113 'success' => false,
114 'run_triggers' => false,
115 'show_errors' => true,
116 );
117 $atts = compact( 'action', 'entry', 'form' );
118 $amount = self::prepare_amount( $action->post_content['amount'], $atts );
119
120 // phpcs:ignore Universal.Operators.StrictComparisons
121 if ( ! $amount || $amount == 000 ) {
122 $response['error'] = __( 'Please specify an amount for the payment', 'formidable' );
123 return $response;
124 }
125
126 if ( ! self::stripe_is_configured() ) {
127 $response['error'] = __( 'Stripe still needs to be configured.', 'formidable' );
128 return $response;
129 }
130
131 $customer = self::set_customer_with_token( $atts );
132
133 if ( ! is_object( $customer ) ) {
134 $response['error'] = $customer;
135 return $response;
136 }
137
138 $one_time_payment_args = compact( 'customer', 'form', 'entry', 'action', 'amount' );
139
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
145 $response['show_errors'] = false;
146 return $response;
147 }
148
149 /**
150 * Check if either Stripe integration is enabled.
151 *
152 * @return bool true if Stripe Connect is set up.
153 */
154 private static function stripe_is_configured() {
155 return FrmStrpLiteAppHelper::call_stripe_helper_class( 'initialize_api' );
156 }
157
158 /**
159 * Set a customer object to $_POST['customer'] to use later.
160 *
161 * @param array $atts
162 *
163 * @return object|string
164 */
165 private static function set_customer_with_token( $atts ) {
166 if ( isset( self::$customer ) ) {
167 // It's an object if this isn't the first Stripe action running.
168 return self::$customer;
169 }
170
171 $payment_info = array(
172 'user_id' => FrmTransLiteAppHelper::get_user_id_for_current_payment(),
173 );
174
175 if ( ! empty( $atts['action']->post_content['email'] ) ) {
176 $payment_info['email'] = apply_filters( 'frm_content', $atts['action']->post_content['email'], $atts['form'], $atts['entry'] );
177 $payment_info['email'] = self::replace_email_shortcode( $payment_info['email'] );
178 }
179
180 self::add_customer_name( $atts, $payment_info );
181
182 $customer = FrmStrpLiteAppHelper::call_stripe_helper_class( 'get_customer', $payment_info );
183 // Set for later use.
184 self::$customer = $customer;
185
186 return $customer;
187 }
188
189 /**
190 * Replace an [email] shortcode with the current user email.
191 *
192 * @param string $email
193 *
194 * @return string
195 */
196 private static function replace_email_shortcode( $email ) {
197 if ( ! str_contains( $email, '[email]' ) ) {
198 return $email;
199 }
200
201 global $current_user;
202 return str_replace(
203 '[email]',
204 ! empty( $current_user->user_email ) ? $current_user->user_email : '',
205 $email
206 );
207 }
208
209 /**
210 * Set the customer name based on the mapped first and last name fields in the Stripe action.
211 *
212 * @since 6.5, introduced in v2.02 of the Stripe add on.
213 *
214 * @param array $atts
215 * @param array $payment_info
216 *
217 * @return void
218 */
219 private static function add_customer_name( $atts, &$payment_info ) {
220 if ( empty( $atts['action']->post_content['billing_first_name'] ) ) {
221 return;
222 }
223
224 $name = '[' . $atts['action']->post_content['billing_first_name'] . ' show="first"]';
225
226 if ( ! empty( $atts['action']->post_content['billing_last_name'] ) ) {
227 $name .= ' [' . $atts['action']->post_content['billing_last_name'] . ' show="last"]';
228 }
229
230 $payment_info['name'] = apply_filters( 'frm_content', $name, $atts['form'], $atts['entry'] );
231 }
232
233 /**
234 * Get the trial period from the settings or from the connected entry.
235 *
236 * @since 6.5, introduced in v1.16 of the Stripe add on.
237 *
238 * @param array $atts Includes 'customer', 'entry', 'action', 'amount'.
239 *
240 * @return int The timestamp when the trial should end. 0 for no trial
241 */
242 public static function get_trial_end_time( $atts ) {
243 $settings = $atts['action']->post_content;
244
245 if ( empty( $settings['trial_interval_count'] ) ) {
246 return 0;
247 }
248
249 $trial = $settings['trial_interval_count'];
250
251 if ( ! is_numeric( $trial ) ) {
252 $trial = FrmTransLiteAppHelper::process_shortcodes(
253 array(
254 'value' => $trial,
255 'entry' => $atts['entry'],
256 )
257 );
258 }
259
260 if ( ! $trial ) {
261 return 0;
262 }
263
264 return strtotime( '+' . absint( $trial ) . ' days' );
265 }
266
267 /**
268 * Convert the amount from 10.00 to 1000.
269 *
270 * @param mixed $amount
271 * @param array $atts
272 *
273 * @return string
274 */
275 public static function prepare_amount( $amount, $atts = array() ) {
276 $amount = parent::prepare_amount( $amount, $atts );
277 $currency = self::get_currency_for_action( $atts );
278 return number_format( $amount, $currency['decimals'], '', '' );
279 }
280
281 /**
282 * Add defaults for additional Stripe action options.
283 *
284 * @param array $defaults
285 *
286 * @return array
287 */
288 public static function add_action_defaults( $defaults ) {
289 // Stripe action options.
290 $defaults['plan_id'] = '';
291 $defaults['capture'] = '';
292 $defaults['stripe_link'] = '';
293
294 // PayPal action options.
295 $defaults['product_name'] = '';
296 $defaults['pay_later'] = '';
297
298 return $defaults;
299 }
300
301 /**
302 * Print additional options for Stripe action settings.
303 *
304 * @param array $atts
305 *
306 * @return void
307 */
308 public static function add_action_options( $atts ) {
309 $form_action = $atts['form_action'];
310 $action_control = $atts['action_control'];
311 include FrmStrpLiteAppHelper::plugin_path() . '/views/action-settings/options.php';
312 }
313
314 /**
315 * Filter Stripe action on save.
316 *
317 * @param array $settings
318 * @param array $action
319 *
320 * @return array
321 */
322 public static function before_save_settings( $settings, $action ) {
323 $settings['currency'] = strtolower( $settings['currency'] );
324
325 // Gateway is a radio button but it should always be an array in the database for
326 // compatibility with the payments submodule where it is a checkbox (when Authorize.Net is active).
327 $settings['gateway'] = ! empty( $settings['gateway'] ) ? (array) $settings['gateway'] : array( 'stripe' );
328
329 $is_stripe = in_array( 'stripe', $settings['gateway'], true );
330
331 if ( ! $is_stripe ) {
332 return $settings;
333 }
334
335 // In Lite Stripe link is always used.
336 $settings['stripe_link'] = 1;
337
338 return self::create_plans( $settings );
339 }
340
341 /**
342 * Create any required Stripe plans, used for subscriptions.
343 *
344 * @param array $settings
345 *
346 * @return array
347 */
348 public static function create_plans( $settings ) {
349 if ( $settings['type'] !== 'recurring' || strpos( $settings['amount'], ']' ) ) {
350 // Don't create a plan for one time payments, or for actions with shortcodes in the value.
351 $settings['plan_id'] = '';
352 return $settings;
353 }
354
355 $plan_opts = FrmStrpLiteSubscriptionHelper::prepare_plan_options( $settings );
356
357 // phpcs:ignore Universal.Operators.StrictComparisons
358 if ( $plan_opts['id'] != $settings['plan_id'] ) {
359 $settings['plan_id'] = FrmStrpLiteSubscriptionHelper::maybe_create_plan( $plan_opts );
360 }
361
362 return $settings;
363 }
364
365 /**
366 * Include settings in the plan description in order to make sure the correct plan is used.
367 *
368 * @param array $settings
369 *
370 * @return string
371 */
372 public static function create_plan_id( $settings ) {
373 $amount = self::prepare_amount( $settings['amount'], $settings );
374 return sanitize_title_with_dashes( $settings['description'] ) . '_' . $amount . '_' . $settings['interval_count'] . $settings['interval'] . '_' . $settings['currency'];
375 }
376
377 /**
378 * If this form submits with ajax, load the scripts on the first page.
379 *
380 * @param array $params
381 *
382 * @return void
383 */
384 public static function maybe_load_scripts( $params ) {
385 // phpcs:ignore Universal.Operators.StrictComparisons
386 if ( $params['form_id'] == $params['posted_form_id'] ) {
387 // This form has already been posted, so we aren't on the first page.
388 return;
389 }
390
391 $form = FrmForm::getOne( $params['form_id'] );
392
393 if ( ! $form ) {
394 return;
395 }
396
397 $credit_card_field = FrmField::getAll(
398 array(
399 'fi.form_id' => $form->id,
400 'type' => 'credit_card',
401 )
402 );
403
404 if ( ! $credit_card_field ) {
405 return;
406 }
407
408 self::load_scripts( (int) $form->id );
409 }
410
411 /**
412 * Load front end JavaScript for a Stripe form.
413 *
414 * @param int $form_id
415 *
416 * @return void
417 */
418 public static function load_scripts( $form_id ) {
419 if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) ) {
420 return;
421 }
422
423 if ( wp_script_is( 'formidable-stripe', 'enqueued' ) ) {
424 return;
425 }
426
427 $stripe_connect_is_setup = FrmStrpLiteConnectHelper::stripe_connect_is_setup();
428
429 if ( ! $stripe_connect_is_setup ) {
430 return;
431 }
432
433 if ( ! $form_id || ! is_int( $form_id ) ) {
434 _doing_it_wrong( __METHOD__, '$form_id parameter must be a non-zero integer', '6.5' );
435 return;
436 }
437
438 $settings = FrmStrpLiteAppHelper::get_settings();
439 $publishable = $settings->get_active_publishable_key();
440
441 wp_register_script(
442 'stripe',
443 'https://js.stripe.com/v3/',
444 array(),
445 '3.0',
446 false
447 );
448
449 $suffix = FrmAppHelper::js_suffix();
450 $dependencies = array( 'stripe', 'formidable' );
451
452 if ( '.min' === $suffix && is_readable( FrmAppHelper::plugin_path() . '/js/frmstrp.min.js' ) ) {
453 // Use the combined file if it is available.
454 $script_url = FrmAppHelper::plugin_url() . '/js/frmstrp.min.js';
455 } else {
456 if ( ! $suffix && ! is_readable( FrmStrpLiteAppHelper::plugin_path() . 'js/frmstrp.js' ) ) {
457 // The unminified file is not included in releases so force the minified script.
458 $suffix = '.min';
459 }
460
461 $script_url = FrmStrpLiteAppHelper::plugin_url() . 'js/frmstrp' . $suffix . '.js';
462 }
463
464 if ( class_exists( 'FrmProStrpLiteController' ) && ( ! $suffix || ! FrmProAppController::has_combo_js_file() ) ) {
465 $dependencies[] = 'formidablepro';
466 }
467
468 $action_settings = self::prepare_settings_for_js( $form_id );
469 $found_gateway = false;
470
471 foreach ( $action_settings as &$action ) {
472 $gateways = $action['gateways'];
473
474 if ( ! $gateways || in_array( 'stripe', (array) $gateways, true ) ) {
475 $found_gateway = true;
476 }
477
478 if ( ! empty( $action['layout'] ) && ! in_array( $action['layout'], array( 'accordion', 'tabs' ), true ) ) {
479 $action['layout'] = '';
480 }
481 }
482 unset( $action );
483
484 if ( ! $found_gateway ) {
485 return;
486 }
487
488 wp_enqueue_script(
489 'formidable-stripe',
490 $script_url,
491 $dependencies,
492 FrmAppHelper::plugin_version(),
493 false
494 );
495
496 $style_settings = self::get_style_settings_for_form( $form_id );
497 $stripe_vars = array(
498 'publishable_key' => $publishable,
499 'form_id' => $form_id,
500 'nonce' => wp_create_nonce( 'frm_strp_ajax' ),
501 'ajax' => esc_url_raw( FrmAppHelper::get_ajax_url() ),
502 'settings' => $action_settings,
503 'locale' => self::get_locale(),
504 'baseFontSize' => $style_settings['field_font_size'],
505 'appearanceRules' => self::get_appearance_rules( $style_settings ),
506 'account_id' => FrmStrpLiteConnectHelper::get_account_id(),
507 );
508
509 wp_localize_script( 'formidable-stripe', 'frm_stripe_vars', $stripe_vars );
510 }
511
512 /**
513 * Get and format the style settings for JavaScript to use with the get_appearance_rules function.
514 *
515 * @since 6.5, introduced in v3.0 of the Stripe add on.
516 *
517 * @param mixed $form_id
518 *
519 * @return array
520 */
521 private static function get_style_settings_for_form( $form_id ) {
522 if ( ! $form_id ) {
523 return array();
524 }
525
526 $style = FrmStylesController::get_form_style( $form_id );
527
528 if ( ! $style ) {
529 return array();
530 }
531
532 $settings = FrmStylesHelper::get_settings_for_output( $style );
533 $disallowed = array( ';', ':', '!important' );
534
535 foreach ( $settings as $k => $s ) {
536 if ( is_string( $s ) ) {
537 $settings[ $k ] = str_replace( $disallowed, '', $s );
538 }
539 }
540
541 return $settings;
542 }
543
544 /**
545 * Get the style rules for Stripe link Authentication and Payment elements.
546 * These settings get set to frm_stripe_vars.appearanceRules.
547 * They're in the format that Stripe accepts.
548 * Documentation for Appearance rules can be found at https://stripe.com/docs/elements/appearance-api?platform=web#rules
549 *
550 * @since 6.5, introduced in v3.0 of the Stripe add on.
551 *
552 * @param array $settings
553 *
554 * @return array
555 */
556 private static function get_appearance_rules( $settings ) {
557 $rules = array(
558 '.Input' => array(
559 'fontFamily' => $settings['font'],
560 'color' => $settings['text_color'],
561 'backgroundColor' => $settings['bg_color'],
562 'padding' => $settings['field_pad'],
563 'lineHeight' => 1.3,
564 'borderColor' => $settings['border_color'],
565 'borderWidth' => self::get_border_width( $settings ),
566 'borderStyle' => $settings['field_border_style'],
567 'borderRadius' => self::get_border_radius( $settings ),
568 'fontWeight' => $settings['field_weight'],
569 ),
570 '.Input::placeholder' => array(
571 'color' => $settings['text_color_disabled'],
572 ),
573 '.Input:focus' => array(
574 'backgroundColor' => $settings['bg_color_active'],
575 ),
576 '.Label' => array(
577 'color' => $settings['label_color'],
578 'fontSize' => $settings['font_size'],
579 'fontWeight' => $settings['weight'],
580 'padding' => $settings['label_padding'],
581 'marginBottom' => 0,
582 ),
583 '.Error' => array(
584 'color' => $settings['border_color_error'],
585 ),
586 );
587
588 /*
589 * Filters the appearance rules for Stripe elements.
590 *
591 * @since 6.21
592 *
593 * @param array $rules
594 * @param array $settings
595 */
596 return apply_filters( 'frm_stripe_appearance_rules', $rules, $settings );
597 }
598
599 /**
600 * Get the border width for Stripe elements.
601 *
602 * @since 6.21
603 *
604 * @param array $settings
605 *
606 * @return string
607 */
608 private static function get_border_width( $settings ) {
609 if ( ! empty( $settings['field_shape_type'] ) && 'underline' === $settings['field_shape_type'] ) {
610 return '0 0 ' . $settings['field_border_width'] . ' 0';
611 }
612 return $settings['field_border_width'];
613 }
614
615 /**
616 * Get the border radius for Stripe elements.
617 *
618 * @since 6.21
619 *
620 * @param array $settings
621 *
622 * @return string
623 */
624 private static function get_border_radius( $settings ) {
625 if ( ! empty( $settings['field_shape_type'] ) ) {
626 switch ( $settings['field_shape_type'] ) {
627 case 'underline':
628 case 'regular':
629 return '0px';
630 case 'circle':
631 return '30px';
632 }
633 }
634 return $settings['border_radius'];
635 }
636
637 /**
638 * Get the language to use for Stripe elements.
639 *
640 * @since 6.5, introduced in v2.0 of the Stripe add on.
641 *
642 * @return string
643 */
644 private static function get_locale() {
645 $allowed = array( 'ar', 'da', 'de', 'en', 'es', 'fi', 'fr', 'he', 'it', 'ja', 'nl', 'no', 'pl', 'ru', 'sv', 'zh' );
646 $current = get_locale();
647 $parts = explode( '_', $current );
648 $part = strtolower( $parts[0] );
649 return in_array( $part, $allowed, true ) ? $part : 'auto';
650 }
651
652 /**
653 * If the names are being used on the CC fields,
654 * make sure it doesn't prevent the submission if Stripe has approved.
655 *
656 * @since 6.7.1
657 *
658 * @param array $errors
659 * @param stdClass $field
660 * @param array $values
661 *
662 * @return array
663 */
664 public static function remove_cc_validation( $errors, $field, $values ) {
665 $has_processed = isset( $_POST[ 'frmintent' . $field->form_id ] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
666
667 if ( ! $has_processed ) {
668 return $errors;
669 }
670
671 return FrmTransLiteActionsController::remove_cc_errors( $errors, $field );
672 }
673 }
674