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/FrmTransLiteActionsController.php +299 -39 6.5.3 → trunk View file →
@@ -16,8 +16,9 @@
16 16 /**
17 17 * Register payment action type.
18 18 *
19 19 * @param array $actions
20 + *
20 21 * @return array
21 22 */
22 23 public static function register_actions( $actions ) {
23 24 $actions['payment'] = 'FrmTransLiteAction';
@@ -34,9 +35,9 @@
34 35 public static function actions_js() {
35 36 wp_enqueue_script(
36 37 'frmtrans_admin',
37 38 FrmTransLiteAppHelper::plugin_url() . '/js/frmtrans_admin.js',
38 - array( 'jquery' ),
39 + array( 'jquery', 'wp-hooks' ),
39 40 FrmAppHelper::plugin_version()
40 41 );
41 42 wp_localize_script(
42 43 'frmtrans_admin',
@@ -50,8 +51,9 @@
50 51 /**
51 52 * Add event types for actions so an email can trigger on a successful payment.
52 53 *
53 54 * @param array $triggers
55 + *
54 56 * @return array
55 57 */
56 58 public static function add_payment_trigger( $triggers ) {
57 59 $triggers['payment-success'] = __( 'Successful Payment', 'formidable' );
@@ -64,8 +66,9 @@
64 66 }
65 67
66 68 /**
67 69 * @param array $options
70 + *
68 71 * @return array
69 72 */
70 73 public static function add_trigger_to_action( $options ) {
71 74 $options['event'][] = 'payment-success';
@@ -80,19 +83,95 @@
80 83 /**
81 84 * @param WP_Post $action
82 85 * @param stdClass $entry
83 86 * @param mixed $form
87 + *
84 88 * @return void
85 89 */
86 90 public static function trigger_action( $action, $entry, $form ) {
87 91 self::prepare_description( $action, compact( 'entry', 'form' ) );
88 - FrmStrpLiteActionsController::trigger_gateway( $action, $entry, $form );
92 +
93 + $gateway = self::get_gateway_for_action( $action );
94 +
95 + if ( ! $gateway ) {
96 + return;
97 + }
98 +
99 + $class_name = FrmTransLiteAppHelper::get_setting_for_gateway( $gateway, 'class' );
100 +
101 + if ( ! $class_name ) {
102 + return;
103 + }
104 +
105 + $class_name = 'Frm' . $class_name . 'ActionsController';
106 + $response = $class_name::trigger_gateway( $action, $entry, $form );
107 +
108 + if ( ! $response['success'] && $response['show_errors'] ) {
109 + // The payment failed
110 + self::show_failed_message( compact( 'action', 'entry', 'form', 'response' ) );
111 + }
89 112 }
90 113
91 114 /**
115 + * @param WP_Post $action
116 + *
117 + * @return array|string
118 + */
119 + private static function get_gateway_for_action( $action ) {
120 + return $action->post_content['gateway'] ?? 'stripe';
121 + }
122 +
123 + /**
124 + * @since 6.10
125 + *
126 + * @param array $args
127 + *
128 + * @return void
129 + */
130 + private static function show_failed_message( $args ) {
131 + global $frm_vars;
132 + $frm_vars['frm_trans'] = array(
133 + 'pay_entry' => $args['entry'],
134 + 'error' => $args['response']['error'] ?? '',
135 + );
136 +
137 + add_filter( 'frm_success_filter', 'FrmTransLiteActionsController::force_message_after_create' );
138 + add_filter( 'frm_pre_display_form', 'FrmTransLiteActionsController::include_form_with_success' );
139 + add_filter( 'frm_main_feedback', 'FrmTransLiteActionsController::replace_success_message', 5 );
140 + add_filter( 'frm_setup_new_fields_vars', 'FrmTransLiteActionsController::fill_entry_from_previous', 20, 2 );
141 + }
142 +
143 + /**
144 + * @since 6.10
145 + *
146 + * @param stdClass $form
147 + *
148 + * @return stdClass
149 + */
150 + public static function include_form_with_success( $form ) {
151 + $form->options['show_form'] = 1;
152 + return $form;
153 + }
154 +
155 + /**
156 + * @return string
157 + */
158 + public static function replace_success_message() {
159 + global $frm_vars;
160 + $message = $frm_vars['frm_trans']['error'] ?? '';
161 +
162 + if ( ! $message ) {
163 + $message = __( 'There was an error processing your payment.', 'formidable' );
164 + }
165 +
166 + return '<div class="frm_error_style">' . $message . '</div>';
167 + }
168 +
169 + /**
92 170 * @param WP_Post $action
93 171 * @param stdClass $entry
94 172 * @param mixed $form
173 + *
95 174 * @return array
96 175 */
97 176 public static function trigger_gateway( $action, $entry, $form ) {
98 177 // This function must be overridden in a subclass.
@@ -113,8 +192,9 @@
113 192 /**
114 193 * @since 6.5, introduced in v1.12 of the Payments submodule.
115 194 *
116 195 * @param object $sub
196 + *
117 197 * @return void
118 198 */
119 199 public static function trigger_subscription_status_change( $sub ) {
120 200 $frm_payment = new FrmTransLitePayment();
@@ -131,14 +211,14 @@
131 211 }
132 212
133 213 /**
134 214 * @param array $atts
215 + *
135 216 * @return void
136 217 */
137 218 public static function trigger_payment_status_change( $atts ) {
138 - $action = isset( $atts['action'] ) ? $atts['action'] : $atts['payment']->action_id;
139 219 $entry_id = isset( $atts['entry'] ) ? $atts['entry']->id : $atts['payment']->item_id;
140 - $atts = array(
220 + $atts = array(
141 221 'trigger' => $atts['status'],
142 222 'entry_id' => $entry_id,
143 223 );
144 224
@@ -153,8 +233,17 @@
153 233
154 234 // Set future-cancel as trigger when applicable.
155 235 $atts['trigger'] = str_replace( '_', '-', $atts['trigger'] );
156 236
237 + /**
238 + * Trigger various hooks including frm_payment_status_complete.
239 + *
240 + * @since 6.25 This was included in the payments submodule, but not included in Lite until 6.25.
241 + *
242 + * @param array $atts
243 + */
244 + do_action( 'frm_payment_status_' . $atts['trigger'], $atts );
245 +
157 246 if ( $atts['payment'] ) {
158 247 self::trigger_actions_after_payment( $atts['payment'], $atts );
159 248 }
160 249 }
@@ -163,8 +252,9 @@
163 252 * Maybe trigger payment-success or payment-failed event after payment so actions (like emails) can run.
164 253 *
165 254 * @param object $payment
166 255 * @param array $atts
256 + *
167 257 * @return void
168 258 */
169 259 public static function trigger_actions_after_payment( $payment, $atts = array() ) {
170 260 if ( 'pending' === $payment->status ) {
@@ -171,20 +261,16 @@
171 261 // 3D Secure has a delayed payment status, so avoid sending a payment failed email for a pending payment.
172 262 return;
173 263 }
174 264
175 - $entry = FrmEntry::getOne( $payment->item_id );
265 + $entry = FrmEntry::getOne( $payment->item_id );
266 + $trigger_event = isset( $atts['trigger'] ) ? 'payment-' . $atts['trigger'] : 'payment-' . $payment->status;
267 + $allowed_triggers = array_keys( self::add_payment_trigger( array() ) );
176 268
177 - if ( isset( $atts['trigger'] ) ) {
178 - $trigger_event = 'payment-' . $atts['trigger'];
179 - } else {
180 - $trigger_event = 'payment-' . $payment->status;
269 + if ( ! in_array( $trigger_event, $allowed_triggers, true ) ) {
270 + $trigger_event = $payment->status === 'complete' ? 'payment-success' : 'payment-failed';
181 271 }
182 272
183 - $allowed_triggers = array_keys( self::add_payment_trigger( array() ) );
184 - if ( ! in_array( $trigger_event, $allowed_triggers, true ) ) {
185 - $trigger_event = ( $payment->status === 'complete' ) ? 'payment-success' : 'payment-failed';
186 - }
187 273 FrmFormActionsController::trigger_actions( $trigger_event, $entry->form_id, $entry->id );
188 274 }
189 275
190 276 /**
@@ -191,17 +277,21 @@
191 277 * Filter fields in description.
192 278 *
193 279 * @param WP_Post $action
194 280 * @param array $atts
281 + *
195 282 * @return void
196 283 */
197 284 public static function prepare_description( &$action, $atts ) {
198 285 $description = $action->post_content['description'];
199 - if ( ! empty( $description ) ) {
200 - $atts['value'] = $description;
201 - $description = FrmTransLiteAppHelper::process_shortcodes( $atts );
202 - $action->post_content['description'] = $description;
286 +
287 + if ( ! $description ) {
288 + return;
203 289 }
290 +
291 + $atts['value'] = $description;
292 + $description = FrmTransLiteAppHelper::process_shortcodes( $atts );
293 + $action->post_content['description'] = $description;
204 294 }
205 295
206 296 /**
207 297 * Convert the amount into 10.00.
@@ -207,24 +297,25 @@
207 297 * Convert the amount into 10.00.
208 298 *
209 299 * @param mixed $amount
210 300 * @param array $atts
301 + *
211 302 * @return string
212 303 */
213 304 public static function prepare_amount( $amount, $atts = array() ) {
214 305 if ( isset( $atts['form'] ) ) {
215 306 $atts['value'] = $amount;
216 - $amount = FrmTransLiteAppHelper::process_shortcodes( $atts );
307 + $amount = FrmTransLiteAppHelper::process_shortcodes( $atts );
217 308 }
218 309
219 - if ( is_string( $amount ) && strlen( $amount ) >= 2 && $amount[0] == '[' && substr( $amount, -1 ) == ']' ) {
220 - // make sure we don't use a field id as the amount
310 + if ( is_string( $amount ) && strlen( $amount ) >= 2 && $amount[0] === '[' && str_ends_with( $amount, ']' ) ) {
311 + // Make sure we don't use a field id as the amount.
221 312 $amount = 0;
222 313 }
223 314
224 315 $currency = self::get_currency_for_action( $atts );
316 + $total = 0;
225 317
226 - $total = 0;
227 318 foreach ( (array) $amount as $a ) {
228 319 $this_amount = self::get_amount_from_string( $a );
229 320 self::maybe_use_decimal( $this_amount, $currency );
230 321 self::normalize_number( $this_amount, $currency );
@@ -239,12 +330,14 @@
239 330 /**
240 331 * Get currency to use when preparing amount.
241 332 *
242 333 * @param array $atts
334 + *
243 335 * @return array
244 336 */
245 337 public static function get_currency_for_action( $atts ) {
246 338 $currency = 'usd';
339 +
247 340 if ( isset( $atts['form'] ) ) {
248 341 $currency = $atts['action']->post_content['currency'];
249 342 } elseif ( isset( $atts['currency'] ) ) {
250 343 $currency = $atts['currency'];
@@ -261,15 +354,15 @@
261 354 private static function get_amount_from_string( $amount ) {
262 355 $amount = html_entity_decode( $amount );
263 356 $amount = trim( $amount );
264 357 preg_match_all( '/[0-9,.]*\.?\,?[0-9]+/', $amount, $matches );
265 - $amount = $matches ? end( $matches[0] ) : 0;
266 - return $amount;
358 + return $matches ? end( $matches[0] ) : 0;
267 359 }
268 360
269 361 /**
270 362 * @param string $amount
271 363 * @param array $currency
364 + *
272 365 * @return void
273 366 */
274 367 private static function maybe_use_decimal( &$amount, $currency ) {
275 368 if ( $currency['thousand_separator'] !== '.' ) {
@@ -275,10 +368,17 @@
275 368 if ( $currency['thousand_separator'] !== '.' ) {
276 369 return;
277 370 }
278 371
279 - $amount_parts = explode( '.', $amount );
280 - $used_for_decimal = count( $amount_parts ) === 2 && strlen( $amount_parts[1] ) === 2;
372 + $amount_parts = explode( '.', $amount );
373 +
374 + if ( 2 !== count( $amount_parts ) ) {
375 + return;
376 + }
377 +
378 + $strlen = strlen( $amount_parts[1] );
379 + $used_for_decimal = $strlen === 1 || $strlen === 2;
380 +
281 381 if ( $used_for_decimal ) {
282 382 $amount = str_replace( '.', $currency['decimal_separator'], $amount );
283 383 }
284 384 }
@@ -285,8 +385,9 @@
285 385
286 386 /**
287 387 * @param string $amount
288 388 * @param array $currency
389 + *
289 390 * @return void
290 391 */
291 392 private static function normalize_number( &$amount, $currency ) {
292 393 $amount = str_replace( $currency['thousand_separator'], '', $amount );
@@ -297,22 +398,26 @@
297 398 /**
298 399 * These settings are included in frm_stripe_vars.settings global JavaScript object on Stripe forms.
299 400 *
300 401 * @param int $form_id
402 + *
301 403 * @return array
302 404 */
303 405 public static function prepare_settings_for_js( $form_id ) {
304 406 $payment_actions = self::get_actions_for_form( $form_id );
305 407 $action_settings = array();
408 +
306 409 foreach ( $payment_actions as $payment_action ) {
307 410 $settings_for_action = array(
308 411 'id' => $payment_action->ID,
309 412 'first_name' => $payment_action->post_content['billing_first_name'],
310 413 'last_name' => $payment_action->post_content['billing_last_name'],
414 + 'address' => $payment_action->post_content['billing_address'] ?? '',
311 415 'gateways' => $payment_action->post_content['gateway'],
312 416 'fields' => self::get_fields_for_price( $payment_action ),
313 417 'one' => $payment_action->post_content['type'],
314 418 'email' => $payment_action->post_content['email'],
419 + 'layout' => $payment_action->post_content['layout'] ?? '',
315 420 );
316 421
317 422 /**
318 423 * @param array $settings_for_action
@@ -318,9 +423,9 @@
318 423 * @param array $settings_for_action
319 424 * @param WP_Post $payment_action
320 425 */
321 426 $settings_for_action = apply_filters( 'frm_trans_settings_for_js', $settings_for_action, $payment_action );
322 - $action_settings[] = $settings_for_action;
427 + $action_settings[] = $settings_for_action;
323 428 }
324 429
325 430 return $action_settings;
326 431 }
@@ -330,14 +435,15 @@
330 435 *
331 436 * @since 6.5, introduced in v2.0 of the Payments submodule.
332 437 *
333 438 * @param WP_Post $action
439 + *
334 440 * @return array|int
335 441 */
336 442 private static function get_fields_for_price( $action ) {
337 443 $amount = $action->post_content['amount'];
338 444 $shortcodes = FrmFieldsHelper::get_shortcodes( $amount, $action->menu_order );
339 - return isset( $shortcodes[2] ) ? $shortcodes[2] : -1;
445 + return $shortcodes[2] ?? -1;
340 446 }
341 447
342 448 /**
343 449 * Get all published payment actions.
@@ -342,8 +448,9 @@
342 448 /**
343 449 * Get all published payment actions.
344 450 *
345 451 * @param int|string $form_id
452 + *
346 453 * @return array
347 454 */
348 455 public static function get_actions_for_form( $form_id ) {
349 456 $action_status = array(
@@ -349,12 +456,10 @@
349 456 $action_status = array(
350 457 'post_status' => 'publish',
351 458 );
352 459 $payment_actions = FrmFormAction::get_action_for_form( $form_id, 'payment', $action_status );
353 - if ( ! $payment_actions ) {
354 - $payment_actions = array();
355 - }
356 - return $payment_actions;
460 +
461 + return $payment_actions ? $payment_actions : array();
357 462 }
358 463
359 464 /**
360 465 * Make sure a gateway field is hidden on the front end.
@@ -360,8 +465,9 @@
360 465 * Make sure a gateway field is hidden on the front end.
361 466 *
362 467 * @param array $values
363 468 * @param stdClass $field
469 + *
364 470 * @return array
365 471 */
366 472 public static function hide_gateway_field_on_front_end( $values, $field ) {
367 473 if ( $field->type !== 'gateway' ) {
@@ -367,12 +473,19 @@
367 473 if ( $field->type !== 'gateway' ) {
368 474 return $values;
369 475 }
370 476
477 + if ( FrmAppHelper::is_form_builder_page() ) {
478 + // The hooks this uses can get called in the form builder and settings pages.
479 + // But we do not need the script in this case.
480 + return $values;
481 + }
482 +
371 483 // This is also called from the frm_enqueue_form_scripts hook.
372 484 // With this here, the value of frm_stripe_vars.settings[0].fields is -1
373 485 // This is because the amount value is processed and a shortcode is not found in '000'.
374 486 FrmStrpLiteActionsController::load_scripts( (int) $field->form_id );
487 + FrmSquareLiteActionsController::load_scripts( (int) $field->form_id );
375 488
376 489 $values['type'] = 'hidden';
377 490 return $values;
378 491 }
@@ -383,14 +496,17 @@
383 496 * @since 6.5.1
384 497 *
385 498 * @param array $values
386 499 * @param stdClass $field
500 + *
387 501 * @return array
388 502 */
389 503 public static function fill_entry_from_previous( $values, $field ) {
390 504 global $frm_vars;
391 - $previous_entry = isset( $frm_vars['frm_trans']['pay_entry'] ) ? $frm_vars['frm_trans']['pay_entry'] : false;
392 - if ( empty( $previous_entry ) || $previous_entry->form_id != $field->form_id ) {
505 + $previous_entry = $frm_vars['frm_trans']['pay_entry'] ?? false;
506 +
507 + // phpcs:ignore Universal.Operators.StrictComparisons
508 + if ( ! $previous_entry || $previous_entry->form_id != $field->form_id ) {
393 509 return $values;
394 510 }
395 511
396 512 if ( is_array( $previous_entry->metas ) && isset( $previous_entry->metas[ $field->id ] ) ) {
@@ -397,10 +513,9 @@
397 513 $values['value'] = $previous_entry->metas[ $field->id ];
398 514 }
399 515
400 516 $frm_vars['trans_filled'] = true;
401 -
402 - $previous_entry_id = $previous_entry->id;
517 + $previous_entry_id = $previous_entry->id;
403 518 self::destroy_entry_later( $previous_entry_id );
404 519
405 520 return $values;
406 521 }
@@ -411,9 +526,10 @@
411 526 * See Formidable Stripe issue #136 for more information.
412 527 *
413 528 * @since 6.5.1
414 529 *
415 - * @param string|int $entry_id
530 + * @param int|string $entry_id
531 + *
416 532 * @return void
417 533 */
418 534 private static function destroy_entry_later( $entry_id ) {
419 535 if ( in_array( (int) $entry_id, self::$entry_ids_to_destroy_later, true ) ) {
@@ -424,17 +540,161 @@
424 540 $destroy_callback =
425 541 /**
426 542 * Destroy an entry and remove this action so it only tries to destroy the entry once.
427 543 *
428 - * @param string|int $entry_id
544 + * @param int|string $entry_id
429 545 * @param Closure $destroy_callback
546 + *
430 547 * @return void
431 548 */
432 - function() use ( $entry_id, &$destroy_callback ) {
549 + function () use ( $entry_id, &$destroy_callback ) {
433 550 FrmEntry::destroy( $entry_id );
434 - remove_action( 'frm_entry_form', $destroy_callback ); // Only call this once.
551 + // Only call this once.
552 + remove_action( 'frm_entry_form', $destroy_callback );
435 553 };
436 554 add_action( 'frm_entry_form', $destroy_callback );
437 555
438 556 self::$entry_ids_to_destroy_later[] = (int) $entry_id;
557 + }
558 +
559 + /**
560 + * Filter payment action on save.
561 + *
562 + * @since 6.22
563 + *
564 + * @param array $settings
565 + * @param array $action
566 + *
567 + * @return array
568 + */
569 + public static function before_save_settings( $settings, $action ) {
570 + $settings['gateway'] = ! empty( $settings['gateway'] ) ? (array) $settings['gateway'] : array( 'stripe' );
571 +
572 + if ( in_array( 'square', $settings['gateway'], true ) ) {
573 + $currency = FrmSquareLiteConnectHelper::get_merchant_currency();
574 + $settings['currency'] = false !== $currency ? strtolower( $currency ) : 'usd';
575 + } else {
576 + $settings['currency'] = strtolower( $settings['currency'] );
577 + }
578 +
579 + $form_id = absint( $action['menu_order'] );
580 +
581 + if ( empty( $settings['credit_card'] ) ) {
582 + $credit_card_field_id = FrmDb::get_var(
583 + 'frm_fields',
584 + array(
585 + 'type' => 'credit_card',
586 + 'form_id' => $form_id,
587 + )
588 + );
589 +
590 + if ( ! $credit_card_field_id ) {
591 + $credit_card_field_id = self::add_a_credit_card_field( $form_id );
592 + }
593 +
594 + if ( $credit_card_field_id ) {
595 + $settings['credit_card'] = $credit_card_field_id;
596 + }
597 + }
598 +
599 + if ( ! in_array( 'stripe', $settings['gateway'], true ) ) {
600 + // We only need a gateway field for Stripe add-on compatibility,
601 + // so unless Stripe is selected, we can return early.
602 + return $settings;
603 + }
604 +
605 + $gateway_field_id = FrmDb::get_var(
606 + 'frm_fields',
607 + array(
608 + 'type' => 'gateway',
609 + 'form_id' => $form_id,
610 + )
611 + );
612 +
613 + if ( ! $gateway_field_id ) {
614 + self::add_a_gateway_field( $form_id );
615 + }
616 +
617 + return $settings;
618 + }
619 +
620 + /**
621 + * A credit card field is added automatically if missing before a Stripe action is updated.
622 + *
623 + * @param int $form_id
624 + *
625 + * @return false|int
626 + */
627 + protected static function add_a_credit_card_field( $form_id ) {
628 + return self::add_a_field( $form_id, 'credit_card', __( 'Payment', 'formidable' ) );
629 + }
630 +
631 + /**
632 + * A gateway field is added automatically for compatibility with the Stripe add on.
633 + * The gateway field is not important for the Stripe Lite implementation.
634 + *
635 + * @param int $form_id
636 + *
637 + * @return false|int
638 + */
639 + protected static function add_a_gateway_field( $form_id ) {
640 + return self::add_a_field( $form_id, 'gateway', __( 'Payment Method', 'formidable' ) );
641 + }
642 +
643 + /**
644 + * @param int $form_id
645 + * @param string $field_type
646 + * @param string $field_name
647 + *
648 + * @return false|int
649 + */
650 + protected static function add_a_field( $form_id, $field_type, $field_name ) {
651 + $new_values = FrmFieldsHelper::setup_new_vars( $field_type, $form_id );
652 + $new_values['name'] = $field_name;
653 + $new_values['field_order'] = self::get_field_order_before_submit( $form_id, $new_values['field_order'] );
654 + return FrmField::create( $new_values );
655 + }
656 +
657 + /**
658 + * When auto-injecting a field, ensure it is placed before the submit button.
659 + *
660 + * @since 6.29
661 + *
662 + * @param int $form_id
663 + * @param int $field_order
664 + *
665 + * @return int
666 + */
667 + private static function get_field_order_before_submit( $form_id, $field_order ) {
668 + $submit_field = FrmSubmitHelper::get_submit_field( $form_id );
669 +
670 + if ( ! $submit_field || $field_order < (int) $submit_field->field_order ) {
671 + return $field_order;
672 + }
673 +
674 + $submit_order = (int) $submit_field->field_order;
675 + FrmField::update( $submit_field->id, array( 'field_order' => $submit_order + 1 ) );
676 + return $submit_order;
677 + }
678 +
679 + /**
680 + * Remove credit card validation errors.
681 + *
682 + * @param array $errors
683 + * @param stdClass $field
684 + *
685 + * @return array
686 + */
687 + public static function remove_cc_errors( $errors, $field ) {
688 + $field_id = $field->temp_id ?? $field->id;
689 +
690 + if ( isset( $errors[ 'field' . $field_id . '-cc' ] ) ) {
691 + unset( $errors[ 'field' . $field_id . '-cc' ] );
692 + }
693 +
694 + if ( isset( $errors[ 'field' . $field_id ] ) ) {
695 + unset( $errors[ 'field' . $field_id ] );
696 + }
697 +
698 + return $errors;
439 699 }
440 700 }