PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.2.6
ShopBuilder – WooCommerce Builder For Elementor v3.2.6
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
shopbuilder / app / Modules / AbandonedCartRecovery / CartActivity.php

CartActivity.php in ShopBuilder – WooCommerce Builder For Elementor 3.2.6, at app/Modules/AbandonedCartRecovery/CartActivity.php

585 lines 22.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Sticky Abandoned Cart Recovery Module Class.
4 *
5 * @package RadiusTheme\SB
6 */
7
8 namespace RadiusTheme\SB\Modules\AbandonedCartRecovery;
9
10 use RadiusTheme\SB\Helpers\Fns;
11 use RadiusTheme\SB\Traits\SingletonTrait;
12 use WC_Coupon;
13 use WC_Order;
14 use WC_Order_Item_Product;
15
16
17 defined( 'ABSPATH' ) || exit();
18
19 /**
20 * Sticky add-to-cart Module Class.
21 */
22 class CartActivity {
23 /**
24 * Singleton Trait.
25 */
26 use SingletonTrait;
27
28 /**
29 * Copy custom cart item meta 'rtsb_restored_item' to order items on checkout.
30 *
31 * @param \WC_Order_Item_Product $item The order item being created.
32 * @param string $cart_item_key Cart item key.
33 * @param array $values Cart item values.
34 */
35 public function checkout_create_order_line_item( $item, $cart_item_key, $values ) {
36 if ( ! empty( $values['rtsb_restored_item'] ) ) {
37 // Add meta to the order item.
38 $item->add_meta_data( 'rtsb_restored_item', $values['rtsb_restored_item'], true );
39 }
40 }
41 /**
42 * ReStored
43 */
44 public function before_calculate_totals() {
45 if ( did_action( 'woocommerce_before_calculate_totals' ) > 1 ) {
46 return; // Skip repeated calls.
47 }
48 // Ensure WooCommerce cart exists.
49 if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
50 return;
51 }
52 $session_id = Fns::getSession( 'rtsb_ca_session_id' );
53 $abandonment = null;
54 if ( ! empty( $session_id ) ) {
55 $abandonment = CartRecoveryDB::getCaAbandonmentBySessionId( $session_id );
56 }
57 if ( empty( $abandonment ) ) {
58 return;
59 }
60 // Split codes into array.
61 $abandonment_coupons = array_map( 'trim', explode( ',', $abandonment['coupon_code'] ) );
62 if ( empty( $abandonment_coupons ) ) {
63 return;
64 }
65 $cart = WC()->cart;
66 // Get all product IDs currently in cart.
67 $cart_product_ids = [];
68 foreach ( $cart->get_cart() as $cart_item ) {
69 $cart_product_ids[] = $cart_item['product_id'];
70 }
71 foreach ( $abandonment_coupons as $coupon_code ) {
72 $coupon = new WC_Coupon( $coupon_code );
73 // Get all meta for the coupon.
74 $coupon_id = $coupon->get_id(); // coupon post ID.
75 $coupon_abandonment = get_post_meta( $coupon_id, 'coupon_created_abandonment_id', true );
76 if ( absint( $abandonment['id'] ) !== absint( $coupon_abandonment ) ) {
77 continue;
78 }
79 // Get restricted product IDs (assigned to coupon).
80 $required_products = $coupon->get_product_ids();
81 if ( empty( $required_products ) ) {
82 continue; // No restriction → skip.
83 }
84 // Check if all required products are in the cart.
85 $all_present = ! array_diff( $required_products, $cart_product_ids );
86 if ( ! $all_present ) {
87 // Remove coupon if any required product is missing.
88 $cart->remove_coupon( $coupon_code );
89 wc_add_notice(
90 sprintf(
91 /* translators: %s: Coupon code */
92 __( 'Coupon "%s" was removed because not all eligible products are in your cart.', 'shopbuilder' ),
93 $coupon_code
94 ),
95 'notice'
96 );
97 }
98 }
99 }
100 /**
101 * Email Click Tracker
102 *
103 * @param array $data Tracker data.
104 *
105 * @return void
106 */
107 public function email_click_tracker( $data = [] ) {
108 if ( ! ( $data['click_email'] ?? false ) ) {
109 return;
110 }
111 if ( ! isset( $data['template_id'] ) ) {
112 return;
113 }
114 if ( ! isset( $data['abandonment_id'] ) ) {
115 return;
116 }
117 $template_id = absint( $data['template_id'] ?? 0 ); // phpcs:ignore WordPress.Security
118 $abandonment_id = absint( $data['abandonment_id'] ?? 0 ); // phpcs:ignore WordPress.Security
119 $exist = CartRecoveryDB::count_abandonment_by_meta_value( $abandonment_id, 'clicked_email_template_id', $template_id );
120 if ( ! $exist ) {
121 CartRecoveryDB::add_ca_abandonment_meta( $abandonment_id, 'clicked_email_template_id', $template_id );
122 $email_send_count = CartRecoveryDB::get_email_template_meta( $template_id, 'email_click_count', 0 );
123 $count = absint( $email_send_count ) + 1;
124 CartRecoveryDB::update_email_template_meta( $template_id, 'email_click_count', $count );
125 }
126 }
127 /**
128 * @return void
129 */
130 public function email_open_tracker() {
131 $request_uri = $_SERVER['REQUEST_URI'] ?? ''; // phpcs:ignore WordPress.Security
132 if ( ! is_string( $request_uri ) || strpos( $request_uri, '/rtsb-ca-email-open/' ) === false ) {
133 return;
134 }
135 $template_id = absint( $_GET['template_id'] ?? 0 ); // phpcs:ignore WordPress.Security
136 $abandonment_id = absint( $_GET['abandonment_id'] ?? 0 ); // phpcs:ignore WordPress.Security
137 if ( ! $template_id || ! $abandonment_id ) {
138 return;
139 }
140 $exist = CartRecoveryDB::getCaAbandonmentByID( $abandonment_id );
141 if ( empty( $exist ) ) {
142 return;
143 }
144 $history_id = absint( $_GET['history_id'] ?? 0 ); // phpcs:ignore WordPress.Security
145 CartRecoveryDB::update_scheduled_email_history( $history_id, [ 'open_time' => gmdate( 'Y-m-d H:i:s', Fns::currentTimestampUTC() ) ] );
146 $opened_data = CartRecoveryDB::get_abandonment_meta( $abandonment_id, 'email_opened_data', [] );
147 $opened_data = maybe_unserialize( $opened_data );
148 // Check if template_id exists without foreach.
149 $exists = is_array( $opened_data ) && in_array( $template_id, array_column( $opened_data, 'template_id' ) ); // phpcs:ignore WordPress.PHP.StrictInArray
150 if ( $exists ) {
151 return;
152 }
153 if ( $history_id ) {
154 CartRecoveryDB::update_scheduled_email_history( $history_id, [ 'action' => 'Opened' ] );
155 }
156 $email_open_data = [
157 'time' => gmdate( 'Y-m-d H:i:s', Fns::currentTimestampUTC() ),
158 'template_id' => $template_id,
159 ];
160 if ( $abandonment_id ) {
161 if ( ! empty( $opened_data ) ) {
162 $opened_data[] = $email_open_data;
163 } else {
164 $opened_data = [ $email_open_data ];
165 }
166 CartRecoveryDB::update_ca_abandonment_meta( $abandonment_id, 'email_opened_data', $opened_data );
167 }
168
169 $email_send_count = CartRecoveryDB::get_email_template_meta( $template_id, 'email_send_total', 0 );
170 if ( ! $email_send_count ) {
171 CartRecoveryDB::update_email_template_meta( $template_id, 'email_send_total', 1 );
172 }
173 $email_opened_count = CartRecoveryDB::get_email_template_meta( $template_id, 'email_opened_count', 0 );
174 $count = absint( $email_opened_count ) + 1;
175 CartRecoveryDB::update_email_template_meta( $template_id, 'email_opened_count', $count );
176 }
177 /**
178 * Retrieves the order metadata and formats it.
179 *
180 * @param array $formatted_meta The formatted meta data.
181 *
182 * @return array
183 */
184 public function get_order_meta( $formatted_meta ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
185 foreach ( $formatted_meta as $key => $meta ) {
186 if ( 'rtsb_restored_item' === $meta->key ) {
187 if ( is_admin() ) {
188 $meta->display_key = '<span class="rtsb-order-meta"><span class="wc-item-meta-label rtsb-stock-text">' . esc_html__( 'Recovered Item', 'shopbuilder' ) . '</span></span>';
189 $meta->display_value = esc_html__( 'Yes', 'shopbuilder' );
190 } else {
191 unset( $formatted_meta[ $key ] );
192 }
193 }
194 }
195 return $formatted_meta;
196 }
197 /**
198 * Delete abandoned cart data when order is completed or processing
199 *
200 * @param int $order_id Order ID.
201 * @param string $old_status Previous order status.
202 * @param string $new_status New order status.
203 * @param WC_Order $order Order object.
204 */
205 public function cart_abandonment_on_status_change( $order_id, $old_status, $new_status, $order ) {
206 // Only act if status changed to 'completed' or 'processing'.
207 if ( ! in_array( $new_status, [ 'completed', 'processing' ], true ) ) {
208 return;
209 }
210 // Get session ID if available.
211 $session_id = Fns::getSession( 'rtsb_ca_session_id' );
212 $abandonment = null;
213 if ( ! is_admin() && ! empty( $session_id ) ) {
214 $abandonment = CartRecoveryDB::getCaAbandonmentBySessionId( $session_id );
215 }
216 $email = $order->get_billing_email();
217 if ( ! $abandonment ) {
218 $abandonment = CartRecoveryDB::getCaAbandonmentByEmail( $email );
219 }
220 if ( ! $abandonment ) {
221 return;
222 }
223 if ( ! empty( $session_id ) ) {
224 $abandonment = CartRecoveryDB::getCaAbandonmentBySessionId( $session_id );
225 if ( ! empty( $abandonment['id'] ) ) {
226 CartRecoveryDB::updateCaAbandonmentById( $abandonment['id'], [ 'order_status' => 'completed' ] );
227 $time = gmdate( 'Y-m-d H:i:s', Fns::currentTimestampUTC() );
228 CartRecoveryDB::update_ca_abandonment_meta( $abandonment['id'], 'completed_time', $time );
229 CartRecoveryDB::delete_unnecessery_email_history_for_abandonment( $abandonment['id'] );
230 CartRecoveryDB::delete_abandonment_meta( $abandonment['id'], 'lost_time' );
231 }
232 $notifyToAdmin = 'on' === CartRecoveryFns::get_options( 'notify_recovery_to_admin', 'on' );
233 if ( ! empty( $abandonment['id'] ) && $notifyToAdmin ) {
234 $recovery_email = RecoveryEmail::instance();
235 $recovery_email->send_recovery_notice_to_admin( $order );
236 }
237 }
238 // Delete normal abandoned cart records for this email.
239 if ( $email ) {
240 CartRecoveryDB::deleteNormalAbandonedByEmail( $email );
241 }
242 $history_id = Fns::getSession( 'rtsb_ca_email_history_id' );
243 if ( $history_id ) {
244 CartRecoveryDB::update_scheduled_email_history( $history_id, [ 'action' => 'Completed' ] );
245 }
246 }
247
248 /**
249 * @return void
250 */
251 public function unsubscribe_cart_from_abandonment() {
252 $unsubscribe_key = wp_unslash( $_GET['rtsbUnsubscribe'] ?? '' ); // phpcs:ignore WordPress.Security
253 if ( empty( $unsubscribe_key ) ) {
254 return;
255 }
256 if ( Fns::getSession( 'unsubscribed_abandonment_unsubscribe_key' ) === $unsubscribe_key ) { // Protect against malicious or unauthorized requests.
257 return;
258 }
259 $decoded = Fns::decode_signed_key( $unsubscribe_key );
260 if ( ! $decoded ) {
261 return; // Invalid or tampered key.
262 }
263 if ( empty( $decoded['unsubscribe'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
264 return;
265 }
266 if ( empty( $decoded['template_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
267 return;
268 }
269
270 $abandonment_id = absint( $decoded['unsubscribe'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
271 $template_id = absint( $decoded['template_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
272 $unsubscribed = CartRecoveryDB::count_email_template_by_meta_value( $template_id, 'unsubscribed_abandonment_id', $abandonment_id );
273 if ( ! empty( $unsubscribed ) ) {
274 return;
275 }
276 $this->email_click_tracker(
277 [
278 'click_email' => true,
279 'template_id' => $template_id,
280 'abandonment_id' => $abandonment_id,
281 ]
282 );
283 CartRecoveryFns::unsebscribe( $abandonment_id );
284 $unsubscribed_count = absint( CartRecoveryDB::get_email_template_meta( $template_id, 'unsubscribed_count', 0 ) );
285 $unsubscribed_count = ++$unsubscribed_count;
286 CartRecoveryDB::update_email_template_meta( $template_id, 'unsubscribed_count', $unsubscribed_count );
287 CartRecoveryDB::add_email_template_meta( $template_id, 'unsubscribed_abandonment_id', $abandonment_id );
288 Fns::removeSession( 'unsubscribed_abandonment_unsubscribe_key' );
289 Fns::setSession( 'unsubscribed_abandonment_unsubscribe_key', $unsubscribe_key );
290 // �
291 Add success notice
292 wc_add_notice( __( 'Your has been successfully unsubscribed.', 'shopbuilder' ), 'success' );
293 $url = get_permalink( CartRecoveryFns::get_options( 'unsubscribe_page', 0 ) ) ?: home_url();
294 if ( ! empty( $decoded['history_id'] ) ) {
295 CartRecoveryDB::update_scheduled_email_history( $decoded['history_id'], [ 'action' => 'Unsubscribe' ] );
296 }
297 wp_safe_redirect( $url );
298 exit;
299 }
300
301 /**
302 * @param array $abandonment Single abandonment records.
303 * @return void
304 */
305 private function prepare_checkout_form_data( $abandonment ) {
306 $fields = $abandonment['other_fields'] ?? [];
307 if ( ! empty( $abandonment['email'] ) ) {
308 WC()->customer->set_billing_email( $abandonment['email'] );
309 }
310 if ( ! empty( $fields['store_api_draft_order'] ) ) {
311 WC()->session->set( 'store_api_draft_order', $fields['store_api_draft_order'] );
312 }
313 if ( ! empty( $fields['billing_first_name'] ) ) {
314 WC()->customer->set_billing_first_name( $fields['billing_first_name'] );
315 }
316 if ( ! empty( $fields['billing_last_name'] ) ) {
317 WC()->customer->set_billing_last_name( $fields['billing_last_name'] );
318 }
319 if ( ! empty( $fields['billing_company'] ) ) {
320 WC()->customer->set_billing_company( $fields['billing_company'] );
321 }
322 if ( ! empty( $fields['billing_phone'] ) ) {
323 WC()->customer->set_billing_phone( $fields['billing_phone'] );
324 }
325 if ( ! empty( $fields['billing_address_1'] ) ) {
326 WC()->customer->set_billing_address_1( $fields['billing_address_1'] );
327 }
328 if ( ! empty( $fields['billing_address_2'] ) ) {
329 WC()->customer->set_billing_address_2( $fields['billing_address_2'] );
330 }
331 if ( ! empty( $fields['billing_city'] ) ) {
332 WC()->customer->set_billing_city( $fields['billing_city'] );
333 }
334 if ( ! empty( $fields['billing_postcode'] ) ) {
335 WC()->customer->set_billing_postcode( $fields['billing_postcode'] );
336 }
337 if ( ! empty( $fields['billing_state'] ) ) {
338 WC()->customer->set_billing_state( $fields['billing_state'] );
339 }
340 if ( ! empty( $fields['billing_country'] ) ) {
341 WC()->customer->set_billing_country( $fields['billing_country'] );
342 }
343 // Shipping fields.
344 if ( ! empty( $fields['shipping_first_name'] ) ) {
345 WC()->customer->set_shipping_first_name( $fields['shipping_first_name'] );
346 }
347 if ( ! empty( $fields['shipping_last_name'] ) ) {
348 WC()->customer->set_shipping_last_name( $fields['shipping_last_name'] );
349 }
350 if ( ! empty( $fields['shipping_company'] ) ) {
351 WC()->customer->set_shipping_company( $fields['shipping_company'] );
352 }
353 if ( ! empty( $fields['shipping_address_1'] ) ) {
354 WC()->customer->set_shipping_address_1( $fields['shipping_address_1'] );
355 }
356 if ( ! empty( $fields['shipping_address_2'] ) ) {
357 WC()->customer->set_shipping_address_2( $fields['shipping_address_2'] );
358 }
359 if ( ! empty( $fields['shipping_city'] ) ) {
360 WC()->customer->set_shipping_city( $fields['shipping_city'] );
361 }
362 if ( ! empty( $fields['shipping_postcode'] ) ) {
363 WC()->customer->set_shipping_postcode( $fields['shipping_postcode'] );
364 }
365 if ( ! empty( $fields['shipping_state'] ) ) {
366 WC()->customer->set_shipping_state( $fields['shipping_state'] );
367 }
368 if ( ! empty( $fields['shipping_country'] ) ) {
369 WC()->customer->set_shipping_country( $fields['shipping_country'] );
370 }
371 // Payment method.
372 if ( ! empty( $fields['payment_method'] ) ) {
373 WC()->session->set( 'chosen_payment_method', $fields['payment_method'] );
374 }
375 }
376 /**
377 * @return void
378 */
379 public function restore_cart_from_abandonment() {
380 $this->email_open_tracker();
381 if ( ! is_checkout() ) {
382 return;
383 }
384 $restore_key = wp_unslash( $_GET['rtsbRestoreCart'] ?? '' ); // phpcs:ignore WordPress.Security
385 if ( empty( $restore_key ) ) {
386 return;
387 }
388 // Clear current cart first.
389 WC()->cart->empty_cart();
390 $decoded = Fns::decode_signed_key( $restore_key );
391 if ( ! $decoded ) {
392 return;
393 }
394 if ( empty( $decoded['restore_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
395 return;
396 }
397 $history_id = absint( $decoded['history_id'] ?? 0 );
398 Fns::setSession( 'rtsb_ca_email_history_id', $history_id );
399 $abandonment_id = absint( $decoded['restore_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
400 $template_id = absint( $decoded['template_id'] ?? 0 ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
401 $abandonment = CartRecoveryDB::getCaAbandonmentByID( $abandonment_id );
402 // Get abandoned cart data (replace this with your own retrieval method).
403 $abandoned_cart = maybe_unserialize( $abandonment['cart_contents'] ?? [] );
404 if ( empty( $abandoned_cart ) ) {
405 return;
406 }
407 if ( 'completed' === $abandonment['order_status'] ) {
408 wc_add_notice( __( 'You have already completed this order.', 'shopbuilder' ), 'notice' );
409 return;
410 }
411 $this->email_click_tracker(
412 [
413 'click_email' => true,
414 'template_id' => $template_id,
415 'abandonment_id' => $abandonment_id,
416 ]
417 );
418 Fns::removeSession( 'rtsb_ca_session_id' );
419 Fns::setSession( 'rtsb_ca_session_id', $abandonment['ca_session_id'] );
420 foreach ( $abandoned_cart as $cart_item ) {
421 $product_id = $cart_item['product_id'];
422 $quantity = $cart_item['quantity'];
423 $variation_id = ! empty( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : 0;
424 $variation = ! empty( $cart_item['variation'] ) ? $cart_item['variation'] : [];
425 $cart_item_data = [
426 'rtsb_restored_item' => $abandonment['email'],
427 ];
428 WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation, $cart_item_data );
429 }
430 $this->prepare_checkout_form_data( $abandonment );
431 $template = $template_id ? CartRecoveryDB::getTemplateById( $template_id ) : [];
432 if ( ! empty( $template ) && ! empty( $template['coupon_auto_apply'] ) ) {
433 $history = CartRecoveryDB::get_history_by_id( $decoded['history_id'] );
434 $coupon_code = $history['coupon_code'] ?? $abandonment['coupon_code'];
435 CartRecoveryDB::updateCaAbandonmentById( $abandonment['id'], [ 'coupon_code' => $coupon_code ] );
436 WC()->cart->apply_coupon( $coupon_code );
437 }
438 $history_id = Fns::getSession( 'rtsb_ca_email_history_id' );
439 if ( $history_id ) {
440 CartRecoveryDB::update_scheduled_email_history( $history_id, [ 'action' => 'Restored' ] );
441 }
442 // �
443 Add success notice.
444 wc_add_notice( __( 'Your cart has been successfully restored.', 'shopbuilder' ), 'success' );
445 wp_safe_redirect( wc_get_checkout_url() );
446 exit;
447 }
448 /**
449 * @return void
450 */
451 public function abandoned_cart_update() {
452 if ( ! wp_verify_nonce( Fns::get_nonce(), rtsb()->nonceText ) ) {
453 return;
454 }
455 $disabled_roles = CartRecoveryFns::get_options( 'disable_tracking_roles', [] );
456 // Get current user.
457 $current_user = wp_get_current_user();
458 // If the user has any of the disabled roles, stop.
459 if ( array_intersect( $current_user->roles, $disabled_roles ) ) {
460 return;
461 }
462 $cart_total = WC()->cart->total;
463 $items_count = WC()->cart->get_cart_contents_count(); // Total items including quantities.
464
465 $session_id = isset( $_POST['sessionId'] ) ? sanitize_text_field( wp_unslash( $_POST['sessionId'] ) ) : '';
466 $user_email = isset( $_POST['email'] ) ? sanitize_text_field( wp_unslash( $_POST['email'] ) ) : '';
467 if ( empty( $session_id ) ) {
468 $return = [
469 'message' => esc_html__( 'Session Missing', 'shopbuilder' ),
470 ];
471 wp_send_json_success( $return );
472 }
473 Fns::removeSession( 'rtsb_ca_session_id' );
474 Fns::setSession( 'rtsb_ca_session_id', $session_id );
475 $draft_order_id = WC()->session->get( 'store_api_draft_order' );
476 $other_fields = [
477 'first_name' => sanitize_text_field( wp_unslash( $_POST['first_name'] ?? '' ) ),
478 'last_name' => sanitize_text_field( wp_unslash( $_POST['last_name'] ?? '' ) ),
479 'item_count' => $items_count,
480 'draft_order_id' => $draft_order_id,
481 ];
482
483 $order = false;
484 if ( ! empty( $draft_order_id ) ) {
485 $order = wc_get_order( $draft_order_id );
486 }
487 if ( $order ) {
488 // Billing fields.
489 $billing_data = [
490 'billing_first_name' => $order->get_billing_first_name(),
491 'billing_last_name' => $order->get_billing_last_name(),
492 'billing_email' => $order->get_billing_email(),
493 'billing_phone' => $order->get_billing_phone(),
494 'billing_company' => $order->get_billing_company(),
495 'billing_address_1' => $order->get_billing_address_1(),
496 'billing_address_2' => $order->get_billing_address_2(),
497 'billing_city' => $order->get_billing_city(),
498 'billing_state' => $order->get_billing_state(),
499 'billing_postcode' => $order->get_billing_postcode(),
500 'billing_country' => $order->get_billing_country(),
501 'shipping_first_name' => $order->get_shipping_first_name(),
502 'shipping_last_name' => $order->get_shipping_last_name(),
503 'shipping_company' => $order->get_shipping_company(),
504 'shipping_address_1' => $order->get_shipping_address_1(),
505 'shipping_address_2' => $order->get_shipping_address_2(),
506 'shipping_city' => $order->get_shipping_city(),
507 'shipping_state' => $order->get_shipping_state(),
508 'shipping_postcode' => $order->get_shipping_postcode(),
509 'shipping_country' => $order->get_shipping_country(),
510 'payment_method' => $order->get_payment_method(),
511 ];
512 // Merge both if needed.
513 $other_fields = array_merge( $other_fields, $billing_data );
514 }
515
516 $other_fields['full_name'] = $other_fields['first_name'] . ' ' . $other_fields['last_name'];
517 // Verify if email is already exists.
518 $session_checkout_details = CartRecoveryDB::getCaAbandonmentBySessionId( $session_id );
519 if ( empty( $session_checkout_details ) ) {
520 $session_checkout_details = CartRecoveryDB::getCaAbandonmentByEmail( $user_email );
521 if ( ! empty( $session_checkout_details['ca_session_id'] ) ) {
522 $session_id = $session_checkout_details['ca_session_id'];
523 Fns::setSession( 'rtsb_ca_session_id', $session_id );
524 }
525 }
526
527 $cart_items = [];
528
529 foreach ( WC()->cart->get_cart() as $cart_item_key => $item ) {
530 $product = $item['data']; // WC_Product object.
531 $cart_items[ $cart_item_key ] = [
532 'name' => $product->get_name(),
533 'image_url' => wp_get_attachment_url( $product->get_image_id() ),
534 'product_id' => $item['product_id'],
535 'variation_id' => $item['variation_id'],
536 'variation' => $item['variation'],
537 'quantity' => $item['quantity'],
538 'line_total' => $item['line_total'],
539 ];
540 }
541
542 // Get applied coupons from cart.
543 $applied_coupons = WC()->cart->get_applied_coupons();
544 $coupon_code = ! empty( $applied_coupons ) ? implode( ', ', $applied_coupons ) : '';
545
546 $checkout_details = [
547 'cart_contents' => $cart_items,
548 'cart_total' => $cart_total ,
549 'other_fields' => $other_fields ,
550 'order_status' => 'normal',
551 'unsubscribed' => 0,
552 'checkout_id' => wc_get_page_id( 'checkout' ), // I don't know what is this for.
553 'coupon_code' => $coupon_code,
554 'email' => $user_email,
555 'ca_session_id' => $session_id,
556 'time' => gmdate( 'Y-m-d H:i:s', Fns::currentTimestampUTC() ),
557 ];
558 $checkout_details = apply_filters( 'rtsb/ca/abandoned/data', $checkout_details );
559 $status = false;
560 if ( $checkout_details['cart_total'] > 0 ) {
561 if ( ! empty( $session_checkout_details ) && in_array( $session_checkout_details['order_status'], [ 'normal' ,'abandoned' ], true ) ) {
562 unset(
563 $checkout_details['ca_session_id'],
564 $checkout_details['order_status'],
565 );
566 if ( 'normal' !== $session_checkout_details['order_status'] ) {
567 unset(
568 $checkout_details['cart_contents'],
569 $checkout_details['time']
570 );
571 }
572 $status = CartRecoveryDB::updateCaAbandonmentBySessionId( $session_id, $checkout_details );
573 } elseif ( empty( $session_checkout_details['order_status'] ) ) {
574 $status = CartRecoveryDB::insertCaAbandonment( $checkout_details );
575 }
576 } else {
577 $status = CartRecoveryDB::deleteCaAbandonmentBySessionId( $session_id );
578 }
579 $return = [
580 'message' => $status ? esc_html__( 'Abandoned cart updated successfully...', 'shopbuilder' ) : esc_html__( 'Abandoned cart updated failed...', 'shopbuilder' ),
581 ];
582 wp_send_json_success( $return );
583 }
584 }
585