PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 2.7.0
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v2.7.0
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
← All changes | includes/admin/class-custom-tables.php +347 -3 1.3.22.7.0 View file →
@@ -43,8 +43,14 @@
43 43 */
44 44 public function __construct() {
45 45 add_action( 'wp_ajax_sellkit_get_applied_discount', [ $this, 'get_applied_discounts' ] );
46 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' ] );
47 53 }
48 54
49 55 /**
50 56 * Gets applied discounts.
@@ -53,11 +59,25 @@
53 59 */
54 60 public function get_applied_discounts() {
55 61 check_ajax_referer( 'sellkit', 'nonce' );
56 62
57 - $page = sellkit_htmlspecialchars( INPUT_GET, 'page' );
58 - $id = sellkit_htmlspecialchars( INPUT_GET, 'id' );
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 + }
59 74
75 + $id = sellkit_htmlspecialchars( INPUT_GET, 'id' );
76 + if ( empty( $id ) ) {
77 + $id = sellkit_htmlspecialchars( INPUT_POST, 'id' );
78 + }
79 +
60 80 if ( empty( $page ) ) {
61 81 $page = 1;
62 82 }
63 83
@@ -89,9 +109,9 @@
89 109 $total = $wpdb->get_results(
90 110 $prepared_total_query,
91 111 ARRAY_A );
92 112
93 - $total_discount_num = ! empty( $total[0]['total_discounts'] ) ? $total[0]['total_discounts'] : '';
113 + $total_discount_num = ! empty( $total[0]['total_discounts'] ) ? (int) $total[0]['total_discounts'] : 0;
94 114 // phpcs:enable
95 115
96 116 wp_send_json_success( [
97 117 'discounts' => $discounts,
@@ -130,9 +150,20 @@
130 150 $expiry_date = get_post_meta( $post->ID, 'date_expires', true );
131 151 $customer_email = get_post_meta( $post->ID, 'customer_email', true );
132 152 $usage_limit = get_post_meta( $post->ID, 'usage_limit', true );
133 153 $usage_count = get_post_meta( $post->ID, 'usage_count', true );
154 + $used_by = get_post_meta( $post->ID, '_used_by', true );
134 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 +
135 166 $post->customer = ! empty( $customer_email ) ? $customer_email : '';
136 167 $post->usage_limit = ! empty( $usage_limit ) ? $usage_limit : '';
137 168 $post->usage_count = ! empty( $usage_count ) ? $usage_count : '';
138 169 $post->created_at = date_i18n( 'Y/m/d h:i A', strtotime( $post->post_date ) );
@@ -148,8 +179,321 @@
148 179 'coupons' => $coupons,
149 180 'max_item_num' => self::CUSTOM_TABLE_PER_PAGE,
150 181 'total' => $query->found_posts,
151 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 + ];
152 496 }
153 497 }
154 498
155 499 Sellkit_Custom_Tables::get_instance();