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 +81 -20 6.28 → trunk View file →
@@ -123,13 +123,13 @@
123 123 return $response;
124 124 }
125 125
126 126 if ( ! self::stripe_is_configured() ) {
127 - $response['error'] = __( 'There was a problem communicating with Stripe. Please try again.', 'formidable' );
127 + $response['error'] = __( 'Stripe still needs to be configured.', 'formidable' );
128 128 return $response;
129 129 }
130 130
131 - $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 132
133 133 if ( ! is_object( $customer ) ) {
134 134 $response['error'] = $customer;
135 135 return $response;
@@ -136,9 +136,13 @@
136 136 }
137 137
138 138 $one_time_payment_args = compact( 'customer', 'form', 'entry', 'action', 'amount' );
139 139
140 - 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 +
141 145 $response['show_errors'] = false;
142 146 return $response;
143 147 }
144 148
@@ -151,15 +155,56 @@
151 155 return FrmStrpLiteAppHelper::call_stripe_helper_class( 'initialize_api' );
152 156 }
153 157
154 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 + /**
155 199 * Set a customer object to $_POST['customer'] to use later.
156 200 *
157 - * @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.
158 203 *
159 204 * @return object|string
160 205 */
161 - private static function set_customer_with_token( $atts ) {
206 + private static function set_customer_with_token( $atts, $customer_id = false ) {
162 207 if ( isset( self::$customer ) ) {
163 208 // It's an object if this isn't the first Stripe action running.
164 209 return self::$customer;
165 210 }
@@ -167,8 +212,12 @@
167 212 $payment_info = array(
168 213 'user_id' => FrmTransLiteAppHelper::get_user_id_for_current_payment(),
169 214 );
170 215
216 + if ( $customer_id ) {
217 + $payment_info['customer_id'] = $customer_id;
218 + }
219 +
171 220 if ( ! empty( $atts['action']->post_content['email'] ) ) {
172 221 $payment_info['email'] = apply_filters( 'frm_content', $atts['action']->post_content['email'], $atts['form'], $atts['entry'] );
173 222 $payment_info['email'] = self::replace_email_shortcode( $payment_info['email'] );
174 223 }
@@ -281,11 +330,17 @@
281 330 *
282 331 * @return array
283 332 */
284 333 public static function add_action_defaults( $defaults ) {
334 + // Stripe action options.
285 335 $defaults['plan_id'] = '';
286 336 $defaults['capture'] = '';
287 337 $defaults['stripe_link'] = '';
338 +
339 + // PayPal action options.
340 + $defaults['product_name'] = '';
341 + $defaults['pay_later'] = '';
342 +
288 343 return $defaults;
289 344 }
290 345
291 346 /**
@@ -312,9 +367,9 @@
312 367 public static function before_save_settings( $settings, $action ) {
313 368 $settings['currency'] = strtolower( $settings['currency'] );
314 369
315 370 // Gateway is a radio button but it should always be an array in the database for
316 - // compatibility with the payments submodule where it is a checkbox.
371 + // compatibility with the payments submodule where it is a checkbox (when Authorize.Net is active).
317 372 $settings['gateway'] = ! empty( $settings['gateway'] ) ? (array) $settings['gateway'] : array( 'stripe' );
318 373
319 374 $is_stripe = in_array( 'stripe', $settings['gateway'], true );
320 375
@@ -360,9 +415,21 @@
360 415 * @return string
361 416 */
362 417 public static function create_plan_id( $settings ) {
363 418 $amount = self::prepare_amount( $settings['amount'], $settings );
364 - return sanitize_title_with_dashes( $settings['description'] ) . '_' . $amount . '_' . $settings['interval_count'] . $settings['interval'] . '_' . $settings['currency'];
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 );
365 432 }
366 433
367 434 /**
368 435 * If this form submits with ajax, load the scripts on the first page.
@@ -457,16 +524,20 @@
457 524
458 525 $action_settings = self::prepare_settings_for_js( $form_id );
459 526 $found_gateway = false;
460 527
461 - foreach ( $action_settings as $action ) {
528 + foreach ( $action_settings as &$action ) {
462 529 $gateways = $action['gateways'];
463 530
464 531 if ( ! $gateways || in_array( 'stripe', (array) $gateways, true ) ) {
465 532 $found_gateway = true;
466 - break;
467 533 }
534 +
535 + if ( ! empty( $action['layout'] ) && ! in_array( $action['layout'], array( 'accordion', 'tabs' ), true ) ) {
536 + $action['layout'] = '';
537 + }
468 538 }
539 + unset( $action );
469 540
470 541 if ( ! $found_gateway ) {
471 542 return;
472 543 }
@@ -653,17 +724,7 @@
653 724 if ( ! $has_processed ) {
654 725 return $errors;
655 726 }
656 727
657 - $field_id = $field->temp_id ?? $field->id;
658 -
659 - if ( isset( $errors[ 'field' . $field_id . '-cc' ] ) ) {
660 - unset( $errors[ 'field' . $field_id . '-cc' ] );
661 - }
662 -
663 - if ( isset( $errors[ 'field' . $field_id ] ) ) {
664 - unset( $errors[ 'field' . $field_id ] );
665 - }
666 -
667 - return $errors;
728 + return FrmTransLiteActionsController::remove_cc_errors( $errors, $field );
668 729 }
669 730 }