PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 2.4.0
Subscriptions for WooCommerce with Stripe Recurring Payments v2.4.0
2.4.0 2.3.0 2.2.0 2.1.0 2.0.0 1.11.2 1.11.1 1.11.0 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.6 1.9.5 trunk 1.3.0 1.3.1 1.3.2 1.4.0 All 65 releases
← All changes | includes/Illuminate/GuestCheckout.php +242 -7 1.10.2 → 2.4.0 View file →
@@ -30,8 +30,13 @@
30 30
31 31 // Enforce Login/Registration in checkout
32 32 add_action( 'woocommerce_checkout_process', [ $this, 'require_account_creation' ] );
33 33 add_filter( 'woocommerce_store_api_checkout_update_order_from_request', [ $this,'require_account_creation_store_api' ], 10, 2 );
34 +
35 + // Guest account creation.
36 + add_action( 'woocommerce_store_api_checkout_update_customer_from_request', [ $this, 'maybe_create_user_from_customer' ], 10, 1 );
37 + add_action( 'woocommerce_store_api_checkout_update_order_from_request', [ $this, 'maybe_assign_user_to_order' ], 5, 1 );
38 + add_action( 'woocommerce_checkout_create_order', [ $this, 'maybe_assign_user_to_order' ], 10, 1 );
34 39 }
35 40
36 41 /**
37 42 * Add Guest Checkout Settings Fields
@@ -43,9 +48,9 @@
43 48 $guest_checkout_fields = [
44 49 [
45 50 'type' => 'heading',
46 51 'group' => 'guest_checkout',
47 - 'priority' => 1,
52 + 'priority' => 2,
48 53 'field_data' => [
49 54 'title' => __( 'Guest Checkout', 'subscription' ),
50 55 'description' => __( 'Manage guest checkout settings for subscriptions.', 'subscription' ),
51 56 ],
@@ -157,12 +162,12 @@
157 162 $account_after_checkout = in_array( get_option( 'woocommerce_enable_delayed_account_creation' ), [ 1, '1', 'yes', 'on' ], true );
158 163
159 164 $issues = [];
160 165 if ( ! $guest_checkout_enabled ) {
161 - $issues[] = 'Guest checkout.';
166 + $issues[] = __( 'Guest checkout.', 'subscription' );
162 167 }
163 168 if ( ! $account_during_checkout ) {
164 - $issues[] = 'Account creation during checkout.';
169 + $issues[] = __( 'Account creation during checkout.', 'subscription' );
165 170 }
166 171
167 172 if ( ! empty( $issues ) ) {
168 173 $settings_url = admin_url( 'admin.php?page=wc-settings&tab=account' );
@@ -172,10 +177,13 @@
172 177 $list_html .= '<li><span class="dashicons dashicons-arrow-right"></span> <strong>' . $issue . '</strong></li>';
173 178 }
174 179
175 180 $requirement_html = '<div class="notice notice-error is-dismissible">' .
176 - '<p>To ensure Subscriptions guest checkout functions correctly, please enable the following settings in WooCommerce. ' .
177 - 'Click <a href="' . $settings_url . '">here</a> to go to the settings.</p>' .
181 + '<p>' . sprintf(
182 + /* translators: %s: URL of the WooCommerce account settings. */
183 + __( 'To ensure Subscriptions guest checkout functions correctly, please enable the following settings in WooCommerce. Click <a href="%s">here</a> to go to the settings.', 'subscription' ),
184 + esc_url( $settings_url )
185 + ) . '</p>' .
178 186 '<ul>' . $list_html . '</ul></div>';
179 187
180 188 echo wp_kses_post( $requirement_html );
181 189 }
@@ -183,10 +191,14 @@
183 191 if ( $account_after_checkout ) {
184 192 $settings_url = admin_url( 'admin.php?page=wc-settings&tab=account' );
185 193
186 194 $requirement_html = '<div class="notice notice-warning is-dismissible">' .
187 - '<p>Enabling <strong>Account creation after checkout</strong> in WooCommerce settings may lead to issues with subscription orders for guest users.</p>' .
188 - '<p>It\'s recommended to disable this option for optimal functionality with Subscriptions. Click <a href="' . $settings_url . '">here</a> to go to the settings.</p></div>';
195 + '<p>' . __( 'Enabling <strong>Account creation after checkout</strong> in WooCommerce settings may lead to issues with subscription orders for guest users.', 'subscription' ) . '</p>' .
196 + '<p>' . sprintf(
197 + /* translators: %s: URL of the WooCommerce account settings. */
198 + __( 'It\'s recommended to disable this option for optimal functionality with Subscriptions. Click <a href="%s">here</a> to go to the settings.', 'subscription' ),
199 + esc_url( $settings_url )
200 + ) . '</p></div>';
189 201
190 202 echo wp_kses_post( $requirement_html );
191 203 }
192 204 }
@@ -277,7 +289,230 @@
277 289 __( 'You are ordering a subscription product. You must be either <strong>logged in</strong> or check the "<strong>Create an account</strong>" option to continue the checkout.', 'subscription' )
278 290 ),
279 291 400
280 292 );
293 + }
294 + }
295 +
296 + /**
297 + * Build user info from order or customer object.
298 + *
299 + * @param \WC_Order|\WC_Customer $order_or_customer Order or Customer object.
300 + */
301 + public function build_user_info( $order_or_customer ): array {
302 + $user_info = [];
303 +
304 + // Billing info.
305 + $user_info['billing_first_name'] = $order_or_customer->get_billing_first_name();
306 + $user_info['billing_last_name'] = $order_or_customer->get_billing_last_name();
307 + $user_info['billing_company'] = $order_or_customer->get_billing_company();
308 + $user_info['billing_address_1'] = $order_or_customer->get_billing_address_1();
309 + $user_info['billing_address_2'] = $order_or_customer->get_billing_address_2();
310 + $user_info['billing_city'] = $order_or_customer->get_billing_city();
311 + $user_info['billing_postcode'] = $order_or_customer->get_billing_postcode();
312 + $user_info['billing_country'] = $order_or_customer->get_billing_country();
313 + $user_info['billing_state'] = $order_or_customer->get_billing_state();
314 + $user_info['billing_email'] = $order_or_customer->get_billing_email();
315 + $user_info['billing_phone'] = $order_or_customer->get_billing_phone();
316 +
317 + // Shipping info.
318 + $user_info['shipping_first_name'] = ! empty( $order_or_customer->get_shipping_first_name() ) ? $order_or_customer->get_shipping_first_name() : $user_info['billing_first_name'];
319 + $user_info['shipping_last_name'] = ! empty( $order_or_customer->get_shipping_last_name() ) ? $order_or_customer->get_shipping_last_name() : $user_info['billing_last_name'];
320 + $user_info['shipping_company'] = ! empty( $order_or_customer->get_shipping_company() ) ? $order_or_customer->get_shipping_company() : $user_info['billing_company'];
321 + $user_info['shipping_address_1'] = ! empty( $order_or_customer->get_shipping_address_1() ) ? $order_or_customer->get_shipping_address_1() : $user_info['billing_address_1'];
322 + $user_info['shipping_address_2'] = ! empty( $order_or_customer->get_shipping_address_2() ) ? $order_or_customer->get_shipping_address_2() : $user_info['billing_address_2'];
323 + $user_info['shipping_city'] = ! empty( $order_or_customer->get_shipping_city() ) ? $order_or_customer->get_shipping_city() : $user_info['billing_city'];
324 + $user_info['shipping_postcode'] = ! empty( $order_or_customer->get_shipping_postcode() ) ? $order_or_customer->get_shipping_postcode() : $user_info['billing_postcode'];
325 + $user_info['shipping_country'] = ! empty( $order_or_customer->get_shipping_country() ) ? $order_or_customer->get_shipping_country() : $user_info['billing_country'];
326 + $user_info['shipping_state'] = ! empty( $order_or_customer->get_shipping_state() ) ? $order_or_customer->get_shipping_state() : $user_info['billing_state'];
327 + $user_info['shipping_phone'] = ! empty( $order_or_customer->get_shipping_phone() ) ? $order_or_customer->get_shipping_phone() : $user_info['billing_phone'];
328 +
329 + return $user_info;
330 + }
331 +
332 + /**
333 + * Maybe create user from user info.
334 + *
335 + * @param array $user_info User info array.
336 + */
337 + public function maybe_create_user( $user_info ): ?int {
338 + // Don't proceed if guest checkout is not allowed.
339 + $is_guest_checkout_allowed = in_array( get_option( 'wp_subscription_allow_guest_checkout', '0' ), [ 1, '1', 'yes', 'on' ], true );
340 + if ( ! $is_guest_checkout_allowed ) {
341 + return null;
342 + }
343 +
344 + $is_new_customer = false;
345 +
346 + // Check if user exists with email.
347 + $user = get_user_by( 'email', $user_info['billing_email'] );
348 + $user_id = $user ? $user->ID : 0;
349 +
350 + if ( ! $user_id ) {
351 + $is_new_customer = true;
352 +
353 + // Not wp_insert_user(): without a `user_pass` it stores wp_hash_password( '' ).
354 + $user_id = wc_create_new_customer(
355 + $user_info['billing_email'],
356 + '',
357 + '',
358 + [
359 + 'first_name' => $user_info['billing_first_name'],
360 + 'last_name' => $user_info['billing_last_name'],
361 + 'source' => 'subscrpt-guest-checkout',
362 + ]
363 + );
364 +
365 + if ( is_wp_error( $user_id ) ) {
366 + subscrpt_write_log( 'Failed to auto-create user during checkout. Error: ' . $user_id->get_error_message() );
367 + return null;
368 + }
369 +
370 + // Set billing info.
371 + update_user_meta( $user_id, 'billing_first_name', $user_info['billing_first_name'] );
372 + update_user_meta( $user_id, 'billing_last_name', $user_info['billing_last_name'] );
373 + update_user_meta( $user_id, 'billing_company', $user_info['billing_company'] );
374 + update_user_meta( $user_id, 'billing_address_1', $user_info['billing_address_1'] );
375 + update_user_meta( $user_id, 'billing_address_2', $user_info['billing_address_2'] );
376 + update_user_meta( $user_id, 'billing_city', $user_info['billing_city'] );
377 + update_user_meta( $user_id, 'billing_postcode', $user_info['billing_postcode'] );
378 + update_user_meta( $user_id, 'billing_country', $user_info['billing_country'] );
379 + update_user_meta( $user_id, 'billing_state', $user_info['billing_state'] );
380 + update_user_meta( $user_id, 'billing_email', $user_info['billing_email'] );
381 + update_user_meta( $user_id, 'billing_phone', $user_info['billing_phone'] );
382 +
383 + // Set shipping info.
384 + update_user_meta( $user_id, 'shipping_first_name', $user_info['shipping_first_name'] );
385 + update_user_meta( $user_id, 'shipping_last_name', $user_info['shipping_last_name'] );
386 + update_user_meta( $user_id, 'shipping_company', $user_info['shipping_company'] );
387 + update_user_meta( $user_id, 'shipping_address_1', $user_info['shipping_address_1'] );
388 + update_user_meta( $user_id, 'shipping_address_2', $user_info['shipping_address_2'] );
389 + update_user_meta( $user_id, 'shipping_city', $user_info['shipping_city'] );
390 + update_user_meta( $user_id, 'shipping_postcode', $user_info['shipping_postcode'] );
391 + update_user_meta( $user_id, 'shipping_country', $user_info['shipping_country'] );
392 + update_user_meta( $user_id, 'shipping_state', $user_info['shipping_state'] );
393 + update_user_meta( $user_id, 'shipping_phone', $user_info['shipping_phone'] );
394 + }
395 +
396 + // Auto-login the newly created account so the subscription can be associated with the user.
397 + // This ONLY runs when $is_new_customer is true — i.e. when wp_insert_user() succeeded
398 + // just above in this same request. It never fires for returning/existing users.
399 + // wc_set_customer_auth_cookie() is the WooCommerce-sanctioned way to log a customer in
400 + // during checkout; wp_set_auth_cookie() is the WP fallback if WC is not available.
401 + if ( ! is_user_logged_in() && $is_new_customer && $user_id ) {
402 + wp_set_current_user( $user_id );
403 + if ( function_exists( 'wc_set_customer_auth_cookie' ) ) {
404 + wc_set_customer_auth_cookie( $user_id );
405 + } else {
406 + wp_set_auth_cookie( $user_id );
407 + }
408 +
409 + subscrpt_write_debug_log( 'Auto-logged in newly created user ID: ' . $user_id . ' after checkout.' );
410 + }
411 +
412 + return $user_id;
413 + }
414 +
415 + /**
416 + * Auto-create a guest account only while login is not enforced.
417 + *
418 + * @return bool
419 + */
420 + protected function should_auto_create_account() {
421 + return self::is_guest_checkout_allowed() && ! self::is_guest_login_enforced();
422 + }
423 +
424 + /**
425 + * Does the current cart contain a subscription product.
426 + *
427 + * @return bool
428 + */
429 + protected function cart_has_subscription() {
430 + if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
431 + return false;
432 + }
433 +
434 + return count( Helper::get_recurrs_from_cart( WC()->cart->get_cart() ) ) > 0;
435 + }
436 +
437 + /**
438 + * Create the guest account before the order exists, for gateway customer binding.
439 + *
440 + * @param \WC_Customer $customer Customer object.
441 + *
442 + * @return void
443 + */
444 + public function maybe_create_user_from_customer( $customer ) {
445 + if ( is_user_logged_in() || ! $this->should_auto_create_account() ) {
446 + return;
447 + }
448 +
449 + // Already backed by a real user.
450 + if ( $customer->get_id() ) {
451 + return;
452 + }
453 +
454 + if ( ! $this->cart_has_subscription() ) {
455 + return;
456 + }
457 +
458 + $billing_email = $customer->get_billing_email();
459 +
460 + // Cannot create an account without an email.
461 + if ( empty( $billing_email ) ) {
462 + return;
463 + }
464 +
465 + // Never $customer->set_id() + save() here: it blanks user_email.
466 + $this->maybe_create_user( $this->build_user_info( $customer ) );
467 + }
468 +
469 + /**
470 + * Assign a user to a guest subscription order, creating one if needed.
471 + *
472 + * @param \WC_Order $order Order object.
473 + *
474 + * @return void
475 + */
476 + public function maybe_assign_user_to_order( $order ) {
477 + if ( ! $this->should_auto_create_account() ) {
478 + return;
479 + }
480 +
481 + if ( ! $order instanceof \WC_Order ) {
482 + return;
483 + }
484 +
485 + // Don't proceed if the order already has a user.
486 + if ( $order->get_customer_id() ) {
487 + return;
488 + }
489 +
490 + if ( ! $this->cart_has_subscription() ) {
491 + return;
492 + }
493 +
494 + // Reuse the user created earlier in this request when there is one.
495 + $user_id = get_current_user_id();
496 +
497 + if ( ! $user_id ) {
498 + $user_info = $this->build_user_info( $order );
499 +
500 + if ( empty( $user_info['billing_email'] ) ) {
501 + return;
502 + }
503 +
504 + $user_id = $this->maybe_create_user( $user_info );
505 + }
506 +
507 + if ( ! $user_id ) {
508 + return;
509 + }
510 +
511 + $order->set_customer_id( $user_id );
512 +
513 + // The classic checkout hands over an unsaved order and persists it itself.
514 + if ( $order->get_id() ) {
515 + $order->save();
281 516 }
282 517 }
283 518 }