PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 1.10.2
Subscriptions for WooCommerce with Stripe Recurring Payments v1.10.2
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 1.4.1 1.4.2 1.5.0 1.5.1 All 61 releases
subscription / includes / Frontend / Checkout.php

Checkout.php in Subscriptions for WooCommerce with Stripe Recurring Payments 1.10.2, at includes/Frontend/Checkout.php

372 lines 14.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Checkout handlers for subscription plugin.
4 *
5 * @package wp_subscription
6 */
7
8 namespace SpringDevs\Subscription\Frontend;
9
10 use SpringDevs\Subscription\Illuminate\Helper;
11 use SpringDevs\Subscription\Illuminate\Subscription\Subscription;
12
13 /**
14 * Checkout class
15 */
16 class Checkout {
17
18 /**
19 * Initialize the class
20 */
21 public function __construct() {
22 // Subscription upgrade/downgrade order created hook.
23 add_action( 'woocommerce_checkout_order_processed', [ $this, 'trigger_subscription_switch_order_created' ] );
24 add_action( 'woocommerce_store_api_checkout_order_processed', [ $this, 'trigger_subscription_switch_order_created_storeapi' ] );
25
26 add_action( 'woocommerce_checkout_order_processed', [ $this, 'create_subscription_after_checkout' ] );
27 add_action( 'woocommerce_store_api_checkout_order_processed', [ $this, 'create_subscription_after_checkout_storeapi' ] );
28 add_action( 'woocommerce_resume_order', [ $this, 'remove_subscriptions' ] );
29 add_action( 'woocommerce_checkout_create_order_line_item', [ $this, 'save_order_item_product_meta' ], 10, 3 );
30 }
31
32 /**
33 * Create subscription during checkout on storeAPI.
34 *
35 * @param \WC_Order $order Order Object.
36 */
37 public function create_subscription_after_checkout_storeapi( $order ) {
38 $this->create_subscription_after_checkout( $order->get_id() );
39 }
40
41 /**
42 * Create subscription during checkout.
43 *
44 * @param int $order_id Order ID.
45 */
46 public function create_subscription_after_checkout( $order_id ) {
47 $order = wc_get_order( $order_id );
48
49 // Grab the post status based on order status.
50 $post_status = 'active';
51 switch ( $order->get_status() ) {
52 case 'on-hold':
53 case 'pending':
54 $post_status = 'pending';
55 break;
56
57 case 'failed':
58 case 'cancelled':
59 $post_status = 'cancelled';
60 break;
61
62 default:
63 break;
64 }
65
66 // Create subscription for order items.
67 $order_items = $order->get_items();
68 foreach ( $order_items as $order_item ) {
69 $product = Subscription::get_subs_product( $order_item['product_id'] );
70
71 if ( $product->is_type( 'simple' ) && ! subscrpt_pro_activated() ) {
72 if ( $product->is_enabled() ) {
73 $is_renew = isset( $order_item['renew_subscrpt'] );
74
75 $timing_option = $product->get_timing_option();
76 $trial = $product->get_trial();
77
78 wc_update_order_item_meta(
79 $order_item->get_id(),
80 '_subscrpt_meta',
81 array(
82 'time' => 1,
83 'type' => $timing_option,
84 'trial' => $trial,
85 )
86 );
87
88 // Renew subscription if need!
89 $renew_subscription_id = Helper::subscription_exists( $product->get_id(), 'expired' );
90 $selected_subscription_id = null;
91 if ( $is_renew && $renew_subscription_id && 'cancelled' !== $post_status ) {
92 $selected_subscription_id = $renew_subscription_id;
93 Helper::process_order_renewal( $selected_subscription_id, $order_id, $order_item->get_id() );
94 } else {
95 $selected_subscription_id = Helper::process_new_subscription_order( $order_item, $post_status, $product );
96 }
97
98 if ( $selected_subscription_id ) {
99 // product related.
100 update_post_meta( $selected_subscription_id, '_subscrpt_timing_option', $timing_option );
101 update_post_meta( $selected_subscription_id, '_subscrpt_price', $product->get_price() );
102 update_post_meta( $selected_subscription_id, '_subscrpt_user_cancel', $product->get_meta( '_subscrpt_user_cancel' ) );
103
104 // order related.
105 update_post_meta( $selected_subscription_id, '_subscrpt_order_id', $order_id );
106 update_post_meta( $selected_subscription_id, '_subscrpt_order_item_id', $order_item->get_id() );
107
108 // subscription related.
109 update_post_meta( $selected_subscription_id, '_subscrpt_trial', $trial );
110
111 do_action( 'subscrpt_order_checkout', $selected_subscription_id, $order_item );
112 }
113 }
114 }
115
116 do_action( 'subscrpt_product_checkout', $order_item, $product, $post_status );
117 }
118 }
119
120 /**
121 * Build user info from order or customer object.
122 *
123 * @param \WC_Order|\WC_Customer $order_or_customer Order or Customer object.
124 */
125 public function build_user_info( $order_or_customer ): array {
126 $user_info = [];
127
128 // Billing info.
129 $user_info['billing_first_name'] = $order_or_customer->get_billing_first_name();
130 $user_info['billing_last_name'] = $order_or_customer->get_billing_last_name();
131 $user_info['billing_company'] = $order_or_customer->get_billing_company();
132 $user_info['billing_address_1'] = $order_or_customer->get_billing_address_1();
133 $user_info['billing_address_2'] = $order_or_customer->get_billing_address_2();
134 $user_info['billing_city'] = $order_or_customer->get_billing_city();
135 $user_info['billing_postcode'] = $order_or_customer->get_billing_postcode();
136 $user_info['billing_country'] = $order_or_customer->get_billing_country();
137 $user_info['billing_state'] = $order_or_customer->get_billing_state();
138 $user_info['billing_email'] = $order_or_customer->get_billing_email();
139 $user_info['billing_phone'] = $order_or_customer->get_billing_phone();
140
141 // Shipping info.
142 $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'];
143 $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'];
144 $user_info['shipping_company'] = ! empty( $order_or_customer->get_shipping_company() ) ? $order_or_customer->get_shipping_company() : $user_info['billing_company'];
145 $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'];
146 $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'];
147 $user_info['shipping_city'] = ! empty( $order_or_customer->get_shipping_city() ) ? $order_or_customer->get_shipping_city() : $user_info['billing_city'];
148 $user_info['shipping_postcode'] = ! empty( $order_or_customer->get_shipping_postcode() ) ? $order_or_customer->get_shipping_postcode() : $user_info['billing_postcode'];
149 $user_info['shipping_country'] = ! empty( $order_or_customer->get_shipping_country() ) ? $order_or_customer->get_shipping_country() : $user_info['billing_country'];
150 $user_info['shipping_state'] = ! empty( $order_or_customer->get_shipping_state() ) ? $order_or_customer->get_shipping_state() : $user_info['billing_state'];
151 $user_info['shipping_phone'] = ! empty( $order_or_customer->get_shipping_phone() ) ? $order_or_customer->get_shipping_phone() : $user_info['billing_phone'];
152
153 return $user_info;
154 }
155
156 /**
157 * Maybe create user from user info.
158 *
159 * @param array $user_info User info array.
160 */
161 public function maybe_create_user( $user_info ): ?int {
162 // Don't proceed if guest checkout is not allowed.
163 $is_guest_checkout_allowed = in_array( get_option( 'wp_subscription_allow_guest_checkout', '0' ), [ 1, '1', 'yes', 'on' ], true );
164 if ( ! $is_guest_checkout_allowed ) {
165 return null;
166 }
167
168 $is_new_customer = false;
169
170 // Check if user exists with email.
171 $user = get_user_by( 'email', $user_info['billing_email'] );
172 $user_id = $user ? $user->ID : 0;
173
174 if ( ! $user_id ) {
175 $is_new_customer = true;
176 $username = sanitize_user( current( explode( '@', $user_info['billing_email'] ) ), true );
177 if ( username_exists( $username ) ) {
178 $username .= '_' . wp_generate_password( 4, false );
179 }
180
181 // Create user.
182 $args = [
183 'user_login' => $username,
184 'user_email' => $user_info['billing_email'],
185 'first_name' => $user_info['billing_first_name'],
186 'last_name' => $user_info['billing_last_name'],
187 'display_name' => trim( "{$user_info['billing_first_name']} {$user_info['billing_last_name']}" ),
188 'role' => 'customer',
189 ];
190
191 $user_id = wp_insert_user( $args );
192
193 if ( is_wp_error( $user_id ) ) {
194 subscrpt_write_log( 'Failed to auto-create user during checkout. Error: ' . $user_id->get_error_message() );
195 return null;
196 }
197
198 // Set billing info.
199 update_user_meta( $user_id, 'billing_first_name', $user_info['billing_first_name'] );
200 update_user_meta( $user_id, 'billing_last_name', $user_info['billing_last_name'] );
201 update_user_meta( $user_id, 'billing_company', $user_info['billing_company'] );
202 update_user_meta( $user_id, 'billing_address_1', $user_info['billing_address_1'] );
203 update_user_meta( $user_id, 'billing_address_2', $user_info['billing_address_2'] );
204 update_user_meta( $user_id, 'billing_city', $user_info['billing_city'] );
205 update_user_meta( $user_id, 'billing_postcode', $user_info['billing_postcode'] );
206 update_user_meta( $user_id, 'billing_country', $user_info['billing_country'] );
207 update_user_meta( $user_id, 'billing_state', $user_info['billing_state'] );
208 update_user_meta( $user_id, 'billing_email', $user_info['billing_email'] );
209 update_user_meta( $user_id, 'billing_phone', $user_info['billing_phone'] );
210
211 // Set shipping info.
212 update_user_meta( $user_id, 'shipping_first_name', $user_info['shipping_first_name'] );
213 update_user_meta( $user_id, 'shipping_last_name', $user_info['shipping_last_name'] );
214 update_user_meta( $user_id, 'shipping_company', $user_info['shipping_company'] );
215 update_user_meta( $user_id, 'shipping_address_1', $user_info['shipping_address_1'] );
216 update_user_meta( $user_id, 'shipping_address_2', $user_info['shipping_address_2'] );
217 update_user_meta( $user_id, 'shipping_city', $user_info['shipping_city'] );
218 update_user_meta( $user_id, 'shipping_postcode', $user_info['shipping_postcode'] );
219 update_user_meta( $user_id, 'shipping_country', $user_info['shipping_country'] );
220 update_user_meta( $user_id, 'shipping_state', $user_info['shipping_state'] );
221 update_user_meta( $user_id, 'shipping_phone', $user_info['shipping_phone'] );
222
223 // User creation notification.
224 do_action( 'woocommerce_created_customer', $user_id, [], true );
225 }
226
227 // Auto-login the newly created account so the subscription can be associated with the user.
228 // This ONLY runs when $is_new_customer is true — i.e. when wp_insert_user() succeeded
229 // just above in this same request. It never fires for returning/existing users.
230 // wc_set_customer_auth_cookie() is the WooCommerce-sanctioned way to log a customer in
231 // during checkout; wp_set_auth_cookie() is the WP fallback if WC is not available.
232 if ( ! is_user_logged_in() && $is_new_customer && $user_id ) {
233 wp_set_current_user( $user_id );
234 if ( function_exists( 'wc_set_customer_auth_cookie' ) ) {
235 wc_set_customer_auth_cookie( $user_id );
236 } else {
237 wp_set_auth_cookie( $user_id );
238 }
239
240 // Set flag for manual login tracking.
241 set_transient( 'subscrpt_manual_login_' . $user_id, true, 15 * MINUTE_IN_SECONDS );
242
243 subscrpt_write_debug_log( 'Auto-logged in newly created user ID: ' . $user_id . ' after checkout.' );
244 }
245
246 return $user_id;
247 }
248
249 /**
250 * Maybe assign user to order.
251 *
252 * @param int $order_id Order ID.
253 */
254 public function maybe_assign_user_to_order( $order_id ) {
255 // Don't proceed if guest checkout is not allowed.
256 $is_guest_checkout_allowed = in_array( get_option( 'wp_subscription_allow_guest_checkout', '0' ), [ 1, '1', 'yes', 'on' ], true );
257 if ( ! $is_guest_checkout_allowed ) {
258 return;
259 }
260
261 $order = wc_get_order( $order_id );
262
263 // Don't proceed if order already have an user.
264 if ( $order->get_customer_id() ) {
265 return;
266 }
267
268 // Build and maybe create a user.
269 $user_info = $this->build_user_info( $order );
270 $user_id = $this->maybe_create_user( $user_info );
271
272 if ( $user_id ) {
273 $order->set_customer_id( $user_id );
274 $order->save();
275 }
276 }
277
278 /**
279 * Remove subscriptions for resumed orders.
280 *
281 * @param int $order_id Order id.
282 *
283 * @return void
284 */
285 public function remove_subscriptions( $order_id ) {
286 global $wpdb;
287 // delete subscriptions & order item meta.
288 $histories = Helper::get_subscriptions_from_order( $order_id );
289 foreach ( $histories as $history ) {
290 $table_name = $wpdb->prefix . 'subscrpt_order_relation';
291 // @phpcs:ignore
292 $relation_count = $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i WHERE subscription_id=%d', array( $table_name, $history->subscription_id ) ) );
293 if ( 1 === (int) $relation_count ) {
294 wp_delete_post( $history->subscription_id, true );
295 }
296 wc_delete_order_item_meta( $history->order_item_id, '_subscrpt_meta' );
297 }
298
299 // delete order subscription relation.
300 global $wpdb;
301 $table_name = $wpdb->prefix . 'subscrpt_order_relation';
302 // phpcs:ignore
303 $wpdb->delete( $table_name, array( 'order_id' => $order_id ), array( '%d' ) );
304 }
305
306 /**
307 * Save renew meta
308 *
309 * @param object $item Item.
310 * @param string $cart_item_key Cart Item Key.
311 * @param array $cart_item Cart Item.
312 */
313 public function save_order_item_product_meta( $item, $cart_item_key, $cart_item ) {
314 if ( isset( $cart_item['renew_subscrpt'] ) ) {
315 $item->update_meta_data( '_renew_subscrpt', $cart_item['renew_subscrpt'] );
316 }
317
318 if ( ! empty( $cart_item['wp_subs_switch'] ?? null ) && ! empty( $cart_item['switch_context'] ?? null ) ) {
319 $switch_context = $cart_item['switch_context'];
320
321 // Add switch context data to order item meta.
322 $item->update_meta_data( '_wp_subs_switch', true, true );
323 $item->update_meta_data( '_wp_subs_switch_context', $switch_context, true );
324 }
325 }
326
327 /**
328 * Trigger subscription switch order created store API.
329 *
330 * @param \WC_Order $order Order.
331 */
332 public function trigger_subscription_switch_order_created_storeapi( $order ) {
333 $this->trigger_subscription_switch_order_created( $order->get_id() ?? 0 );
334 }
335
336 /**
337 * Trigger subscription switch order created.
338 *
339 * @param int $order_id Order ID.
340 */
341 public function trigger_subscription_switch_order_created( $order_id ) {
342 if ( ! $order_id || ! subscrpt_pro_activated() ) {
343 return;
344 }
345
346 $order = wc_get_order( $order_id );
347 $order_items = $order->get_items();
348
349 foreach ( $order_items as $order_item ) {
350 $is_switch = in_array( $order_item->get_meta( '_wp_subs_switch' ), [ true, 1, '1' ], true );
351 $switch_context = $order_item->get_meta( '_wp_subs_switch_context' );
352
353 if ( $is_switch ) {
354 $switch_type = $switch_context['switch_type'] ?? 'upgrade';
355
356 unset( $switch_context['nonce'] );
357 unset( $switch_context['redirect_back_url'] );
358
359 /**
360 * Action fired when subscription switch order is created.
361 *
362 * @param string $switch_type Switch type (upgrade/downgrade).
363 * @param \WC_Order $order Order object.
364 * @param \WC_Order_Item_Product $order_item Order Item object.
365 * @param array $switch_context Switch context data. [ 'switch_type', 'subscription_id', 'order_id', 'product_id', 'old_variation_id', 'new_variation_id' ]
366 */
367 do_action( 'subscrpt_switch_order_created', $switch_type, $order, $order_item, $switch_context );
368 }
369 }
370 }
371 }
372