PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.9
4.4.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 All 140 releases
← All changes | inc/curds/class-lp-user-curd.php +738 -738 4.3.9 → 4.4.9 View file →
@@ -1,738 +1,738 @@
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 -
36 - /**
37 - * Get courses of an user.
38 - *
39 - * @param array $args
40 - *
41 - * @return array
42 - * @since 3.3.0
43 - * @deprecated 4.2.4
44 - */
45 - public function get_courses( $args = array() ) {
46 - _deprecated_function( __METHOD__, '4.2.4' );
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 - * @param LP_User $user
224 - */
225 - public function create( &$user ) {
226 -
227 - }
228 -
229 - /**
230 - * @param LP_User $user
231 - */
232 - public function update( &$user ) {
233 - // TODO: Implement update() method.
234 - }
235 -
236 - /**
237 - * @param LP_User $user
238 - */
239 - public function delete( &$user ) {
240 - // TODO: Implement delete() method.
241 - }
242 -
243 - /**
244 - * Load user data
245 - *
246 - * @param LP_User|LP_Abstract_User $user
247 - *
248 - * @return mixed;
249 - */
250 - public function load( &$user ) {
251 - $user_id = $user->get_id();
252 - $user_object = get_user_by( 'id', $user_id );
253 -
254 - if ( false !== $user_object ) {
255 - $user->set_data(
256 - array(
257 - 'email' => $user_object->user_email,
258 - 'user_login' => $user_object->user_login,
259 - 'description' => $user_object->description,
260 - 'first_name' => $user_object->first_name ?? '',
261 - 'last_name' => $user_object->last_name ?? '',
262 - 'nickname' => $user_object->nickname ?? '',
263 - 'display_name' => $user_object->display_name,
264 - 'date_created' => $user_object->user_registered,
265 - 'date_modified' => get_user_meta( $user_id, 'last_update', true ),
266 - 'role' => $user_object->roles[0] ?? '',
267 - 'roles' => $user_object->roles,
268 - 'profile_picture' => get_user_meta( $user_id, '_lp_profile_picture', true ),
269 - 'profile_privacy' => get_user_meta( $user_id, '_lp_profile_privacy', true ),
270 - )
271 - );
272 - }
273 -
274 - return true;
275 - }
276 -
277 - /**
278 - * Get all orders of an user grouped by id of course.
279 - *
280 - * A course can have multi orders, each element is an array of order ids
281 - * with the key is id of the course. The orders is sorted from highest
282 - * to lowest. With the highest value is the latest order user placed (current order).
283 - *
284 - * Format:
285 - * array(
286 - * course_id_1 => array( order_id_1, order_id_2, ...),
287 - * course_id_2 => array( order_id_3, order_id_4, ...),
288 - * ...
289 - * )
290 - *
291 - * @param int $user_id
292 - * @param array $args
293 - *
294 - * @return array|mixed
295 - */
296 - public function get_orders( $user_id, $args = array() ) {
297 - $user = learn_press_get_user( $user_id );
298 -
299 - if ( ! $user_id || ! $user ) {
300 - return false;
301 - }
302 -
303 - $cache_key = false;
304 - if ( $args ) {
305 - $args = wp_parse_args(
306 - $args,
307 - array(
308 - 'group_by_order' => false,
309 - 'status' => '',
310 - )
311 - );
312 -
313 - ksort( $args );
314 - $cache_key = md5( serialize( $args ) );
315 -
316 - /**
317 - * Get orders from cache by args
318 - */
319 - $orders = LP_Object_Cache::get( "user-{$user_id}-" . $cache_key, 'lp-user-orders' );
320 -
321 - if ( false !== $orders ) {
322 - return $orders;
323 - }
324 - }
325 -
326 - // Get orders for the user from cache
327 - $orders = LP_Object_Cache::get( 'user-' . $user_id, 'lp-user-orders' );
328 -
329 - if ( false === $orders ) {
330 - global $wpdb;
331 -
332 - $orders = array();
333 - $post_status_in = array_keys( LP_Order::get_order_statuses() );
334 - $post_status_in_format = array_fill( 0, sizeof( $post_status_in ), '%s' );
335 - $user_id_str = $wpdb->prepare( '%"%d"%', $user_id );
336 -
337 - // Get order by user
338 - $sql_orders = $wpdb->prepare(
339 - "
340 - SELECT p.*
341 - FROM {$wpdb->posts} p
342 - INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND meta_key = %s AND (meta_value = %d OR meta_value like '%s')
343 - ",
344 - '_user_id',
345 - $user_id,
346 - $user_id_str
347 - );
348 -
349 - /**
350 - * Get order checked out by Guest but with the email of the user are getting
351 - * Error when checkout with guest then register error Start Quiz - nhamdv.
352 - */
353 - // $sql_guest_orders = $wpdb->prepare(
354 - // "
355 - // SELECT p.*
356 - // FROM {$wpdb->posts} p
357 - // INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND meta_key = %s AND meta_value = %s
358 - // LEFT JOIN {$wpdb->postmeta} pmu ON p.ID = pmu.post_id AND pmu.meta_key = %s AND pmu.meta_value IS NULL
359 - // ",
360 - // '_checkout_email',
361 - // $user->get_email(),
362 - // '_user_id'
363 - // );
364 -
365 - /**
366 - * The rest
367 - */
368 - $sql_rest = $wpdb->prepare(
369 - '
370 - HAVING p.post_type = %s
371 - AND p.post_status IN(' . join( ',', $post_status_in_format ) . ')
372 - ORDER BY ID DESC
373 - ',
374 - array_merge(
375 - array(
376 - LP_ORDER_CPT,
377 - ),
378 - $post_status_in
379 - )
380 - );
381 -
382 - $sql = $sql_orders /* . ' UNION ' . $sql_guest_orders */ . $sql_rest;
383 -
384 - $order_posts = $wpdb->get_results( $sql );
385 -
386 - if ( $order_posts ) {
387 - $order_ids = array();
388 -
389 - foreach ( $order_posts as $order_post ) {
390 - $_post = sanitize_post( $order_post, 'raw' );
391 - wp_cache_add( $_post->ID, $_post, 'posts' );
392 -
393 - $order_ids[] = $_post->ID;
394 - }
395 -
396 - $order_ids_format = array_fill( 0, sizeof( $order_ids ), '%d' );
397 - $query = $wpdb->prepare(
398 - "
399 - SELECT meta_value as course_id, order_id
400 - FROM {$wpdb->learnpress_order_items} oi
401 - INNER JOIN {$wpdb->learnpress_order_itemmeta} oim ON oi.order_item_id = oim.learnpress_order_item_id AND oim.meta_key = %s
402 - WHERE oi.order_id IN (" . join( ',', $order_ids_format ) . ')
403 - ORDER BY FIELD(order_id, ' . join( ',', $order_ids_format ) . ')
404 - ',
405 - array_merge( array( '_course_id' ), $order_ids, $order_ids )
406 - );
407 -
408 - $results = $wpdb->get_results( $query );
409 -
410 - if ( $results ) {
411 - foreach ( $results as $result ) {
412 - if ( empty( $orders[ $result->course_id ] ) ) {
413 - $orders[ $result->course_id ] = array();
414 - }
415 - $orders[ $result->course_id ][] = $result->order_id;
416 - }
417 - }
418 - }
419 -
420 - LP_Object_Cache::set( 'user-' . $user_id, $orders, 'lp-user-orders' );
421 - }
422 -
423 - if ( $orders ) {
424 - if ( array_key_exists( 'status', $args ) && $args['status'] ) {
425 - LP_Helper::sanitize_order_status( $args['status'] );
426 -
427 - $statuses = (array) $args['status'];
428 - foreach ( $orders as $course_id => $order_ids ) {
429 - $orders[ $course_id ] = array();
430 - foreach ( $order_ids as $order_id ) {
431 - if ( in_array( get_post_status( $order_id ), $statuses ) ) {
432 - $orders[ $course_id ][] = $order_id;
433 - }
434 - }
435 - }
436 - }
437 -
438 - if ( array_key_exists( 'group_by_order', $args ) && $args['group_by_order'] ) {
439 - $this->_group_orders( $orders );
440 - }
441 - }
442 -
443 - if ( $cache_key ) {
444 - LP_Object_Cache::set( "user-{$user_id}-" . $cache_key, $orders, 'lp-user-orders' );
445 - }
446 -
447 - return $orders;
448 - }
449 -
450 - protected function _group_orders( &$orders ) {
451 - $groups = array();
452 - foreach ( $orders as $course_id => $order_ids ) {
453 - foreach ( $order_ids as $order_id ) {
454 - if ( empty( $groups[ $order_id ] ) ) {
455 - $groups[ $order_id ] = array();
456 - }
457 - $groups[ $order_id ][] = $course_id;
458 - }
459 - }
460 - $orders = $groups;
461 - krsort( $orders );
462 -
463 - return $orders;
464 - }
465 -
466 - /**
467 - * Read meta data of an user item.
468 - *
469 - * @param $item
470 - *
471 - * @deprecated 4.2.4
472 - */
473 - protected function _read_item_meta( &$item ) {
474 - _deprecated_function( __METHOD__, '4.2.4' );
475 - global $wpdb;
476 - $query = $wpdb->prepare(
477 - "
478 - SELECT *
479 - FROM {$wpdb->learnpress_user_itemmeta}
480 - WHERE learnpress_user_item_id = %d
481 - ",
482 - $item['user_item_id']
483 - );
484 -
485 - update_meta_cache( 'learnpress_user_item', $item['user_item_id'] );
486 -
487 - if ( $meta = $wpdb->get_results( $query, ARRAY_A ) ) {
488 - $item['meta'] = array();
489 - foreach ( $meta as $k => $v ) {
490 - $v['meta_value'] = LP_Helper::maybe_unserialize( $v['meta_value'] );
491 - $item['meta'][ $v['meta_id'] ] = $v;
492 - }
493 - }
494 - }
495 -
496 - /**
497 - * @param int $user_item_id
498 - * @param string $type
499 - *
500 - * @return array
501 - */
502 - public function get_user_item_by_id( $user_item_id, $type = '' ) {
503 - global $wpdb;
504 -
505 - $query = $wpdb->prepare(
506 - "
507 - SELECT *
508 - FROM {$wpdb->learnpress_user_items}
509 - WHERE user_item_id = %d
510 - " . ( $type ? $wpdb->prepare( 'AND item_type = %s', $type ) : '' ) . '
511 - ',
512 - $user_item_id
513 - );
514 - $item = $wpdb->get_row( $query, ARRAY_A );
515 -
516 - return $item;
517 - }
518 -
519 - /**
520 - * Update status of an user item by id.
521 - *
522 - * @param int $user_item_id
523 - * @param string $new_status
524 - *
525 - * @return mixed
526 - */
527 - public function update_user_item_status( $user_item_id, $new_status ) {
528 - global $wpdb;
529 - $item = $this->get_user_item_by_id( $user_item_id );
530 - if ( ! $item ) {
531 - return false;
532 - }
533 -
534 - // No need to update if it is not change
535 - if ( $item['status'] === $new_status ) {
536 - return false;
537 - }
538 -
539 - $updated = $wpdb->update(
540 - $wpdb->learnpress_user_items,
541 - array( 'status' => $new_status ),
542 - array( 'user_item_id' => $user_item_id ),
543 - array( '%s' ),
544 - array( '%d' )
545 - );
546 - // if ( $updated ) {
547 - // $this->update_user_item_meta( $user_item_id, '_last_status', $item['status'] );
548 - // $this->update_user_item_meta( $user_item_id, '_current_status', $new_status );
549 - // }
550 -
551 - return $updated;
552 - }
553 -
554 - /**
555 - * Delete user item by fields.
556 - *
557 - * @param string $args
558 - *
559 - * @return bool
560 - */
561 - public function delete_user_item( $args = '' ) {
562 - global $wpdb;
563 - $args = wp_parse_args(
564 - $args,
565 - array(
566 - 'user_id' => 0,
567 - 'item_id' => 0,
568 - 'ref_id' => 0,
569 - 'parent_id' => 0,
570 - )
571 - );
572 - $where = array();
573 - foreach ( $args as $k => $v ) {
574 - if ( $v ) {
575 - $where[ $k ] = $v;
576 - }
577 - }
578 -
579 - if ( ! $where ) {
580 - return false;
581 - }
582 - $query_where = array();
583 - foreach ( $where as $k => $v ) {
584 - $query_where[] = "{$k} = %d";
585 - }
586 -
587 - $query = $wpdb->prepare(
588 - "SELECT user_item_id FROM {$wpdb->learnpress_user_items} WHERE " . join(
589 - ' AND ',
590 - $query_where
591 - ),
592 - array_values( $where )
593 - );
594 - $user_item_ids = $wpdb->get_col( $query );
595 -
596 - $wpdb->delete(
597 - $wpdb->learnpress_user_items,
598 - $where,
599 - array_fill( 0, sizeof( $where ), '%d' )
600 - );
601 -
602 - foreach ( $user_item_ids as $user_item_id ) {
603 - $wpdb->query(
604 - $wpdb->prepare(
605 - "DELETE FROM {$wpdb->learnpress_user_itemmeta} WHERE learnpress_user_item_id = %d",
606 - $user_item_id
607 - )
608 - );
609 - do_action( 'learn-press/deleted-user-item', $user_item_id );
610 - }
611 -
612 - return true;
613 - }
614 -
615 - /**
616 - * Get courses user has purchased via orders are completed
617 - * but it is not already added to user-items table.
618 - *
619 - * @param int $user_id
620 - *
621 - * @return array|bool|mixed
622 - * @deprecated 4.2.4
623 - */
624 - public function query_courses_by_order( $user_id ) {
625 - _deprecated_function( __METHOD__, '4.2.4' );
626 -
627 - return false;
628 - global $wpdb;
629 -
630 - $query = $wpdb->prepare(
631 - "
632 - SELECT item_id
633 - FROM {$wpdb->learnpress_user_items}
634 - WHERE user_id = %d
635 - AND item_type = %s
636 - ",
637 - $user_id,
638 - LP_COURSE_CPT
639 - );
640 - $user_item_ids = $wpdb->get_col( $query );
641 -
642 - $orders = $this->get_orders(
643 - $user_id,
644 - array(
645 - 'status' => 'completed',
646 - 'group_by_order' => true,
647 - )
648 - );
649 -
650 - if ( ! $orders ) {
651 - return false;
652 - }
653 -
654 - $course_ids = array_shift( $orders );
655 -
656 - foreach ( $orders as $ids ) {
657 - if ( ! $ids ) {
658 - continue;
659 - }
660 - $course_ids = array_merge( $course_ids, $ids );
661 - }
662 -
663 - if ( $user_item_ids ) {
664 - $course_ids = array_diff( $course_ids, $user_item_ids );
665 - }
666 -
667 - return $course_ids;
668 - }
669 -
670 - /**
671 - * @deprecated 4.2.4
672 - */
673 - public function read_course_info( $course ) {
674 - _deprecated_function( __METHOD__, '4.2.4' );
675 -
676 - return [];
677 - $data = $course;
678 - global $wpdb;
679 - $query = $wpdb->prepare(
680 - "
681 - SELECT *
682 - FROM {$wpdb->learnpress_user_itemmeta}
683 - WHERE learnpress_user_item_id = %d
684 - ",
685 - $course['user_item_id']
686 - );
687 -
688 - $itemmeta = $wpdb->get_results( $query, ARRAY_A );
689 -
690 - if ( $itemmeta ) {
691 - foreach ( $itemmeta as $item ) {
692 - $data[ $item['meta_key'] ] = $item['meta_value'];
693 - }
694 - }
695 -
696 - return $data;
697 - }
698 -
699 - public function update_item( $item ) {
700 - global $wpdb;
701 - if ( empty( $item['user_item_id'] ) ) {
702 - $wpdb->insert(
703 - $wpdb->learnpress_user_items,
704 - $item
705 - );
706 - }
707 - }
708 -
709 - /**
710 - * @deprecated 4.2.4
711 - */
712 - public function get_current_user_order( $user_id, $course_id ) {
713 - _deprecated_function( __METHOD__, '4.2.4' );
714 -
715 - return 0;
716 - global $wpdb;
717 - $sql = $wpdb->prepare(
718 - "
719 - SELECT MAX(ID) AS order_id
720 - FROM {$wpdb->posts} p
721 - 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
722 - INNER JOIN {$wpdb->learnpress_order_items} oi ON oi.order_id = p.id
723 - INNER JOIN {$wpdb->learnpress_order_itemmeta} oim ON oim.meta_key = %s and oim.meta_value = %d
724 - ",
725 - '_user_id',
726 - $user_id,
727 - '_course_id',
728 - $course_id
729 - );
730 - $order_id = $wpdb->get_var( $sql );
731 -
732 - return $order_id;
733 - }
734 -
735 - public function duplicate( &$user, $args = array() ) {
736 - // TODO: Implement duplicate() method.
737 - }
738 -}
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 +
36 + /**
37 + * Get courses of an user.
38 + *
39 + * @param array $args
40 + *
41 + * @return array
42 + * @since 3.3.0
43 + * @deprecated 4.2.4
44 + */
45 + public function get_courses( $args = array() ) {
46 + _deprecated_function( __METHOD__, '4.2.4' );
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 + * @param LP_User $user
224 + */
225 + public function create( &$user ) {
226 +
227 + }
228 +
229 + /**
230 + * @param LP_User $user
231 + */
232 + public function update( &$user ) {
233 + // TODO: Implement update() method.
234 + }
235 +
236 + /**
237 + * @param LP_User $user
238 + */
239 + public function delete( &$user ) {
240 + // TODO: Implement delete() method.
241 + }
242 +
243 + /**
244 + * Load user data
245 + *
246 + * @param LP_User|LP_Abstract_User $user
247 + *
248 + * @return mixed;
249 + */
250 + public function load( &$user ) {
251 + $user_id = $user->get_id();
252 + $user_object = get_user_by( 'id', $user_id );
253 +
254 + if ( false !== $user_object ) {
255 + $user->set_data(
256 + array(
257 + 'email' => $user_object->user_email,
258 + 'user_login' => $user_object->user_login,
259 + 'description' => $user_object->description,
260 + 'first_name' => $user_object->first_name ?? '',
261 + 'last_name' => $user_object->last_name ?? '',
262 + 'nickname' => $user_object->nickname ?? '',
263 + 'display_name' => $user_object->display_name,
264 + 'date_created' => $user_object->user_registered,
265 + 'date_modified' => get_user_meta( $user_id, 'last_update', true ),
266 + 'role' => $user_object->roles[0] ?? '',
267 + 'roles' => $user_object->roles,
268 + 'profile_picture' => get_user_meta( $user_id, '_lp_profile_picture', true ),
269 + 'profile_privacy' => get_user_meta( $user_id, '_lp_profile_privacy', true ),
270 + )
271 + );
272 + }
273 +
274 + return true;
275 + }
276 +
277 + /**
278 + * Get all orders of an user grouped by id of course.
279 + *
280 + * A course can have multi orders, each element is an array of order ids
281 + * with the key is id of the course. The orders is sorted from highest
282 + * to lowest. With the highest value is the latest order user placed (current order).
283 + *
284 + * Format:
285 + * array(
286 + * course_id_1 => array( order_id_1, order_id_2, ...),
287 + * course_id_2 => array( order_id_3, order_id_4, ...),
288 + * ...
289 + * )
290 + *
291 + * @param int $user_id
292 + * @param array $args
293 + *
294 + * @return array|mixed
295 + */
296 + public function get_orders( $user_id, $args = array() ) {
297 + $user = learn_press_get_user( $user_id );
298 +
299 + if ( ! $user_id || ! $user ) {
300 + return false;
301 + }
302 +
303 + $cache_key = false;
304 + if ( $args ) {
305 + $args = wp_parse_args(
306 + $args,
307 + array(
308 + 'group_by_order' => false,
309 + 'status' => '',
310 + )
311 + );
312 +
313 + ksort( $args );
314 + $cache_key = md5( serialize( $args ) );
315 +
316 + /**
317 + * Get orders from cache by args
318 + */
319 + $orders = LP_Object_Cache::get( "user-{$user_id}-" . $cache_key, 'lp-user-orders' );
320 +
321 + if ( false !== $orders ) {
322 + return $orders;
323 + }
324 + }
325 +
326 + // Get orders for the user from cache
327 + $orders = LP_Object_Cache::get( 'user-' . $user_id, 'lp-user-orders' );
328 +
329 + if ( false === $orders ) {
330 + global $wpdb;
331 +
332 + $orders = array();
333 + $post_status_in = array_keys( LP_Order::get_order_statuses() );
334 + $post_status_in_format = array_fill( 0, sizeof( $post_status_in ), '%s' );
335 + $user_id_str = $wpdb->prepare( '%"%d"%', $user_id );
336 +
337 + // Get order by user
338 + $sql_orders = $wpdb->prepare(
339 + "
340 + SELECT p.*
341 + FROM {$wpdb->posts} p
342 + INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND meta_key = %s AND (meta_value = %d OR meta_value like '%s')
343 + ",
344 + '_user_id',
345 + $user_id,
346 + $user_id_str
347 + );
348 +
349 + /**
350 + * Get order checked out by Guest but with the email of the user are getting
351 + * Error when checkout with guest then register error Start Quiz - nhamdv.
352 + */
353 + // $sql_guest_orders = $wpdb->prepare(
354 + // "
355 + // SELECT p.*
356 + // FROM {$wpdb->posts} p
357 + // INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND meta_key = %s AND meta_value = %s
358 + // LEFT JOIN {$wpdb->postmeta} pmu ON p.ID = pmu.post_id AND pmu.meta_key = %s AND pmu.meta_value IS NULL
359 + // ",
360 + // '_checkout_email',
361 + // $user->get_email(),
362 + // '_user_id'
363 + // );
364 +
365 + /**
366 + * The rest
367 + */
368 + $sql_rest = $wpdb->prepare(
369 + '
370 + HAVING p.post_type = %s
371 + AND p.post_status IN(' . join( ',', $post_status_in_format ) . ')
372 + ORDER BY ID DESC
373 + ',
374 + array_merge(
375 + array(
376 + LP_ORDER_CPT,
377 + ),
378 + $post_status_in
379 + )
380 + );
381 +
382 + $sql = $sql_orders /* . ' UNION ' . $sql_guest_orders */ . $sql_rest;
383 +
384 + $order_posts = $wpdb->get_results( $sql );
385 +
386 + if ( $order_posts ) {
387 + $order_ids = array();
388 +
389 + foreach ( $order_posts as $order_post ) {
390 + $_post = sanitize_post( $order_post, 'raw' );
391 + wp_cache_add( $_post->ID, $_post, 'posts' );
392 +
393 + $order_ids[] = $_post->ID;
394 + }
395 +
396 + $order_ids_format = array_fill( 0, sizeof( $order_ids ), '%d' );
397 + $query = $wpdb->prepare(
398 + "
399 + SELECT meta_value as course_id, order_id
400 + FROM {$wpdb->learnpress_order_items} oi
401 + INNER JOIN {$wpdb->learnpress_order_itemmeta} oim ON oi.order_item_id = oim.learnpress_order_item_id AND oim.meta_key = %s
402 + WHERE oi.order_id IN (" . join( ',', $order_ids_format ) . ')
403 + ORDER BY FIELD(order_id, ' . join( ',', $order_ids_format ) . ')
404 + ',
405 + array_merge( array( '_course_id' ), $order_ids, $order_ids )
406 + );
407 +
408 + $results = $wpdb->get_results( $query );
409 +
410 + if ( $results ) {
411 + foreach ( $results as $result ) {
412 + if ( empty( $orders[ $result->course_id ] ) ) {
413 + $orders[ $result->course_id ] = array();
414 + }
415 + $orders[ $result->course_id ][] = $result->order_id;
416 + }
417 + }
418 + }
419 +
420 + LP_Object_Cache::set( 'user-' . $user_id, $orders, 'lp-user-orders' );
421 + }
422 +
423 + if ( $orders ) {
424 + if ( array_key_exists( 'status', $args ) && $args['status'] ) {
425 + LP_Helper::sanitize_order_status( $args['status'] );
426 +
427 + $statuses = (array) $args['status'];
428 + foreach ( $orders as $course_id => $order_ids ) {
429 + $orders[ $course_id ] = array();
430 + foreach ( $order_ids as $order_id ) {
431 + if ( in_array( get_post_status( $order_id ), $statuses ) ) {
432 + $orders[ $course_id ][] = $order_id;
433 + }
434 + }
435 + }
436 + }
437 +
438 + if ( array_key_exists( 'group_by_order', $args ) && $args['group_by_order'] ) {
439 + $this->_group_orders( $orders );
440 + }
441 + }
442 +
443 + if ( $cache_key ) {
444 + LP_Object_Cache::set( "user-{$user_id}-" . $cache_key, $orders, 'lp-user-orders' );
445 + }
446 +
447 + return $orders;
448 + }
449 +
450 + protected function _group_orders( &$orders ) {
451 + $groups = array();
452 + foreach ( $orders as $course_id => $order_ids ) {
453 + foreach ( $order_ids as $order_id ) {
454 + if ( empty( $groups[ $order_id ] ) ) {
455 + $groups[ $order_id ] = array();
456 + }
457 + $groups[ $order_id ][] = $course_id;
458 + }
459 + }
460 + $orders = $groups;
461 + krsort( $orders );
462 +
463 + return $orders;
464 + }
465 +
466 + /**
467 + * Read meta data of an user item.
468 + *
469 + * @param $item
470 + *
471 + * @deprecated 4.2.4
472 + */
473 + protected function _read_item_meta( &$item ) {
474 + _deprecated_function( __METHOD__, '4.2.4' );
475 + global $wpdb;
476 + $query = $wpdb->prepare(
477 + "
478 + SELECT *
479 + FROM {$wpdb->learnpress_user_itemmeta}
480 + WHERE learnpress_user_item_id = %d
481 + ",
482 + $item['user_item_id']
483 + );
484 +
485 + update_meta_cache( 'learnpress_user_item', $item['user_item_id'] );
486 +
487 + if ( $meta = $wpdb->get_results( $query, ARRAY_A ) ) {
488 + $item['meta'] = array();
489 + foreach ( $meta as $k => $v ) {
490 + $v['meta_value'] = LP_Helper::maybe_unserialize( $v['meta_value'] );
491 + $item['meta'][ $v['meta_id'] ] = $v;
492 + }
493 + }
494 + }
495 +
496 + /**
497 + * @param int $user_item_id
498 + * @param string $type
499 + *
500 + * @return array
501 + */
502 + public function get_user_item_by_id( $user_item_id, $type = '' ) {
503 + global $wpdb;
504 +
505 + $query = $wpdb->prepare(
506 + "
507 + SELECT *
508 + FROM {$wpdb->learnpress_user_items}
509 + WHERE user_item_id = %d
510 + " . ( $type ? $wpdb->prepare( 'AND item_type = %s', $type ) : '' ) . '
511 + ',
512 + $user_item_id
513 + );
514 + $item = $wpdb->get_row( $query, ARRAY_A );
515 +
516 + return $item;
517 + }
518 +
519 + /**
520 + * Update status of an user item by id.
521 + *
522 + * @param int $user_item_id
523 + * @param string $new_status
524 + *
525 + * @return mixed
526 + */
527 + public function update_user_item_status( $user_item_id, $new_status ) {
528 + global $wpdb;
529 + $item = $this->get_user_item_by_id( $user_item_id );
530 + if ( ! $item ) {
531 + return false;
532 + }
533 +
534 + // No need to update if it is not change
535 + if ( $item['status'] === $new_status ) {
536 + return false;
537 + }
538 +
539 + $updated = $wpdb->update(
540 + $wpdb->learnpress_user_items,
541 + array( 'status' => $new_status ),
542 + array( 'user_item_id' => $user_item_id ),
543 + array( '%s' ),
544 + array( '%d' )
545 + );
546 + // if ( $updated ) {
547 + // $this->update_user_item_meta( $user_item_id, '_last_status', $item['status'] );
548 + // $this->update_user_item_meta( $user_item_id, '_current_status', $new_status );
549 + // }
550 +
551 + return $updated;
552 + }
553 +
554 + /**
555 + * Delete user item by fields.
556 + *
557 + * @param string $args
558 + *
559 + * @return bool
560 + */
561 + public function delete_user_item( $args = '' ) {
562 + global $wpdb;
563 + $args = wp_parse_args(
564 + $args,
565 + array(
566 + 'user_id' => 0,
567 + 'item_id' => 0,
568 + 'ref_id' => 0,
569 + 'parent_id' => 0,
570 + )
571 + );
572 + $where = array();
573 + foreach ( $args as $k => $v ) {
574 + if ( $v ) {
575 + $where[ $k ] = $v;
576 + }
577 + }
578 +
579 + if ( ! $where ) {
580 + return false;
581 + }
582 + $query_where = array();
583 + foreach ( $where as $k => $v ) {
584 + $query_where[] = "{$k} = %d";
585 + }
586 +
587 + $query = $wpdb->prepare(
588 + "SELECT user_item_id FROM {$wpdb->learnpress_user_items} WHERE " . join(
589 + ' AND ',
590 + $query_where
591 + ),
592 + array_values( $where )
593 + );
594 + $user_item_ids = $wpdb->get_col( $query );
595 +
596 + $wpdb->delete(
597 + $wpdb->learnpress_user_items,
598 + $where,
599 + array_fill( 0, sizeof( $where ), '%d' )
600 + );
601 +
602 + foreach ( $user_item_ids as $user_item_id ) {
603 + $wpdb->query(
604 + $wpdb->prepare(
605 + "DELETE FROM {$wpdb->learnpress_user_itemmeta} WHERE learnpress_user_item_id = %d",
606 + $user_item_id
607 + )
608 + );
609 + do_action( 'learn-press/deleted-user-item', $user_item_id );
610 + }
611 +
612 + return true;
613 + }
614 +
615 + /**
616 + * Get courses user has purchased via orders are completed
617 + * but it is not already added to user-items table.
618 + *
619 + * @param int $user_id
620 + *
621 + * @return array|bool|mixed
622 + * @deprecated 4.2.4
623 + */
624 + public function query_courses_by_order( $user_id ) {
625 + _deprecated_function( __METHOD__, '4.2.4' );
626 +
627 + return false;
628 + global $wpdb;
629 +
630 + $query = $wpdb->prepare(
631 + "
632 + SELECT item_id
633 + FROM {$wpdb->learnpress_user_items}
634 + WHERE user_id = %d
635 + AND item_type = %s
636 + ",
637 + $user_id,
638 + LP_COURSE_CPT
639 + );
640 + $user_item_ids = $wpdb->get_col( $query );
641 +
642 + $orders = $this->get_orders(
643 + $user_id,
644 + array(
645 + 'status' => 'completed',
646 + 'group_by_order' => true,
647 + )
648 + );
649 +
650 + if ( ! $orders ) {
651 + return false;
652 + }
653 +
654 + $course_ids = array_shift( $orders );
655 +
656 + foreach ( $orders as $ids ) {
657 + if ( ! $ids ) {
658 + continue;
659 + }
660 + $course_ids = array_merge( $course_ids, $ids );
661 + }
662 +
663 + if ( $user_item_ids ) {
664 + $course_ids = array_diff( $course_ids, $user_item_ids );
665 + }
666 +
667 + return $course_ids;
668 + }
669 +
670 + /**
671 + * @deprecated 4.2.4
672 + */
673 + public function read_course_info( $course ) {
674 + _deprecated_function( __METHOD__, '4.2.4' );
675 +
676 + return [];
677 + $data = $course;
678 + global $wpdb;
679 + $query = $wpdb->prepare(
680 + "
681 + SELECT *
682 + FROM {$wpdb->learnpress_user_itemmeta}
683 + WHERE learnpress_user_item_id = %d
684 + ",
685 + $course['user_item_id']
686 + );
687 +
688 + $itemmeta = $wpdb->get_results( $query, ARRAY_A );
689 +
690 + if ( $itemmeta ) {
691 + foreach ( $itemmeta as $item ) {
692 + $data[ $item['meta_key'] ] = $item['meta_value'];
693 + }
694 + }
695 +
696 + return $data;
697 + }
698 +
699 + public function update_item( $item ) {
700 + global $wpdb;
701 + if ( empty( $item['user_item_id'] ) ) {
702 + $wpdb->insert(
703 + $wpdb->learnpress_user_items,
704 + $item
705 + );
706 + }
707 + }
708 +
709 + /**
710 + * @deprecated 4.2.4
711 + */
712 + public function get_current_user_order( $user_id, $course_id ) {
713 + _deprecated_function( __METHOD__, '4.2.4' );
714 +
715 + return 0;
716 + global $wpdb;
717 + $sql = $wpdb->prepare(
718 + "
719 + SELECT MAX(ID) AS order_id
720 + FROM {$wpdb->posts} p
721 + 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
722 + INNER JOIN {$wpdb->learnpress_order_items} oi ON oi.order_id = p.id
723 + INNER JOIN {$wpdb->learnpress_order_itemmeta} oim ON oim.meta_key = %s and oim.meta_value = %d
724 + ",
725 + '_user_id',
726 + $user_id,
727 + '_course_id',
728 + $course_id
729 + );
730 + $order_id = $wpdb->get_var( $sql );
731 +
732 + return $order_id;
733 + }
734 +
735 + public function duplicate( &$user, $args = array() ) {
736 + // TODO: Implement duplicate() method.
737 + }
738 +}