'heading',
'group' => 'guest_checkout',
'priority' => 2,
'field_data' => [
'title' => __( 'Guest Checkout', 'subscription' ),
'description' => __( 'Manage guest checkout settings for subscriptions.', 'subscription' ),
],
],
[
'type' => 'toggle',
'group' => 'guest_checkout',
'priority' => 1,
'field_data' => [
'id' => 'wp_subscription_allow_guest_checkout',
'title' => __( 'Allow Guest Checkout', 'subscription' ),
'description' => __( 'Allow customers to checkout without logging in.', 'subscription' ) . '
' . __( 'Note: You will need to enable Guest checkout and Allow customers to create an account during checkout options in WooCommerce settings for this to work properly.', 'subscription' ) . '',
'value' => '1',
'checked' => '1' === get_option( 'wp_subscription_allow_guest_checkout', '0' ),
],
],
[
'type' => 'toggle',
'group' => 'guest_checkout',
'priority' => 2,
'field_data' => [
'id' => 'wp_subscription_enforce_login',
'title' => __( 'Enforce Login', 'subscription' ),
'description' => __( 'Force customers to login or check the "Create account" checkbox before checking out.', 'subscription' ),
'value' => '1',
'checked' => '1' === get_option( 'wp_subscription_enforce_login', '1' ),
],
],
];
return array_merge( $settings_fields, $guest_checkout_fields );
}
/**
* Register settings option.
*/
public function register_settings() {
register_setting(
'wp_subscription_settings',
'wp_subscription_allow_guest_checkout',
array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
)
);
register_setting(
'wp_subscription_settings',
'wp_subscription_enforce_login',
array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
)
);
}
/**
* Is guest checkout allowed
*/
public static function is_guest_checkout_allowed() {
return in_array( get_option( 'wp_subscription_allow_guest_checkout', '0' ), [ 1, '1' ], true );
}
/**
* Is guest login enforced
*/
public static function is_guest_login_enforced() {
return in_array( get_option( 'wp_subscription_enforce_login', '1' ), [ 1, '1' ], true );
}
/**
* Check if cart/order has subscription and guest checkout are allowed.
*/
public function is_subs_and_guest_checkout_allowed() {
$is_user_logged_in = is_user_logged_in();
$is_guest_checkout_allowed = self::is_guest_checkout_allowed();
$cart_have_subscription = false;
// Check in cart.
if ( function_exists( 'WC' ) ) {
$cart_items = WC()->cart->get_cart();
$recurrs = Helper::get_recurrs_from_cart( $cart_items );
$cart_have_subscription = count( $recurrs ) > 0;
}
if ( $cart_have_subscription ) {
return $is_user_logged_in || $is_guest_checkout_allowed;
} else {
return true;
}
}
/**
* Check WooCommerce checkout settings and show admin notice if guest checkout is disabled.
*/
public function check_woocommerce_checkout_settings() {
// Check if WooCommerce is active
if ( ! class_exists( 'WooCommerce' ) ) {
return;
}
$subs_guest_checkout_allowed = self::is_guest_checkout_allowed();
if ( ! $subs_guest_checkout_allowed ) {
return;
}
$guest_checkout_enabled = in_array( get_option( 'woocommerce_enable_guest_checkout' ), [ 1, '1', 'yes', 'on' ], true );
$account_during_checkout = in_array( get_option( 'woocommerce_enable_signup_and_login_from_checkout' ), [ 1, '1', 'yes', 'on' ], true );
$account_after_checkout = in_array( get_option( 'woocommerce_enable_delayed_account_creation' ), [ 1, '1', 'yes', 'on' ], true );
$issues = [];
if ( ! $guest_checkout_enabled ) {
$issues[] = 'Guest checkout.';
}
if ( ! $account_during_checkout ) {
$issues[] = 'Account creation during checkout.';
}
if ( ! empty( $issues ) ) {
$settings_url = admin_url( 'admin.php?page=wc-settings&tab=account' );
$list_html = '';
foreach ( $issues as $issue ) {
$list_html .= '
' . $issue . '';
}
$requirement_html = '' .
'
To ensure Subscriptions guest checkout functions correctly, please enable the following settings in WooCommerce. ' .
'Click here to go to the settings.
' .
'
';
echo wp_kses_post( $requirement_html );
}
if ( $account_after_checkout ) {
$settings_url = admin_url( 'admin.php?page=wc-settings&tab=account' );
$requirement_html = '' .
'
Enabling Account creation after checkout in WooCommerce settings may lead to issues with subscription orders for guest users.
' .
'
It\'s recommended to disable this option for optimal functionality with Subscriptions. Click here to go to the settings.
';
echo wp_kses_post( $requirement_html );
}
}
/**
* Validate guest checkout.
*/
public function validate_guest_checkout() {
if ( ! $this->is_subs_and_guest_checkout_allowed() ) {
wc_add_notice( __( 'You are trying to buy a subscription. You must be logged in to continue.', 'subscription' ), 'error' );
return;
}
}
/**
* Validate guest checkout on storeAPI.
*
* @param \WP_Error $errors Errors object.
* @return \WP_Error
*/
public function validate_guest_checkout_storeapi( $errors ) {
if ( ! $this->is_subs_and_guest_checkout_allowed() ) {
$errors->add( 'wp_subscription_login_required', __( 'You are trying to buy a subscription. You must be logged in to continue.', 'subscription' ) );
return $errors;
}
}
/**
* Enforce account creation in checkout.
*/
public function require_account_creation() {
if ( is_user_logged_in() || ! self::is_guest_checkout_allowed() ) {
return;
}
// Check cart for subscriptions.
$cart_have_subscription = false;
if ( function_exists( 'WC' ) ) {
$cart_items = WC()->cart->get_cart();
$recurrs = Helper::get_recurrs_from_cart( $cart_items );
$cart_have_subscription = count( $recurrs ) > 0;
}
if ( ! $cart_have_subscription ) {
return;
}
// phpcs:ignore WordPress.Security.NonceVerification
$is_create_account = isset( $_POST['createaccount'] ) ? (bool) sanitize_text_field( wp_unslash( $_POST['createaccount'] ) ) : false;
$is_login_enforced = self::is_guest_login_enforced();
if ( $is_login_enforced && ! $is_create_account ) {
wc_add_notice(
wp_kses_post(
__( 'You are ordering a subscription product. You must be either logged in or check the "Create an account" option to continue the checkout.', 'subscription' )
),
'error'
);
}
}
/**
* Enforce account creation in Store API checkout.
*
* @param WC_Order $order Order object.
* @param WP_REST_Request $request Request object.
*
* @throws \WC_Data_Exception If account creation is required but not selected.
*/
public function require_account_creation_store_api( $order, $request ) {
if ( is_user_logged_in() || ! self::is_guest_checkout_allowed() ) {
return;
}
$is_subscription_order = Helper::order_has_subscription_item( $order );
if ( ! $is_subscription_order ) {
return;
}
$request_body = $request->get_json_params();
$is_create_account = $request_body['create_account'] ?? false;
$is_login_enforced = self::is_guest_login_enforced();
if ( $is_login_enforced && ! $is_create_account ) {
throw new \WC_Data_Exception(
'wp_subscription_account_required',
wp_kses_post(
__( 'You are ordering a subscription product. You must be either logged in or check the "Create an account" option to continue the checkout.', 'subscription' )
),
400
);
}
}
/**
* Build user info from order or customer object.
*
* @param \WC_Order|\WC_Customer $order_or_customer Order or Customer object.
*/
public function build_user_info( $order_or_customer ): array {
$user_info = [];
// Billing info.
$user_info['billing_first_name'] = $order_or_customer->get_billing_first_name();
$user_info['billing_last_name'] = $order_or_customer->get_billing_last_name();
$user_info['billing_company'] = $order_or_customer->get_billing_company();
$user_info['billing_address_1'] = $order_or_customer->get_billing_address_1();
$user_info['billing_address_2'] = $order_or_customer->get_billing_address_2();
$user_info['billing_city'] = $order_or_customer->get_billing_city();
$user_info['billing_postcode'] = $order_or_customer->get_billing_postcode();
$user_info['billing_country'] = $order_or_customer->get_billing_country();
$user_info['billing_state'] = $order_or_customer->get_billing_state();
$user_info['billing_email'] = $order_or_customer->get_billing_email();
$user_info['billing_phone'] = $order_or_customer->get_billing_phone();
// Shipping info.
$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'];
$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'];
$user_info['shipping_company'] = ! empty( $order_or_customer->get_shipping_company() ) ? $order_or_customer->get_shipping_company() : $user_info['billing_company'];
$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'];
$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'];
$user_info['shipping_city'] = ! empty( $order_or_customer->get_shipping_city() ) ? $order_or_customer->get_shipping_city() : $user_info['billing_city'];
$user_info['shipping_postcode'] = ! empty( $order_or_customer->get_shipping_postcode() ) ? $order_or_customer->get_shipping_postcode() : $user_info['billing_postcode'];
$user_info['shipping_country'] = ! empty( $order_or_customer->get_shipping_country() ) ? $order_or_customer->get_shipping_country() : $user_info['billing_country'];
$user_info['shipping_state'] = ! empty( $order_or_customer->get_shipping_state() ) ? $order_or_customer->get_shipping_state() : $user_info['billing_state'];
$user_info['shipping_phone'] = ! empty( $order_or_customer->get_shipping_phone() ) ? $order_or_customer->get_shipping_phone() : $user_info['billing_phone'];
return $user_info;
}
/**
* Maybe create user from user info.
*
* @param array $user_info User info array.
*/
public function maybe_create_user( $user_info ): ?int {
// Don't proceed if guest checkout is not allowed.
$is_guest_checkout_allowed = in_array( get_option( 'wp_subscription_allow_guest_checkout', '0' ), [ 1, '1', 'yes', 'on' ], true );
if ( ! $is_guest_checkout_allowed ) {
return null;
}
$is_new_customer = false;
// Check if user exists with email.
$user = get_user_by( 'email', $user_info['billing_email'] );
$user_id = $user ? $user->ID : 0;
if ( ! $user_id ) {
$is_new_customer = true;
// Not wp_insert_user(): without a `user_pass` it stores wp_hash_password( '' ).
$user_id = wc_create_new_customer(
$user_info['billing_email'],
'',
'',
[
'first_name' => $user_info['billing_first_name'],
'last_name' => $user_info['billing_last_name'],
'source' => 'subscrpt-guest-checkout',
]
);
if ( is_wp_error( $user_id ) ) {
subscrpt_write_log( 'Failed to auto-create user during checkout. Error: ' . $user_id->get_error_message() );
return null;
}
// Set billing info.
update_user_meta( $user_id, 'billing_first_name', $user_info['billing_first_name'] );
update_user_meta( $user_id, 'billing_last_name', $user_info['billing_last_name'] );
update_user_meta( $user_id, 'billing_company', $user_info['billing_company'] );
update_user_meta( $user_id, 'billing_address_1', $user_info['billing_address_1'] );
update_user_meta( $user_id, 'billing_address_2', $user_info['billing_address_2'] );
update_user_meta( $user_id, 'billing_city', $user_info['billing_city'] );
update_user_meta( $user_id, 'billing_postcode', $user_info['billing_postcode'] );
update_user_meta( $user_id, 'billing_country', $user_info['billing_country'] );
update_user_meta( $user_id, 'billing_state', $user_info['billing_state'] );
update_user_meta( $user_id, 'billing_email', $user_info['billing_email'] );
update_user_meta( $user_id, 'billing_phone', $user_info['billing_phone'] );
// Set shipping info.
update_user_meta( $user_id, 'shipping_first_name', $user_info['shipping_first_name'] );
update_user_meta( $user_id, 'shipping_last_name', $user_info['shipping_last_name'] );
update_user_meta( $user_id, 'shipping_company', $user_info['shipping_company'] );
update_user_meta( $user_id, 'shipping_address_1', $user_info['shipping_address_1'] );
update_user_meta( $user_id, 'shipping_address_2', $user_info['shipping_address_2'] );
update_user_meta( $user_id, 'shipping_city', $user_info['shipping_city'] );
update_user_meta( $user_id, 'shipping_postcode', $user_info['shipping_postcode'] );
update_user_meta( $user_id, 'shipping_country', $user_info['shipping_country'] );
update_user_meta( $user_id, 'shipping_state', $user_info['shipping_state'] );
update_user_meta( $user_id, 'shipping_phone', $user_info['shipping_phone'] );
}
// Auto-login the newly created account so the subscription can be associated with the user.
// This ONLY runs when $is_new_customer is true — i.e. when wp_insert_user() succeeded
// just above in this same request. It never fires for returning/existing users.
// wc_set_customer_auth_cookie() is the WooCommerce-sanctioned way to log a customer in
// during checkout; wp_set_auth_cookie() is the WP fallback if WC is not available.
if ( ! is_user_logged_in() && $is_new_customer && $user_id ) {
wp_set_current_user( $user_id );
if ( function_exists( 'wc_set_customer_auth_cookie' ) ) {
wc_set_customer_auth_cookie( $user_id );
} else {
wp_set_auth_cookie( $user_id );
}
subscrpt_write_debug_log( 'Auto-logged in newly created user ID: ' . $user_id . ' after checkout.' );
}
return $user_id;
}
/**
* Auto-create a guest account only while login is not enforced.
*
* @return bool
*/
protected function should_auto_create_account() {
return self::is_guest_checkout_allowed() && ! self::is_guest_login_enforced();
}
/**
* Does the current cart contain a subscription product.
*
* @return bool
*/
protected function cart_has_subscription() {
if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
return false;
}
return count( Helper::get_recurrs_from_cart( WC()->cart->get_cart() ) ) > 0;
}
/**
* Create the guest account before the order exists, for gateway customer binding.
*
* @param \WC_Customer $customer Customer object.
*
* @return void
*/
public function maybe_create_user_from_customer( $customer ) {
if ( is_user_logged_in() || ! $this->should_auto_create_account() ) {
return;
}
// Already backed by a real user.
if ( $customer->get_id() ) {
return;
}
if ( ! $this->cart_has_subscription() ) {
return;
}
$billing_email = $customer->get_billing_email();
// Cannot create an account without an email.
if ( empty( $billing_email ) ) {
return;
}
// Never $customer->set_id() + save() here: it blanks user_email.
$this->maybe_create_user( $this->build_user_info( $customer ) );
}
/**
* Assign a user to a guest subscription order, creating one if needed.
*
* @param \WC_Order $order Order object.
*
* @return void
*/
public function maybe_assign_user_to_order( $order ) {
if ( ! $this->should_auto_create_account() ) {
return;
}
if ( ! $order instanceof \WC_Order ) {
return;
}
// Don't proceed if the order already has a user.
if ( $order->get_customer_id() ) {
return;
}
if ( ! $this->cart_has_subscription() ) {
return;
}
// Reuse the user created earlier in this request when there is one.
$user_id = get_current_user_id();
if ( ! $user_id ) {
$user_info = $this->build_user_info( $order );
if ( empty( $user_info['billing_email'] ) ) {
return;
}
$user_id = $this->maybe_create_user( $user_info );
}
if ( ! $user_id ) {
return;
}
$order->set_customer_id( $user_id );
// The classic checkout hands over an unsaved order and persists it itself.
if ( $order->get_id() ) {
$order->save();
}
}
}