PluginProbe ʕ •ᴥ•ʔ
OttoKit: All-in-One Automation Platform / 1.1.35
OttoKit: All-in-One Automation Platform v1.1.35
1.1.37 1.1.36 1.1.35 1.1.34 1.1.33 1.1.32 1.1.31 1.1.30 1.1.29 1.1.28 1.1.27 1.1.9 trunk 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.20 1.0.21 1.0.22 1.0.23 1.0.24 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 1.0.39 1.0.40 1.0.41 1.0.42 1.0.43 1.0.44 1.0.45 1.0.46 1.0.47 1.0.48 1.0.49 1.0.50 1.0.51 1.0.52 1.0.53 1.0.54 1.0.55 1.0.56 1.0.57 1.0.58 1.0.59 1.0.60 1.0.61 1.0.62 1.0.63 1.0.64 1.0.65 1.0.66 1.0.67 1.0.68 1.0.69 1.0.7 1.0.70 1.0.71 1.0.72 1.0.73 1.0.74 1.0.75 1.0.76 1.0.77 1.0.78 1.0.79 1.0.8 1.0.80 1.0.81 1.0.82 1.0.83 1.0.84 1.0.85 1.0.86 1.0.87 1.0.88 1.0.89 1.0.9 1.0.90 1.1.0 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 1.1.20 1.1.21 1.1.22 1.1.23 1.1.24 1.1.25 1.1.26 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8
suretriggers / src / Integrations / woocommerce / actions / check-cart-status.php
suretriggers / src / Integrations / woocommerce / actions Last commit date
add-attribute-terms.php 9 months ago add-customer.php 10 months ago add-emails-to-coupon.php 9 months ago add-order-note.php 11 months ago add-product-attributes.php 9 months ago add-product-to-cart.php 9 months ago add-update-order-custom-fields.php 11 months ago apply-coupon.php 9 months ago check-cart-status.php 9 months ago check-if-order-is-renewal.php 5 months ago create-attribute.php 9 months ago create-bundle-product-order.php 7 months ago create-coupon-code.php 11 months ago create-multi-product-order.php 8 months ago create-new-order.php 11 months ago create-product-variation.php 1 year ago create-product.php 1 year ago create-variable-product.php 9 months ago delete-coupon.php 1 year ago delete-customer.php 9 months ago fetch-coupon-details.php 11 months ago find-orders-by-user-id.php 11 months ago get-all-customers.php 9 months ago get-all-products.php 9 months ago get-customer-by-email.php 9 months ago get-customer-by-id.php 9 months ago get-order-details-by-order-id.php 11 months ago get-order-type-by-order-id.php 5 months ago get-orders-by-email.php 9 months ago get-product-by-id.php 1 year ago list-all-order-notes.php 9 months ago list-all-orders.php 9 months ago remove-product-from-cart.php 9 months ago retrieve-coupons-totals.php 11 months ago retrieve-customers-totals.php 11 months ago retrieve-orders-totals.php 11 months ago retrieve-products-totals.php 11 months ago retrieve-refunds-list.php 11 months ago retrieve-reviews-totals.php 11 months ago retrieve-sales-report.php 11 months ago retrieve-top-sellers-report.php 11 months ago update-product-price.php 9 months ago update-product-stock-quantity.php 9 months ago update-status-of-order.php 11 months ago
check-cart-status.php
405 lines
1 <?php
2 /**
3 * CheckCartStatus.
4 * php version 5.6
5 *
6 * @category CheckCartStatus
7 * @package SureTriggers
8 * @author BSF <username@example.com>
9 * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3
10 * @link https://www.brainstormforce.com/
11 * @since 1.0.0
12 */
13
14 namespace SureTriggers\Integrations\WooCommerce\Actions;
15
16 use Exception;
17 use SureTriggers\Integrations\AutomateAction;
18 use SureTriggers\Integrations\WooCommerce\WooCommerce;
19 use SureTriggers\Traits\SingletonLoader;
20 use WP_Error;
21
22 /**
23 * CheckCartStatus
24 *
25 * @category CheckCartStatus
26 * @package SureTriggers
27 * @author BSF <username@example.com>
28 * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3
29 * @link https://www.brainstormforce.com/
30 * @since 1.0.0
31 */
32 class CheckCartStatus extends AutomateAction {
33
34 use SingletonLoader;
35
36 /**
37 * Integration type.
38 *
39 * @var string
40 */
41 public $integration = 'WooCommerce';
42
43 /**
44 * Action name.
45 *
46 * @var string
47 */
48 public $action = 'wc_check_cart_status';
49
50 /**
51 * Register the action.
52 *
53 * @param array $actions Actions array.
54 * @return array
55 */
56 public function register( $actions ) {
57 $actions[ $this->integration ][ $this->action ] = [
58 'label' => __( 'Check Cart Status', 'suretriggers' ),
59 'action' => $this->action,
60 'function' => [ $this, 'action_listener' ],
61 ];
62
63 return $actions;
64 }
65
66 /**
67 * Action listener.
68 *
69 * @param int $user_id User ID.
70 * @param int $automation_id Automation ID.
71 * @param array $fields Fields.
72 * @param array $selected_options Selected options.
73 * @return array|WP_Error
74 * @throws Exception If WooCommerce functions are missing.
75 */
76 public function _action_listener( $user_id, $automation_id, $fields, $selected_options ) {
77 if ( ! function_exists( 'WC' ) || ! class_exists( 'WooCommerce' ) ) {
78 return new WP_Error( 'woocommerce_not_available', __( 'WooCommerce is not available.', 'suretriggers' ) );
79 }
80
81 $user_identifier = isset( $selected_options['user_identifier'] ) ? trim( $selected_options['user_identifier'] ) : '';
82 $identifier_type = isset( $selected_options['identifier_type'] ) ? $selected_options['identifier_type'] : 'user_id';
83 $abandoned_threshold = isset( $selected_options['abandoned_threshold'] ) ? intval( $selected_options['abandoned_threshold'] ) : 60; // Minutes.
84
85 // Validate identifier type.
86 $valid_types = [ 'user_id', 'email', 'session_id' ];
87 if ( ! in_array( $identifier_type, $valid_types, true ) ) {
88 return new WP_Error( 'invalid_identifier_type', __( 'Invalid identifier type. Use "user_id", "email", or "session_id".', 'suretriggers' ) );
89 }
90
91 try {
92 $cart_data = $this->get_cart_data( $user_identifier, $identifier_type );
93
94 if ( is_wp_error( $cart_data ) ) {
95 return $cart_data;
96 }
97
98 $cart_status = $this->determine_cart_status( $cart_data, $abandoned_threshold );
99
100 $response_data = [
101 'success' => true,
102 'cart_status' => $cart_status['status'],
103 'status_description' => $cart_status['description'],
104 'cart_id' => $cart_data['cart_id'],
105 'user_id' => $cart_data['user_id'],
106 'user_email' => $cart_data['user_email'],
107 'cart_contents' => $cart_data['contents'],
108 'cart_total' => $cart_data['total'],
109 'cart_subtotal' => $cart_data['subtotal'],
110 'item_count' => $cart_data['item_count'],
111 'last_updated' => $cart_data['last_updated'],
112 'abandoned_duration' => $cart_status['abandoned_duration'],
113 'recovery_info' => $cart_status['recovery_info'],
114 'cart_url' => $this->get_cart_recovery_url( $cart_data ),
115 'message' => sprintf( __( 'Cart status: %s', 'suretriggers' ), $cart_status['description'] ),
116 ];
117
118 return $response_data;
119
120 } catch ( Exception $e ) {
121 return new WP_Error( 'check_failed', sprintf( __( 'Failed to check cart status: %s', 'suretriggers' ), $e->getMessage() ) );
122 }
123 }
124
125 /**
126 * Get cart data based on identifier.
127 *
128 * @param string $identifier Identifier value.
129 * @param string $type Identifier type.
130 * @return array|WP_Error
131 */
132 private function get_cart_data( $identifier, $type ) {
133 global $wpdb;
134
135 if ( empty( $identifier ) ) {
136 return new WP_Error( 'missing_identifier', __( 'User identifier is required.', 'suretriggers' ) );
137 }
138
139 $cart_data = null;
140 $user_id = 0;
141 $user_email = '';
142
143 switch ( $type ) {
144 case 'user_id':
145 $user_id = intval( $identifier );
146 $user = get_user_by( 'id', $user_id );
147 if ( ! $user ) {
148 return new WP_Error( 'user_not_found', __( 'User not found.', 'suretriggers' ) );
149 }
150 $user_email = $user->user_email;
151 $cart_data = $this->get_user_cart_data( $user_id );
152 break;
153
154 case 'email':
155 $user = get_user_by( 'email', $identifier );
156 if ( $user ) {
157 $user_id = $user->ID;
158 $user_email = $user->user_email;
159 $cart_data = $this->get_user_cart_data( $user_id );
160 } else {
161 $user_email = $identifier;
162 $cart_data = $this->get_guest_cart_data( $identifier );
163 }
164 break;
165
166 case 'session_id':
167 $cart_data = $this->get_session_cart_data( $identifier );
168 break;
169 }
170
171 if ( ! $cart_data ) {
172 return new WP_Error( 'cart_not_found', __( 'No cart found for the specified identifier.', 'suretriggers' ) );
173 }
174
175 $cart_data['user_id'] = $user_id;
176 $cart_data['user_email'] = $user_email;
177
178 return $cart_data;
179 }
180
181 /**
182 * Get cart data for registered user.
183 *
184 * @param int $user_id User ID.
185 * @return array|null
186 */
187 private function get_user_cart_data( $user_id ) {
188 global $wpdb;
189
190 // Get cart from user meta (persistent cart).
191 $cart_meta = get_user_meta( $user_id, '_woocommerce_persistent_cart_' . get_current_blog_id(), true );
192
193 if ( empty( $cart_meta ) || ! is_array( $cart_meta ) || empty( $cart_meta['cart'] ) ) {
194 // Try to get from sessions table.
195 $session_data = $wpdb->get_row(
196 $wpdb->prepare(
197 "SELECT session_value, session_expiry FROM {$wpdb->prefix}woocommerce_sessions WHERE session_key = %s",
198 $user_id
199 )
200 );
201
202 if ( $session_data ) {
203 $cart_data = maybe_unserialize( $session_data->session_value );
204 if ( is_array( $cart_data ) && isset( $cart_data['cart'] ) ) {
205 $cart_meta = [ 'cart' => $cart_data['cart'] ];
206 }
207 }
208 }
209
210 if ( empty( $cart_meta ) || ! is_array( $cart_meta ) || empty( $cart_meta['cart'] ) ) {
211 return null;
212 }
213
214 return $this->format_cart_data( $cart_meta['cart'], "user_{$user_id}" );
215 }
216
217 /**
218 * Get cart data for guest user.
219 *
220 * @param string $email Guest email.
221 * @return array|null
222 */
223 private function get_guest_cart_data( $email ) {
224 global $wpdb;
225
226 // Check if there's an abandoned cart plugin table.
227 $table_name = $wpdb->prefix . 'ac_abandoned_cart_history_lite';
228
229 if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) ) === $table_name ) {
230 $abandoned_cart = $wpdb->get_row(
231 $wpdb->prepare(
232 'SELECT * FROM ' . esc_sql( $table_name ) . ' WHERE email = %s ORDER BY time DESC LIMIT 1',
233 $email
234 )
235 );
236
237 if ( $abandoned_cart && ! empty( $abandoned_cart->abandoned_cart_info ) && isset( $abandoned_cart->time ) ) {
238 $cart_info = json_decode( $abandoned_cart->abandoned_cart_info, true );
239 if ( is_array( $cart_info ) ) {
240 return $this->format_cart_data( $cart_info, "guest_{$email}", $abandoned_cart->time );
241 }
242 }
243 }
244
245 return null;
246 }
247
248 /**
249 * Get cart data by session ID.
250 *
251 * @param string $session_id Session ID.
252 * @return array|null
253 */
254 private function get_session_cart_data( $session_id ) {
255 global $wpdb;
256
257 $session_data = $wpdb->get_row(
258 $wpdb->prepare(
259 "SELECT session_value, session_expiry FROM {$wpdb->prefix}woocommerce_sessions WHERE session_key = %s",
260 $session_id
261 )
262 );
263
264 if ( ! $session_data ) {
265 return null;
266 }
267
268 $cart_data = maybe_unserialize( $session_data->session_value );
269
270 if ( ! is_array( $cart_data ) || empty( $cart_data['cart'] ) ) {
271 return null;
272 }
273
274 return $this->format_cart_data( $cart_data['cart'], $session_id, null, $session_data->session_expiry );
275 }
276
277 /**
278 * Format cart data into standardized format.
279 *
280 * @param array $cart_contents Cart contents.
281 * @param string $cart_id Cart identifier.
282 * @param string $timestamp Last updated timestamp.
283 * @param int $expiry Session expiry.
284 * @return array
285 */
286 private function format_cart_data( $cart_contents, $cart_id, $timestamp = null, $expiry = null ) {
287 $total = 0;
288 $subtotal = 0;
289 $item_count = 0;
290 $formatted_contents = [];
291
292 foreach ( $cart_contents as $cart_item_key => $cart_item ) {
293 $product = wc_get_product( $cart_item['product_id'] );
294 if ( ! $product ) {
295 continue;
296 }
297
298 $item_total = isset( $cart_item['line_total'] ) ? $cart_item['line_total'] : ( $product->get_price() * $cart_item['quantity'] );
299 $item_subtotal = isset( $cart_item['line_subtotal'] ) ? $cart_item['line_subtotal'] : $item_total;
300
301 $formatted_contents[] = [
302 'product_id' => $cart_item['product_id'],
303 'product_name' => $product->get_name(),
304 'quantity' => $cart_item['quantity'],
305 'price' => $product->get_price(),
306 'line_total' => $item_total,
307 'line_subtotal' => $item_subtotal,
308 'sku' => $product->get_sku(),
309 ];
310
311 $total += $item_total;
312 $subtotal += $item_subtotal;
313 $item_count += $cart_item['quantity'];
314 }
315
316 return [
317 'cart_id' => $cart_id,
318 'contents' => $formatted_contents,
319 'total' => wc_format_decimal( $total, 2 ),
320 'subtotal' => wc_format_decimal( $subtotal, 2 ),
321 'item_count' => $item_count,
322 'last_updated' => $timestamp ? $timestamp : current_time( 'mysql' ),
323 'expiry' => $expiry,
324 ];
325 }
326
327 /**
328 * Determine cart status based on data and threshold.
329 *
330 * @param array $cart_data Cart data.
331 * @param int $abandoned_threshold Abandoned threshold in minutes.
332 * @return array
333 */
334 private function determine_cart_status( $cart_data, $abandoned_threshold ) {
335 $current_time = time();
336 $last_updated = strtotime( $cart_data['last_updated'] );
337 $time_diff_minutes = ( $current_time - $last_updated ) / 60;
338
339 $status = [
340 'status' => 'active',
341 'description' => __( 'Cart is active', 'suretriggers' ),
342 'abandoned_duration' => 0,
343 'recovery_info' => null,
344 ];
345
346 // Check if cart is expired.
347 if ( ! empty( $cart_data['expiry'] ) && $current_time > $cart_data['expiry'] ) {
348 $status['status'] = 'expired';
349 $status['description'] = __( 'Cart session has expired', 'suretriggers' );
350 $status['abandoned_duration'] = $time_diff_minutes;
351 return $status;
352 }
353
354 // Check if cart is abandoned.
355 if ( $time_diff_minutes >= $abandoned_threshold ) {
356 $status['status'] = 'abandoned';
357 $status['description'] = sprintf( __( 'Cart has been abandoned for %d minutes', 'suretriggers' ), round( $time_diff_minutes ) );
358 $status['abandoned_duration'] = $time_diff_minutes;
359
360 // Check if there have been recovery attempts.
361 $recovery_attempts = $this->get_recovery_attempts( $cart_data['cart_id'] );
362 if ( ! empty( $recovery_attempts ) ) {
363 $status['status'] = 'recovery_sent';
364 $status['description'] = __( 'Cart is abandoned and recovery emails have been sent', 'suretriggers' );
365 $status['recovery_info'] = $recovery_attempts;
366 }
367 }
368
369 return $status;
370 }
371
372 /**
373 * Get recovery attempts for a cart.
374 *
375 * @param string $cart_id Cart ID.
376 * @return array
377 */
378 private function get_recovery_attempts( $cart_id ) {
379 return [];
380 }
381
382 /**
383 * Generate cart recovery URL.
384 *
385 * @param array $cart_data Cart data.
386 * @return string
387 */
388 private function get_cart_recovery_url( $cart_data ) {
389 $base_url = wc_get_cart_url();
390
391 // Add recovery token if needed.
392 $recovery_token = md5( $cart_data['cart_id'] . time() );
393
394 return add_query_arg(
395 [
396 'cart_recovery' => $recovery_token,
397 'cart_id' => base64_encode( $cart_data['cart_id'] ),
398 ],
399 $base_url
400 );
401 }
402 }
403
404 CheckCartStatus::get_instance();
405