PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 1.2.1
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v1.2.1
2.7.0 2.6.0 trunk 1.1.0 1.1.4 1.2.1 1.2.2 1.2.3 1.2.5 1.2.9 1.3.1 1.3.2 1.5.0 1.5.1 1.5.4 1.5.7 1.5.8 1.5.9 1.6.2 1.6.5 1.6.8 1.7.2 1.7.4 1.7.5 1.7.9 All 43 releases
sellkit / includes / contact-segmentation / contact-data-updater.php

contact-data-updater.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster 1.2.1, at includes/contact-segmentation/contact-data-updater.php

418 lines 10.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Sellkit\Contact_Segmentation;
4
5 use Sellkit\Contact_Segmentation\libraries\Mobile_Detect;
6 use Sellkit\Database;
7
8 defined( 'ABSPATH' ) || die();
9
10 /**
11 * Class Contact Data Updater.
12 *
13 * @package Sellkit\Contact_Segmentation
14 * @SuppressWarnings(ExcessiveClassComplexity)
15 * @since 1.1.0
16 */
17 class Contact_Data_Updater {
18
19 const SELLKIT_CONTACT_SEGMENTATION_LOCATION_API = 'sjYudEYJDjBMDDoKyxHd'; // TODO we should get it dynamically.
20 const SELLKIT_CONTACT_SEGMENTATION_FORCE_UPDATE = 'sellkit_contact_segmentation_force_update';
21
22 /**
23 * Class instance.
24 *
25 * @since 1.1.0
26 * @var Contact_Data_Updater
27 */
28 private static $instance = null;
29
30 /**
31 * Contact data.
32 *
33 * @since 1.1.0
34 * @var array Contact data.
35 */
36 public $data;
37
38 /**
39 * New contact data.
40 *
41 * @since 1.1.0
42 * @var array Contact data.
43 */
44 public static $new_data = [];
45
46 /**
47 * Check if data is expired or not.
48 *
49 * @since 1.1.0
50 * @var boolean Is data expired.
51 */
52 public $is_expired = false;
53
54 /**
55 * Contact_Data constructor.
56 *
57 * @since 1.1.0
58 */
59 public function __construct() {
60 if ( wp_doing_ajax() ) {
61 return;
62 }
63
64 $this->data = Contact_Data::$historical_data;
65
66 if ( ! is_user_logged_in() ) {
67 $this->update_browser_language();
68 $this->maybe_update_device();
69 $this->update_utm_data();
70 $this->maybe_update_ip();
71 $this->maybe_update_locations();
72
73 add_action( 'wp', [ $this, 'update_viewed_details' ], 10 );
74 add_action( 'wp', [ $this, 'maybe_update_data' ], 9999 );
75 return;
76 }
77
78 $this->update_utm_data();
79
80 add_action( 'wp', [ $this, 'update_viewed_details' ], 10 );
81
82 $force_update = get_user_meta( get_current_user_id(), self::SELLKIT_CONTACT_SEGMENTATION_FORCE_UPDATE, true );
83
84 if ( empty( $this->data ) ) {
85 $force_update = true;
86 }
87
88 $this->maybe_update_ip();
89 $this->maybe_update_locations();
90 $this->maybe_update_device();
91
92 if ( true == $force_update ) { //phpcs:ignore
93 $this->update_order_info();
94 }
95
96 add_action( 'wp', [ $this, 'maybe_update_data' ], 9999 );
97 }
98
99 /**
100 * If updating is required start to update.
101 *
102 * @since 1.1.0
103 */
104 public function maybe_update_data() {
105 if ( empty( self::$new_data ) ) {
106 return;
107 }
108
109 if ( ! is_user_logged_in() && is_array( self::$new_data ) ) {
110 setcookie( 'sellkit_contact_segmentation', wp_json_encode( array_merge( Contact_Data::$historical_data, self::$new_data ) ), 2147483647, '/' );
111 return;
112 }
113
114 if ( empty( Contact_Data::$historical_data ) && ! empty( self::$new_data ) ) {
115 self::$new_data['email'] = Contact_Data::get_user_email();
116
117 sellkit()->db->insert( 'contact_segmentation', self::$new_data );
118
119 update_user_meta( get_current_user_id(), self::SELLKIT_CONTACT_SEGMENTATION_FORCE_UPDATE, false );
120
121 return;
122 }
123
124 self::update_contact_segmentation( self::$new_data, Contact_Data::get_user_email() );
125 }
126
127 /**
128 * Get the class instance.
129 *
130 * @since 1.1.0
131 */
132 public static function get_instance() {
133 if ( null === self::$instance ) {
134 self::$instance = new self();
135 }
136
137 return self::$instance;
138 }
139
140 /**
141 * Update utm data.
142 *
143 * @since 1.1.0
144 */
145 private function update_utm_data() {
146 $utm_source = sellkit_htmlspecialchars( INPUT_GET, 'utm_source' );
147 $utm_campaign = sellkit_htmlspecialchars( INPUT_GET, 'utm_campaign' );
148 $utm_medium = sellkit_htmlspecialchars( INPUT_GET, 'utm_medium' );
149 $utm_content = sellkit_htmlspecialchars( INPUT_GET, 'utm_content' );
150 $utm_term = sellkit_htmlspecialchars( INPUT_GET, 'utm_term' );
151
152 if ( $this->check_utm_is_new( $utm_source, 'utm_source' ) ) {
153 self::$new_data['utm_source'] = $utm_source;
154 }
155
156 if ( $this->check_utm_is_new( $utm_campaign, 'utm_campaign' ) ) {
157 self::$new_data['utm_campaign'] = $utm_campaign;
158 }
159
160 if ( $this->check_utm_is_new( $utm_content, 'utm_content' ) ) {
161 self::$new_data['utm_content'] = $utm_content;
162 }
163
164 if ( $this->check_utm_is_new( $utm_term, 'utm_term' ) ) {
165 self::$new_data['utm_term'] = $utm_term;
166 }
167
168 if ( $this->check_utm_is_new( $utm_medium, 'utm_medium' ) ) {
169 self::$new_data['utm_medium'] = $utm_medium;
170 }
171 }
172
173 /**
174 * Update locations data from API.
175 *
176 * @since 1.1.0
177 */
178 private function maybe_update_locations() {
179 $ip = sellkit_get_ip();
180
181 if ( ! empty( $this->data['ip'] ) && $ip === $this->data['ip'] ) {
182 return;
183 }
184
185 $response = wp_remote_get( 'https://location.stg.growmatik.ai/v1', [
186 'timeout' => 10,
187 'body' => [
188 'apiKey' => self::SELLKIT_CONTACT_SEGMENTATION_LOCATION_API,
189 'ip' => $ip,
190 ],
191 ] );
192
193 $response_code = wp_remote_retrieve_response_code( $response );
194
195 if ( ! is_wp_error( $response ) && ! empty( $response['body'] ) && 200 === (int) $response_code ) {
196 $location_data = json_decode( $response['body'] );
197 self::$new_data['visitor_country'] = strtolower( $location_data->country );
198 self::$new_data['visitor_city'] = strtolower( $location_data->city );
199 }
200
201 self::$new_data['updated_at'] = time();
202 }
203
204 /**
205 * Updates device types.
206 *
207 * @since 1.1.0
208 */
209 private function maybe_update_device() {
210 $detector = new Mobile_Detect();
211 $current_display = 'desktop';
212
213 if ( $detector->isMobile() ) {
214 $current_display = 'mobile';
215 }
216
217 if ( $detector->isTablet() ) {
218 $current_display = 'tablet';
219 }
220
221 if ( ! empty( $this->data['user_device'] ) && $this->data['user_device'] === $current_display ) {
222 return;
223 }
224
225 self::$new_data['user_device'] = $current_display;
226 }
227
228 /**
229 * Update browser language.
230 *
231 * @since 1.1.0
232 */
233 private function update_browser_language() {
234 $data = explode( ',', $_SERVER['HTTP_ACCEPT_LANGUAGE'] ); // phpcs:ignore
235 $language = ! empty( $data[0] ) ? $data[0] : '';
236
237 if ( empty( $language ) ) {
238 return;
239 }
240
241 if ( empty( $this->data['browser_language'] ) || ( $this->data['browser_language'] !== $language ) ) {
242 self::$new_data['browser_language'] = $language;
243 }
244 }
245
246 /**
247 * Updates the IP if it's changed.
248 *
249 * @since 1.2.1
250 */
251 private function maybe_update_ip() {
252 $ip = sellkit_get_ip();
253
254 if ( ! empty( $this->data['ip'] ) && $this->data['ip'] === $ip ) {
255 return;
256 }
257
258 self::$new_data['ip'] = $ip;
259 }
260
261 /**
262 * Checks utm value.
263 *
264 * @param string $new_utm New Utm.
265 * @param string $type Utm type.
266 * @return bool
267 */
268 private function check_utm_is_new( $new_utm, $type ) {
269 if ( empty( $new_utm ) ) {
270 return false;
271 }
272
273 if ( empty( $this->data[ $type ] ) ) {
274 return true;
275 }
276
277 if ( $new_utm !== $this->data[ $type ] ) {
278 return true;
279 }
280 }
281
282 /**
283 * Updates user information.
284 *
285 * @since 1.1.0
286 */
287 public function update_order_info() {
288 $current_user = wp_get_current_user();
289
290 $args = [
291 'customer_id' => $current_user->ID,
292 'post_status' => 'completed',
293 'post_type' => 'shop_order',
294 'limit' => -1,
295 'orderby' => 'id',
296 'order' => 'DESC',
297 ];
298
299 $orders = wc_get_orders( $args );
300 $order_number = count( $orders );
301 $total_spent = 0;
302 $first_order = ! empty( end( $orders ) ) ? end( $orders ) : '';
303 $last_order = ! empty( $orders[0] ) ? $orders[0] : '';
304 $purchased_products = [];
305 $purchased_categories = [];
306 $billing_countries = [];
307 $billing_cities = [];
308 $shipping_countries = [];
309 $shipping_cities = [];
310
311 foreach ( $orders as $order ) {
312 $total_spent += $order->get_total();
313 $billing_countries[] = $order->get_billing_country();
314 $billing_cities[] = $order->get_billing_city();
315 $shipping_countries[] = $order->get_shipping_country();
316 $shipping_cities[] = $order->get_shipping_city();
317
318 foreach ( $order->get_items() as $item ) {
319 $purchased_products[] = $item['product_id'];
320
321 $term_list = wp_get_post_terms( $item['product_id'], 'product_cat', [ 'fields' => 'ids' ] );
322 $purchased_categories = array_merge( $purchased_categories, $term_list );
323 }
324 }
325
326 $first_order_date = $first_order ? strtotime( $first_order->get_date_completed()->date( 'Y-m-d H:i:s' ) ) : '';
327 $last_order_date = $last_order ? strtotime( $last_order->get_date_completed()->date( 'Y-m-d H:i:s' ) ) : '';
328
329 self::$new_data['total_order_count'] = $order_number;
330 self::$new_data['total_spent'] = $total_spent;
331 self::$new_data['first_order_date'] = $first_order_date;
332 self::$new_data['last_order_date'] = $last_order_date;
333 self::$new_data['purchased_product'] = array_unique( $purchased_products );
334 self::$new_data['billing_country'] = array_unique( $billing_countries );
335 self::$new_data['billing_city'] = array_unique( $billing_cities );
336 self::$new_data['shipping_country'] = array_unique( $shipping_countries );
337 self::$new_data['shipping_city'] = array_unique( $shipping_cities );
338 self::$new_data['purchased_category'] = array_unique( $purchased_categories );
339
340 if ( $order_number > 0 ) {
341 self::$new_data['user_type'] = 'customer';
342 return;
343 }
344
345 self::$new_data['user_type'] = 'lead';
346 }
347
348 /**
349 * Force update data.
350 *
351 * @since 1.1.0
352 * @param string $order_id Order id.
353 */
354 public static function force_update_data( $order_id ) {
355 $user_id = get_post_meta( $order_id, '_customer_user', true );
356
357 if ( empty( $user_id ) ) {
358 $order = wc_get_order( $order_id );
359 $user = $order->get_billing_email();
360 $user_id = email_exists( $user );
361 }
362
363 if ( ! empty( $user_id ) ) {
364 update_user_meta( $user_id, self::SELLKIT_CONTACT_SEGMENTATION_FORCE_UPDATE, true );
365 }
366 }
367
368 /**
369 * Update viewed products. it should be done in wp hook so we have to update the data directly.
370 * it would be better to update these data with the main updating process.
371 *
372 * @since 1.1.0
373 */
374 public function update_viewed_details() {
375 $old_data = Contact_Data::$historical_data;
376
377 if ( is_singular( 'product' ) ) {
378 $product_id = get_the_ID();
379 $new_products = [];
380
381 if ( ! empty( $old_data['viewed_product'] ) ) {
382 $new_products = $old_data['viewed_product'];
383 }
384
385 if ( empty( $old_data['viewed_product'] ) || ! in_array( $product_id, $old_data['viewed_product'], false ) ) { // phpcs:ignore
386 self::$new_data['viewed_product'] = array_unique( array_merge( [ $product_id ], $new_products ) );
387 }
388 }
389
390 $queries = get_queried_object();
391 if ( ! empty( $queries->taxonomy ) && 'product_cat' === $queries->taxonomy ) {
392 $current_cat_id = $queries->term_id;
393 $new_cats = [];
394
395 if ( ! empty( $old_data['viewed_category'] ) ) {
396 $new_cats = $old_data['viewed_category'];
397 }
398
399 if ( empty( $old_data['viewed_category'] ) || ! in_array( $current_cat_id, $old_data['viewed_category'], false ) ) { // phpcs:ignore
400 self::$new_data['viewed_category'] = array_unique( array_merge( [ $current_cat_id ], $new_cats ) );
401 }
402 }
403 }
404
405 /**
406 * Updates contact segmentation data.
407 *
408 * @since 1.1.0
409 * @param array $data Data.
410 * @param string $email Email.
411 */
412 public static function update_contact_segmentation( $data, $email ) {
413 sellkit()->db->update( 'contact_segmentation', $data, [ 'email' => $email ] );
414
415 update_user_meta( get_current_user_id(), self::SELLKIT_CONTACT_SEGMENTATION_FORCE_UPDATE, false );
416 }
417 }
418