PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.1.7.1
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.1.7.1
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / inc / curds / class-lp-user-curd.php

class-lp-user-curd.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.1.7.1, at inc/curds/class-lp-user-curd.php

2,159 lines 55.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class LP_User_CURD
5 *
6 * @since 3.0
7 */
8 class LP_User_CURD extends LP_Object_Data_CURD implements LP_Interface_CURD {
9
10 /**
11 * @var string
12 */
13 protected $_meta_type = 'user';
14
15 /**
16 * @var int
17 */
18 protected $_user_id = 0;
19
20 /**
21 * @var int
22 */
23 protected $_course_id = 0;
24
25 /**
26 * LP_User_CURD constructor.
27 *
28 * @param int $the_user
29 * @param int $the_course
30 */
31 public function __construct( $the_user = 0, $the_course = 0 ) {
32 $this->_user_id = $the_user;
33 $this->_course_id = $the_course;
34
35 // add_action( 'init', array( $this, 'init' ) );
36 }
37
38 /**
39 * Get courses of an user.
40 *
41 * @param array $args
42 *
43 * @return array
44 * @since 3.3.0
45 */
46 public function get_courses( $args = array() ) {
47
48 global $wpdb;
49
50 $no_join_users = isset( $args['no_join_users'] ) && $args['no_join_users'];
51 $args = wp_parse_args(
52 $args,
53 array(
54 'offset' => 0,
55 'limit' => 10,
56 'expired' => false,
57 'status' => '',
58 'user_id' => 0,
59 'paginate' => false,
60 )
61 );
62
63 // Join
64 $join = "
65 INNER JOIN {$wpdb->posts} p ON p.ID = X.item_id
66 ";
67
68 if ( ! $no_join_users ) {
69 $join .= "
70 INNER JOIN {$wpdb->users} u ON u.ID = X.user_id
71 ";
72 }
73
74 $join .= $wpdb->prepare(
75 "LEFT JOIN {$wpdb->learnpress_user_itemmeta} uim ON uim.learnpress_user_item_id = X.user_item_id AND uim.meta_key = %s",
76 'grade'
77 );
78
79 // Where
80 $where = $wpdb->prepare(
81 'WHERE 1
82 AND X.item_type = %s
83 ',
84 LP_COURSE_CPT
85 );
86
87 if ( $args['user_id'] ) {
88
89 if ( ! is_array( $args['user_id'] ) ) {
90 $user__in = preg_split( '!\s*,\s*!', $args['user_id'] );
91 } else {
92 $user__in = $args['user_id'];
93 }
94
95 $where .= 'AND u.ID IN(' . join( ',', $user__in ) . ')';
96 }
97
98 // Limitation
99 $limit = $args['limit'] > 0 ? '
100 LIMIT ' . $args['offset'] . ', ' . $args['limit'] : '';
101
102 if ( $args['status'] ) {
103
104 if ( ! is_array( $args['status'] ) ) {
105 $status__in = preg_split( '!\s*,\s*!', $args['status'] );
106 } else {
107 $status__in = $args['status'];
108 }
109
110 $where .= " AND ( X.status IN('" . join( "','", $status__in ) . "')";
111
112 $status__in_1 = array();
113 $status__in_2 = array();
114
115 if ( in_array( 'failed', $status__in ) ) {
116 $status__in_1[] = 'finished';
117 $status__in_2[] = 'failed';
118 }
119
120 if ( in_array( 'passed', $status__in ) ) {
121 $status__in_1[] = 'finished';
122 $status__in_2[] = 'passed';
123 }
124
125 if ( in_array( 'in-progress', $status__in ) ) {
126 $status__in_1[] = 'enrolled';
127 $status__in_2[] = 'in-progress';
128 }
129
130 if ( in_array( 'finished', $status__in ) ) {
131 $status__in_1[] = 'passed';
132 $status__in_1[] = 'failed';
133 $status__in_2[] = 'passed';
134 $status__in_2[] = 'failed';
135 }
136
137 if ( $status__in_1 || $status__in_2 ) {
138
139 $where .= " OR (
140 X.status IN('" . join( "','", $status__in_1 ) . "')";
141
142 if ( ! in_array( 'in-progress', $status__in ) ) {
143 $where .= "AND ( uim.meta_value IN('" . join( "','", $status__in_2 ) . "')
144 " . ( in_array( 'in-progress', $status__in ) ? ' OR uim.meta_value IS NULL' : '' ) . ')';
145 }
146 $where .= ')';
147 }
148
149 $where .= ' )';
150
151 }
152
153 if ( $args['expired'] ) {
154 $where .= ' AND expiration_time <= UTC_TIMESTAMP()';
155 }
156
157 if ( $args['paginate'] && ! empty( $limit ) ) {
158 $found_rows = 'SQL_CALC_FOUND_ROWS';
159 } else {
160 $found_rows = '';
161 }
162
163 $query = $wpdb->prepare(
164 "
165 SELECT {$found_rows} p.ID course_id, X.*, IF(X.status = %s AND uim.meta_value IS NOT NULL, uim.meta_value, X.status) status
166 FROM(
167 SELECT ui.*
168 FROM {$wpdb->learnpress_user_items} ui
169 LEFT JOIN {$wpdb->learnpress_user_items} uix
170 ON ui.item_id = uix.item_id
171 AND ui.user_id = uix.user_id
172 AND ui.user_item_id < uix.user_item_id
173 WHERE uix.user_item_id IS NULL
174 ) X
175 $join
176 $where
177 $limit
178 ",
179 'finished'
180 );
181
182 $rows = $wpdb->get_results( $query );
183
184 // echo nl2br( $query );
185
186 if ( $args['paginate'] && $args['limit'] ) {
187 $found_courses = sizeof( $rows ) ? $wpdb->get_var( 'SELECT FOUND_ROWS()' ) : 0;
188
189 $return = array(
190 'courses' => $rows,
191 'found_courses' => $found_courses,
192 'max_num_pages' => $found_courses ? ceil( $found_courses / $args['limit'] ) : 0,
193 );
194 } else {
195 $return = $rows;
196 }
197
198 // $query = $wpdb->prepare( "
199 // SELECT X.*
200 // FROM(
201 // SELECT ui.*
202 // FROM {$wpdb->learnpress_user_items} ui
203 // LEFT JOIN {$wpdb->learnpress_user_items} uix
204 // ON ui.item_id = uix.item_id
205 // AND ui.user_id = uix.user_id
206 // AND ui.user_item_id < uix.user_item_id
207 // WHERE uix.user_item_id IS NULL
208 // ) X
209 //
210 // WHERE
211 // AND X.status = %s
212 // AND expiration_time_gmt <= UTC_TIMESTAMP()
213 // LIMIT 0, 10
214 // ", LP_COURSE_CPT, 'enrolled' );
215
216 // echo nl2br( $query );
217 // learn_press_debug( $return );
218
219 return $return;
220 }
221
222 /**
223 * @return void
224 * @deprecated 4.1.6.1
225 */
226 public function init() {
227 if ( $this->_user_id || $this->_course_id ) {
228 if ( ! $this->_course_id ) {
229 $this->_course_id = get_the_ID();
230 }
231
232 if ( ! $this->_user_id ) {
233 $this->_user_id = get_current_user_id();
234 }
235 }
236
237 $user = learn_press_get_user( $this->_user_id );
238
239 if ( $user ) {
240 $this->load( $user );
241 $this->read_course( $user->get_id(), $this->_course_id );
242 }
243 }
244
245 /**
246 * @param LP_User $user
247 */
248 public function create( &$user ) {
249
250 }
251
252 /**
253 * @param LP_User $user
254 */
255 public function update( &$user ) {
256 // TODO: Implement update() method.
257 }
258
259 /**
260 * @param LP_User $user
261 */
262 public function delete( &$user ) {
263 // TODO: Implement delete() method.
264 }
265
266 /**
267 * Load user data
268 *
269 * @param LP_User|LP_Abstract_User $user
270 *
271 * @return mixed;
272 */
273 public function load( &$user ) {
274 $user_id = $user->get_id();
275 $user_object = get_user_by( 'id', $user_id );
276
277 if ( false !== $user_object ) {
278 $user->set_data(
279 array(
280 'email' => $user_object->user_email,
281 'user_login' => $user_object->user_login,
282 'description' => $user_object->description,
283 'first_name' => isset( $user_object->first_name ) ? $user_object->first_name : '',
284 'last_name' => isset( $user_object->last_name ) ? $user_object->last_name : '',
285 'nickname' => isset( $user_object->nickname ) ? $user_object->nickname : '',
286 'display_name' => $user_object->display_name,
287 'date_created' => $user_object->user_registered,
288 'date_modified' => get_user_meta( $user_id, 'last_update', true ),
289 'role' => ! empty( $user_object->roles[0] ) ? $user_object->roles[0] : 'student',
290 'roles' => ! empty( $user_object->roles ) ? $user_object->roles : array( 'student' ),
291 'profile_picture' => get_user_meta( $user_id, '_lp_profile_picture', true ),
292 'profile_privacy' => get_user_meta( $user_id, '_lp_profile_privacy', true ),
293 )
294 );
295 }
296
297 return true;
298 }
299
300 /**
301 * Get all orders of an user grouped by id of course.
302 *
303 * A course can have multi orders, each element is an array of order ids
304 * with the key is id of the course. The orders is sorted from highest
305 * to lowest. With the highest value is the latest order user placed (current order).
306 *
307 * Format:
308 * array(
309 * course_id_1 => array( order_id_1, order_id_2, ...),
310 * course_id_2 => array( order_id_3, order_id_4, ...),
311 * ...
312 * )
313 *
314 * @param int $user_id
315 * @param array $args
316 *
317 * @return array|mixed
318 */
319 public function get_orders( $user_id, $args = array() ) {
320 $user = learn_press_get_user( $user_id );
321
322 if ( ! $user_id || ! $user ) {
323 return false;
324 }
325
326 $cache_key = false;
327 if ( $args ) {
328 $args = wp_parse_args(
329 $args,
330 array(
331 'group_by_order' => false,
332 'status' => '',
333 )
334 );
335
336 ksort( $args );
337 $cache_key = md5( serialize( $args ) );
338
339 /**
340 * Get orders from cache by args
341 */
342 $orders = LP_Object_Cache::get( "user-{$user_id}-" . $cache_key, 'lp-user-orders' );
343
344 if ( false !== $orders ) {
345 return $orders;
346 }
347 }
348
349 // Get orders for the user from cache
350 $orders = LP_Object_Cache::get( 'user-' . $user_id, 'lp-user-orders' );
351
352 if ( false === $orders ) {
353 global $wpdb;
354
355 $orders = array();
356 $post_status_in = learn_press_get_order_statuses( true, true );
357 $post_status_in_format = array_fill( 0, sizeof( $post_status_in ), '%s' );
358 $user_id_str = $wpdb->prepare( '%"%d"%', $user_id );
359
360 // Get order by user
361 $sql_orders = $wpdb->prepare(
362 "
363 SELECT p.*
364 FROM {$wpdb->posts} p
365 INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND meta_key = %s AND (meta_value = %d OR meta_value like '%s')
366 ",
367 '_user_id',
368 $user_id,
369 $user_id_str
370 );
371
372 /**
373 * Get order checked out by Guest but with the email of the user are getting
374 * Error when checkout with guest then register error Start Quiz - nhamdv.
375 */
376 // $sql_guest_orders = $wpdb->prepare(
377 // "
378 // SELECT p.*
379 // FROM {$wpdb->posts} p
380 // INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND meta_key = %s AND meta_value = %s
381 // LEFT JOIN {$wpdb->postmeta} pmu ON p.ID = pmu.post_id AND pmu.meta_key = %s AND pmu.meta_value IS NULL
382 // ",
383 // '_checkout_email',
384 // $user->get_email(),
385 // '_user_id'
386 // );
387
388 /**
389 * The rest
390 */
391 $sql_rest = $wpdb->prepare(
392 '
393 HAVING p.post_type = %s
394 AND p.post_status IN(' . join( ',', $post_status_in_format ) . ')
395 ORDER BY ID DESC
396 ',
397 array_merge(
398 array(
399 LP_ORDER_CPT,
400 ),
401 $post_status_in
402 )
403 );
404
405 $sql = $sql_orders /* . ' UNION ' . $sql_guest_orders */ . $sql_rest;
406
407 $order_posts = $wpdb->get_results( $sql );
408
409 if ( $order_posts ) {
410 $order_ids = array();
411
412 foreach ( $order_posts as $order_post ) {
413 $_post = sanitize_post( $order_post, 'raw' );
414 wp_cache_add( $_post->ID, $_post, 'posts' );
415
416 $order_ids[] = $_post->ID;
417 }
418
419 $order_ids_format = array_fill( 0, sizeof( $order_ids ), '%d' );
420 $query = $wpdb->prepare(
421 "
422 SELECT meta_value as course_id, order_id
423 FROM {$wpdb->learnpress_order_items} oi
424 INNER JOIN {$wpdb->learnpress_order_itemmeta} oim ON oi.order_item_id = oim.learnpress_order_item_id AND oim.meta_key = %s
425 WHERE oi.order_id IN (" . join( ',', $order_ids_format ) . ')
426 ORDER BY FIELD(order_id, ' . join( ',', $order_ids_format ) . ')
427 ',
428 array_merge( array( '_course_id' ), $order_ids, $order_ids )
429 );
430
431 $results = $wpdb->get_results( $query );
432
433 if ( $results ) {
434 foreach ( $results as $result ) {
435 if ( empty( $orders[ $result->course_id ] ) ) {
436 $orders[ $result->course_id ] = array();
437 }
438 $orders[ $result->course_id ][] = $result->order_id;
439 }
440 }
441 }
442
443 LP_Object_Cache::set( 'user-' . $user_id, $orders, 'lp-user-orders' );
444 }
445
446 if ( $orders ) {
447 if ( array_key_exists( 'status', $args ) && $args['status'] ) {
448 LP_Helper::sanitize_order_status( $args['status'] );
449
450 $statuses = (array) $args['status'];
451 foreach ( $orders as $course_id => $order_ids ) {
452 $orders[ $course_id ] = array();
453 foreach ( $order_ids as $order_id ) {
454 if ( in_array( get_post_status( $order_id ), $statuses ) ) {
455 $orders[ $course_id ][] = $order_id;
456 }
457 }
458 }
459 }
460
461 if ( array_key_exists( 'group_by_order', $args ) && $args['group_by_order'] ) {
462 $this->_group_orders( $orders );
463 }
464 }
465
466 if ( $cache_key ) {
467 LP_Object_Cache::set( "user-{$user_id}-" . $cache_key, $orders, 'lp-user-orders' );
468 }
469
470 return $orders;
471 }
472
473 /**
474 * @param $user_id
475 * @param array $args
476 *
477 * @return array|bool|mixed
478 * @editor tungnx
479 * @modify 4.1.4 - comment - not use
480 */
481 // public function read_orders( $user_id, $args = array() ) {
482 // $user = learn_press_get_user( $user_id );
483 //
484 // if ( ! $user_id || ! $user ) {
485 // return false;
486 // }
487 //
488 // $cache_key = false;
489 //
490 // if ( $args ) {
491 // $args = wp_parse_args(
492 // $args,
493 // array(
494 // 'group_by_order' => false,
495 // 'status' => '',
496 // )
497 // );
498 //
499 // ksort( $args );
500 // $cache_key = md5( serialize( $args ) );
501 //
502 // /**
503 // * Get orders from cache by args
504 // */
505 // $orders = LP_Object_Cache::get( "user-{$user_id}-" . $cache_key, 'learn-press/user-orders' );
506 //
507 // if ( false !== $orders ) {
508 // return $orders;
509 // }
510 // }
511 //
512 // $orders = LP_Object_Cache::get( 'user-' . $user_id, 'learn-press/user-orders' );
513 //
514 // if ( false === $orders ) {
515 // global $wpdb;
516 //
517 // $orders = array();
518 // $post_status_in = learn_press_get_order_statuses( true, true );
519 // $post_status_in_format = array_fill( 0, sizeof( $post_status_in ), '%s' );
520 //
521 // // Get order by user
522 // $sql_orders = $wpdb->prepare(
523 // "
524 // SELECT ID, post_title, post_name, post_status, post_type, post_parent, post_date
525 // FROM {$wpdb->posts} p
526 // INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND meta_key = %s AND meta_value = %d
527 // ",
528 // '_user_id',
529 // $user_id
530 // );
531 //
532 // /**
533 // * Get order checked out by Guest but with the email of the user are getting
534 // */
535 // $sql_guest_orders = $wpdb->prepare(
536 // "
537 // SELECT ID, post_title, post_name, post_status, post_type, post_parent, post_date
538 // FROM {$wpdb->posts} p
539 // INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND meta_key = %s AND meta_value = %s
540 // LEFT JOIN {$wpdb->postmeta} pmu ON p.ID = pmu.post_id AND pmu.meta_key = %s AND pmu.meta_value IS NULL
541 // ",
542 // '_checkout_email',
543 // $user->get_email(),
544 // '_user_id'
545 // );
546 //
547 // /**
548 // * The rest
549 // */
550 // $sql_rest = $wpdb->prepare(
551 // '
552 // HAVING p.post_type = %s
553 // AND p.post_status IN(' . join( ',', $post_status_in_format ) . ')
554 // ORDER BY ID DESC
555 // ',
556 // array_merge(
557 // array(
558 // LP_ORDER_CPT,
559 // ),
560 // $post_status_in
561 // )
562 // );
563 //
564 // $sql = $sql_orders . ' UNION ' . $sql_guest_orders . $sql_rest;
565 //
566 // $order_posts = $wpdb->get_results( $sql );
567 //
568 // if ( $order_posts ) {
569 // $order_ids = array();
570 // foreach ( $order_posts as $order_post ) {
571 //
572 // // Put post into cache to user later ... maybe.
573 // $_post = sanitize_post( $order_post, 'raw' );
574 // wp_cache_add( $_post->ID, $_post, 'posts' );
575 //
576 // $order_ids[] = $_post->ID;
577 // }
578 //
579 // $order_ids_format = array_fill( 0, sizeof( $order_ids ), '%d' );
580 // $query = $wpdb->prepare(
581 // "
582 // SELECT meta_value as course_id, order_id
583 // FROM {$wpdb->learnpress_order_items} oi
584 // INNER JOIN {$wpdb->learnpress_order_itemmeta} oim ON oi.order_item_id = oim.learnpress_order_item_id AND oim.meta_key = %s
585 // WHERE oi.order_id IN (" . join( ',', $order_ids_format ) . ')
586 // ORDER BY FIELD(order_id, ' . join( ',', $order_ids_format ) . ')
587 // ',
588 // array_merge( array( '_course_id' ), $order_ids, $order_ids )
589 // );
590 //
591 // if ( $results = $wpdb->get_results( $query ) ) {
592 // foreach ( $results as $result ) {
593 // if ( empty( $orders[ $result->course_id ] ) ) {
594 // $orders[ $result->course_id ] = array();
595 // }
596 // $orders[ $result->course_id ][] = $result->order_id;
597 // }
598 // }
599 // }
600 // // Store to cache
601 // LP_Object_Cache::set( 'user-' . $user_id, $orders, 'learn-press/user-orders' );
602 // }
603 //
604 // if ( $orders ) {
605 //
606 // /*** TEST CACHE */
607 // $all_orders = call_user_func_array( 'array_merge', $orders );
608 //// $curd = new LP_Object_Data_CURD();
609 //// $curd->read_meta_by_ids( $all_orders, 'post' );
610 //
611 // if ( array_key_exists( 'status', $args ) && $args['status'] ) {
612 // LP_Helper::sanitize_order_status( $args['status'] );
613 //
614 // $statuses = (array) $args['status'];
615 // foreach ( $orders as $course_id => $order_ids ) {
616 // $orders[ $course_id ] = array();
617 // foreach ( $order_ids as $order_id ) {
618 // if ( in_array( get_post_status( $order_id ), $statuses ) ) {
619 // $orders[ $course_id ][] = $order_id;
620 // }
621 // }
622 // }
623 // }
624 //
625 // if ( array_key_exists( 'group_by_order', $args ) && $args['group_by_order'] ) {
626 // $this->_group_orders( $orders );
627 // }
628 // }
629 //
630 // if ( $cache_key ) {
631 // LP_Object_Cache::set( "user-{$user_id}-" . $cache_key, $orders, 'learn-press/user-orders' );
632 // }
633 //
634 // return $orders;
635 // }
636
637 protected function _group_orders( &$orders ) {
638 $groups = array();
639 foreach ( $orders as $course_id => $order_ids ) {
640 foreach ( $order_ids as $order_id ) {
641 if ( empty( $groups[ $order_id ] ) ) {
642 $groups[ $order_id ] = array();
643 }
644 $groups[ $order_id ][] = $course_id;
645 }
646 }
647 $orders = $groups;
648 krsort( $orders );
649
650 return $orders;
651 }
652
653 /**
654 * Read course data for an user.
655 *
656 * @param int $user_id
657 * @param int $course_id
658 * @param bool $force - ignore caching.
659 *
660 * @return bool
661 * @editor tungnx
662 * @modify 4.1.2
663 * @Todo should rewrite
664 */
665 public function read_course( int $user_id = 0, int $course_id = null, bool $force = false ) {
666 $lp_user_items_db = LP_User_Items_DB::getInstance();
667
668 if ( is_null( $user_id ) ) {
669 $user_id = get_current_user_id();
670 }
671
672 if ( ! $user_id ) {
673 return false;
674 }
675
676 if ( is_null( $course_id ) ) {
677 $course_id = get_the_ID();
678 }
679
680 if ( is_numeric( $course_id ) && LP_COURSE_CPT !== learn_press_get_post_type( $course_id ) ) {
681 return false;
682 }
683
684 /*$result = LP_Object_Cache::get( 'course-' . $user_id . '-' . $course_id, 'learn-press/user-item-courses' );
685 if ( false !== $result ) {
686 return $result;
687 }*/
688 $last_user_course = false;
689
690 try {
691 /**
692 * Get newest item-course in table user-items
693 */
694 $filter = new LP_User_Items_Filter();
695 $filter->item_id = $course_id;
696 $filter->user_id = $user_id;
697 $last_user_course = $lp_user_items_db->get_last_user_course( $filter );
698
699 if ( ! $last_user_course ) {
700 return false;
701 }
702
703 $last_user_course = (array) $last_user_course;
704 } catch ( Throwable $e ) {
705 error_log( $e->getMessage() );
706 }
707
708 //LP_Object_Cache::set( 'course-' . $user_id . '-' . $course_id, $result, 'learn-press/user-item-courses' );
709
710 return $last_user_course;
711 }
712
713 /**
714 * Load user items by item_id of course item
715 *
716 * @param int $user_item_id
717 *
718 * @return array|bool
719 * @editor tungnx
720 * @deprecated 4.1.5
721 */
722 /*public function read_course_items_by_user_item_id( $user_item_id ) {
723 global $wpdb;
724
725 if ( ! $user_item_id ) {
726 return false;
727 }
728
729 $query = $wpdb->prepare(
730 "
731 SELECT *
732 FROM {$wpdb->learnpress_user_items} ui
733 WHERE ui.parent_id = %d
734 ",
735 $user_item_id
736 );
737
738 $items = $wpdb->get_results( $query );
739
740 return $items;
741 }*/
742
743 /**
744 * @editor tungnx
745 * @deprecated 4.1.5
746 */
747 /*public function read_course_data( $course_id, $user_id ) {
748 global $wpdb;
749
750 $course = learn_press_get_course( $course_id );
751 $course_item_ids = $course->get_items();
752 $course_item_ids_format = LP_Helper::db_format_array( $course_item_ids, '%d' );
753
754 $query = LP_Helper::prepare(
755 "
756 SELECT MAX(user_item_id) user_item_id
757 FROM {$wpdb->learnpress_user_items}
758 WHERE user_id = %d
759 AND item_id IN (" . $course_item_ids_format . ')
760 GROUP BY item_id
761 ',
762 $user_id,
763 $course_item_ids
764 );
765
766 if ( $user_item_ids = $wpdb->get_col( $query ) ) {
767
768 $item_types = learn_press_get_course_item_types();
769 $item_types_format = LP_Helper::db_format_array( $item_types, '%s' );
770 $query = LP_Helper::prepare(
771 "
772 SELECT ui.*, p.post_type AS item_type, grade.meta_value as grade, data.meta_value as data, results.meta_value as results, version.meta_value as version
773 FROM {$wpdb->learnpress_user_items} ui
774 LEFT JOIN {$wpdb->learnpress_user_itemmeta} grade ON ui.user_item_id = grade.learnpress_user_item_id AND grade.meta_key = '%s'
775 LEFT JOIN {$wpdb->learnpress_user_itemmeta} data ON ui.user_item_id = data.learnpress_user_item_id AND data.meta_key = '%s'
776 LEFT JOIN {$wpdb->learnpress_user_itemmeta} results ON ui.user_item_id = results.learnpress_user_item_id AND results.meta_key = '%s'
777 LEFT JOIN {$wpdb->learnpress_user_itemmeta} version ON ui.user_item_id = version.learnpress_user_item_id AND version.meta_key = '%s'
778 INNER JOIN {$wpdb->posts} p ON p.ID = ui.item_id
779 WHERE user_item_id IN(" . LP_Helper::db_format_array( $user_item_ids ) . ')
780 AND p.post_type IN(' . $item_types_format . ')
781 ',
782 'grade',
783 'data',
784 'results',
785 'version',
786 $user_item_ids,
787 $item_types
788 );
789
790 return $wpdb->get_results( $query );
791 }
792
793 return false;
794 }*/
795
796 /**
797 * Get a row in table user-items by user_item_id key
798 *
799 * @param int $user_item_id
800 *
801 * @return object
802 * @editor tungnx
803 * @deprecated 4.1.5
804 */
805 /*public function get_item_by_user_item_id( $user_item_id ) {
806 global $wpdb;
807
808 $query = $wpdb->prepare(
809 "SELECT * FROM {$wpdb->learnpress_user_items} WHERE user_item_id = %d",
810 $user_item_id
811 );
812
813 return $wpdb->get_row( $query );
814 }*/
815
816 /**
817 * Load user items by item_id of course item
818 *
819 * @param object $parent_item
820 * @param bool $force - Optional. Force to read new data from DB (ignore caching).
821 *
822 * @return bool
823 * @editor tungnx
824 * @deprecated 4.1.5
825 */
826 /*public function read_course_items_bak( &$parent_item, $force = false ) {
827 global $wpdb;
828
829 $item_types = learn_press_get_course_item_types();
830 $args = array_merge( $item_types, array( $parent_item['user_item_id'] ) );
831 $format = array_fill( 0, sizeof( $item_types ), '%s' );
832
833 $query = $wpdb->prepare(
834 "
835 SELECT *
836 FROM {$wpdb->learnpress_user_items}
837 WHERE item_type IN(" . join( ',', $format ) . ')
838 AND parent_id = %d
839 ORDER BY item_id, user_item_id DESC
840 ',
841 $args
842 );
843
844 if ( $results = $wpdb->get_results( $query ) ) {
845 $items = array();
846 $meta_ids = array();
847 foreach ( $results as $result ) {
848 $result = (array) $result;
849 $user_item_id = $result['item_id'];
850 if ( empty( $items[ $user_item_id ] ) ) {
851 $items[ $user_item_id ] = array();
852 $parent_item['items'][ $user_item_id ] = $user_item_id;
853 }
854 // $this->_read_item_meta( $result );
855 $meta_ids[] = $result['user_item_id'];
856
857 $items[ $user_item_id ][ $result['user_item_id'] ] = $result;
858 }
859
860 // Batch updating user item meta
861 update_meta_cache( 'learnpress_user_item', $meta_ids );
862 // LP_Helper_CURD::update_meta_cache( 'learnpress_user_item', $meta_ids );
863
864 foreach ( $items as $user_item_id => $_items ) {
865 $cache_name = sprintf(
866 'course-item-%d-%d-%d',
867 $parent_item['user_id'],
868 $parent_item['item_id'],
869 $user_item_id
870 );
871 // Refresh caching
872 LP_Object_Cache::set( $cache_name, $_items, 'learn-press/user-course-items' );
873 }
874 }
875
876 return true;
877 }*/
878
879 /**
880 * Get all items user has already started/completed.
881 *
882 * @param int $user_id
883 * @param int $course_id
884 *
885 * @return mixed
886 * @depecated 4.1.6.9.1
887 */
888 /*public function get_user_items( $user_id, $course_id ) {
889 if ( false === ( $course_data = LP_Object_Cache::get(
890 'course-' . $user_id . '-' . $course_id,
891 'learn-press/user-item-courses'
892 ) ) ) {
893 return false;
894 }
895
896 return $course_data['items'];
897 }*/
898
899 /**
900 * @depecated 4.1.6.9.1
901 */
902 /*public function get_user_completed_items( $user_id, $course_id ) {
903 if ( ! $items = $this->get_user_items( $user_id, $course_id ) ) {
904 return false;
905 }
906 foreach ( $items as $item ) {
907
908 }
909 }*/
910
911 /**
912 * Read meta data of an user item.
913 *
914 * @param $item
915 */
916 protected function _read_item_meta( &$item ) {
917 global $wpdb;
918 $query = $wpdb->prepare(
919 "
920 SELECT *
921 FROM {$wpdb->learnpress_user_itemmeta}
922 WHERE learnpress_user_item_id = %d
923 ",
924 $item['user_item_id']
925 );
926
927 update_meta_cache( 'learnpress_user_item', $item['user_item_id'] );
928
929 if ( $meta = $wpdb->get_results( $query, ARRAY_A ) ) {
930 $item['meta'] = array();
931 foreach ( $meta as $k => $v ) {
932 $v['meta_value'] = LP_Helper::maybe_unserialize( $v['meta_value'] );
933 $item['meta'][ $v['meta_id'] ] = $v;
934 }
935 }
936 }
937
938 public function update_user_item_course() {
939
940 }
941
942 public function update_user_item_course_item() {
943
944 }
945
946 /**
947 * @param int $user_id
948 * @param int $item_id
949 * @param array $item_data
950 * @param int $course_id
951 *
952 * @return mixed
953 * @depecated 4.1.6.9
954 */
955 // public function update_user_item( $user_id, $item_id, $item_data = array(), $course_id = 0 ) {
956 // global $wpdb;
957 //
958 // $user = learn_press_get_user( $user_id );
959 // if ( ! $user || ( $user->get_id() != $user_id ) ) {
960 // return false;
961 // }
962 //
963 // if ( array_key_exists( 'user_item_id', $item_data ) && empty( $item_data['user_item_id'] ) ) {
964 // $item = false;
965 // } else {
966 // if ( func_num_args() == 4 ) {
967 // // $item = $this->get_user_item( $user_id, $item_id, $course_id );
968 // $item = $this->read_course( $user_id, $course_id );
969 // } else {
970 // $item = $this->get_user_item( $user_id, $item_id );
971 // }
972 // }
973 //
974 // // Table fields
975 // $table_fields = array(
976 // 'user_id' => '%d',
977 // 'item_id' => '%d',
978 // 'ref_id' => '%d',
979 // 'start_time' => '%s',
980 // 'end_time' => '%s',
981 // 'item_type' => '%s',
982 // 'status' => '%s',
983 // 'ref_type' => '%s',
984 // 'parent_id' => '%d',
985 // );
986 //
987 // // Data and format
988 // $data = array();
989 // $data_format = array();
990 //
991 // // Update it later...
992 // $new_status = false;
993 // if ( array_key_exists( 'status', $item_data ) && $item_data['status'] != $item['status'] ) {
994 // $new_status = $item_data['status'];
995 // unset( $item_data['status'] );
996 // }
997 //
998 // // Build data and data format
999 // foreach ( $item_data as $field => $value ) {
1000 // if ( ! empty( $table_fields[ $field ] ) ) {
1001 // $data[ $field ] = $value;
1002 // $data_format[ $field ] = $table_fields[ $field ];
1003 // }
1004 // }
1005 //
1006 // $data['user_id'] = $user_id;
1007 // $data['item_id'] = $item_id;
1008 //
1009 // if ( $course_id ) {
1010 // $data['ref_id'] = $course_id;
1011 // $data['ref_type'] = LP_COURSE_CPT;
1012 // } else {
1013 // $data['item_type'] = LP_COURSE_CPT;
1014 // }
1015 //
1016 // foreach ( $data as $k => $v ) {
1017 // $data_format[ $k ] = $table_fields[ $k ];
1018 // }
1019 //
1020 // $data_format = array_values( $data_format );
1021 //
1022 // if ( ! $item || empty( $item['user_item_id'] ) ) {
1023 // if ( $data['ref_type'] === LP_COURSE_CPT && empty( $data['parent_id'] ) ) {
1024 // return false;
1025 // }
1026 //
1027 // $wpdb->insert(
1028 // $wpdb->learnpress_user_items,
1029 // $data,
1030 // $data_format
1031 // );
1032 // $user_item_id = $wpdb->insert_id;
1033 // $item = $this->get_user_item_by_id( $user_item_id );
1034 // } else {
1035 // $user_item_id = $item['user_item_id'];
1036 // $wpdb->update(
1037 // $wpdb->learnpress_user_items,
1038 // $data,
1039 // array( 'user_item_id' => $user_item_id ),
1040 // $data_format,
1041 // array( '%d' )
1042 // );
1043 //
1044 // $item = array_merge( $item, $data );
1045 // }
1046 //
1047 // $is_course = ( ! $course_id ) && ( learn_press_get_post_type( $item['item_id'] ) === LP_COURSE_CPT );
1048 //
1049 // if ( $user_item_id ) {
1050 //
1051 // // Track last status if it is updated new status.
1052 // if ( $new_status !== false ) {
1053 // if ( $this->update_user_item_status( $user_item_id, $new_status ) ) {
1054 // $item['status'] = $new_status;
1055 // }
1056 // }
1057 //
1058 // if ( $is_course ) {
1059 // $course_id = $item['item_id'];
1060 // // Update cache to effect the change right way!
1061 // LP_Object_Cache::set( 'course-' . $user_id . '-' . $course_id, $item, 'learn-press/user-dcourses' );
1062 // } else {
1063 //
1064 // $user = learn_press_get_user( $user_id );
1065 // $user_course = $user->get_course_data( $course_id );
1066 //
1067 // $user_course->set_item( $item );
1068 //
1069 // // Update cache
1070 // $existed = false !== ( $items = LP_Object_Cache::get(
1071 // 'course-item-' . $user_id . '-' . $course_id . '-' . $item_id,
1072 // 'learn-press/user-course-items'
1073 // ) );
1074 //
1075 // if ( false === $items || ! empty( $items[ $user_item_id ] ) ) {
1076 // if ( is_array( $items ) ) {
1077 // $items[ $user_item_id ] = $item;
1078 // } else {
1079 // $items = array( $user_item_id => $item );
1080 // }
1081 // } else {
1082 // $items = array( $user_item_id => $item ) + $items;
1083 // }
1084 //
1085 // LP_Object_Cache::set(
1086 // 'course-item-' . $user_id . '-' . $course_id . '-' . $item_id,
1087 // $items,
1088 // 'learn-press/user-course-items'
1089 // );
1090 //
1091 // }
1092 //
1093 // wp_cache_delete( 'course-' . $user_id . '-' . $course_id, 'learn-press/user-item-object-courses' );
1094 //
1095 // /*
1096 // if ( $existed ) {
1097 // wp_cache_replace( 'course-item-' . $user_id . '-' . $course_id . '-' . $item_id, $items, 'learn-press/user-course-items' );
1098 // } else {
1099 // wp_cache_add( 'course-item-' . $user_id . '-' . $course_id . '-' . $item_id, $items, 'learn-press/user-course-items' );
1100 // }*/
1101 // }
1102 //
1103 // return $user_item_id;
1104 // }
1105
1106 /**
1107 * Get user item from user_items tables.
1108 * If course_id is not passed then return course,
1109 * otherwise return item in that course.
1110 *
1111 * @param int $user_id
1112 * @param int $item_id
1113 * @param int $course_id - Optional. If passed then $item_id should be id of a course's item (such as lesson, quiz, etc...)
1114 * @param bool $last
1115 *
1116 * @return bool|mixed
1117 */
1118 public function get_user_item( $user_id, $item_id, $course_id = 0, $last = true ) {
1119 $num_args = func_num_args();
1120
1121 if ( $num_args == 2 ) {
1122 $this->read_course( $user_id, $item_id );
1123 $item = LP_Object_Cache::get( 'course-' . $user_id . '-' . $item_id, 'learn-press/user-item-courses' );
1124 } else {
1125 $this->read_course( $user_id, $course_id );
1126 $cache_name = sprintf( 'course-item-%d-%d-%d', $user_id, $course_id, $item_id );
1127 $item = LP_Object_Cache::get( $cache_name, 'learn-press/user-course-items' );
1128
1129 if ( $last && $item ) {
1130 $item = reset( $item );
1131 }
1132 }
1133
1134 return $item;
1135 }
1136
1137 /**
1138 * @param int $user_item_id
1139 * @param string $type
1140 *
1141 * @return array
1142 */
1143 public function get_user_item_by_id( $user_item_id, $type = '' ) {
1144 global $wpdb;
1145
1146 $query = $wpdb->prepare(
1147 "
1148 SELECT *
1149 FROM {$wpdb->learnpress_user_items}
1150 WHERE user_item_id = %d
1151 " . ( $type ? $wpdb->prepare( 'AND item_type = %s', $type ) : '' ) . '
1152 ',
1153 $user_item_id
1154 );
1155 $item = $wpdb->get_row( $query, ARRAY_A );
1156
1157 return $item;
1158 }
1159
1160 /**
1161 * @param int $user_item_id
1162 *
1163 * @return bool|LP_User_Item_Course
1164 * @depecated 4.1.6.9
1165 */
1166 /*public function get_user_item_course( $user_item_id ) {
1167 if ( $item = $this->get_user_item_by_id( $user_item_id, LP_COURSE_CPT ) ) {
1168 return new LP_User_Item_Course( $item );
1169 }
1170
1171 return false;
1172 }*/
1173
1174 /**
1175 * @depecated 4.1.6.9
1176 */
1177 /*public function get_user_item_meta( $user_item_id, $meta_key, $single = true ) {
1178 return learn_press_get_user_item_meta( $user_item_id, $meta_key, $single );
1179 }*/
1180
1181 /**
1182 * @depecated 4.1.6.9
1183 */
1184 /*public function update_user_item_meta( $user_item_id, $meta_key, $meta_value, $prev = '' ) {
1185 return learn_press_update_user_item_meta( $user_item_id, $meta_key, $meta_value, $prev );
1186 }*/
1187
1188 /**
1189 * Update user item data by id.
1190 *
1191 * @param int $user_item_id
1192 * @param array $item_data
1193 *
1194 * @return bool
1195 * @editor tungnx
1196 * @modify 4.1.3 - comment - not use
1197 */
1198 /*public function update_user_item_by_id( $user_item_id, $item_data = array() ) {
1199 global $wpdb;
1200
1201 $item = $this->get_user_item_by_id( $user_item_id );
1202
1203 if ( ! $item ) {
1204 return false;
1205 }
1206
1207 // Table fields
1208 $table_fields = array(
1209 'user_item_id' => '%d',
1210 'user_id' => '%d',
1211 'item_id' => '%d',
1212 'ref_id' => '%d',
1213 'start_time' => '%s',
1214 'end_time' => '%s',
1215 'item_type' => '%s',
1216 'status' => '%s',
1217 'ref_type' => '%s',
1218 'parent_id' => '%d',
1219 );
1220
1221 // Data and format
1222 $data = array();
1223 $data_format = array();
1224
1225 // Update it later...
1226 $new_status = false;
1227 if ( array_key_exists( 'status', $item_data ) && $item_data['status'] != $item['status'] ) {
1228 $new_status = $item_data['status'];
1229 unset( $item_data['status'] );
1230 }
1231
1232 // Build data and data format
1233 foreach ( $item_data as $field => $value ) {
1234 if ( ! empty( $table_fields[ $field ] ) ) {
1235 $data[ $field ] = $value;
1236 $data_format[ $field ] = $table_fields[ $field ];
1237 }
1238 }
1239
1240 if ( $data ) {
1241 $updated = $wpdb->update(
1242 $wpdb->learnpress_user_items,
1243 $data,
1244 array( 'user_item_id' => $user_item_id ),
1245 $data_format,
1246 array( '%d' )
1247 );
1248 }
1249
1250 // Track last status if it is updated new status.
1251 if ( $new_status !== false ) {
1252 $this->update_user_item_status( $user_item_id, $new_status );
1253 }
1254
1255 return isset( $updated ) ? $updated : $user_item_id;
1256 }*/
1257
1258 /**
1259 * Update status of an user item by id.
1260 *
1261 * @param int $user_item_id
1262 * @param string $new_status
1263 *
1264 * @return mixed
1265 */
1266 public function update_user_item_status( $user_item_id, $new_status ) {
1267 global $wpdb;
1268 $item = $this->get_user_item_by_id( $user_item_id );
1269 if ( ! $item ) {
1270 return false;
1271 }
1272
1273 // No need to update if it is not change
1274 if ( $item['status'] === $new_status ) {
1275 return false;
1276 }
1277
1278 $updated = $wpdb->update(
1279 $wpdb->learnpress_user_items,
1280 array( 'status' => $new_status ),
1281 array( 'user_item_id' => $user_item_id ),
1282 array( '%s' ),
1283 array( '%d' )
1284 );
1285 // if ( $updated ) {
1286 // $this->update_user_item_meta( $user_item_id, '_last_status', $item['status'] );
1287 // $this->update_user_item_meta( $user_item_id, '_current_status', $new_status );
1288 // }
1289
1290 return $updated;
1291 }
1292
1293 // public function restore_last_status( $user_item_id ) {
1294 // $item = $this->get_user_item_by_id( $user_item_id );
1295 // if ( ! $item ) {
1296 // return false;
1297 // }
1298
1299 // if ( $last_status = $this->get_user_item_meta( $item['user_item_id'], '_last_status', true ) ) {
1300 // $this->update_user_item_status( $user_item_id, $last_status );
1301 // learn_press_delete_user_item_meta( $user_item_id, '_last_status', '', true );
1302 // }
1303
1304 // return $last_status;
1305 // }
1306
1307 /**
1308 * Delete user item by fields.
1309 *
1310 * @param string $args
1311 *
1312 * @return bool
1313 */
1314 public function delete_user_item( $args = '' ) {
1315 global $wpdb;
1316 $args = wp_parse_args(
1317 $args,
1318 array(
1319 'user_id' => 0,
1320 'item_id' => 0,
1321 'ref_id' => 0,
1322 'parent_id' => 0,
1323 )
1324 );
1325 $where = array();
1326 foreach ( $args as $k => $v ) {
1327 if ( $v ) {
1328 $where[ $k ] = $v;
1329 }
1330 }
1331
1332 if ( ! $where ) {
1333 return false;
1334 }
1335 $query_where = array();
1336 foreach ( $where as $k => $v ) {
1337 $query_where[] = "{$k} = %d";
1338 }
1339
1340 $query = $wpdb->prepare(
1341 "SELECT user_item_id FROM {$wpdb->learnpress_user_items} WHERE " . join(
1342 ' AND ',
1343 $query_where
1344 ),
1345 array_values( $where )
1346 );
1347 $user_item_ids = $wpdb->get_col( $query );
1348
1349 $wpdb->delete(
1350 $wpdb->learnpress_user_items,
1351 $where,
1352 array_fill( 0, sizeof( $where ), '%d' )
1353 );
1354
1355 foreach ( $user_item_ids as $user_item_id ) {
1356 $wpdb->query(
1357 $wpdb->prepare(
1358 "DELETE FROM {$wpdb->learnpress_user_itemmeta} WHERE learnpress_user_item_id = %d",
1359 $user_item_id
1360 )
1361 );
1362 do_action( 'learn-press/deleted-user-item', $user_item_id );
1363 }
1364
1365 return true;
1366 }
1367
1368 /**
1369 * Delete a row from user items by user_item_id key.
1370 *
1371 * @param int $user_item_id
1372 *
1373 * @return mixed
1374 */
1375 /*public function delete_by_user_item_id( $user_item_id ) {
1376 global $wpdb;
1377
1378 $query = $wpdb->prepare(
1379 "
1380 SELECT *
1381 FROM {$wpdb->learnpress_user_items}
1382 WHERE parent_id = %d
1383 ",
1384 $user_item_id
1385 );
1386
1387 // Delete child items (lessons, quizzes, etc) in case the item being deleted is a course
1388 if ( $child = $wpdb->get_col( $query ) ) {
1389 foreach ( $child as $child_id ) {
1390 $this->delete_by_user_item_id( $child_id );
1391 }
1392 }
1393
1394 // Delete origin item
1395 $query = $wpdb->prepare(
1396 "
1397 DELETE
1398 FROM ui, uim
1399 USING {$wpdb->prefix}learnpress_user_items AS ui
1400 LEFT JOIN {$wpdb->prefix}learnpress_user_itemmeta AS uim ON ui.user_item_id = uim.learnpress_user_item_id
1401 WHERE user_item_id = %d
1402 ",
1403 $user_item_id
1404 );
1405
1406 return $wpdb->query( $query );
1407 }*/
1408
1409 /**
1410 * Query own courses of an user.
1411 *
1412 * @param int $user_id
1413 * @param array $args
1414 *
1415 * @return LP_Query_List_Table
1416 * @editor tungnx
1417 * @modify 4.1.5 - comment
1418 * @deprecated 4.1.5
1419 */
1420 /*public function query_own_courses( int $user_id = 0, array $args = array() ): LP_Query_List_Table {
1421 global $wpdb, $wp;
1422 $paged = 1;
1423
1424 if ( ! empty( $wp->query_vars['view_id'] ) ) {
1425 $paged = absint( $wp->query_vars['view_id'] );
1426 }
1427
1428 $limit = LP_Settings::get_option( 'archive_course_limit', 6 );
1429 if ( empty( $limit ) ) {
1430 $limit = 6;
1431 }
1432
1433 $paged = max( $paged, 1 );
1434 $args = wp_parse_args(
1435 $args,
1436 array(
1437 'paged' => $paged,
1438 'limit' => $limit,
1439 'status' => '',
1440 )
1441 );
1442
1443 if ( ! $user_id ) {
1444 $user_id = get_current_user_id();
1445 }
1446
1447 $cache_key = sprintf( 'own-courses-%d-%s', $user_id, md5( build_query( $args ) ) );
1448 $courses = LP_Object_Cache::get( $cache_key, 'learn-press/user-courses' );
1449
1450 if ( false === $courses ) {
1451 $courses = array(
1452 'total' => 0,
1453 'paged' => $args['paged'],
1454 'limit' => $args['limit'],
1455 'pages' => 0,
1456 'items' => array(),
1457 );
1458
1459 try {
1460 $query = array(
1461 'total' => 0,
1462 'pages' => 0,
1463 'items' => false,
1464 );
1465
1466 $limit = $args['limit'];
1467 $where = 'WHERE 1';
1468 $offset = ( $args['paged'] - 1 ) * $limit;
1469
1470 if ( ! empty( $args['status'] ) ) {
1471 if ( is_array( $args['status'] ) ) {
1472 $a = array_fill( 0, sizeof( $where ), '%d' );
1473 $where .= $wpdb->prepare( ' AND post_status IN(' . join( ',', $where ) . ')', $a );
1474 } else {
1475 if ( 'pending' === $args['status'] ) {
1476 $where .= $wpdb->prepare( ' AND post_status IN( %s, %s )', array( 'draft', 'pending' ) );
1477 } elseif ( $args['status'] !== '*' ) {
1478 $where .= $wpdb->prepare( ' AND post_status = %s', $args['status'] );
1479 }
1480 }
1481 } else {
1482 $where .= $wpdb->prepare( ' AND post_status NOT IN (%s, %s)', array( 'trash', 'auto-draft' ) );
1483 }
1484
1485 $where = $where . $wpdb->prepare( ' AND post_type = %s AND post_author = %d', LP_COURSE_CPT, $user_id );
1486
1487 $join = '';
1488
1489 do_action( 'learnpress/user-curd/query_where_join_own_courses', $where, $join );
1490
1491 $sql = "
1492 SELECT SQL_CALC_FOUND_ROWS ID
1493 FROM {$wpdb->posts} c
1494 {$join}
1495 {$where}
1496 ORDER BY ID DESC
1497 LIMIT {$offset}, {$limit}
1498 ";
1499
1500 do_action( 'learnpress/user-curd/query_string_own_courses', $sql );
1501
1502 $items = $wpdb->get_results( $sql );
1503 $count = $wpdb->get_var( 'SELECT FOUND_ROWS()' );
1504 $all_courses = learnpress_get_count_by_user( $user_id, 'lp_course' );
1505
1506 if ( $items ) {
1507 $course_ids = wp_list_pluck( $items, 'ID' );
1508 LP_Helper::cache_posts( $course_ids );
1509
1510 $courses['total'] = $count;
1511 $courses['pages'] = ceil( $count / $args['limit'] );
1512
1513 foreach ( $items as $item ) {
1514 $courses['items'][] = $item->ID;
1515 }
1516 }
1517
1518 $courses['counts'] = array(
1519 'all' => $all_courses['all'],
1520 'publish' => $all_courses['publish'],
1521 'pending' => $all_courses['pending'],
1522 );
1523 } catch ( Exception $ex ) {
1524 learn_press_add_message( $ex->getMessage() );
1525 }
1526
1527 LP_Object_Cache::set( $cache_key, $courses, 'learn-press/user-courses' );
1528 }
1529
1530 $courses['single'] = __( 'course', 'learnpress' );
1531 $courses['plural'] = __( 'courses', 'learnpress' );
1532
1533 return new LP_Query_List_Table( $courses );
1534 }*/
1535
1536 /**
1537 * Query courses by user
1538 *
1539 * @param int $user_id
1540 * @param array $args
1541 *
1542 * @return LP_Query_List_Table
1543 * @editor tungnx
1544 * @modify 4.1.5 - comment
1545 * @deprecated 4.1.5
1546 */
1547 /*public function query_purchased_courses( int $user_id = 0, array $args = array() ): LP_Query_List_Table {
1548 global $wpdb, $wp;
1549 $paged = 1;
1550
1551 if ( ! empty( $wp->query_vars['view_id'] ) ) {
1552 $paged = absint( $wp->query_vars['view_id'] );
1553 }
1554
1555 $limit = LP_Settings::get_option( 'archive_course_limit', 6 );
1556 if ( empty( $limit ) ) {
1557 $limit = 6;
1558 }
1559
1560 $args = wp_parse_args(
1561 $args,
1562 array(
1563 'paged' => $paged,
1564 'limit' => $limit,
1565 'status' => '',
1566 )
1567 );
1568
1569 $args['paged'] = max( $args['paged'], 1 );
1570
1571 if ( ! $user_id ) {
1572 $user_id = get_current_user_id();
1573 }
1574
1575 $cache_key = sprintf( 'purchased-courses-%d-%s', $user_id, md5( build_query( $args ) ) );
1576 $courses = LP_Object_Cache::get( $cache_key, 'learn-press/user-courses' );
1577
1578 if ( false === $courses ) {
1579 $courses = array(
1580 'total' => 0,
1581 'paged' => $args['paged'],
1582 'limit' => $args['limit'],
1583 'pages' => 0,
1584 'items' => array(),
1585 );
1586
1587 try {
1588 $orders = $this->get_orders( $user_id, array( 'status' => 'completed' ) );
1589
1590 $course_ids = array();
1591
1592 if ( $orders ) {
1593 $course_ids = array_keys( $orders );
1594 }
1595
1596 $item_ids = $wpdb->get_col(
1597 $wpdb->prepare(
1598 "SELECT item_id FROM {$wpdb->learnpress_user_items} WHERE user_id=%d AND item_type=%s",
1599 $user_id,
1600 LP_COURSE_CPT
1601 )
1602 );
1603
1604 if ( $item_ids ) {
1605 $course_ids = array_merge( $course_ids, $item_ids );
1606 }
1607
1608 $query = array(
1609 'total' => 0,
1610 'pages' => 0,
1611 'items' => false,
1612 );
1613
1614 if ( ! $course_ids ) {
1615 throw new Exception( '', 0 );
1616 }
1617
1618 $query_args = $course_ids;
1619 $query_args[] = $user_id;
1620 $limit = $args['limit'];
1621 $offset = ( $args['paged'] - 1 ) * $limit;
1622
1623 // SELECT
1624 $select = 'SELECT c.ID, c.post_title, ui.*';
1625
1626 // FROM
1627 $from = "FROM {$wpdb->learnpress_user_items} ui";
1628
1629 // JOIN
1630 $join = $wpdb->prepare(
1631 "INNER JOIN {$wpdb->posts} c ON ui.item_id = c.ID AND c.post_type = %s",
1632 LP_COURSE_CPT
1633 );
1634
1635 // WHERE - modify by tungnx
1636 $where = $wpdb->prepare(
1637 '
1638 WHERE ui.user_id = %d
1639 AND c.ID IN(' . join( ',', $course_ids ) . ')
1640 AND c.post_status = %s
1641 ',
1642 $user_id,
1643 'publish'
1644 );
1645 $count_where = $where;
1646
1647 // HAVING
1648 $having = 'HAVING 1';
1649
1650 // ORDER BY
1651 $orderby = 'ORDER BY start_time DESC';
1652
1653 if ( ! empty( $args['status'] ) ) {
1654 switch ( $args['status'] ) {
1655 case 'finished':
1656 case 'passed':
1657 case 'failed':
1658 $where .= $wpdb->prepare(
1659 ' AND ui.status IN( %s )',
1660 array(
1661 'finished',
1662 )
1663 );
1664
1665 if ( $args['status'] !== 'finished' ) {
1666 if ( 'passed' === $args['status'] ) {
1667 $having .= $wpdb->prepare( ' AND ui.graduation = %s', 'passed' );
1668 } else {
1669 $having .= $wpdb->prepare( ' AND ( ui.graduation = %s )', 'failed' );
1670 }
1671 }
1672
1673 break;
1674 case 'in-progress':
1675 $where .= $wpdb->prepare(
1676 ' AND ui.status IN( %s )',
1677 array(
1678 'enrolled',
1679 )
1680 );
1681
1682 $having .= $wpdb->prepare( ' AND ui.graduation = %s', 'in-progress' );
1683
1684 break;
1685 case 'not-enrolled':
1686 $where .= $wpdb->prepare(
1687 ' AND ui.status NOT IN( %s, %s, %s )',
1688 array(
1689 'enrolled',
1690 'finished',
1691 'pending',
1692 )
1693 );
1694 }
1695 }
1696
1697 // Comment by tungnx
1698 //$where .= $wpdb->prepare( ' AND ui.status NOT IN(%s) ', 'pending' );
1699
1700 $query_parts = apply_filters(
1701 'learn-press/query/user-purchased-courses',
1702 compact( 'select', 'from', 'join', 'where', 'having', 'orderby' ),
1703 $user_id,
1704 $args
1705 );
1706
1707 list( $select, $from, $join, $where, $having, $orderby ) = array_values( $query_parts );
1708
1709 if ( $args['limit'] > 0 ) {
1710 $limit = "LIMIT {$offset}, {$limit}";
1711 } else {
1712 $limit = '';
1713 }
1714
1715 do_action( 'learnpress/user-curd/query_where_join_purchased_courses', $where, $join );
1716
1717 $sql = "
1718 SELECT SQL_CALC_FOUND_ROWS *
1719 FROM
1720 (
1721 {$select}
1722 {$from}
1723 {$join}
1724 {$where}
1725 {$having}
1726 ORDER BY item_id, user_item_id DESC
1727 ) X
1728 GROUP BY item_id
1729 {$orderby}
1730 $limit
1731 ";
1732
1733 do_action( 'learnpress/user-curd/query_string_purchased_courses', $sql );
1734
1735 $items = $wpdb->get_results( $sql );
1736
1737 if ( $items ) {
1738 $count = $wpdb->get_var( 'SELECT FOUND_ROWS()' );
1739 $course_ids = wp_list_pluck( $items, 'item_id' );
1740 LP_Helper::cache_posts( $course_ids );
1741
1742 $courses['total'] = $count;
1743 $courses['pages'] = $args['limit'] > 0 ? ceil( $count / $args['limit'] ) : 1;
1744 foreach ( $items as $item ) {
1745 $item = (array) $item;
1746 $course_item = new LP_User_Item_Course( $item );
1747 $courses['items'][] = $course_item;
1748 }
1749 }
1750
1751 $counts = array(
1752 'all' => 0,
1753 'enrolled' => 0,
1754 'finished' => 0,
1755 );
1756
1757 $sql = "
1758 SELECT user_item_id
1759 FROM
1760 (
1761 {$select}
1762 {$from}
1763 {$join}
1764 {$count_where}
1765 ) X
1766 GROUP BY item_id
1767 ";
1768
1769 $user_item_ids = $wpdb->get_col( $sql );
1770 if ( $user_item_ids ) {
1771 $rows = $wpdb->get_results(
1772 "
1773 SELECT status, COUNT(user_item_id) count
1774 FROM {$wpdb->learnpress_user_items}
1775 WHERE user_item_id in(" . join( ',', $user_item_ids ) . ')
1776 GROUP BY status
1777 '
1778 );
1779
1780 if ( $rows ) {
1781 foreach ( $rows as $row ) {
1782 $counts[ $row->status ] = $row->count;
1783 $counts['all'] += $row->count;
1784 }
1785 }
1786 }
1787
1788 $counts['not-enrolled'] = $counts['all'] - ( $counts['enrolled'] + $counts['finished'] );
1789 $sql = $wpdb->prepare(
1790 "
1791 SELECT COUNT(meta_id) count, meta_value `status`
1792 FROM (
1793 SELECT user_id, item_id, MAX(user_item_id) max_id
1794 FROM {$wpdb->learnpress_user_items} GROUP BY user_id, item_id
1795 ) X
1796 INNER JOIN {$wpdb->learnpress_user_items} ui ON X.max_id = ui.user_item_id
1797 INNER JOIN {$wpdb->learnpress_user_itemmeta} uim ON ui.user_item_id=uim.learnpress_user_item_id
1798 WHERE uim.meta_key LIKE '%grade%'
1799 AND ui.user_id = %d AND ui.item_type = %s
1800 GROUP BY meta_value
1801 ",
1802 $user_id,
1803 LP_COURSE_CPT
1804 );
1805
1806 $rows = $wpdb->get_results( $sql );
1807 if ( $rows ) {
1808 foreach ( $rows as $row ) {
1809 $counts[ $row->status ] = $row->count;
1810 }
1811 }
1812
1813 $courses['counts'] = $counts;
1814 } catch ( Exception $ex ) {
1815
1816 }
1817
1818 LP_Object_Cache::set( $cache_key, $courses, 'learn-press/user-courses' );
1819 }
1820
1821 $courses['single'] = __( 'course', 'learnpress' );
1822 $courses['plural'] = __( 'courses', 'learnpress' );
1823
1824 return new LP_Query_List_Table( $courses );
1825 }*/
1826
1827 /**
1828 * Get courses user has purchased via orders are completed
1829 * but it is not already added to user-items table.
1830 *
1831 * @param int $user_id
1832 *
1833 * @return array|bool|mixed
1834 */
1835 public function query_courses_by_order( $user_id ) {
1836 global $wpdb;
1837
1838 $query = $wpdb->prepare(
1839 "
1840 SELECT item_id
1841 FROM {$wpdb->learnpress_user_items}
1842 WHERE user_id = %d
1843 AND item_type = %s
1844 ",
1845 $user_id,
1846 LP_COURSE_CPT
1847 );
1848 $user_item_ids = $wpdb->get_col( $query );
1849
1850 $orders = $this->get_orders(
1851 $user_id,
1852 array(
1853 'status' => 'completed',
1854 'group_by_order' => true,
1855 )
1856 );
1857
1858 if ( ! $orders ) {
1859 return false;
1860 }
1861
1862 $course_ids = array_shift( $orders );
1863
1864 foreach ( $orders as $ids ) {
1865 if ( ! $ids ) {
1866 continue;
1867 }
1868 $course_ids = array_merge( $course_ids, $ids );
1869 }
1870
1871 if ( $user_item_ids ) {
1872 $course_ids = array_diff( $course_ids, $user_item_ids );
1873 }
1874
1875 return $course_ids;
1876 }
1877
1878 /**
1879 * Query quizzes by user.
1880 *
1881 * @param int $user_id
1882 * @param string $args
1883 *
1884 * @return LP_Query_List_Table
1885 */
1886 public function query_quizzes( $user_id = 0, $args = '' ) {
1887 global $wpdb, $wp;
1888
1889 $paged = 1;
1890
1891 if ( ! empty( $wp->query_vars['view_id'] ) ) {
1892 $paged = absint( $wp->query_vars['view_id'] );
1893 }
1894
1895 $paged = max( $paged, 1 );
1896 $args = wp_parse_args(
1897 $args,
1898 array(
1899 'paged' => $paged,
1900 'limit' => 10,
1901 'status' => '',
1902 )
1903 );
1904
1905 if ( ! $user_id ) {
1906 $user_id = get_current_user_id();
1907 }
1908
1909 $cache_key = sprintf( 'quizzes-%d-%s', $user_id, md5( build_query( $args ) ) );
1910 $quizzes = LP_Object_Cache::get( $cache_key, 'learn-press/user-quizzes' );
1911
1912 if ( false === $quizzes ) {
1913 $orders = $this->get_orders( $user_id );
1914 $query = array(
1915 'total' => 0,
1916 'pages' => 0,
1917 'items' => false,
1918 );
1919
1920 $quizzes = array(
1921 'total' => 0,
1922 'paged' => $args['paged'],
1923 'limit' => $args['limit'],
1924 'pages' => 0,
1925 'items' => array(),
1926 );
1927
1928 try {
1929 if ( ! $orders ) {
1930 throw new Exception( __( 'No item in Order', 'learnpress' ), 0 );
1931 }
1932
1933 $course_ids = array_keys( $orders );
1934 $query_args = $course_ids;
1935 $query_args[] = $user_id;
1936
1937 $select = 'SELECT * ';
1938 $from = "FROM {$wpdb->learnpress_user_items} ui";
1939 $join = '';
1940 $where = 'WHERE 1=1 ';
1941 $where .= $wpdb->prepare( 'AND user_id = %d ', $user_id );
1942 $where .= $wpdb->prepare( 'AND item_type = %s ', LP_QUIZ_CPT );
1943 $where .= $wpdb->prepare( 'AND status IN (%s, %s) ', LP_ITEM_COMPLETED, LP_ITEM_STARTED );
1944 $having = 'HAVING 1';
1945 $orderby = 'ORDER BY item_id, user_item_id DESC';
1946
1947 if ( ! empty( $args['status'] ) ) {
1948 switch ( $args['status'] ) {
1949 case 'completed':
1950 case 'passed':
1951 case 'failed':
1952 $having .= $wpdb->prepare(
1953 ' AND X.status IN( %s )',
1954 array(
1955 'completed',
1956 )
1957 );
1958
1959 if ( $args['status'] !== 'completed' ) {
1960 if ( 'passed' === $args['status'] ) {
1961 $having .= $wpdb->prepare( ' AND X.graduation = %s', 'passed' );
1962 } elseif ( 'failed' === $args['status'] ) {
1963 $having .= $wpdb->prepare( ' AND X.graduation = %s', 'failed' );
1964 } else {
1965 $having .= $wpdb->prepare( ' AND ( X.graduation IS NULL OR X.graduation <> %s )', 'passed' );
1966 }
1967 }
1968 break;
1969
1970 case 'in-progress':
1971 $having .= $wpdb->prepare(
1972 ' AND X.status IN( %s ) AND X.graduation NOT IN ( %s, %s )',
1973 array(
1974 'started',
1975 'passed',
1976 'failed',
1977 )
1978 );
1979 break;
1980
1981 case 'not-started':
1982 $having .= $wpdb->prepare(
1983 ' AND X.status NOT IN( %s, %s )',
1984 array(
1985 'started',
1986 'completed',
1987 )
1988 );
1989 break;
1990 }
1991 } else {
1992
1993 $having .= $wpdb->prepare(
1994 ' AND X.status IN( %s, %s )',
1995 array(
1996 'started',
1997 'completed',
1998 )
1999 );
2000 }
2001 $limit = $args['limit'];
2002 $offset = ( $args['paged'] - 1 ) * $limit;
2003
2004 $query_parts = apply_filters(
2005 'learn-press/query/user-quizzes',
2006 compact( 'select', 'from', 'join', 'where', 'having', 'orderby' ),
2007 $user_id,
2008 $args
2009 );
2010
2011 list( $select, $from, $join, $where, $having, $orderby ) = array_values( $query_parts );
2012
2013 $sql = $wpdb->prepare(
2014 "
2015 SELECT * FROM (
2016 SELECT *
2017 FROM
2018 (
2019 {$select}
2020 {$from}
2021 {$join}
2022 {$where}
2023 ORDER BY user_item_id DESC
2024 ) AS G_Item
2025 GROUP BY G_Item.item_id
2026 ) AS G_User_Item
2027 ORDER BY G_User_Item.user_item_id DESC
2028 LIMIT %d, %d
2029 ",
2030 $offset,
2031 $limit
2032 );
2033
2034 $sql = "SELECT DISTINCT item_id, MAX(user_item_id) as user_item_id , user_id, item_type, start_time, end_time, status, graduation, parent_id
2035 FROM $wpdb->learnpress_user_items
2036 WHERE user_id = $user_id
2037 AND item_type = 'lp_quiz'
2038 AND status IN ('completed', 'started')
2039 GROUP BY item_id
2040 ORDER BY MAX(user_item_id) DESC";
2041
2042 $items = $wpdb->get_results( $sql, ARRAY_A );
2043
2044 if ( $items ) {
2045 $count = $wpdb->get_var( 'SELECT FOUND_ROWS()' );
2046 $course_ids = wp_list_pluck( $items, 'item_id' );
2047 // LP_Helper::cache_posts( $course_ids );
2048
2049 $quizzes['total'] = $count;
2050 $quizzes['pages'] = ceil( $count / $args['limit'] );
2051
2052 foreach ( $items as $item ) {
2053 $quizzes['items'][] = new LP_User_Item_Quiz( $item );
2054 }
2055 }
2056 } catch ( Exception $ex ) {
2057
2058 }
2059 LP_Object_Cache::set( $cache_key, $quizzes, 'learn-press/user-course' );
2060 }
2061
2062 $quizzes['single'] = __( 'quiz', 'learnpress' );
2063 $quizzes['plural'] = __( 'quizzes', 'learnpress' );
2064
2065 return new LP_Query_List_Table( $quizzes );
2066 }
2067
2068 public function read_course_info( $course ) {
2069 $data = $course;
2070 global $wpdb;
2071 $query = $wpdb->prepare(
2072 "
2073 SELECT *
2074 FROM {$wpdb->learnpress_user_itemmeta}
2075 WHERE learnpress_user_item_id = %d
2076 ",
2077 $course['user_item_id']
2078 );
2079
2080 $itemmeta = $wpdb->get_results( $query, ARRAY_A );
2081
2082 if ( $itemmeta ) {
2083 foreach ( $itemmeta as $item ) {
2084 $data[ $item['meta_key'] ] = $item['meta_value'];
2085 }
2086 }
2087
2088 return $data;
2089 }
2090
2091 public function update_item( $item ) {
2092 global $wpdb;
2093 if ( empty( $item['user_item_id'] ) ) {
2094 $wpdb->insert(
2095 $wpdb->learnpress_user_items,
2096 $item
2097 );
2098 }
2099 }
2100
2101 public function get_current_user_order( $user_id, $course_id ) {
2102 global $wpdb;
2103 $sql = $wpdb->prepare(
2104 "
2105 SELECT MAX(ID) AS order_id
2106 FROM {$wpdb->posts} p
2107 INNER JOIN {$wpdb->postmeta} pm_u ON pm_u.post_id = p.ID AND pm_u.meta_key = %s AND pm_u.meta_value = %d
2108 INNER JOIN {$wpdb->learnpress_order_items} oi ON oi.order_id = p.id
2109 INNER JOIN {$wpdb->learnpress_order_itemmeta} oim ON oim.meta_key = %s and oim.meta_value = %d
2110 ",
2111 '_user_id',
2112 $user_id,
2113 '_course_id',
2114 $course_id
2115 );
2116 $order_id = $wpdb->get_var( $sql );
2117
2118 return $order_id;
2119 }
2120
2121 public function duplicate( &$user, $args = array() ) {
2122 // TODO: Implement duplicate() method.
2123 }
2124
2125 public static function create_user( $email, $username, $password ) {
2126 if ( empty( $email ) || ! is_email( $email ) ) {
2127 return new WP_Error( 'registration-error-invalid-email', __( 'Please provide a valid email address.', 'learnpress' ) );
2128 }
2129
2130 if ( email_exists( $email ) ) {
2131 return new WP_Error( 'registration-error-email-exists', __( 'An account is already registered with your email address. Please log in.', 'learnpress' ) );
2132 }
2133
2134 $username = sanitize_user( $username );
2135
2136 if ( empty( $username ) || ! validate_username( $username ) ) {
2137 return new WP_Error( 'registration-error-invalid-username', __( 'Please enter a valid account username.', 'learnpress' ) );
2138 }
2139
2140 if ( username_exists( $username ) ) {
2141 return new WP_Error( 'registration-error-username-exists', __( 'An account is already registered with that username. Please choose another.', 'learnpress' ) );
2142 }
2143
2144 $new_user = wp_insert_user(
2145 array(
2146 'user_login' => $username,
2147 'user_pass' => $password,
2148 'user_email' => $email,
2149 )
2150 );
2151
2152 if ( is_wp_error( $new_user ) ) {
2153 return new WP_Error( 'registration-error', __( 'Failed to create user', 'learnpress' ) );
2154 }
2155
2156 return $new_user;
2157 }
2158 }
2159