PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / trunk
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster vtrunk
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 1.8.1 All 42 releases
sellkit / includes / admin / class-custom-tables.php

class-custom-tables.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster trunk, at includes/admin/class-custom-tables.php

500 lines 14.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use Sellkit\Database;
4
5 defined( 'ABSPATH' ) || die();
6
7 /**
8 * Components class.
9 *
10 * @since 1.1.0
11 */
12 class Sellkit_Custom_Tables {
13
14 const CUSTOM_TABLE_PER_PAGE = 20;
15
16 /**
17 * Class instance.
18 *
19 * @since 1.1.0
20 * @var Sellkit_Custom_Tables
21 */
22 private static $instance = null;
23
24 /**
25 * Get a class instance.
26 *
27 * @since 1.1.0
28 *
29 * @return Sellkit_Custom_Tables Class instance.
30 */
31 public static function get_instance() {
32 if ( null === self::$instance ) {
33 self::$instance = new self();
34 }
35
36 return self::$instance;
37 }
38
39 /**
40 * Class constructor.
41 *
42 * @since 1.1.0
43 */
44 public function __construct() {
45 add_action( 'wp_ajax_sellkit_get_applied_discount', [ $this, 'get_applied_discounts' ] );
46 add_action( 'wp_ajax_sellkit_get_generated_coupons', [ $this, 'get_generated_coupons' ] );
47 add_action( 'wp_ajax_sellkit_funnel_get_contacts', [ $this, 'get_contacts' ] );
48 add_action( 'wp_ajax_sellkit_funnel_get_contacts_history', [ $this, 'get_history' ] );
49 add_action( 'wp_ajax_sellkit_funnel_delete_contact', [ $this, 'delete_contact' ] );
50 add_action( 'wp_ajax_sellkit_funnel_get_contact_details', [ $this, 'get_contact_details' ] );
51 add_action( 'wp_ajax_sellkit_funnel_get_funnel_orders', [ $this, 'get_funnel_orders' ] );
52 add_action( 'wp_ajax_sellkit_funnel_save_contact_details', [ $this, 'save_contact_details' ] );
53 }
54
55 /**
56 * Gets applied discounts.
57 *
58 * @since 1.1.0
59 */
60 public function get_applied_discounts() {
61 check_ajax_referer( 'sellkit', 'nonce' );
62
63 // Prefer `paged` — `page` can collide with other WP query usage; accept both GET/POST for ajax.
64 $page = sellkit_htmlspecialchars( INPUT_GET, 'paged' );
65 if ( empty( $page ) ) {
66 $page = sellkit_htmlspecialchars( INPUT_POST, 'paged' );
67 }
68 if ( empty( $page ) ) {
69 $page = sellkit_htmlspecialchars( INPUT_GET, 'page' );
70 }
71 if ( empty( $page ) ) {
72 $page = sellkit_htmlspecialchars( INPUT_POST, 'page' );
73 }
74
75 $id = sellkit_htmlspecialchars( INPUT_GET, 'id' );
76 if ( empty( $id ) ) {
77 $id = sellkit_htmlspecialchars( INPUT_POST, 'id' );
78 }
79
80 if ( empty( $page ) ) {
81 $page = 1;
82 }
83
84 $page_index = ( $page - 1 ) * self::CUSTOM_TABLE_PER_PAGE;
85 $limit = self::CUSTOM_TABLE_PER_PAGE;
86
87 global $wpdb;
88
89 $sellkit_prefix = Database::DATABASE_PREFIX;
90 $discount_table = "{$wpdb->prefix}{$sellkit_prefix}applied_discount";
91
92 // phpcs:disable
93 $prepared_query = $wpdb->prepare( "SELECT $discount_table.*, {$wpdb->prefix}users.ID as user_id FROM {$discount_table}
94 LEFT JOIN {$wpdb->prefix}users on {$discount_table}.email = {$wpdb->prefix}users.user_email
95 where {$discount_table}.discount_id = %d order by {$discount_table}.id desc limit %d , %d;",
96 $id,
97 $page_index,
98 $limit
99 );
100
101 $prepared_total_query = $wpdb->prepare( "SELECT count(*) as total_discounts FROM {$wpdb->prefix}{$sellkit_prefix}applied_discount where discount_id = %d;",
102 $id
103 );
104
105 $discounts = $wpdb->get_results(
106 $prepared_query,
107 ARRAY_A );
108
109 $total = $wpdb->get_results(
110 $prepared_total_query,
111 ARRAY_A );
112
113 $total_discount_num = ! empty( $total[0]['total_discounts'] ) ? (int) $total[0]['total_discounts'] : 0;
114 // phpcs:enable
115
116 wp_send_json_success( [
117 'discounts' => $discounts,
118 'total' => $total_discount_num,
119 'max_item_num' => self::CUSTOM_TABLE_PER_PAGE,
120 ] );
121 }
122
123 /**
124 * Gets generated coupons.
125 *
126 * @since 1.1.0
127 */
128 public function get_generated_coupons() {
129 check_ajax_referer( 'sellkit', 'nonce' );
130
131 $page = sellkit_htmlspecialchars( INPUT_GET, 'page' );
132 $id = sellkit_htmlspecialchars( INPUT_GET, 'id' );
133
134 $args = [
135 'post_type' => 'shop_coupon',
136 'post_status' => 'publish',
137 'posts_per_page' => self::CUSTOM_TABLE_PER_PAGE,
138 'paged' => sanitize_text_field( $page ),
139 'orderby' => 'ID',
140 'order' => 'DESC',
141 'meta_key' => 'sellkit_personalised_coupon_rule', // phpcs:ignore
142 'meta_value' => sanitize_text_field( $id ), // phpcs:ignore
143 ];
144
145 $query = new WP_Query( $args );
146
147 $coupons = [];
148
149 foreach ( $query->posts as $post ) {
150 $expiry_date = get_post_meta( $post->ID, 'date_expires', true );
151 $customer_email = get_post_meta( $post->ID, 'customer_email', true );
152 $usage_limit = get_post_meta( $post->ID, 'usage_limit', true );
153 $usage_count = get_post_meta( $post->ID, 'usage_count', true );
154 $used_by = get_post_meta( $post->ID, '_used_by', true );
155
156 if ( empty( $customer_email ) && ! empty( $used_by ) ) {
157 $used_by_customer = is_email( $used_by ) ? $used_by : '';
158
159 if ( empty( $used_by_customer ) ) {
160 $used_by_customer = get_userdata( intval( $used_by ) )->user_email;
161 }
162
163 $customer_email = [ $used_by_customer ];
164 }
165
166 $post->customer = ! empty( $customer_email ) ? $customer_email : '';
167 $post->usage_limit = ! empty( $usage_limit ) ? $usage_limit : '';
168 $post->usage_count = ! empty( $usage_count ) ? $usage_count : '';
169 $post->created_at = date_i18n( 'Y/m/d h:i A', strtotime( $post->post_date ) );
170
171 if ( ! empty( $expiry_date ) ) {
172 $post->expiry_date = round( ( get_post_meta( $post->ID, 'date_expires', true ) - time() ) / 86400 );
173 }
174
175 $coupons[] = $post;
176 }
177
178 wp_send_json_success( [
179 'coupons' => $coupons,
180 'max_item_num' => self::CUSTOM_TABLE_PER_PAGE,
181 'total' => $query->found_posts,
182 ] );
183 }
184
185 /**
186 * Gets contacts.
187 *
188 * @since 1.5.0
189 */
190 public function get_contacts() {
191 check_ajax_referer( 'sellkit', 'nonce' );
192
193 $page = sellkit_htmlspecialchars( INPUT_GET, 'page' );
194 $funnel_id = sellkit_htmlspecialchars( INPUT_GET, 'funnel_id' );
195
196 if ( empty( $page ) ) {
197 $page = 1;
198 }
199
200 $page_index = ( $page - 1 ) * self::CUSTOM_TABLE_PER_PAGE;
201 $limit = self::CUSTOM_TABLE_PER_PAGE;
202
203 global $wpdb;
204
205 $sellkit_prefix = Database::DATABASE_PREFIX;
206 $contact_table = "{$wpdb->prefix}{$sellkit_prefix}funnel_contact";
207 $users_table = "{$wpdb->prefix}users ";
208
209 // phpcs:disable
210 $contacts = $wpdb->get_results(
211 $wpdb->prepare( "SELECT ct.user_id as user_id, ct.id as id, ct.created_at, ut.user_email, ut.display_name, SUM( ct.total_spent ) as sum_total_spent FROM {$contact_table} AS ct
212 LEFT JOIN {$users_table} ut ON ut.ID = ct.user_id
213 where ct.funnel_id = %d
214 group by ct.user_id
215 order by ct.id desc limit %d , %d;", $funnel_id, $page_index, $limit ), ARRAY_A );
216
217 // Must match the grouped list query (one row per user), not raw row count.
218 $total_contacts = $wpdb->get_results(
219 $wpdb->prepare(
220 "SELECT COUNT(*) AS total_contacts FROM ( SELECT user_id FROM {$contact_table} WHERE funnel_id = %d GROUP BY user_id ) AS grouped_contacts",
221 $funnel_id
222 ),
223 ARRAY_A
224 );
225 $total_contacts_num = ! empty( $total_contacts[0]['total_contacts'] ) ? $total_contacts[0]['total_contacts'] : '';
226 // phpcs:enable
227
228 wp_send_json_success( [
229 'contacts' => $contacts,
230 'total' => intval( $total_contacts_num ),
231 'max_item_num' => self::CUSTOM_TABLE_PER_PAGE,
232 ] );
233 }
234
235 /**
236 * Gets contacts.
237 *
238 * @since 1.5.0
239 */
240 public function get_history() {
241 check_ajax_referer( 'sellkit', 'nonce' );
242
243 $page = sellkit_htmlspecialchars( INPUT_GET, 'page' );
244 $funnel_id = sellkit_htmlspecialchars( INPUT_GET, 'funnel_id' );
245 $contact_id = sellkit_htmlspecialchars( INPUT_GET, 'contact_id' );
246 $user_id = $this->get_user_id_by_contact_table( $contact_id );
247
248 if ( empty( $user_id ) ) {
249 wp_send_json_error( esc_html__( 'Something went wrong.', 'sellkit' ) );
250 }
251
252 if ( empty( $page ) ) {
253 $page = 1;
254 }
255
256 $page_index = ( $page - 1 ) * self::CUSTOM_TABLE_PER_PAGE;
257 $limit = self::CUSTOM_TABLE_PER_PAGE;
258
259 global $wpdb;
260
261 $sellkit_prefix = Database::DATABASE_PREFIX;
262 $contact_table = "{$wpdb->prefix}{$sellkit_prefix}funnel_contact";
263 $users_table = "{$wpdb->prefix}users ";
264
265 // phpcs:disable
266 $contacts = $wpdb->get_results(
267 $wpdb->prepare( "SELECT ct.*, ct.created_at, ut.user_email, ut.display_name, ct.total_spent as sum_total_spent FROM {$contact_table} AS ct
268 LEFT JOIN {$users_table} ut ON ut.ID = ct.user_id
269 where ct.funnel_id = %d and ct.user_id = %d
270 order by ct.id desc limit %d , %d;", $funnel_id, $user_id, $page_index, $limit ), ARRAY_A );
271
272 $total_contacts = $wpdb->get_results(
273 $wpdb->prepare( "SELECT count(*) as total_contacts FROM {$contact_table} WHERE funnel_id = %d AND user_id = %d;", $funnel_id, $user_id ), ARRAY_A );
274 $total_contacts_num = ! empty( $total_contacts[0]['total_contacts'] ) ? $total_contacts[0]['total_contacts'] : '';
275 // phpcs:enable
276
277 wp_send_json_success( [
278 'contacts' => $contacts,
279 'total' => intval( $total_contacts_num ),
280 'max_item_num' => self::CUSTOM_TABLE_PER_PAGE,
281 ] );
282 }
283
284 /**
285 * Delete a single contact.
286 *
287 * @since 1.5.0
288 */
289 public function delete_contact() {
290 check_ajax_referer( 'sellkit', 'nonce' );
291
292 $entry_id = sellkit_htmlspecialchars( INPUT_GET, 'entry_id' );
293
294 global $wpdb;
295
296 $sellkit_prefix = Database::DATABASE_PREFIX;
297 $contact_table = "{$wpdb->prefix}{$sellkit_prefix}funnel_contact";
298
299 // phpcs:disable
300 $delete_result = $wpdb->delete( $contact_table, [ 'id' => intval( $entry_id ) ] );
301 // phpcs:enable
302
303 if ( ! $delete_result ) {
304 wp_send_json_error();
305 }
306
307 wp_send_json_success();
308 }
309
310 /**
311 * Gets contact details.
312 *
313 * @since 1.5.0
314 */
315 public function get_contact_details() {
316 check_ajax_referer( 'sellkit', 'nonce' );
317
318 $contact_id = sellkit_htmlspecialchars( INPUT_GET, 'contact_id' );
319
320 global $wpdb;
321
322 $sellkit_prefix = Database::DATABASE_PREFIX;
323 $contact_table = "{$wpdb->prefix}{$sellkit_prefix}funnel_contact";
324 $contact_segmentation = "{$wpdb->prefix}{$sellkit_prefix}contact_segmentation";
325 $users_table = "{$wpdb->prefix}users ";
326
327 // phpcs:disable
328 $contact_details = $wpdb->get_results(
329 $wpdb->prepare( "SELECT ct.*, ut.user_email, ut.display_name, cs.* FROM {$contact_table} AS ct
330 LEFT JOIN {$users_table} ut ON ut.ID = ct.user_id
331 LEFT JOIN {$contact_segmentation} cs ON ut.user_email = cs.email
332 WHERE ct.id = %d limit 1;", $contact_id ), ARRAY_A );
333 // phpcs:enable
334
335 if ( empty( $contact_details[0] ) || ! is_array( $contact_details[0] ) ) {
336 wp_send_json_error( esc_html__( 'Something went wrong.', 'sellkit' ) );
337 }
338
339 $user_id = $contact_details[0]['user_id'];
340
341 wp_send_json_success( [
342 'user_details' => $contact_details[0],
343 'user_meta' => array_merge( get_user_meta( $user_id ), [ 'user_role' => get_userdata( $user_id )->roles ] ),
344 ] );
345 }
346
347 /**
348 * Gets funnel orders.
349 *
350 * @since 1.5.0
351 */
352 public function get_funnel_orders() {
353 check_ajax_referer( 'sellkit', 'nonce' );
354
355 $contact_id = sellkit_htmlspecialchars( INPUT_GET, 'contact_id' );
356 $funnel_id = sellkit_htmlspecialchars( INPUT_GET, 'funnel_id' );
357 $page_index = sellkit_htmlspecialchars( INPUT_GET, 'page' );
358 $limit = self::CUSTOM_TABLE_PER_PAGE;
359 $user_id = $this->get_user_id_by_contact_table( $contact_id );
360
361 if ( empty( $user_id ) ) {
362 wp_send_json_error( esc_html__( 'Something went wrong.', 'sellkit' ) );
363 }
364
365 $contact_orders = $this->get_contact_order_details( $funnel_id, $user_id, $page_index, $limit );
366
367 wp_send_json_success( [
368 'user_orders' => $contact_orders['orders'],
369 'total' => intval( $contact_orders['total'] ),
370 'max_item_num' => self::CUSTOM_TABLE_PER_PAGE,
371 ] );
372 }
373
374 /**
375 * Gets funnel id by contact table.
376 *
377 * @since 1.5.0
378 * @param string $contact_id Contact Id.
379 */
380 public function get_user_id_by_contact_table( $contact_id ) {
381 global $wpdb;
382
383 $sellkit_prefix = Database::DATABASE_PREFIX;
384 $contact_table = "{$wpdb->prefix}{$sellkit_prefix}funnel_contact";
385
386 // phpcs:disable
387 $contact_details = $wpdb->get_results(
388 $wpdb->prepare( "SELECT ct.user_id FROM {$contact_table} AS ct
389 WHERE ct.id = %d limit 1;", $contact_id ), ARRAY_A );
390 // phpcs:enable
391
392 if ( empty( $contact_details[0] ) || ! is_array( $contact_details[0] ) ) {
393 return false;
394 }
395
396 return $contact_details[0]['user_id'];
397 }
398
399 /**
400 * Saves contact details.
401 *
402 * @since 1.5.0
403 */
404 public function save_contact_details() {
405 check_ajax_referer( 'sellkit', 'nonce' );
406
407 $fields = sellkit_post( 'fields' );
408 $first_name = ! empty( $fields['contacts_detail_first_name'] ) ? sanitize_text_field( $fields['contacts_detail_first_name'] ) : '';
409 $last_name = ! empty( $fields['contacts_detail_last_name'] ) ? sanitize_text_field( $fields['contacts_detail_last_name'] ) : '';
410 $user_id = filter_input( INPUT_POST, 'user_id', FILTER_SANITIZE_NUMBER_INT );
411
412 $result = wp_update_user( [
413 'ID' => $user_id,
414 'first_name' => $first_name,
415 'last_name' => $last_name,
416 ] );
417
418 if ( is_wp_error( $result ) ) {
419 wp_send_json_error( $result->get_error_message() );
420 }
421
422 wp_send_json_success( esc_html__( 'The details have been updated.', 'sellkit' ) );
423 }
424
425 /**
426 * Get order details of a contact ID related to a given funnel ID.
427 *
428 * @param int $funnel_id ID of the funnel.
429 * @param int $user_id Equals user ID of WordPress, customer ID of woocommerce and contact ID of sellkit.
430 * @param int $page Page number.
431 * @param int $limit Page limitation.
432 * @return array Order details with a custom structure which is parsed in frontend.
433 *
434 * @since 1.5.0
435 * @access private
436 */
437 private function get_contact_order_details( $funnel_id, $user_id, $page, $limit ) {
438 $funnel_orders = [];
439
440 $total_orders = wc_get_orders( [
441 'customer_id' => $user_id,
442 'meta_key' => 'sellkit_funnel_id', // phpcs:ignore
443 'meta_value' => $funnel_id, // phpcs:ignore
444 'meta_compare' => '=',
445 'limit' => -1,
446 ] );
447
448 $orders = wc_get_orders( [
449 'customer_id' => $user_id,
450 'meta_key' => 'sellkit_funnel_id', // phpcs:ignore
451 'meta_value' => $funnel_id, // phpcs:ignore
452 'meta_compare' => '=',
453 'limit' => $limit,
454 'paged' => $page,
455 'return' => 'objects'
456 ] );
457
458 foreach ( $orders as $order ) {
459 $products = [];
460
461 foreach ( $order->get_items() as $order_item ) {
462 $data = $order_item->get_data();
463
464 if ( ! array_key_exists( 'product_id', $data ) ) {
465 continue;
466 }
467
468 $product = wc_get_product( $data['product_id'] );
469
470 if ( empty( $product ) ) {
471 continue;
472 }
473
474 $products[] = [
475 'id' => $data['product_id'],
476 'name' => $data['name'],
477 'quantity' => $data['quantity'],
478 'order_price' => floatval( $data['total'] / $data['quantity'] ),
479 'regular_price' => floatval( $product->get_regular_price() ),
480 'image_src' => wp_get_attachment_image_src( $product->get_image_id() ),
481 ];
482 }
483
484 $funnel_orders[] = [
485 'order_number' => $order->get_order_number(),
486 'order_date' => $order->get_date_created()->date( 'Y/m/d g:i A' ),
487 'order_revenue' => $order->get_total() - $order->get_total_tax(),
488 'products' => $products,
489 ];
490 }
491
492 return [
493 'orders' => $funnel_orders,
494 'total' => count( $total_orders ),
495 ];
496 }
497 }
498
499 Sellkit_Custom_Tables::get_instance();
500