PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.1.7.2
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.1.7.2
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.2, at inc/curds/class-lp-user-curd.php

2,160 lines 55.5 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 * @depecated 4.1.7.2
1118 */
1119 /*public function get_user_item( $user_id, $item_id, $course_id = 0, $last = true ) {
1120 $num_args = func_num_args();
1121
1122 if ( $num_args == 2 ) {
1123 $this->read_course( $user_id, $item_id );
1124 $item = LP_Object_Cache::get( 'course-' . $user_id . '-' . $item_id, 'learn-press/user-item-courses' );
1125 } else {
1126 $this->read_course( $user_id, $course_id );
1127 $cache_name = sprintf( 'course-item-%d-%d-%d', $user_id, $course_id, $item_id );
1128 $item = LP_Object_Cache::get( $cache_name, 'learn-press/user-course-items' );
1129
1130 if ( $last && $item ) {
1131 $item = reset( $item );
1132 }
1133 }
1134
1135 return $item;
1136 }*/
1137
1138 /**
1139 * @param int $user_item_id
1140 * @param string $type
1141 *
1142 * @return array
1143 */
1144 public function get_user_item_by_id( $user_item_id, $type = '' ) {
1145 global $wpdb;
1146
1147 $query = $wpdb->prepare(
1148 "
1149 SELECT *
1150 FROM {$wpdb->learnpress_user_items}
1151 WHERE user_item_id = %d
1152 " . ( $type ? $wpdb->prepare( 'AND item_type = %s', $type ) : '' ) . '
1153 ',
1154 $user_item_id
1155 );
1156 $item = $wpdb->get_row( $query, ARRAY_A );
1157
1158 return $item;
1159 }
1160
1161 /**
1162 * @param int $user_item_id
1163 *
1164 * @return bool|LP_User_Item_Course
1165 * @depecated 4.1.6.9
1166 */
1167 /*public function get_user_item_course( $user_item_id ) {
1168 if ( $item = $this->get_user_item_by_id( $user_item_id, LP_COURSE_CPT ) ) {
1169 return new LP_User_Item_Course( $item );
1170 }
1171
1172 return false;
1173 }*/
1174
1175 /**
1176 * @depecated 4.1.6.9
1177 */
1178 /*public function get_user_item_meta( $user_item_id, $meta_key, $single = true ) {
1179 return learn_press_get_user_item_meta( $user_item_id, $meta_key, $single );
1180 }*/
1181
1182 /**
1183 * @depecated 4.1.6.9
1184 */
1185 /*public function update_user_item_meta( $user_item_id, $meta_key, $meta_value, $prev = '' ) {
1186 return learn_press_update_user_item_meta( $user_item_id, $meta_key, $meta_value, $prev );
1187 }*/
1188
1189 /**
1190 * Update user item data by id.
1191 *
1192 * @param int $user_item_id
1193 * @param array $item_data
1194 *
1195 * @return bool
1196 * @editor tungnx
1197 * @modify 4.1.3 - comment - not use
1198 */
1199 /*public function update_user_item_by_id( $user_item_id, $item_data = array() ) {
1200 global $wpdb;
1201
1202 $item = $this->get_user_item_by_id( $user_item_id );
1203
1204 if ( ! $item ) {
1205 return false;
1206 }
1207
1208 // Table fields
1209 $table_fields = array(
1210 'user_item_id' => '%d',
1211 'user_id' => '%d',
1212 'item_id' => '%d',
1213 'ref_id' => '%d',
1214 'start_time' => '%s',
1215 'end_time' => '%s',
1216 'item_type' => '%s',
1217 'status' => '%s',
1218 'ref_type' => '%s',
1219 'parent_id' => '%d',
1220 );
1221
1222 // Data and format
1223 $data = array();
1224 $data_format = array();
1225
1226 // Update it later...
1227 $new_status = false;
1228 if ( array_key_exists( 'status', $item_data ) && $item_data['status'] != $item['status'] ) {
1229 $new_status = $item_data['status'];
1230 unset( $item_data['status'] );
1231 }
1232
1233 // Build data and data format
1234 foreach ( $item_data as $field => $value ) {
1235 if ( ! empty( $table_fields[ $field ] ) ) {
1236 $data[ $field ] = $value;
1237 $data_format[ $field ] = $table_fields[ $field ];
1238 }
1239 }
1240
1241 if ( $data ) {
1242 $updated = $wpdb->update(
1243 $wpdb->learnpress_user_items,
1244 $data,
1245 array( 'user_item_id' => $user_item_id ),
1246 $data_format,
1247 array( '%d' )
1248 );
1249 }
1250
1251 // Track last status if it is updated new status.
1252 if ( $new_status !== false ) {
1253 $this->update_user_item_status( $user_item_id, $new_status );
1254 }
1255
1256 return isset( $updated ) ? $updated : $user_item_id;
1257 }*/
1258
1259 /**
1260 * Update status of an user item by id.
1261 *
1262 * @param int $user_item_id
1263 * @param string $new_status
1264 *
1265 * @return mixed
1266 */
1267 public function update_user_item_status( $user_item_id, $new_status ) {
1268 global $wpdb;
1269 $item = $this->get_user_item_by_id( $user_item_id );
1270 if ( ! $item ) {
1271 return false;
1272 }
1273
1274 // No need to update if it is not change
1275 if ( $item['status'] === $new_status ) {
1276 return false;
1277 }
1278
1279 $updated = $wpdb->update(
1280 $wpdb->learnpress_user_items,
1281 array( 'status' => $new_status ),
1282 array( 'user_item_id' => $user_item_id ),
1283 array( '%s' ),
1284 array( '%d' )
1285 );
1286 // if ( $updated ) {
1287 // $this->update_user_item_meta( $user_item_id, '_last_status', $item['status'] );
1288 // $this->update_user_item_meta( $user_item_id, '_current_status', $new_status );
1289 // }
1290
1291 return $updated;
1292 }
1293
1294 // public function restore_last_status( $user_item_id ) {
1295 // $item = $this->get_user_item_by_id( $user_item_id );
1296 // if ( ! $item ) {
1297 // return false;
1298 // }
1299
1300 // if ( $last_status = $this->get_user_item_meta( $item['user_item_id'], '_last_status', true ) ) {
1301 // $this->update_user_item_status( $user_item_id, $last_status );
1302 // learn_press_delete_user_item_meta( $user_item_id, '_last_status', '', true );
1303 // }
1304
1305 // return $last_status;
1306 // }
1307
1308 /**
1309 * Delete user item by fields.
1310 *
1311 * @param string $args
1312 *
1313 * @return bool
1314 */
1315 public function delete_user_item( $args = '' ) {
1316 global $wpdb;
1317 $args = wp_parse_args(
1318 $args,
1319 array(
1320 'user_id' => 0,
1321 'item_id' => 0,
1322 'ref_id' => 0,
1323 'parent_id' => 0,
1324 )
1325 );
1326 $where = array();
1327 foreach ( $args as $k => $v ) {
1328 if ( $v ) {
1329 $where[ $k ] = $v;
1330 }
1331 }
1332
1333 if ( ! $where ) {
1334 return false;
1335 }
1336 $query_where = array();
1337 foreach ( $where as $k => $v ) {
1338 $query_where[] = "{$k} = %d";
1339 }
1340
1341 $query = $wpdb->prepare(
1342 "SELECT user_item_id FROM {$wpdb->learnpress_user_items} WHERE " . join(
1343 ' AND ',
1344 $query_where
1345 ),
1346 array_values( $where )
1347 );
1348 $user_item_ids = $wpdb->get_col( $query );
1349
1350 $wpdb->delete(
1351 $wpdb->learnpress_user_items,
1352 $where,
1353 array_fill( 0, sizeof( $where ), '%d' )
1354 );
1355
1356 foreach ( $user_item_ids as $user_item_id ) {
1357 $wpdb->query(
1358 $wpdb->prepare(
1359 "DELETE FROM {$wpdb->learnpress_user_itemmeta} WHERE learnpress_user_item_id = %d",
1360 $user_item_id
1361 )
1362 );
1363 do_action( 'learn-press/deleted-user-item', $user_item_id );
1364 }
1365
1366 return true;
1367 }
1368
1369 /**
1370 * Delete a row from user items by user_item_id key.
1371 *
1372 * @param int $user_item_id
1373 *
1374 * @return mixed
1375 */
1376 /*public function delete_by_user_item_id( $user_item_id ) {
1377 global $wpdb;
1378
1379 $query = $wpdb->prepare(
1380 "
1381 SELECT *
1382 FROM {$wpdb->learnpress_user_items}
1383 WHERE parent_id = %d
1384 ",
1385 $user_item_id
1386 );
1387
1388 // Delete child items (lessons, quizzes, etc) in case the item being deleted is a course
1389 if ( $child = $wpdb->get_col( $query ) ) {
1390 foreach ( $child as $child_id ) {
1391 $this->delete_by_user_item_id( $child_id );
1392 }
1393 }
1394
1395 // Delete origin item
1396 $query = $wpdb->prepare(
1397 "
1398 DELETE
1399 FROM ui, uim
1400 USING {$wpdb->prefix}learnpress_user_items AS ui
1401 LEFT JOIN {$wpdb->prefix}learnpress_user_itemmeta AS uim ON ui.user_item_id = uim.learnpress_user_item_id
1402 WHERE user_item_id = %d
1403 ",
1404 $user_item_id
1405 );
1406
1407 return $wpdb->query( $query );
1408 }*/
1409
1410 /**
1411 * Query own courses of an user.
1412 *
1413 * @param int $user_id
1414 * @param array $args
1415 *
1416 * @return LP_Query_List_Table
1417 * @editor tungnx
1418 * @modify 4.1.5 - comment
1419 * @deprecated 4.1.5
1420 */
1421 /*public function query_own_courses( int $user_id = 0, array $args = array() ): LP_Query_List_Table {
1422 global $wpdb, $wp;
1423 $paged = 1;
1424
1425 if ( ! empty( $wp->query_vars['view_id'] ) ) {
1426 $paged = absint( $wp->query_vars['view_id'] );
1427 }
1428
1429 $limit = LP_Settings::get_option( 'archive_course_limit', 6 );
1430 if ( empty( $limit ) ) {
1431 $limit = 6;
1432 }
1433
1434 $paged = max( $paged, 1 );
1435 $args = wp_parse_args(
1436 $args,
1437 array(
1438 'paged' => $paged,
1439 'limit' => $limit,
1440 'status' => '',
1441 )
1442 );
1443
1444 if ( ! $user_id ) {
1445 $user_id = get_current_user_id();
1446 }
1447
1448 $cache_key = sprintf( 'own-courses-%d-%s', $user_id, md5( build_query( $args ) ) );
1449 $courses = LP_Object_Cache::get( $cache_key, 'learn-press/user-courses' );
1450
1451 if ( false === $courses ) {
1452 $courses = array(
1453 'total' => 0,
1454 'paged' => $args['paged'],
1455 'limit' => $args['limit'],
1456 'pages' => 0,
1457 'items' => array(),
1458 );
1459
1460 try {
1461 $query = array(
1462 'total' => 0,
1463 'pages' => 0,
1464 'items' => false,
1465 );
1466
1467 $limit = $args['limit'];
1468 $where = 'WHERE 1';
1469 $offset = ( $args['paged'] - 1 ) * $limit;
1470
1471 if ( ! empty( $args['status'] ) ) {
1472 if ( is_array( $args['status'] ) ) {
1473 $a = array_fill( 0, sizeof( $where ), '%d' );
1474 $where .= $wpdb->prepare( ' AND post_status IN(' . join( ',', $where ) . ')', $a );
1475 } else {
1476 if ( 'pending' === $args['status'] ) {
1477 $where .= $wpdb->prepare( ' AND post_status IN( %s, %s )', array( 'draft', 'pending' ) );
1478 } elseif ( $args['status'] !== '*' ) {
1479 $where .= $wpdb->prepare( ' AND post_status = %s', $args['status'] );
1480 }
1481 }
1482 } else {
1483 $where .= $wpdb->prepare( ' AND post_status NOT IN (%s, %s)', array( 'trash', 'auto-draft' ) );
1484 }
1485
1486 $where = $where . $wpdb->prepare( ' AND post_type = %s AND post_author = %d', LP_COURSE_CPT, $user_id );
1487
1488 $join = '';
1489
1490 do_action( 'learnpress/user-curd/query_where_join_own_courses', $where, $join );
1491
1492 $sql = "
1493 SELECT SQL_CALC_FOUND_ROWS ID
1494 FROM {$wpdb->posts} c
1495 {$join}
1496 {$where}
1497 ORDER BY ID DESC
1498 LIMIT {$offset}, {$limit}
1499 ";
1500
1501 do_action( 'learnpress/user-curd/query_string_own_courses', $sql );
1502
1503 $items = $wpdb->get_results( $sql );
1504 $count = $wpdb->get_var( 'SELECT FOUND_ROWS()' );
1505 $all_courses = learnpress_get_count_by_user( $user_id, 'lp_course' );
1506
1507 if ( $items ) {
1508 $course_ids = wp_list_pluck( $items, 'ID' );
1509 LP_Helper::cache_posts( $course_ids );
1510
1511 $courses['total'] = $count;
1512 $courses['pages'] = ceil( $count / $args['limit'] );
1513
1514 foreach ( $items as $item ) {
1515 $courses['items'][] = $item->ID;
1516 }
1517 }
1518
1519 $courses['counts'] = array(
1520 'all' => $all_courses['all'],
1521 'publish' => $all_courses['publish'],
1522 'pending' => $all_courses['pending'],
1523 );
1524 } catch ( Exception $ex ) {
1525 learn_press_add_message( $ex->getMessage() );
1526 }
1527
1528 LP_Object_Cache::set( $cache_key, $courses, 'learn-press/user-courses' );
1529 }
1530
1531 $courses['single'] = __( 'course', 'learnpress' );
1532 $courses['plural'] = __( 'courses', 'learnpress' );
1533
1534 return new LP_Query_List_Table( $courses );
1535 }*/
1536
1537 /**
1538 * Query courses by user
1539 *
1540 * @param int $user_id
1541 * @param array $args
1542 *
1543 * @return LP_Query_List_Table
1544 * @editor tungnx
1545 * @modify 4.1.5 - comment
1546 * @deprecated 4.1.5
1547 */
1548 /*public function query_purchased_courses( int $user_id = 0, array $args = array() ): LP_Query_List_Table {
1549 global $wpdb, $wp;
1550 $paged = 1;
1551
1552 if ( ! empty( $wp->query_vars['view_id'] ) ) {
1553 $paged = absint( $wp->query_vars['view_id'] );
1554 }
1555
1556 $limit = LP_Settings::get_option( 'archive_course_limit', 6 );
1557 if ( empty( $limit ) ) {
1558 $limit = 6;
1559 }
1560
1561 $args = wp_parse_args(
1562 $args,
1563 array(
1564 'paged' => $paged,
1565 'limit' => $limit,
1566 'status' => '',
1567 )
1568 );
1569
1570 $args['paged'] = max( $args['paged'], 1 );
1571
1572 if ( ! $user_id ) {
1573 $user_id = get_current_user_id();
1574 }
1575
1576 $cache_key = sprintf( 'purchased-courses-%d-%s', $user_id, md5( build_query( $args ) ) );
1577 $courses = LP_Object_Cache::get( $cache_key, 'learn-press/user-courses' );
1578
1579 if ( false === $courses ) {
1580 $courses = array(
1581 'total' => 0,
1582 'paged' => $args['paged'],
1583 'limit' => $args['limit'],
1584 'pages' => 0,
1585 'items' => array(),
1586 );
1587
1588 try {
1589 $orders = $this->get_orders( $user_id, array( 'status' => 'completed' ) );
1590
1591 $course_ids = array();
1592
1593 if ( $orders ) {
1594 $course_ids = array_keys( $orders );
1595 }
1596
1597 $item_ids = $wpdb->get_col(
1598 $wpdb->prepare(
1599 "SELECT item_id FROM {$wpdb->learnpress_user_items} WHERE user_id=%d AND item_type=%s",
1600 $user_id,
1601 LP_COURSE_CPT
1602 )
1603 );
1604
1605 if ( $item_ids ) {
1606 $course_ids = array_merge( $course_ids, $item_ids );
1607 }
1608
1609 $query = array(
1610 'total' => 0,
1611 'pages' => 0,
1612 'items' => false,
1613 );
1614
1615 if ( ! $course_ids ) {
1616 throw new Exception( '', 0 );
1617 }
1618
1619 $query_args = $course_ids;
1620 $query_args[] = $user_id;
1621 $limit = $args['limit'];
1622 $offset = ( $args['paged'] - 1 ) * $limit;
1623
1624 // SELECT
1625 $select = 'SELECT c.ID, c.post_title, ui.*';
1626
1627 // FROM
1628 $from = "FROM {$wpdb->learnpress_user_items} ui";
1629
1630 // JOIN
1631 $join = $wpdb->prepare(
1632 "INNER JOIN {$wpdb->posts} c ON ui.item_id = c.ID AND c.post_type = %s",
1633 LP_COURSE_CPT
1634 );
1635
1636 // WHERE - modify by tungnx
1637 $where = $wpdb->prepare(
1638 '
1639 WHERE ui.user_id = %d
1640 AND c.ID IN(' . join( ',', $course_ids ) . ')
1641 AND c.post_status = %s
1642 ',
1643 $user_id,
1644 'publish'
1645 );
1646 $count_where = $where;
1647
1648 // HAVING
1649 $having = 'HAVING 1';
1650
1651 // ORDER BY
1652 $orderby = 'ORDER BY start_time DESC';
1653
1654 if ( ! empty( $args['status'] ) ) {
1655 switch ( $args['status'] ) {
1656 case 'finished':
1657 case 'passed':
1658 case 'failed':
1659 $where .= $wpdb->prepare(
1660 ' AND ui.status IN( %s )',
1661 array(
1662 'finished',
1663 )
1664 );
1665
1666 if ( $args['status'] !== 'finished' ) {
1667 if ( 'passed' === $args['status'] ) {
1668 $having .= $wpdb->prepare( ' AND ui.graduation = %s', 'passed' );
1669 } else {
1670 $having .= $wpdb->prepare( ' AND ( ui.graduation = %s )', 'failed' );
1671 }
1672 }
1673
1674 break;
1675 case 'in-progress':
1676 $where .= $wpdb->prepare(
1677 ' AND ui.status IN( %s )',
1678 array(
1679 'enrolled',
1680 )
1681 );
1682
1683 $having .= $wpdb->prepare( ' AND ui.graduation = %s', 'in-progress' );
1684
1685 break;
1686 case 'not-enrolled':
1687 $where .= $wpdb->prepare(
1688 ' AND ui.status NOT IN( %s, %s, %s )',
1689 array(
1690 'enrolled',
1691 'finished',
1692 'pending',
1693 )
1694 );
1695 }
1696 }
1697
1698 // Comment by tungnx
1699 //$where .= $wpdb->prepare( ' AND ui.status NOT IN(%s) ', 'pending' );
1700
1701 $query_parts = apply_filters(
1702 'learn-press/query/user-purchased-courses',
1703 compact( 'select', 'from', 'join', 'where', 'having', 'orderby' ),
1704 $user_id,
1705 $args
1706 );
1707
1708 list( $select, $from, $join, $where, $having, $orderby ) = array_values( $query_parts );
1709
1710 if ( $args['limit'] > 0 ) {
1711 $limit = "LIMIT {$offset}, {$limit}";
1712 } else {
1713 $limit = '';
1714 }
1715
1716 do_action( 'learnpress/user-curd/query_where_join_purchased_courses', $where, $join );
1717
1718 $sql = "
1719 SELECT SQL_CALC_FOUND_ROWS *
1720 FROM
1721 (
1722 {$select}
1723 {$from}
1724 {$join}
1725 {$where}
1726 {$having}
1727 ORDER BY item_id, user_item_id DESC
1728 ) X
1729 GROUP BY item_id
1730 {$orderby}
1731 $limit
1732 ";
1733
1734 do_action( 'learnpress/user-curd/query_string_purchased_courses', $sql );
1735
1736 $items = $wpdb->get_results( $sql );
1737
1738 if ( $items ) {
1739 $count = $wpdb->get_var( 'SELECT FOUND_ROWS()' );
1740 $course_ids = wp_list_pluck( $items, 'item_id' );
1741 LP_Helper::cache_posts( $course_ids );
1742
1743 $courses['total'] = $count;
1744 $courses['pages'] = $args['limit'] > 0 ? ceil( $count / $args['limit'] ) : 1;
1745 foreach ( $items as $item ) {
1746 $item = (array) $item;
1747 $course_item = new LP_User_Item_Course( $item );
1748 $courses['items'][] = $course_item;
1749 }
1750 }
1751
1752 $counts = array(
1753 'all' => 0,
1754 'enrolled' => 0,
1755 'finished' => 0,
1756 );
1757
1758 $sql = "
1759 SELECT user_item_id
1760 FROM
1761 (
1762 {$select}
1763 {$from}
1764 {$join}
1765 {$count_where}
1766 ) X
1767 GROUP BY item_id
1768 ";
1769
1770 $user_item_ids = $wpdb->get_col( $sql );
1771 if ( $user_item_ids ) {
1772 $rows = $wpdb->get_results(
1773 "
1774 SELECT status, COUNT(user_item_id) count
1775 FROM {$wpdb->learnpress_user_items}
1776 WHERE user_item_id in(" . join( ',', $user_item_ids ) . ')
1777 GROUP BY status
1778 '
1779 );
1780
1781 if ( $rows ) {
1782 foreach ( $rows as $row ) {
1783 $counts[ $row->status ] = $row->count;
1784 $counts['all'] += $row->count;
1785 }
1786 }
1787 }
1788
1789 $counts['not-enrolled'] = $counts['all'] - ( $counts['enrolled'] + $counts['finished'] );
1790 $sql = $wpdb->prepare(
1791 "
1792 SELECT COUNT(meta_id) count, meta_value `status`
1793 FROM (
1794 SELECT user_id, item_id, MAX(user_item_id) max_id
1795 FROM {$wpdb->learnpress_user_items} GROUP BY user_id, item_id
1796 ) X
1797 INNER JOIN {$wpdb->learnpress_user_items} ui ON X.max_id = ui.user_item_id
1798 INNER JOIN {$wpdb->learnpress_user_itemmeta} uim ON ui.user_item_id=uim.learnpress_user_item_id
1799 WHERE uim.meta_key LIKE '%grade%'
1800 AND ui.user_id = %d AND ui.item_type = %s
1801 GROUP BY meta_value
1802 ",
1803 $user_id,
1804 LP_COURSE_CPT
1805 );
1806
1807 $rows = $wpdb->get_results( $sql );
1808 if ( $rows ) {
1809 foreach ( $rows as $row ) {
1810 $counts[ $row->status ] = $row->count;
1811 }
1812 }
1813
1814 $courses['counts'] = $counts;
1815 } catch ( Exception $ex ) {
1816
1817 }
1818
1819 LP_Object_Cache::set( $cache_key, $courses, 'learn-press/user-courses' );
1820 }
1821
1822 $courses['single'] = __( 'course', 'learnpress' );
1823 $courses['plural'] = __( 'courses', 'learnpress' );
1824
1825 return new LP_Query_List_Table( $courses );
1826 }*/
1827
1828 /**
1829 * Get courses user has purchased via orders are completed
1830 * but it is not already added to user-items table.
1831 *
1832 * @param int $user_id
1833 *
1834 * @return array|bool|mixed
1835 */
1836 public function query_courses_by_order( $user_id ) {
1837 global $wpdb;
1838
1839 $query = $wpdb->prepare(
1840 "
1841 SELECT item_id
1842 FROM {$wpdb->learnpress_user_items}
1843 WHERE user_id = %d
1844 AND item_type = %s
1845 ",
1846 $user_id,
1847 LP_COURSE_CPT
1848 );
1849 $user_item_ids = $wpdb->get_col( $query );
1850
1851 $orders = $this->get_orders(
1852 $user_id,
1853 array(
1854 'status' => 'completed',
1855 'group_by_order' => true,
1856 )
1857 );
1858
1859 if ( ! $orders ) {
1860 return false;
1861 }
1862
1863 $course_ids = array_shift( $orders );
1864
1865 foreach ( $orders as $ids ) {
1866 if ( ! $ids ) {
1867 continue;
1868 }
1869 $course_ids = array_merge( $course_ids, $ids );
1870 }
1871
1872 if ( $user_item_ids ) {
1873 $course_ids = array_diff( $course_ids, $user_item_ids );
1874 }
1875
1876 return $course_ids;
1877 }
1878
1879 /**
1880 * Query quizzes by user.
1881 *
1882 * @param int $user_id
1883 * @param string $args
1884 *
1885 * @return LP_Query_List_Table
1886 */
1887 public function query_quizzes( $user_id = 0, $args = '' ) {
1888 global $wpdb, $wp;
1889
1890 $paged = 1;
1891
1892 if ( ! empty( $wp->query_vars['view_id'] ) ) {
1893 $paged = absint( $wp->query_vars['view_id'] );
1894 }
1895
1896 $paged = max( $paged, 1 );
1897 $args = wp_parse_args(
1898 $args,
1899 array(
1900 'paged' => $paged,
1901 'limit' => 10,
1902 'status' => '',
1903 )
1904 );
1905
1906 if ( ! $user_id ) {
1907 $user_id = get_current_user_id();
1908 }
1909
1910 $cache_key = sprintf( 'quizzes-%d-%s', $user_id, md5( build_query( $args ) ) );
1911 $quizzes = LP_Object_Cache::get( $cache_key, 'learn-press/user-quizzes' );
1912
1913 if ( false === $quizzes ) {
1914 $orders = $this->get_orders( $user_id );
1915 $query = array(
1916 'total' => 0,
1917 'pages' => 0,
1918 'items' => false,
1919 );
1920
1921 $quizzes = array(
1922 'total' => 0,
1923 'paged' => $args['paged'],
1924 'limit' => $args['limit'],
1925 'pages' => 0,
1926 'items' => array(),
1927 );
1928
1929 try {
1930 if ( ! $orders ) {
1931 throw new Exception( __( 'No item in Order', 'learnpress' ), 0 );
1932 }
1933
1934 $course_ids = array_keys( $orders );
1935 $query_args = $course_ids;
1936 $query_args[] = $user_id;
1937
1938 $select = 'SELECT * ';
1939 $from = "FROM {$wpdb->learnpress_user_items} ui";
1940 $join = '';
1941 $where = 'WHERE 1=1 ';
1942 $where .= $wpdb->prepare( 'AND user_id = %d ', $user_id );
1943 $where .= $wpdb->prepare( 'AND item_type = %s ', LP_QUIZ_CPT );
1944 $where .= $wpdb->prepare( 'AND status IN (%s, %s) ', LP_ITEM_COMPLETED, LP_ITEM_STARTED );
1945 $having = 'HAVING 1';
1946 $orderby = 'ORDER BY item_id, user_item_id DESC';
1947
1948 if ( ! empty( $args['status'] ) ) {
1949 switch ( $args['status'] ) {
1950 case 'completed':
1951 case 'passed':
1952 case 'failed':
1953 $having .= $wpdb->prepare(
1954 ' AND X.status IN( %s )',
1955 array(
1956 'completed',
1957 )
1958 );
1959
1960 if ( $args['status'] !== 'completed' ) {
1961 if ( 'passed' === $args['status'] ) {
1962 $having .= $wpdb->prepare( ' AND X.graduation = %s', 'passed' );
1963 } elseif ( 'failed' === $args['status'] ) {
1964 $having .= $wpdb->prepare( ' AND X.graduation = %s', 'failed' );
1965 } else {
1966 $having .= $wpdb->prepare( ' AND ( X.graduation IS NULL OR X.graduation <> %s )', 'passed' );
1967 }
1968 }
1969 break;
1970
1971 case 'in-progress':
1972 $having .= $wpdb->prepare(
1973 ' AND X.status IN( %s ) AND X.graduation NOT IN ( %s, %s )',
1974 array(
1975 'started',
1976 'passed',
1977 'failed',
1978 )
1979 );
1980 break;
1981
1982 case 'not-started':
1983 $having .= $wpdb->prepare(
1984 ' AND X.status NOT IN( %s, %s )',
1985 array(
1986 'started',
1987 'completed',
1988 )
1989 );
1990 break;
1991 }
1992 } else {
1993
1994 $having .= $wpdb->prepare(
1995 ' AND X.status IN( %s, %s )',
1996 array(
1997 'started',
1998 'completed',
1999 )
2000 );
2001 }
2002 $limit = $args['limit'];
2003 $offset = ( $args['paged'] - 1 ) * $limit;
2004
2005 $query_parts = apply_filters(
2006 'learn-press/query/user-quizzes',
2007 compact( 'select', 'from', 'join', 'where', 'having', 'orderby' ),
2008 $user_id,
2009 $args
2010 );
2011
2012 list( $select, $from, $join, $where, $having, $orderby ) = array_values( $query_parts );
2013
2014 $sql = $wpdb->prepare(
2015 "
2016 SELECT * FROM (
2017 SELECT *
2018 FROM
2019 (
2020 {$select}
2021 {$from}
2022 {$join}
2023 {$where}
2024 ORDER BY user_item_id DESC
2025 ) AS G_Item
2026 GROUP BY G_Item.item_id
2027 ) AS G_User_Item
2028 ORDER BY G_User_Item.user_item_id DESC
2029 LIMIT %d, %d
2030 ",
2031 $offset,
2032 $limit
2033 );
2034
2035 $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
2036 FROM $wpdb->learnpress_user_items
2037 WHERE user_id = $user_id
2038 AND item_type = 'lp_quiz'
2039 AND status IN ('completed', 'started')
2040 GROUP BY item_id
2041 ORDER BY MAX(user_item_id) DESC";
2042
2043 $items = $wpdb->get_results( $sql, ARRAY_A );
2044
2045 if ( $items ) {
2046 $count = $wpdb->get_var( 'SELECT FOUND_ROWS()' );
2047 $course_ids = wp_list_pluck( $items, 'item_id' );
2048 // LP_Helper::cache_posts( $course_ids );
2049
2050 $quizzes['total'] = $count;
2051 $quizzes['pages'] = ceil( $count / $args['limit'] );
2052
2053 foreach ( $items as $item ) {
2054 $quizzes['items'][] = new LP_User_Item_Quiz( $item );
2055 }
2056 }
2057 } catch ( Exception $ex ) {
2058
2059 }
2060 LP_Object_Cache::set( $cache_key, $quizzes, 'learn-press/user-course' );
2061 }
2062
2063 $quizzes['single'] = __( 'quiz', 'learnpress' );
2064 $quizzes['plural'] = __( 'quizzes', 'learnpress' );
2065
2066 return new LP_Query_List_Table( $quizzes );
2067 }
2068
2069 public function read_course_info( $course ) {
2070 $data = $course;
2071 global $wpdb;
2072 $query = $wpdb->prepare(
2073 "
2074 SELECT *
2075 FROM {$wpdb->learnpress_user_itemmeta}
2076 WHERE learnpress_user_item_id = %d
2077 ",
2078 $course['user_item_id']
2079 );
2080
2081 $itemmeta = $wpdb->get_results( $query, ARRAY_A );
2082
2083 if ( $itemmeta ) {
2084 foreach ( $itemmeta as $item ) {
2085 $data[ $item['meta_key'] ] = $item['meta_value'];
2086 }
2087 }
2088
2089 return $data;
2090 }
2091
2092 public function update_item( $item ) {
2093 global $wpdb;
2094 if ( empty( $item['user_item_id'] ) ) {
2095 $wpdb->insert(
2096 $wpdb->learnpress_user_items,
2097 $item
2098 );
2099 }
2100 }
2101
2102 public function get_current_user_order( $user_id, $course_id ) {
2103 global $wpdb;
2104 $sql = $wpdb->prepare(
2105 "
2106 SELECT MAX(ID) AS order_id
2107 FROM {$wpdb->posts} p
2108 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
2109 INNER JOIN {$wpdb->learnpress_order_items} oi ON oi.order_id = p.id
2110 INNER JOIN {$wpdb->learnpress_order_itemmeta} oim ON oim.meta_key = %s and oim.meta_value = %d
2111 ",
2112 '_user_id',
2113 $user_id,
2114 '_course_id',
2115 $course_id
2116 );
2117 $order_id = $wpdb->get_var( $sql );
2118
2119 return $order_id;
2120 }
2121
2122 public function duplicate( &$user, $args = array() ) {
2123 // TODO: Implement duplicate() method.
2124 }
2125
2126 public static function create_user( $email, $username, $password ) {
2127 if ( empty( $email ) || ! is_email( $email ) ) {
2128 return new WP_Error( 'registration-error-invalid-email', __( 'Please provide a valid email address.', 'learnpress' ) );
2129 }
2130
2131 if ( email_exists( $email ) ) {
2132 return new WP_Error( 'registration-error-email-exists', __( 'An account is already registered with your email address. Please log in.', 'learnpress' ) );
2133 }
2134
2135 $username = sanitize_user( $username );
2136
2137 if ( empty( $username ) || ! validate_username( $username ) ) {
2138 return new WP_Error( 'registration-error-invalid-username', __( 'Please enter a valid account username.', 'learnpress' ) );
2139 }
2140
2141 if ( username_exists( $username ) ) {
2142 return new WP_Error( 'registration-error-username-exists', __( 'An account is already registered with that username. Please choose another.', 'learnpress' ) );
2143 }
2144
2145 $new_user = wp_insert_user(
2146 array(
2147 'user_login' => $username,
2148 'user_pass' => $password,
2149 'user_email' => $email,
2150 )
2151 );
2152
2153 if ( is_wp_error( $new_user ) ) {
2154 return new WP_Error( 'registration-error', __( 'Failed to create user', 'learnpress' ) );
2155 }
2156
2157 return $new_user;
2158 }
2159 }
2160