PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.1.6.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.1.6.9
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.6.9, 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 */
887 public function get_user_items( $user_id, $course_id ) {
888 if ( false === ( $course_data = LP_Object_Cache::get(
889 'course-' . $user_id . '-' . $course_id,
890 'learn-press/user-item-courses'
891 ) ) ) {
892 return false;
893 }
894
895 return $course_data['items'];
896 }
897
898 public function get_user_completed_items( $user_id, $course_id ) {
899 if ( ! $items = $this->get_user_items( $user_id, $course_id ) ) {
900 return false;
901 }
902 foreach ( $items as $item ) {
903
904 }
905 }
906
907 /**
908 * Read meta data of an user item.
909 *
910 * @param $item
911 */
912 protected function _read_item_meta( &$item ) {
913 global $wpdb;
914 $query = $wpdb->prepare(
915 "
916 SELECT *
917 FROM {$wpdb->learnpress_user_itemmeta}
918 WHERE learnpress_user_item_id = %d
919 ",
920 $item['user_item_id']
921 );
922
923 update_meta_cache( 'learnpress_user_item', $item['user_item_id'] );
924
925 if ( $meta = $wpdb->get_results( $query, ARRAY_A ) ) {
926 $item['meta'] = array();
927 foreach ( $meta as $k => $v ) {
928 $v['meta_value'] = LP_Helper::maybe_unserialize( $v['meta_value'] );
929 $item['meta'][ $v['meta_id'] ] = $v;
930 }
931 }
932 }
933
934 public function update_user_item_course() {
935
936 }
937
938 public function update_user_item_course_item() {
939
940 }
941
942 /**
943 * @param int $user_id
944 * @param int $item_id
945 * @param array $item_data
946 * @param int $course_id
947 *
948 * @return mixed
949 * @depecated 4.1.6.9
950 */
951 // public function update_user_item( $user_id, $item_id, $item_data = array(), $course_id = 0 ) {
952 // global $wpdb;
953 //
954 // $user = learn_press_get_user( $user_id );
955 // if ( ! $user || ( $user->get_id() != $user_id ) ) {
956 // return false;
957 // }
958 //
959 // if ( array_key_exists( 'user_item_id', $item_data ) && empty( $item_data['user_item_id'] ) ) {
960 // $item = false;
961 // } else {
962 // if ( func_num_args() == 4 ) {
963 // // $item = $this->get_user_item( $user_id, $item_id, $course_id );
964 // $item = $this->read_course( $user_id, $course_id );
965 // } else {
966 // $item = $this->get_user_item( $user_id, $item_id );
967 // }
968 // }
969 //
970 // // Table fields
971 // $table_fields = array(
972 // 'user_id' => '%d',
973 // 'item_id' => '%d',
974 // 'ref_id' => '%d',
975 // 'start_time' => '%s',
976 // 'end_time' => '%s',
977 // 'item_type' => '%s',
978 // 'status' => '%s',
979 // 'ref_type' => '%s',
980 // 'parent_id' => '%d',
981 // );
982 //
983 // // Data and format
984 // $data = array();
985 // $data_format = array();
986 //
987 // // Update it later...
988 // $new_status = false;
989 // if ( array_key_exists( 'status', $item_data ) && $item_data['status'] != $item['status'] ) {
990 // $new_status = $item_data['status'];
991 // unset( $item_data['status'] );
992 // }
993 //
994 // // Build data and data format
995 // foreach ( $item_data as $field => $value ) {
996 // if ( ! empty( $table_fields[ $field ] ) ) {
997 // $data[ $field ] = $value;
998 // $data_format[ $field ] = $table_fields[ $field ];
999 // }
1000 // }
1001 //
1002 // $data['user_id'] = $user_id;
1003 // $data['item_id'] = $item_id;
1004 //
1005 // if ( $course_id ) {
1006 // $data['ref_id'] = $course_id;
1007 // $data['ref_type'] = LP_COURSE_CPT;
1008 // } else {
1009 // $data['item_type'] = LP_COURSE_CPT;
1010 // }
1011 //
1012 // foreach ( $data as $k => $v ) {
1013 // $data_format[ $k ] = $table_fields[ $k ];
1014 // }
1015 //
1016 // $data_format = array_values( $data_format );
1017 //
1018 // if ( ! $item || empty( $item['user_item_id'] ) ) {
1019 // if ( $data['ref_type'] === LP_COURSE_CPT && empty( $data['parent_id'] ) ) {
1020 // return false;
1021 // }
1022 //
1023 // $wpdb->insert(
1024 // $wpdb->learnpress_user_items,
1025 // $data,
1026 // $data_format
1027 // );
1028 // $user_item_id = $wpdb->insert_id;
1029 // $item = $this->get_user_item_by_id( $user_item_id );
1030 // } else {
1031 // $user_item_id = $item['user_item_id'];
1032 // $wpdb->update(
1033 // $wpdb->learnpress_user_items,
1034 // $data,
1035 // array( 'user_item_id' => $user_item_id ),
1036 // $data_format,
1037 // array( '%d' )
1038 // );
1039 //
1040 // $item = array_merge( $item, $data );
1041 // }
1042 //
1043 // $is_course = ( ! $course_id ) && ( learn_press_get_post_type( $item['item_id'] ) === LP_COURSE_CPT );
1044 //
1045 // if ( $user_item_id ) {
1046 //
1047 // // Track last status if it is updated new status.
1048 // if ( $new_status !== false ) {
1049 // if ( $this->update_user_item_status( $user_item_id, $new_status ) ) {
1050 // $item['status'] = $new_status;
1051 // }
1052 // }
1053 //
1054 // if ( $is_course ) {
1055 // $course_id = $item['item_id'];
1056 // // Update cache to effect the change right way!
1057 // LP_Object_Cache::set( 'course-' . $user_id . '-' . $course_id, $item, 'learn-press/user-dcourses' );
1058 // } else {
1059 //
1060 // $user = learn_press_get_user( $user_id );
1061 // $user_course = $user->get_course_data( $course_id );
1062 //
1063 // $user_course->set_item( $item );
1064 //
1065 // // Update cache
1066 // $existed = false !== ( $items = LP_Object_Cache::get(
1067 // 'course-item-' . $user_id . '-' . $course_id . '-' . $item_id,
1068 // 'learn-press/user-course-items'
1069 // ) );
1070 //
1071 // if ( false === $items || ! empty( $items[ $user_item_id ] ) ) {
1072 // if ( is_array( $items ) ) {
1073 // $items[ $user_item_id ] = $item;
1074 // } else {
1075 // $items = array( $user_item_id => $item );
1076 // }
1077 // } else {
1078 // $items = array( $user_item_id => $item ) + $items;
1079 // }
1080 //
1081 // LP_Object_Cache::set(
1082 // 'course-item-' . $user_id . '-' . $course_id . '-' . $item_id,
1083 // $items,
1084 // 'learn-press/user-course-items'
1085 // );
1086 //
1087 // }
1088 //
1089 // wp_cache_delete( 'course-' . $user_id . '-' . $course_id, 'learn-press/user-item-object-courses' );
1090 //
1091 // /*
1092 // if ( $existed ) {
1093 // wp_cache_replace( 'course-item-' . $user_id . '-' . $course_id . '-' . $item_id, $items, 'learn-press/user-course-items' );
1094 // } else {
1095 // wp_cache_add( 'course-item-' . $user_id . '-' . $course_id . '-' . $item_id, $items, 'learn-press/user-course-items' );
1096 // }*/
1097 // }
1098 //
1099 // return $user_item_id;
1100 // }
1101
1102 /**
1103 * Get user item from user_items tables.
1104 * If course_id is not passed then return course,
1105 * otherwise return item in that course.
1106 *
1107 * @param int $user_id
1108 * @param int $item_id
1109 * @param int $course_id - Optional. If passed then $item_id should be id of a course's item (such as lesson, quiz, etc...)
1110 * @param bool $last
1111 *
1112 * @return bool|mixed
1113 */
1114 public function get_user_item( $user_id, $item_id, $course_id = 0, $last = true ) {
1115 $num_args = func_num_args();
1116
1117 if ( $num_args == 2 ) {
1118 $this->read_course( $user_id, $item_id );
1119 $item = LP_Object_Cache::get( 'course-' . $user_id . '-' . $item_id, 'learn-press/user-item-courses' );
1120 } else {
1121 $this->read_course( $user_id, $course_id );
1122 $cache_name = sprintf( 'course-item-%d-%d-%d', $user_id, $course_id, $item_id );
1123 $item = LP_Object_Cache::get( $cache_name, 'learn-press/user-course-items' );
1124
1125 if ( $last && $item ) {
1126 $item = reset( $item );
1127 }
1128 }
1129
1130 return $item;
1131 }
1132
1133 /**
1134 * @param int $user_item_id
1135 * @param string $type
1136 *
1137 * @return array
1138 */
1139 public function get_user_item_by_id( $user_item_id, $type = '' ) {
1140 global $wpdb;
1141
1142 $query = $wpdb->prepare(
1143 "
1144 SELECT *
1145 FROM {$wpdb->learnpress_user_items}
1146 WHERE user_item_id = %d
1147 " . ( $type ? $wpdb->prepare( 'AND item_type = %s', $type ) : '' ) . '
1148 ',
1149 $user_item_id
1150 );
1151 $item = $wpdb->get_row( $query, ARRAY_A );
1152
1153 return $item;
1154 }
1155
1156 /**
1157 * @param int $user_item_id
1158 *
1159 * @return bool|LP_User_Item_Course
1160 * @depecated 4.1.6.9
1161 */
1162 /*public function get_user_item_course( $user_item_id ) {
1163 if ( $item = $this->get_user_item_by_id( $user_item_id, LP_COURSE_CPT ) ) {
1164 return new LP_User_Item_Course( $item );
1165 }
1166
1167 return false;
1168 }*/
1169
1170 /**
1171 * @depecated 4.1.6.9
1172 */
1173 /*public function get_user_item_meta( $user_item_id, $meta_key, $single = true ) {
1174 return learn_press_get_user_item_meta( $user_item_id, $meta_key, $single );
1175 }*/
1176
1177 /**
1178 * @depecated 4.1.6.9
1179 */
1180 /*public function update_user_item_meta( $user_item_id, $meta_key, $meta_value, $prev = '' ) {
1181 return learn_press_update_user_item_meta( $user_item_id, $meta_key, $meta_value, $prev );
1182 }*/
1183
1184 /**
1185 * Update user item data by id.
1186 *
1187 * @param int $user_item_id
1188 * @param array $item_data
1189 *
1190 * @return bool
1191 * @editor tungnx
1192 * @modify 4.1.3 - comment - not use
1193 */
1194 /*public function update_user_item_by_id( $user_item_id, $item_data = array() ) {
1195 global $wpdb;
1196
1197 $item = $this->get_user_item_by_id( $user_item_id );
1198
1199 if ( ! $item ) {
1200 return false;
1201 }
1202
1203 // Table fields
1204 $table_fields = array(
1205 'user_item_id' => '%d',
1206 'user_id' => '%d',
1207 'item_id' => '%d',
1208 'ref_id' => '%d',
1209 'start_time' => '%s',
1210 'end_time' => '%s',
1211 'item_type' => '%s',
1212 'status' => '%s',
1213 'ref_type' => '%s',
1214 'parent_id' => '%d',
1215 );
1216
1217 // Data and format
1218 $data = array();
1219 $data_format = array();
1220
1221 // Update it later...
1222 $new_status = false;
1223 if ( array_key_exists( 'status', $item_data ) && $item_data['status'] != $item['status'] ) {
1224 $new_status = $item_data['status'];
1225 unset( $item_data['status'] );
1226 }
1227
1228 // Build data and data format
1229 foreach ( $item_data as $field => $value ) {
1230 if ( ! empty( $table_fields[ $field ] ) ) {
1231 $data[ $field ] = $value;
1232 $data_format[ $field ] = $table_fields[ $field ];
1233 }
1234 }
1235
1236 if ( $data ) {
1237 $updated = $wpdb->update(
1238 $wpdb->learnpress_user_items,
1239 $data,
1240 array( 'user_item_id' => $user_item_id ),
1241 $data_format,
1242 array( '%d' )
1243 );
1244 }
1245
1246 // Track last status if it is updated new status.
1247 if ( $new_status !== false ) {
1248 $this->update_user_item_status( $user_item_id, $new_status );
1249 }
1250
1251 return isset( $updated ) ? $updated : $user_item_id;
1252 }*/
1253
1254 /**
1255 * Update status of an user item by id.
1256 *
1257 * @param int $user_item_id
1258 * @param string $new_status
1259 *
1260 * @return mixed
1261 */
1262 public function update_user_item_status( $user_item_id, $new_status ) {
1263 global $wpdb;
1264 $item = $this->get_user_item_by_id( $user_item_id );
1265 if ( ! $item ) {
1266 return false;
1267 }
1268
1269 // No need to update if it is not change
1270 if ( $item['status'] === $new_status ) {
1271 return false;
1272 }
1273
1274 $updated = $wpdb->update(
1275 $wpdb->learnpress_user_items,
1276 array( 'status' => $new_status ),
1277 array( 'user_item_id' => $user_item_id ),
1278 array( '%s' ),
1279 array( '%d' )
1280 );
1281 // if ( $updated ) {
1282 // $this->update_user_item_meta( $user_item_id, '_last_status', $item['status'] );
1283 // $this->update_user_item_meta( $user_item_id, '_current_status', $new_status );
1284 // }
1285
1286 return $updated;
1287 }
1288
1289 // public function restore_last_status( $user_item_id ) {
1290 // $item = $this->get_user_item_by_id( $user_item_id );
1291 // if ( ! $item ) {
1292 // return false;
1293 // }
1294
1295 // if ( $last_status = $this->get_user_item_meta( $item['user_item_id'], '_last_status', true ) ) {
1296 // $this->update_user_item_status( $user_item_id, $last_status );
1297 // learn_press_delete_user_item_meta( $user_item_id, '_last_status', '', true );
1298 // }
1299
1300 // return $last_status;
1301 // }
1302
1303 /**
1304 * Delete user item by fields.
1305 *
1306 * @param string $args
1307 *
1308 * @return bool
1309 */
1310 public function delete_user_item( $args = '' ) {
1311 global $wpdb;
1312 $args = wp_parse_args(
1313 $args,
1314 array(
1315 'user_id' => 0,
1316 'item_id' => 0,
1317 'ref_id' => 0,
1318 'parent_id' => 0,
1319 )
1320 );
1321 $where = array();
1322 foreach ( $args as $k => $v ) {
1323 if ( $v ) {
1324 $where[ $k ] = $v;
1325 }
1326 }
1327
1328 if ( ! $where ) {
1329 return false;
1330 }
1331 $query_where = array();
1332 foreach ( $where as $k => $v ) {
1333 $query_where[] = "{$k} = %d";
1334 }
1335
1336 $query = $wpdb->prepare(
1337 "SELECT user_item_id FROM {$wpdb->learnpress_user_items} WHERE " . join(
1338 ' AND ',
1339 $query_where
1340 ),
1341 array_values( $where )
1342 );
1343 $user_item_ids = $wpdb->get_col( $query );
1344
1345 $wpdb->delete(
1346 $wpdb->learnpress_user_items,
1347 $where,
1348 array_fill( 0, sizeof( $where ), '%d' )
1349 );
1350
1351 foreach ( $user_item_ids as $user_item_id ) {
1352 $wpdb->query(
1353 $wpdb->prepare(
1354 "DELETE FROM {$wpdb->learnpress_user_itemmeta} WHERE learnpress_user_item_id = %d",
1355 $user_item_id
1356 )
1357 );
1358 do_action( 'learn-press/deleted-user-item', $user_item_id );
1359 }
1360
1361 return true;
1362 }
1363
1364 /**
1365 * Delete a row from user items by user_item_id key.
1366 *
1367 * @param int $user_item_id
1368 *
1369 * @return mixed
1370 */
1371 /*public function delete_by_user_item_id( $user_item_id ) {
1372 global $wpdb;
1373
1374 $query = $wpdb->prepare(
1375 "
1376 SELECT *
1377 FROM {$wpdb->learnpress_user_items}
1378 WHERE parent_id = %d
1379 ",
1380 $user_item_id
1381 );
1382
1383 // Delete child items (lessons, quizzes, etc) in case the item being deleted is a course
1384 if ( $child = $wpdb->get_col( $query ) ) {
1385 foreach ( $child as $child_id ) {
1386 $this->delete_by_user_item_id( $child_id );
1387 }
1388 }
1389
1390 // Delete origin item
1391 $query = $wpdb->prepare(
1392 "
1393 DELETE
1394 FROM ui, uim
1395 USING {$wpdb->prefix}learnpress_user_items AS ui
1396 LEFT JOIN {$wpdb->prefix}learnpress_user_itemmeta AS uim ON ui.user_item_id = uim.learnpress_user_item_id
1397 WHERE user_item_id = %d
1398 ",
1399 $user_item_id
1400 );
1401
1402 return $wpdb->query( $query );
1403 }*/
1404
1405 /**
1406 * Query own courses of an user.
1407 *
1408 * @param int $user_id
1409 * @param array $args
1410 *
1411 * @return LP_Query_List_Table
1412 * @editor tungnx
1413 * @modify 4.1.5 - comment
1414 * @deprecated 4.1.5
1415 */
1416 /*public function query_own_courses( int $user_id = 0, array $args = array() ): LP_Query_List_Table {
1417 global $wpdb, $wp;
1418 $paged = 1;
1419
1420 if ( ! empty( $wp->query_vars['view_id'] ) ) {
1421 $paged = absint( $wp->query_vars['view_id'] );
1422 }
1423
1424 $limit = LP_Settings::get_option( 'archive_course_limit', 6 );
1425 if ( empty( $limit ) ) {
1426 $limit = 6;
1427 }
1428
1429 $paged = max( $paged, 1 );
1430 $args = wp_parse_args(
1431 $args,
1432 array(
1433 'paged' => $paged,
1434 'limit' => $limit,
1435 'status' => '',
1436 )
1437 );
1438
1439 if ( ! $user_id ) {
1440 $user_id = get_current_user_id();
1441 }
1442
1443 $cache_key = sprintf( 'own-courses-%d-%s', $user_id, md5( build_query( $args ) ) );
1444 $courses = LP_Object_Cache::get( $cache_key, 'learn-press/user-courses' );
1445
1446 if ( false === $courses ) {
1447 $courses = array(
1448 'total' => 0,
1449 'paged' => $args['paged'],
1450 'limit' => $args['limit'],
1451 'pages' => 0,
1452 'items' => array(),
1453 );
1454
1455 try {
1456 $query = array(
1457 'total' => 0,
1458 'pages' => 0,
1459 'items' => false,
1460 );
1461
1462 $limit = $args['limit'];
1463 $where = 'WHERE 1';
1464 $offset = ( $args['paged'] - 1 ) * $limit;
1465
1466 if ( ! empty( $args['status'] ) ) {
1467 if ( is_array( $args['status'] ) ) {
1468 $a = array_fill( 0, sizeof( $where ), '%d' );
1469 $where .= $wpdb->prepare( ' AND post_status IN(' . join( ',', $where ) . ')', $a );
1470 } else {
1471 if ( 'pending' === $args['status'] ) {
1472 $where .= $wpdb->prepare( ' AND post_status IN( %s, %s )', array( 'draft', 'pending' ) );
1473 } elseif ( $args['status'] !== '*' ) {
1474 $where .= $wpdb->prepare( ' AND post_status = %s', $args['status'] );
1475 }
1476 }
1477 } else {
1478 $where .= $wpdb->prepare( ' AND post_status NOT IN (%s, %s)', array( 'trash', 'auto-draft' ) );
1479 }
1480
1481 $where = $where . $wpdb->prepare( ' AND post_type = %s AND post_author = %d', LP_COURSE_CPT, $user_id );
1482
1483 $join = '';
1484
1485 do_action( 'learnpress/user-curd/query_where_join_own_courses', $where, $join );
1486
1487 $sql = "
1488 SELECT SQL_CALC_FOUND_ROWS ID
1489 FROM {$wpdb->posts} c
1490 {$join}
1491 {$where}
1492 ORDER BY ID DESC
1493 LIMIT {$offset}, {$limit}
1494 ";
1495
1496 do_action( 'learnpress/user-curd/query_string_own_courses', $sql );
1497
1498 $items = $wpdb->get_results( $sql );
1499 $count = $wpdb->get_var( 'SELECT FOUND_ROWS()' );
1500 $all_courses = learnpress_get_count_by_user( $user_id, 'lp_course' );
1501
1502 if ( $items ) {
1503 $course_ids = wp_list_pluck( $items, 'ID' );
1504 LP_Helper::cache_posts( $course_ids );
1505
1506 $courses['total'] = $count;
1507 $courses['pages'] = ceil( $count / $args['limit'] );
1508
1509 foreach ( $items as $item ) {
1510 $courses['items'][] = $item->ID;
1511 }
1512 }
1513
1514 $courses['counts'] = array(
1515 'all' => $all_courses['all'],
1516 'publish' => $all_courses['publish'],
1517 'pending' => $all_courses['pending'],
1518 );
1519 } catch ( Exception $ex ) {
1520 learn_press_add_message( $ex->getMessage() );
1521 }
1522
1523 LP_Object_Cache::set( $cache_key, $courses, 'learn-press/user-courses' );
1524 }
1525
1526 $courses['single'] = __( 'course', 'learnpress' );
1527 $courses['plural'] = __( 'courses', 'learnpress' );
1528
1529 return new LP_Query_List_Table( $courses );
1530 }*/
1531
1532 /**
1533 * Query courses by user
1534 *
1535 * @param int $user_id
1536 * @param array $args
1537 *
1538 * @return LP_Query_List_Table
1539 * @editor tungnx
1540 * @modify 4.1.5 - comment
1541 * @deprecated 4.1.5
1542 */
1543 /*public function query_purchased_courses( int $user_id = 0, array $args = array() ): LP_Query_List_Table {
1544 global $wpdb, $wp;
1545 $paged = 1;
1546
1547 if ( ! empty( $wp->query_vars['view_id'] ) ) {
1548 $paged = absint( $wp->query_vars['view_id'] );
1549 }
1550
1551 $limit = LP_Settings::get_option( 'archive_course_limit', 6 );
1552 if ( empty( $limit ) ) {
1553 $limit = 6;
1554 }
1555
1556 $args = wp_parse_args(
1557 $args,
1558 array(
1559 'paged' => $paged,
1560 'limit' => $limit,
1561 'status' => '',
1562 )
1563 );
1564
1565 $args['paged'] = max( $args['paged'], 1 );
1566
1567 if ( ! $user_id ) {
1568 $user_id = get_current_user_id();
1569 }
1570
1571 $cache_key = sprintf( 'purchased-courses-%d-%s', $user_id, md5( build_query( $args ) ) );
1572 $courses = LP_Object_Cache::get( $cache_key, 'learn-press/user-courses' );
1573
1574 if ( false === $courses ) {
1575 $courses = array(
1576 'total' => 0,
1577 'paged' => $args['paged'],
1578 'limit' => $args['limit'],
1579 'pages' => 0,
1580 'items' => array(),
1581 );
1582
1583 try {
1584 $orders = $this->get_orders( $user_id, array( 'status' => 'completed' ) );
1585
1586 $course_ids = array();
1587
1588 if ( $orders ) {
1589 $course_ids = array_keys( $orders );
1590 }
1591
1592 $item_ids = $wpdb->get_col(
1593 $wpdb->prepare(
1594 "SELECT item_id FROM {$wpdb->learnpress_user_items} WHERE user_id=%d AND item_type=%s",
1595 $user_id,
1596 LP_COURSE_CPT
1597 )
1598 );
1599
1600 if ( $item_ids ) {
1601 $course_ids = array_merge( $course_ids, $item_ids );
1602 }
1603
1604 $query = array(
1605 'total' => 0,
1606 'pages' => 0,
1607 'items' => false,
1608 );
1609
1610 if ( ! $course_ids ) {
1611 throw new Exception( '', 0 );
1612 }
1613
1614 $query_args = $course_ids;
1615 $query_args[] = $user_id;
1616 $limit = $args['limit'];
1617 $offset = ( $args['paged'] - 1 ) * $limit;
1618
1619 // SELECT
1620 $select = 'SELECT c.ID, c.post_title, ui.*';
1621
1622 // FROM
1623 $from = "FROM {$wpdb->learnpress_user_items} ui";
1624
1625 // JOIN
1626 $join = $wpdb->prepare(
1627 "INNER JOIN {$wpdb->posts} c ON ui.item_id = c.ID AND c.post_type = %s",
1628 LP_COURSE_CPT
1629 );
1630
1631 // WHERE - modify by tungnx
1632 $where = $wpdb->prepare(
1633 '
1634 WHERE ui.user_id = %d
1635 AND c.ID IN(' . join( ',', $course_ids ) . ')
1636 AND c.post_status = %s
1637 ',
1638 $user_id,
1639 'publish'
1640 );
1641 $count_where = $where;
1642
1643 // HAVING
1644 $having = 'HAVING 1';
1645
1646 // ORDER BY
1647 $orderby = 'ORDER BY start_time DESC';
1648
1649 if ( ! empty( $args['status'] ) ) {
1650 switch ( $args['status'] ) {
1651 case 'finished':
1652 case 'passed':
1653 case 'failed':
1654 $where .= $wpdb->prepare(
1655 ' AND ui.status IN( %s )',
1656 array(
1657 'finished',
1658 )
1659 );
1660
1661 if ( $args['status'] !== 'finished' ) {
1662 if ( 'passed' === $args['status'] ) {
1663 $having .= $wpdb->prepare( ' AND ui.graduation = %s', 'passed' );
1664 } else {
1665 $having .= $wpdb->prepare( ' AND ( ui.graduation = %s )', 'failed' );
1666 }
1667 }
1668
1669 break;
1670 case 'in-progress':
1671 $where .= $wpdb->prepare(
1672 ' AND ui.status IN( %s )',
1673 array(
1674 'enrolled',
1675 )
1676 );
1677
1678 $having .= $wpdb->prepare( ' AND ui.graduation = %s', 'in-progress' );
1679
1680 break;
1681 case 'not-enrolled':
1682 $where .= $wpdb->prepare(
1683 ' AND ui.status NOT IN( %s, %s, %s )',
1684 array(
1685 'enrolled',
1686 'finished',
1687 'pending',
1688 )
1689 );
1690 }
1691 }
1692
1693 // Comment by tungnx
1694 //$where .= $wpdb->prepare( ' AND ui.status NOT IN(%s) ', 'pending' );
1695
1696 $query_parts = apply_filters(
1697 'learn-press/query/user-purchased-courses',
1698 compact( 'select', 'from', 'join', 'where', 'having', 'orderby' ),
1699 $user_id,
1700 $args
1701 );
1702
1703 list( $select, $from, $join, $where, $having, $orderby ) = array_values( $query_parts );
1704
1705 if ( $args['limit'] > 0 ) {
1706 $limit = "LIMIT {$offset}, {$limit}";
1707 } else {
1708 $limit = '';
1709 }
1710
1711 do_action( 'learnpress/user-curd/query_where_join_purchased_courses', $where, $join );
1712
1713 $sql = "
1714 SELECT SQL_CALC_FOUND_ROWS *
1715 FROM
1716 (
1717 {$select}
1718 {$from}
1719 {$join}
1720 {$where}
1721 {$having}
1722 ORDER BY item_id, user_item_id DESC
1723 ) X
1724 GROUP BY item_id
1725 {$orderby}
1726 $limit
1727 ";
1728
1729 do_action( 'learnpress/user-curd/query_string_purchased_courses', $sql );
1730
1731 $items = $wpdb->get_results( $sql );
1732
1733 if ( $items ) {
1734 $count = $wpdb->get_var( 'SELECT FOUND_ROWS()' );
1735 $course_ids = wp_list_pluck( $items, 'item_id' );
1736 LP_Helper::cache_posts( $course_ids );
1737
1738 $courses['total'] = $count;
1739 $courses['pages'] = $args['limit'] > 0 ? ceil( $count / $args['limit'] ) : 1;
1740 foreach ( $items as $item ) {
1741 $item = (array) $item;
1742 $course_item = new LP_User_Item_Course( $item );
1743 $courses['items'][] = $course_item;
1744 }
1745 }
1746
1747 $counts = array(
1748 'all' => 0,
1749 'enrolled' => 0,
1750 'finished' => 0,
1751 );
1752
1753 $sql = "
1754 SELECT user_item_id
1755 FROM
1756 (
1757 {$select}
1758 {$from}
1759 {$join}
1760 {$count_where}
1761 ) X
1762 GROUP BY item_id
1763 ";
1764
1765 $user_item_ids = $wpdb->get_col( $sql );
1766 if ( $user_item_ids ) {
1767 $rows = $wpdb->get_results(
1768 "
1769 SELECT status, COUNT(user_item_id) count
1770 FROM {$wpdb->learnpress_user_items}
1771 WHERE user_item_id in(" . join( ',', $user_item_ids ) . ')
1772 GROUP BY status
1773 '
1774 );
1775
1776 if ( $rows ) {
1777 foreach ( $rows as $row ) {
1778 $counts[ $row->status ] = $row->count;
1779 $counts['all'] += $row->count;
1780 }
1781 }
1782 }
1783
1784 $counts['not-enrolled'] = $counts['all'] - ( $counts['enrolled'] + $counts['finished'] );
1785 $sql = $wpdb->prepare(
1786 "
1787 SELECT COUNT(meta_id) count, meta_value `status`
1788 FROM (
1789 SELECT user_id, item_id, MAX(user_item_id) max_id
1790 FROM {$wpdb->learnpress_user_items} GROUP BY user_id, item_id
1791 ) X
1792 INNER JOIN {$wpdb->learnpress_user_items} ui ON X.max_id = ui.user_item_id
1793 INNER JOIN {$wpdb->learnpress_user_itemmeta} uim ON ui.user_item_id=uim.learnpress_user_item_id
1794 WHERE uim.meta_key LIKE '%grade%'
1795 AND ui.user_id = %d AND ui.item_type = %s
1796 GROUP BY meta_value
1797 ",
1798 $user_id,
1799 LP_COURSE_CPT
1800 );
1801
1802 $rows = $wpdb->get_results( $sql );
1803 if ( $rows ) {
1804 foreach ( $rows as $row ) {
1805 $counts[ $row->status ] = $row->count;
1806 }
1807 }
1808
1809 $courses['counts'] = $counts;
1810 } catch ( Exception $ex ) {
1811
1812 }
1813
1814 LP_Object_Cache::set( $cache_key, $courses, 'learn-press/user-courses' );
1815 }
1816
1817 $courses['single'] = __( 'course', 'learnpress' );
1818 $courses['plural'] = __( 'courses', 'learnpress' );
1819
1820 return new LP_Query_List_Table( $courses );
1821 }*/
1822
1823 /**
1824 * Get courses user has purchased via orders are completed
1825 * but it is not already added to user-items table.
1826 *
1827 * @param int $user_id
1828 *
1829 * @return array|bool|mixed
1830 */
1831 public function query_courses_by_order( $user_id ) {
1832 global $wpdb;
1833
1834 $query = $wpdb->prepare(
1835 "
1836 SELECT item_id
1837 FROM {$wpdb->learnpress_user_items}
1838 WHERE user_id = %d
1839 AND item_type = %s
1840 ",
1841 $user_id,
1842 LP_COURSE_CPT
1843 );
1844 $user_item_ids = $wpdb->get_col( $query );
1845
1846 $orders = $this->get_orders(
1847 $user_id,
1848 array(
1849 'status' => 'completed',
1850 'group_by_order' => true,
1851 )
1852 );
1853
1854 if ( ! $orders ) {
1855 return false;
1856 }
1857
1858 $course_ids = array_shift( $orders );
1859
1860 foreach ( $orders as $ids ) {
1861 if ( ! $ids ) {
1862 continue;
1863 }
1864 $course_ids = array_merge( $course_ids, $ids );
1865 }
1866
1867 if ( $user_item_ids ) {
1868 $course_ids = array_diff( $course_ids, $user_item_ids );
1869 }
1870
1871 return $course_ids;
1872 }
1873
1874 /**
1875 * Query quizzes by user.
1876 *
1877 * @param int $user_id
1878 * @param string $args
1879 *
1880 * @return LP_Query_List_Table
1881 */
1882 public function query_quizzes( $user_id = 0, $args = '' ) {
1883 global $wpdb, $wp;
1884
1885 $paged = 1;
1886
1887 if ( ! empty( $wp->query_vars['view_id'] ) ) {
1888 $paged = absint( $wp->query_vars['view_id'] );
1889 }
1890
1891 $paged = max( $paged, 1 );
1892 $args = wp_parse_args(
1893 $args,
1894 array(
1895 'paged' => $paged,
1896 'limit' => 10,
1897 'status' => '',
1898 )
1899 );
1900
1901 if ( ! $user_id ) {
1902 $user_id = get_current_user_id();
1903 }
1904
1905 $cache_key = sprintf( 'quizzes-%d-%s', $user_id, md5( build_query( $args ) ) );
1906 $quizzes = LP_Object_Cache::get( $cache_key, 'learn-press/user-quizzes' );
1907
1908 if ( false === $quizzes ) {
1909 $orders = $this->get_orders( $user_id );
1910 $query = array(
1911 'total' => 0,
1912 'pages' => 0,
1913 'items' => false,
1914 );
1915
1916 $quizzes = array(
1917 'total' => 0,
1918 'paged' => $args['paged'],
1919 'limit' => $args['limit'],
1920 'pages' => 0,
1921 'items' => array(),
1922 );
1923
1924 try {
1925 if ( ! $orders ) {
1926 throw new Exception( __( 'No item in Order', 'learnpress' ), 0 );
1927 }
1928
1929 $course_ids = array_keys( $orders );
1930 $query_args = $course_ids;
1931 $query_args[] = $user_id;
1932
1933 $select = 'SELECT * ';
1934 $from = "FROM {$wpdb->learnpress_user_items} ui";
1935 $join = '';
1936 $where = 'WHERE 1=1 ';
1937 $where .= $wpdb->prepare( 'AND user_id = %d ', $user_id );
1938 $where .= $wpdb->prepare( 'AND item_type = %s ', LP_QUIZ_CPT );
1939 $where .= $wpdb->prepare( 'AND status IN (%s, %s) ', LP_ITEM_COMPLETED, LP_ITEM_STARTED );
1940 $having = 'HAVING 1';
1941 $orderby = 'ORDER BY item_id, user_item_id DESC';
1942
1943 if ( ! empty( $args['status'] ) ) {
1944 switch ( $args['status'] ) {
1945 case 'completed':
1946 case 'passed':
1947 case 'failed':
1948 $having .= $wpdb->prepare(
1949 ' AND X.status IN( %s )',
1950 array(
1951 'completed',
1952 )
1953 );
1954
1955 if ( $args['status'] !== 'completed' ) {
1956 if ( 'passed' === $args['status'] ) {
1957 $having .= $wpdb->prepare( ' AND X.graduation = %s', 'passed' );
1958 } elseif ( 'failed' === $args['status'] ) {
1959 $having .= $wpdb->prepare( ' AND X.graduation = %s', 'failed' );
1960 } else {
1961 $having .= $wpdb->prepare( ' AND ( X.graduation IS NULL OR X.graduation <> %s )', 'passed' );
1962 }
1963 }
1964 break;
1965
1966 case 'in-progress':
1967 $having .= $wpdb->prepare(
1968 ' AND X.status IN( %s ) AND X.graduation NOT IN ( %s, %s )',
1969 array(
1970 'started',
1971 'passed',
1972 'failed',
1973 )
1974 );
1975 break;
1976
1977 case 'not-started':
1978 $having .= $wpdb->prepare(
1979 ' AND X.status NOT IN( %s, %s )',
1980 array(
1981 'started',
1982 'completed',
1983 )
1984 );
1985 break;
1986 }
1987 } else {
1988
1989 $having .= $wpdb->prepare(
1990 ' AND X.status IN( %s, %s )',
1991 array(
1992 'started',
1993 'completed',
1994 )
1995 );
1996 }
1997 $limit = $args['limit'];
1998 $offset = ( $args['paged'] - 1 ) * $limit;
1999
2000 $query_parts = apply_filters(
2001 'learn-press/query/user-quizzes',
2002 compact( 'select', 'from', 'join', 'where', 'having', 'orderby' ),
2003 $user_id,
2004 $args
2005 );
2006
2007 list( $select, $from, $join, $where, $having, $orderby ) = array_values( $query_parts );
2008
2009 $sql = $wpdb->prepare(
2010 "
2011 SELECT * FROM (
2012 SELECT *
2013 FROM
2014 (
2015 {$select}
2016 {$from}
2017 {$join}
2018 {$where}
2019 ORDER BY user_item_id DESC
2020 ) AS G_Item
2021 GROUP BY G_Item.item_id
2022 ) AS G_User_Item
2023 ORDER BY G_User_Item.user_item_id DESC
2024 LIMIT %d, %d
2025 ",
2026 $offset,
2027 $limit
2028 );
2029
2030 $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
2031 FROM $wpdb->learnpress_user_items
2032 WHERE user_id = $user_id
2033 AND item_type = 'lp_quiz'
2034 AND status IN ('completed', 'started')
2035 GROUP BY item_id
2036 ORDER BY MAX(user_item_id) DESC";
2037
2038 $items = $wpdb->get_results( $sql, ARRAY_A );
2039
2040 if ( $items ) {
2041 $count = $wpdb->get_var( 'SELECT FOUND_ROWS()' );
2042 $course_ids = wp_list_pluck( $items, 'item_id' );
2043 // LP_Helper::cache_posts( $course_ids );
2044
2045 $quizzes['total'] = $count;
2046 $quizzes['pages'] = ceil( $count / $args['limit'] );
2047
2048 foreach ( $items as $item ) {
2049 $quizzes['items'][] = new LP_User_Item_Quiz( $item );
2050 }
2051 }
2052 } catch ( Exception $ex ) {
2053
2054 }
2055 LP_Object_Cache::set( $cache_key, $quizzes, 'learn-press/user-course' );
2056 }
2057
2058 $quizzes['single'] = __( 'quiz', 'learnpress' );
2059 $quizzes['plural'] = __( 'quizzes', 'learnpress' );
2060
2061 return new LP_Query_List_Table( $quizzes );
2062 }
2063
2064 public function read_course_info( $course ) {
2065 $data = $course;
2066 global $wpdb;
2067 $query = $wpdb->prepare(
2068 "
2069 SELECT *
2070 FROM {$wpdb->learnpress_user_itemmeta}
2071 WHERE learnpress_user_item_id = %d
2072 ",
2073 $course['user_item_id']
2074 );
2075
2076 $itemmeta = $wpdb->get_results( $query, ARRAY_A );
2077
2078 if ( $itemmeta ) {
2079 foreach ( $itemmeta as $item ) {
2080 $data[ $item['meta_key'] ] = $item['meta_value'];
2081 }
2082 }
2083
2084 return $data;
2085 }
2086
2087 public function update_item( $item ) {
2088 global $wpdb;
2089 if ( empty( $item['user_item_id'] ) ) {
2090 $wpdb->insert(
2091 $wpdb->learnpress_user_items,
2092 $item
2093 );
2094 }
2095 }
2096
2097 public function get_current_user_order( $user_id, $course_id ) {
2098 global $wpdb;
2099 $sql = $wpdb->prepare(
2100 "
2101 SELECT MAX(ID) AS order_id
2102 FROM {$wpdb->posts} p
2103 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
2104 INNER JOIN {$wpdb->learnpress_order_items} oi ON oi.order_id = p.id
2105 INNER JOIN {$wpdb->learnpress_order_itemmeta} oim ON oim.meta_key = %s and oim.meta_value = %d
2106 ",
2107 '_user_id',
2108 $user_id,
2109 '_course_id',
2110 $course_id
2111 );
2112 $order_id = $wpdb->get_var( $sql );
2113
2114 return $order_id;
2115 }
2116
2117 public function evaluate_course_results() {
2118
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