( $new_payment_method->id );
$default_payment_method->detach();
// In this case Subscription's 'default_payment_method' doesn't have to be explicitly set and defaults to Customer's 'default_payment_method'.
return '';
}
// In case Customer's 'default_payment_method' is set and its fingerprint doesn't match with a new PaymentMethod, several things need to be done:
// - Scan all active subscriptions for 'default_payment_method' with a same fingerprint as a new PaymentMethod.
// - Change all matching subscriptions 'default_payment_method' to a new PaymentMethod.
// - Delete all PaymentMethods previously set as 'default_payment_method' for matching subscriptions.
$this->detach_remote_subscriptions_duplicated_payment_methods( $new_payment_method );
// In this case Subscription's 'default_payment_method' has to be explicitly set
// because Customer's 'default_payment_method' contains a different PaymentMethod and cannot be defaulted to.
return $new_payment_method->id;
}
/**
* Update 'default_payment_method' for a Customer stored on a Stripe side.
*
* @since 1.8.2
*
* @param string $payment_method_id PaymentMethod id.
*
* @throws Exception If a Customer fails to update.
*/
protected function update_remote_customer_default_payment_method( $payment_method_id ) {
Customer::update(
$this->get_customer( 'id' ),
[
'invoice_settings' => [
'default_payment_method' => $payment_method_id,
],
],
Helpers::get_auth_opts()
);
}
/**
* Detach all active Subscriptions PaymentMethods having the same fingerprint as a given PaymentMethod.
*
* @since 1.8.2
*
* @param PaymentMethod $new_payment_method PaymentMethod object.
*
* @throws Exception In case of Stripe API error.
*/
protected function detach_remote_subscriptions_duplicated_payment_methods( $new_payment_method ) {
$subscriptions = Subscription::all(
[
'customer' => $this->get_customer( 'id' ),
'status' => 'active',
'limit' => 100, // Maximum limit allowed by Stripe (https://stripe.com/docs/api/subscriptions/list#list_subscriptions-limit).
'expand' => [ 'data.default_payment_method' ],
],
Helpers::get_auth_opts()
);
$detach_methods = [];
foreach ( $subscriptions as $subscription ) {
if ( empty( $subscription->default_payment_method ) ) {
continue;
}
if ( $new_payment_method->card->fingerprint === $subscription->default_payment_method->card->fingerprint ) {
Subscription::update(
$subscription->id,
[ 'default_payment_method' => $new_payment_method->id ],
Helpers::get_auth_opts()
);
$detach_methods[ $subscription->default_payment_method->id ] = $subscription->default_payment_method;
}
}
foreach ( $detach_methods as $detach_method ) {
$detach_method->detach();
}
}
/**
* Set an encrypted token as a PaymentIntent metadata item.
*
* @since 1.8.2
*
* @throws ApiErrorException In case payment intent save wasn't successful.
*/
private function set_bypass_captcha_3dsecure_token() {
$form_data = wpforms()->get( 'process' )->form_data;
// Set token only if captcha is enabled for the form.
if ( empty( $form_data['settings']['recaptcha'] ) ) {
return;
}
$this->intent->metadata['captcha_3dsecure_token'] = Crypto::encrypt( $this->intent->id );
$this->intent->update( $this->intent->id, $this->intent->serializeParameters(), Helpers::get_auth_opts() );
}
/**
* Bypass CAPTCHA check on successful 3dSecure check.
*
* @since 1.8.2
*
* @param bool $is_bypassed True if CAPTCHA is bypassed.
* @param array $entry Form entry data.
* @param array $form_data Form data and settings.
*
* @return bool
*
* @throws ApiErrorException In case payment intent save wasn't successful.
*/
public function bypass_captcha_on_3dsecure_submit( $is_bypassed, $entry, $form_data ) {
// Firstly, run checks that may prevent bypassing:
// 1) Sanity check to prevent possible tinkering with captcha on non-payment forms.
// 2) Both reCAPTCHA and hCaptcha are enabled by the same setting.
if (
! Helpers::is_payments_enabled( $form_data ) ||
empty( $form_data['settings']['recaptcha'] ) ||
empty( $entry['payment_intent_id'] )
) {
return $is_bypassed;
}
// This is executed before payment processing kicks in and fills `$this->intent`.
// PaymentIntent intent has to be retrieved from Stripe instead of getting it from `$this->intent`.
$intent = $this->retrieve_payment_intent( $entry['payment_intent_id'] );
if ( empty( $intent->status ) || $intent->status !== 'succeeded' ) {
return $is_bypassed;
}
$token = ! empty( $intent->metadata['captcha_3dsecure_token'] ) ? $intent->metadata['captcha_3dsecure_token'] : '';
if ( Crypto::decrypt( $token ) !== $intent->id ) {
return $is_bypassed;
}
// Cleanup the token to prevent its repeated usage and declutter the metadata.
$intent->metadata['captcha_3dsecure_token'] = null;
$intent->update( $intent->id, $intent->serializeParameters(), Helpers::get_auth_opts() );
return true;
}
/**
* Retrieve Mandate object from Stripe.
*
* @since 1.8.7
*
* @param string $id Mandate id.
* @param array $args Additional arguments.
*
* @throws ApiErrorException If the request fails.
*
* @return Mandate|null
*/
public function retrieve_mandate( string $id, array $args = [] ) {
try {
$defaults = [ 'id' => $id ];
if ( isset( $args['mode'] ) ) {
$auth_opts = [ 'api_key' => Helpers::get_stripe_key( 'secret', $args['mode'] ) ];
unset( $args['mode'] );
}
$args = wp_parse_args( $args, $defaults );
return Mandate::retrieve( $args, $auth_opts ?? Helpers::get_auth_opts() );
} catch ( Exception $e ) {
wpforms_log(
'Stripe: Unable to get Mandate.',
$e->getMessage(),
[
'type' => [ 'payment', 'error' ],
]
);
}
return null;
}
/**
* Create Stripe Setup Intent.
*
* @since 1.8.7
*
* @param array $intent_data Intent data.
* @param array $args Additional arguments.
*
* @throws ApiErrorException If the request fails.
*
* @return SetupIntent|null
*/
public function create_setup_intent( array $intent_data, array $args ) {
try {
if ( isset( $args['mode'] ) ) {
$auth_opts = [ 'api_key' => Helpers::get_stripe_key( 'secret', $args['mode'] ) ];
}
return SetupIntent::create( $intent_data, $auth_opts ?? Helpers::get_auth_opts() );
} catch ( Exception $e ) {
wpforms_log(
'Stripe: Unable to create Setup Intent.',
$e->getMessage(),
[
'type' => [ 'payment', 'error' ],
]
);
}
return null;
}
}
Fatal error: Uncaught Error: Class 'WPForms\Integrations\Stripe\Api\PaymentIntents' not found in /home/candoodesigncom/public_html/wp-content/plugins/wpforms-lite/src/Integrations/Stripe/Stripe.php:55
Stack trace:
#0 /home/candoodesigncom/public_html/wp-content/plugins/wpforms-lite/src/Integrations/Loader.php(78): WPForms\Integrations\Stripe\Stripe->load()
#1 /home/candoodesigncom/public_html/wp-content/plugins/wpforms-lite/src/Integrations/Loader.php(63): WPForms\Integrations\Loader->load_integration(Object(WPForms\Integrations\Stripe\Stripe))
#2 /home/candoodesigncom/public_html/wp-content/plugins/wpforms-lite/src/Integrations/Loader.php(22): WPForms\Integrations\Loader->__construct()
#3 /home/candoodesigncom/public_html/wp-includes/class-wp-hook.php(324): WPForms\Integrations\Loader::get_instance('')
#4 /home/candoodesigncom/public_html/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters(Object(WPForms\Providers\Providers), Array)
#5 /home/candoodesigncom/public_html/wp-includes/plugin.php(517): WP_Hook->do_acti in /home/candoodesigncom/public_html/wp-content/plugins/wpforms-lite/src/Integrations/Stripe/Stripe.php on line 55