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/user-item/class-lp-user-item.php +808 -808 4.3.8 → 4.4.9 View file →
@@ -1,808 +1,808 @@
1 -<?php
2 -
3 -/**
4 - * Class LP_User_Item
5 - *
6 - * @since 3.0.0
7 - */
8 -class LP_User_Item extends LP_Abstract_Object_Data {
9 - /**
10 - * Auto increment
11 - *
12 - * @var int
13 - */
14 - public $_user_item_id = 0;
15 - /**
16 - * User id
17 - *
18 - * @var string
19 - */
20 - public $_user_id = 0;
21 - /**
22 - * Item id (course, lesson, quiz ...)
23 - *
24 - * @var string
25 - */
26 - public $_item_id = 0;
27 - /**
28 - * @var string
29 - */
30 - public $_start_time = '';
31 - /**
32 - * @var string
33 - */
34 - public $_end_time = '';
35 - /**
36 - * Item type (course, lesson, quiz ...)
37 - *
38 - * @var string
39 - */
40 - public $_item_type = '';
41 - /**
42 - * Status
43 - *
44 - * @var string
45 - */
46 - public $_status = '';
47 - /**
48 - * Graduation
49 - *
50 - * @var string
51 - */
52 - public $_graduation = '';
53 - /**
54 - * Ref id (Order, course ...)
55 - *
56 - * @var string
57 - */
58 - public $_ref_id = '';
59 - /**
60 - * Ref type (Order, course ...)
61 - *
62 - * @var string
63 - */
64 - public $_ref_type = '';
65 - /**
66 - * Parent id
67 - *
68 - * @var string
69 - */
70 - public $_parent_id = '';
71 - /**
72 - * Key get data start time form DB.
73 - */
74 - const KEY_DATA_START_TIME = 'start_time';
75 - /**
76 - * Key get data end time form DB.
77 - */
78 - const KEY_DATA_END_TIME = 'end_time';
79 -
80 - /**
81 - * LP_User_Item constructor.
82 - *
83 - * @param array $item . A record fetched from table _learnpress_user_items
84 - */
85 - public function __construct( $item ) {
86 - if ( is_numeric( $item ) ) {
87 - $item = array( 'item_id' => $item );
88 - } else {
89 - $item = (array) $item;
90 - }
91 -
92 - // $this->_data = self::get_empty_item();
93 -
94 - parent::__construct( $item );
95 - $this->set_default_data( $item );
96 -
97 - }
98 -
99 - /**
100 - * Set data from passed args
101 - *
102 - * @param array $item
103 - */
104 - protected function set_default_data( $item ) {
105 - $this->_changes = array();
106 - $item_id = 0;
107 -
108 - if ( ! empty( $item['user_item_id'] ) ) {
109 - $this->set_data( 'user_item_id', absint( $item['user_item_id'] ) );
110 - }
111 -
112 - if ( ! empty( $item['item_id'] ) ) {
113 - $item['item_id'] = absint( $item['item_id'] );
114 -
115 - $this->set_id( $item['item_id'] );
116 - $this->set_data( 'item_id', $item['item_id'] );
117 - $this->set_data( 'item_type', learn_press_get_post_type( $item['item_id'] ) );
118 - $item_id = $item['item_id'];
119 - }
120 -
121 - $this->set_start_time( $item[ self::KEY_DATA_START_TIME ] ?? time() );
122 - $this->set_end_time( $item[ self::KEY_DATA_END_TIME ] ?? '' );
123 - $this->set_user_id( absint( $item['user_id'] ?? get_current_user_id() ) );
124 - $this->set_status( $item['status'] ?? '' );
125 -
126 - if ( ! empty( $item['ref_id'] ) ) {
127 - $item['ref_id'] = absint( $item['ref_id'] );
128 -
129 - $this->set_ref_id( $item['ref_id'] );
130 - if ( empty( $item['ref_type'] ) ) {
131 - $this->set_data( 'ref_type', learn_press_get_post_type( $item['ref_id'] ) );
132 - }
133 - }
134 -
135 - if ( ! empty( $item['ref_type'] ) ) {
136 - $this->set_data( 'ref_type', $item['ref_type'] );
137 - }
138 -
139 - if ( ! empty( $item['parent_id'] ) ) {
140 - $item['parent_id'] = absint( $item['parent_id'] );
141 -
142 - $this->set_parent_id( $item['parent_id'] );
143 - }
144 -
145 - if ( ! empty( $item['access_level'] ) ) {
146 - $this->set_data( 'access_level', $item['access_level'] );
147 - }
148 -
149 - $this->set_data( 'graduation', $item['graduation'] ?? '' );
150 - }
151 -
152 - public function set_user_id( $user_id ) {
153 - $this->set_data( 'user_id', $user_id );
154 - }
155 -
156 - public function get_user_id() {
157 - return $this->get_data( 'user_id' );
158 - }
159 -
160 - public function set_ref_id( $ref_id ) {
161 - $this->set_data( 'ref_id', $ref_id );
162 - $this->set_data( 'ref_type', learn_press_get_post_type( $ref_id ) );
163 - }
164 -
165 - public function get_parent_id() {
166 - return absint( $this->get_data( 'parent_id' ) );
167 - }
168 -
169 - public function set_parent_id( $parent_id ) {
170 - $this->set_data( 'parent_id', $parent_id );
171 - }
172 -
173 - /**
174 - * Get access level to a course.
175 - *
176 - * @return int
177 - * @since 3.x.x
178 - */
179 - public function get_access_level() {
180 - return absint( $this->get_data( 'access_level' ) );
181 - }
182 -
183 - /**
184 - * Get type of item. Consider is post-type.
185 - *
186 - * @return array|mixed
187 - */
188 - public function get_type() {
189 - return $this->get_data( 'item_type' );
190 - }
191 -
192 - /**
193 - * Set start-time.
194 - *
195 - * @param mixed $time .
196 - *
197 - * @return $this
198 - */
199 - public function set_start_time( $time = '' ): LP_User_Item {
200 - $this->set_data_date( 'start_time', $time );
201 -
202 - return $this;
203 - }
204 -
205 - /**
206 - * Get start-time.
207 - *
208 - * @param string $format
209 - * @param bool $local
210 - *
211 - * @return string|LP_Datetime|false
212 - */
213 - public function get_start_time( string $format = '', $local = false ) {
214 - $date = $this->get_data( self::KEY_DATA_START_TIME );
215 -
216 - return $this->format_time( $date, $format, $local );
217 - }
218 -
219 - /**
220 - * Set end-time for item.
221 - *
222 - * @param mixed $time
223 - *
224 - * @return $this
225 - */
226 - public function set_end_time( $time = '' ): LP_User_Item {
227 - $this->set_data_date( 'end_time', $time );
228 -
229 - return $this;
230 - }
231 -
232 - /**
233 - * Get end-time.
234 - *
235 - * @param string $format
236 - *
237 - * @return string|LP_Datetime
238 - */
239 - public function get_end_time( string $format = '' ) {
240 - $date = $this->get_data( self::KEY_DATA_END_TIME );
241 -
242 - return $this->format_time( $date, $format );
243 - }
244 -
245 - /**
246 - * @param string|int|LP_Datetime $date
247 - * @param string $format
248 - * @param bool $local
249 - *
250 - * @return bool|float|int|LP_Datetime|string
251 - */
252 - public function format_time( $date, $format = '', $local = false ) {
253 - if ( ! $date ) {
254 - return false;
255 - }
256 -
257 - if ( ! $date instanceof LP_Datetime ) {
258 - $date = new LP_Datetime( $date );
259 - }
260 -
261 - return $format ? $date->format( $format, $local ) : $date;
262 - }
263 -
264 - /**
265 - * Get expiration time.
266 - *
267 - * @return string|LP_Datetime $time
268 - * @since 3.3.0
269 - * @version 3.3.2
270 - */
271 - public function get_expiration_time() {
272 - $duration = get_post_meta( $this->get_item_id(), '_lp_duration', true );
273 - $start_time = $this->get_start_time()->getTimestamp();
274 -
275 - if ( ! absint( $duration ) || ! $start_time ) {
276 - $expire = null;
277 - } else {
278 - // Convert duration from string to seconds.
279 - if ( ! is_numeric( $duration ) ) {
280 - $duration = strtotime( $duration ) - time();
281 - }
282 -
283 - $expire_time = $start_time + $duration;
284 - $expire = new LP_Datetime( $expire_time );
285 - }
286 -
287 - return apply_filters( 'learn-press/user-item/expiration-time', $expire, $duration, $this );
288 - }
289 -
290 - /**
291 - * Set item-status.
292 - *
293 - * @param string $status .
294 - *
295 - * @return $this
296 - */
297 - public function set_status( string $status ): LP_User_Item {
298 - $this->_set_data( 'status', $status );
299 -
300 - return $this;
301 - }
302 -
303 - /**
304 - * Get item status.
305 - *
306 - * @param string $field
307 - * @param bool $force_cache Reset first cache
308 - *
309 - * @version 1.0.1
310 - * @return string
311 - * @editor tungnx
312 - * @modify 4.1.3
313 - */
314 - public function get_status( string $field = 'status', bool $force_cache = false ): string {
315 - $got_status = '';
316 -
317 - try {
318 - // User is Guest
319 - if ( (int) $this->get_user_id() === 0 ) {
320 - return $got_status;
321 - }
322 -
323 - if ( LP_COURSE_CPT === $this->get_type() ) {
324 - return $this->get_data( $field );
325 - }
326 -
327 - /*error_log('status user item id: ' . $this->get_id());
328 - error_log('status user item type: ' . $this->get_type());
329 - error_log('status user course status: ' . $this->get_data( $field ));*/
330 -
331 - $lp_user_item = LP_User_Items_DB::getInstance();
332 - $filter = new LP_User_Items_Filter();
333 -
334 - $filter->user_id = $this->get_user_id();
335 - $filter->item_id = $this->get_item_id();
336 - $filter->ref_id = $this->get_data( 'ref_id' );
337 - $filter->parent_id = $this->get_parent_id();
338 -
339 - $user_item = $lp_user_item->get_user_course_item( $filter, $force_cache );
340 -
341 - if ( ! empty( $user_item ) && isset( $user_item->$field ) ) {
342 - $got_status = $user_item->$field;
343 - }
344 -
345 - $this->set_data( $field, $got_status );
346 - } catch ( Throwable $e ) {
347 - LP_Debug::error_log( $e );
348 - }
349 -
350 - return $got_status;
351 - }
352 -
353 - public function is_exists() {
354 - return ! ! $this->get_user_item_id();
355 - }
356 -
357 - /**
358 - * @param string $return
359 - *
360 - * @return LP_User|int
361 - */
362 - public function get_user( $return = '' ) {
363 - return $this->get_data( 'user_id', 0 );
364 - }
365 -
366 - /**
367 - * Get course.
368 - *
369 - * @param string $return
370 - *
371 - * @return bool|LP_Course|int|mixed
372 - */
373 - public function get_course( string $return = '' ) {
374 - $course_id = $this->get_data( 'ref_id', 0 );
375 - if ( $return == '' ) {
376 - return $course_id ? learn_press_get_course( $course_id ) : false;
377 - }
378 -
379 - return $course_id;
380 - }
381 -
382 - /**
383 - * @return int
384 - */
385 - public function get_user_item_id() {
386 - return intval( $this->get_data( 'user_item_id' ) );
387 - }
388 -
389 - /**
390 - * Change the primary key user_item_id of user-items.
391 - * Only use zero value to force creating new item.
392 - *
393 - * @param int $user_item_id
394 - */
395 - public function set_user_item_id( $user_item_id ) {
396 - $this->_set_data( 'user_item_id', absint( $user_item_id ) );
397 - }
398 -
399 - public function get_item_id() {
400 - return $this->get_data( 'item_id' );
401 - }
402 -
403 - public function get_parent() {
404 - $user = learn_press_get_user( $this->get_user_id() );
405 - $ref_id = $this->get_data( 'ref_id' );
406 -
407 - if ( get_post_type( $ref_id ) === LP_COURSE_CPT ) {
408 - return $user->get_course_data( $ref_id );
409 - }
410 -
411 - return false;
412 - }
413 -
414 - public function get_result( $prop = 'result' ) {
415 - $result = array(
416 - 'result' => $this->is_completed() ? 100 : 0,
417 - 'grade' => $this->is_completed() ? 'passed' : 'failed',
418 - );
419 -
420 - return $prop && array_key_exists( $prop, $result ) ? $result[ $prop ] : $result;
421 - }
422 -
423 - public function read_meta() {
424 - global $wpdb;
425 - $query = $wpdb->prepare(
426 - "
427 - SELECT *
428 - FROM {$wpdb->learnpress_user_itemmeta}
429 - WHERE learnpress_user_item_id = %d
430 - ",
431 - $this->get_user_item_id()
432 - );
433 -
434 - $results = $wpdb->get_results( $query );
435 - if ( $results ) {
436 - foreach ( $results as $result ) {
437 - $result->meta_value = LP_Helper::maybe_unserialize( $result->meta_value );
438 - $this->_meta_data[] = $result;
439 - }
440 - }
441 -
442 - }
443 -
444 - /**
445 - * Get structure of an user item.
446 - *
447 - * @return array
448 - * @since 3.1.0
449 - */
450 - public static function get_empty_item() {
451 - return array(
452 - 'user_item_id' => 0,
453 - 'user_id' => 0,
454 - 'item_id' => 0,
455 - 'start_time' => '',
456 - 'end_time' => '',
457 - 'item_type' => '',
458 - 'status' => '',
459 - 'graduation' => '',
460 - 'access_level' => 50,
461 - 'ref_id' => '',
462 - 'ref_type' => '',
463 - 'parent_id' => 0,
464 - );
465 - }
466 -
467 - /**
468 - * Get user-item meta data.
469 - * Check if meta data does not exist then return FALSE.
470 - *
471 - * @updated 3.1.0
472 - *
473 - * @param string $key
474 - * @param bool $single
475 - *
476 - * @return bool|mixed
477 - */
478 - public function get_meta( $key, $single = true ) {
479 - if ( ! metadata_exists( 'learnpress_user_item', $this->get_user_item_id(), $key ) ) {
480 - return false;
481 - }
482 -
483 - return learn_press_get_user_item_meta( $this->get_user_item_id(), $key, $single );
484 - }
485 -
486 - /**
487 - * Update meta data
488 - *
489 - * @updated 3.1.0
490 - *
491 - * @param string $key
492 - * @param string $value
493 - * @param string $prev_value
494 - *
495 - * @editor tungnx add bk method
496 - */
497 - public function update_meta_bk( $key = '', $value = '', $prev_value = '' ) {
498 - if ( func_num_args() === 0 ) {
499 - if ( $this->_meta_data ) {
500 - foreach ( $this->_meta_data as $meta_data ) {
501 - if ( $meta_data->meta_value ) {
502 - learn_press_update_user_item_meta(
503 - $this->get_user_item_id(),
504 - $meta_data->meta_key,
505 - $meta_data->meta_value
506 - );
507 - } else {
508 - learn_press_delete_user_item_meta( $this->get_user_item_id(), $meta_data->meta_key );
509 - }
510 - }
511 - }
512 - } else {
513 - if ( is_array( $key ) ) {
514 - foreach ( $key as $k => $v ) {
515 - if ( $v === false ) {
516 - learn_press_delete_user_item_meta( $this->get_user_item_id(), $k );
517 - } else {
518 - learn_press_update_user_item_meta( $this->get_user_item_id(), $k, $v );
519 - }
520 - }
521 - } else {
522 - if ( $value === false ) {
523 - learn_press_delete_user_item_meta( $this->get_user_item_id(), $key );
524 - } else {
525 - learn_press_update_user_item_meta( $this->get_user_item_id(), $key, $value, $prev_value );
526 - }
527 - }
528 - }
529 - }
530 -
531 - /**
532 - * Update meta data
533 - *
534 - * @param string $key .
535 - * @param string $value .
536 - * @param string $prev_value .
537 - *
538 - * @return int|bool
539 - * @editor tungnx
540 - */
541 - public function update_meta( $key = '', $value = '', $prev_value = '' ) {
542 - $result = false;
543 -
544 - if ( is_array( $key ) ) {
545 - $result = $this->update_meta_multiple_keys( $key );
546 - } else {
547 - if ( false === $value ) {
548 - $result = learn_press_delete_user_item_meta( $this->get_user_item_id(), $key );
549 - } else {
550 - $result = learn_press_update_user_item_meta( $this->get_user_item_id(), $key, $value, $prev_value );
551 - }
552 - }
553 -
554 - return $result;
555 - }
556 -
557 - /**
558 - * Update metadata with array keys values
559 - *
560 - * @param array $meta_datas .
561 - *
562 - * @return bool|int
563 - */
564 - public function update_meta_multiple_keys( $meta_datas = array() ) {
565 - $result = false;
566 -
567 - foreach ( $meta_datas as $k => $v ) {
568 - if ( false === $v ) {
569 - $result = learn_press_delete_user_item_meta( $this->get_user_item_id(), $k );
570 - } else {
571 - $result = learn_press_update_user_item_meta( $this->get_user_item_id(), $k, $v );
572 - }
573 - }
574 -
575 - return $result;
576 - }
577 -
578 - public function get_mysql_data() {
579 - /**
580 - * @var LP_Datetime $v
581 - */
582 - $columns = array();
583 -
584 - foreach ( $this->get_data() as $k => $v ) {
585 - $columns[ $k ] = $v;
586 - }
587 -
588 - return $columns;
589 - }
590 -
591 - /**
592 - * @param $data
593 - *
594 - * @return LP_User_Item|bool
595 - */
596 - public static function get_item_object( $data ) {
597 - $item_id = 0;
598 -
599 - if ( is_array( $data ) && isset( $data['item_id'] ) ) {
600 - $item_id = $data['item_id'];
601 - } elseif ( is_object( $data ) && isset( $data->item_id ) ) {
602 - $item_id = $data->item_id;
603 - } elseif ( is_numeric( $data ) ) {
604 - $item_id = absint( $data );
605 - } elseif ( $data instanceof LP_User_Item ) {
606 - $item_id = $data->get_id();
607 - }
608 -
609 - $item = false;
610 - $item_type = learn_press_get_post_type( $item_id );
611 -
612 - switch ( $item_type ) {
613 - case LP_LESSON_CPT:
614 - $item = new LP_User_Item( $data );
615 - break;
616 - case LP_QUIZ_CPT:
617 - $item = new LP_User_Item_Quiz( $data );
618 - break;
619 - default:
620 - break;
621 - }
622 -
623 - return apply_filters( 'learn-press/user-item-object', $item, $data, $item_type );
624 - }
625 -
626 - /**
627 - * Set graduation
628 - *
629 - * @param string $graduation .
630 - *
631 - * @return $this
632 - */
633 - public function set_graduation( string $graduation ): LP_User_Item {
634 - $this->_set_data( 'graduation', $graduation );
635 -
636 - return $this;
637 - }
638 -
639 - /**
640 - * Get graduation
641 - *
642 - * @param string $context
643 - *
644 - * @return string
645 - */
646 - public function get_graduation( string $context = '' ): string {
647 - $grade = $this->get_data( 'graduation', '' );
648 - if ( ! $grade ) {
649 - return '';
650 - }
651 - return $context == 'display' ? learn_press_course_grade_html( $grade, false ) : $grade;
652 - }
653 -
654 - /**
655 - * Update data from memory to database.
656 - *
657 - * @updated 3.1.0
658 - *
659 - * @return bool|mixed
660 - */
661 - public function update( $force = false, $wp_error = false ) {
662 - $data = $this->get_mysql_data();
663 - $data = apply_filters( 'learn-press/update-user-item-data', $data, $this->get_user_item_id() );
664 - $where = array();
665 -
666 - if ( $this->get_user_item_id() ) {
667 - $where = array( 'user_item_id' => $this->get_user_item_id() );
668 - }
669 -
670 - $rs = learn_press_update_user_item_field( $data, $where );
671 -
672 - // Clear cache first status
673 - $this->get_status( 'status', true );
674 -
675 - if ( $rs ) {
676 - foreach ( (array) $rs as $k => $v ) {
677 - $this->_set_data( $k, $v );
678 - }
679 - $this->_changes = array();
680 - }
681 -
682 - return $rs;
683 - }
684 -
685 - public function get_status_label( $status = '' ) {
686 - $statuses = array(
687 - LP_COURSE_ENROLLED => esc_html__( 'Enrolled', 'learnpress' ),
688 - LP_COURSE_PURCHASED => esc_html__( 'Purchased', 'learnpress' ),
689 - LP_ITEM_COMPLETED => esc_html__( 'Completed', 'learnpress' ),
690 - LP_ITEM_STARTED => esc_html__( 'Started', 'learnpress' ),
691 - LP_COURSE_FINISHED => esc_html__( 'Finished', 'learnpress' ),
692 - );
693 -
694 - if ( ! $status ) {
695 - $status = $this->get_status();
696 - }
697 -
698 - return ! empty( $statuses[ $status ] ) ? $statuses[ $status ] : esc_html__( 'Not Enrolled', 'learnpress' );
699 - }
700 -
701 - /**
702 - * Get time from user started to ended.
703 - *
704 - * @param string $context
705 - *
706 - * @return bool|int
707 - */
708 - public function get_time_interval( $context = '' ) {
709 - $start = $this->get_start_time();
710 - $end = $this->get_end_time();
711 -
712 - if ( ! $start instanceof LP_Datetime || ! $end instanceof LP_Datetime ) {
713 - return false;
714 - }
715 -
716 - if ( $start->is_null() || $end->is_null() ) {
717 - return false;
718 - }
719 -
720 - return $end->getTimestamp() - $start->getTimestamp();
721 - }
722 -
723 - /**
724 - * Return true of item is completed/finished
725 - *
726 - * @param string $status
727 - *
728 - * @return bool
729 - */
730 - public function is_completed( $status = 'completed' ) {
731 - return $this->get_status() === $status;
732 - }
733 -
734 - /**
735 - * Complete item
736 - *
737 - * @editor tungnx
738 - * @modify 4.1.4.1 - should review to improve
739 - * @version 4.0.1
740 - */
741 - public function complete( $status = 'completed' ) {
742 - try {
743 - $this->set_end_time( time() );
744 - $this->set_status( $status );
745 - $this->update();
746 - } catch ( Throwable $e ) {
747 - error_log( __FUNCTION__ . ':' . $e->getMessage() );
748 - return false;
749 - }
750 -
751 - return true;
752 - }
753 -
754 - /**
755 - * Get post type of item.
756 - *
757 - * @return string
758 - */
759 - public function get_post_type() {
760 - return learn_press_get_post_type( $this->get_item_id() );
761 - }
762 -
763 - /**
764 - * @return bool
765 - */
766 - public function is_passed(): bool {
767 - return LP_COURSE_GRADUATION_PASSED === $this->get_graduation();
768 - }
769 -
770 - /**
771 - * @param int $decimal
772 - *
773 - * @return mixed|null
774 - */
775 - public function get_percent_result( $decimal = 1 ) {
776 - return apply_filters(
777 - 'learn-press/user/item-percent-result',
778 - sprintf( '%s%', round( $this->get_result( 'result' ), $decimal ) ),
779 - $this->get_user_id(),
780 - $this->get_item_id()
781 - );
782 - }
783 -
784 - public function offsetSet( $offset, $value ) {
785 - _deprecated_function( __METHOD__, '4.2.3.5' );
786 - // TODO: Implement offsetSet() method.
787 - }
788 -
789 - public function offsetGet( $offset ) {
790 - _deprecated_function( __METHOD__, '4.2.3.5' );
791 - if ( is_callable( array( $this, 'get_' . $offset ) ) ) {
792 - return call_user_func( array( $this, 'get_' . $offset ) );
793 - }
794 -
795 - return false;
796 - }
797 -
798 - public function offsetUnset( $offset ) {
799 - _deprecated_function( __METHOD__, '4.2.3.5' );
800 - // TODO: Implement offsetUnset() method.
801 - }
802 -
803 - public function offsetExists( $offset ) {
804 - _deprecated_function( __METHOD__, '4.2.3.5' );
805 - // TODO: Implement offsetExists() method.
806 - }
807 -}
808 -
1 +<?php
2 +
3 +/**
4 + * Class LP_User_Item
5 + *
6 + * @since 3.0.0
7 + */
8 +class LP_User_Item extends LP_Abstract_Object_Data {
9 + /**
10 + * Auto increment
11 + *
12 + * @var int
13 + */
14 + public $_user_item_id = 0;
15 + /**
16 + * User id
17 + *
18 + * @var string
19 + */
20 + public $_user_id = 0;
21 + /**
22 + * Item id (course, lesson, quiz ...)
23 + *
24 + * @var string
25 + */
26 + public $_item_id = 0;
27 + /**
28 + * @var string
29 + */
30 + public $_start_time = '';
31 + /**
32 + * @var string
33 + */
34 + public $_end_time = '';
35 + /**
36 + * Item type (course, lesson, quiz ...)
37 + *
38 + * @var string
39 + */
40 + public $_item_type = '';
41 + /**
42 + * Status
43 + *
44 + * @var string
45 + */
46 + public $_status = '';
47 + /**
48 + * Graduation
49 + *
50 + * @var string
51 + */
52 + public $_graduation = '';
53 + /**
54 + * Ref id (Order, course ...)
55 + *
56 + * @var string
57 + */
58 + public $_ref_id = '';
59 + /**
60 + * Ref type (Order, course ...)
61 + *
62 + * @var string
63 + */
64 + public $_ref_type = '';
65 + /**
66 + * Parent id
67 + *
68 + * @var string
69 + */
70 + public $_parent_id = '';
71 + /**
72 + * Key get data start time form DB.
73 + */
74 + const KEY_DATA_START_TIME = 'start_time';
75 + /**
76 + * Key get data end time form DB.
77 + */
78 + const KEY_DATA_END_TIME = 'end_time';
79 +
80 + /**
81 + * LP_User_Item constructor.
82 + *
83 + * @param array $item . A record fetched from table _learnpress_user_items
84 + */
85 + public function __construct( $item ) {
86 + if ( is_numeric( $item ) ) {
87 + $item = array( 'item_id' => $item );
88 + } else {
89 + $item = (array) $item;
90 + }
91 +
92 + // $this->_data = self::get_empty_item();
93 +
94 + parent::__construct( $item );
95 + $this->set_default_data( $item );
96 +
97 + }
98 +
99 + /**
100 + * Set data from passed args
101 + *
102 + * @param array $item
103 + */
104 + protected function set_default_data( $item ) {
105 + $this->_changes = array();
106 + $item_id = 0;
107 +
108 + if ( ! empty( $item['user_item_id'] ) ) {
109 + $this->set_data( 'user_item_id', absint( $item['user_item_id'] ) );
110 + }
111 +
112 + if ( ! empty( $item['item_id'] ) ) {
113 + $item['item_id'] = absint( $item['item_id'] );
114 +
115 + $this->set_id( $item['item_id'] );
116 + $this->set_data( 'item_id', $item['item_id'] );
117 + $this->set_data( 'item_type', learn_press_get_post_type( $item['item_id'] ) );
118 + $item_id = $item['item_id'];
119 + }
120 +
121 + $this->set_start_time( $item[ self::KEY_DATA_START_TIME ] ?? time() );
122 + $this->set_end_time( $item[ self::KEY_DATA_END_TIME ] ?? '' );
123 + $this->set_user_id( absint( $item['user_id'] ?? get_current_user_id() ) );
124 + $this->set_status( $item['status'] ?? '' );
125 +
126 + if ( ! empty( $item['ref_id'] ) ) {
127 + $item['ref_id'] = absint( $item['ref_id'] );
128 +
129 + $this->set_ref_id( $item['ref_id'] );
130 + if ( empty( $item['ref_type'] ) ) {
131 + $this->set_data( 'ref_type', learn_press_get_post_type( $item['ref_id'] ) );
132 + }
133 + }
134 +
135 + if ( ! empty( $item['ref_type'] ) ) {
136 + $this->set_data( 'ref_type', $item['ref_type'] );
137 + }
138 +
139 + if ( ! empty( $item['parent_id'] ) ) {
140 + $item['parent_id'] = absint( $item['parent_id'] );
141 +
142 + $this->set_parent_id( $item['parent_id'] );
143 + }
144 +
145 + if ( ! empty( $item['access_level'] ) ) {
146 + $this->set_data( 'access_level', $item['access_level'] );
147 + }
148 +
149 + $this->set_data( 'graduation', $item['graduation'] ?? '' );
150 + }
151 +
152 + public function set_user_id( $user_id ) {
153 + $this->set_data( 'user_id', $user_id );
154 + }
155 +
156 + public function get_user_id() {
157 + return $this->get_data( 'user_id' );
158 + }
159 +
160 + public function set_ref_id( $ref_id ) {
161 + $this->set_data( 'ref_id', $ref_id );
162 + $this->set_data( 'ref_type', learn_press_get_post_type( $ref_id ) );
163 + }
164 +
165 + public function get_parent_id() {
166 + return absint( $this->get_data( 'parent_id' ) );
167 + }
168 +
169 + public function set_parent_id( $parent_id ) {
170 + $this->set_data( 'parent_id', $parent_id );
171 + }
172 +
173 + /**
174 + * Get access level to a course.
175 + *
176 + * @return int
177 + * @since 3.x.x
178 + */
179 + public function get_access_level() {
180 + return absint( $this->get_data( 'access_level' ) );
181 + }
182 +
183 + /**
184 + * Get type of item. Consider is post-type.
185 + *
186 + * @return array|mixed
187 + */
188 + public function get_type() {
189 + return $this->get_data( 'item_type' );
190 + }
191 +
192 + /**
193 + * Set start-time.
194 + *
195 + * @param mixed $time .
196 + *
197 + * @return $this
198 + */
199 + public function set_start_time( $time = '' ): LP_User_Item {
200 + $this->set_data_date( 'start_time', $time );
201 +
202 + return $this;
203 + }
204 +
205 + /**
206 + * Get start-time.
207 + *
208 + * @param string $format
209 + * @param bool $local
210 + *
211 + * @return string|LP_Datetime|false
212 + */
213 + public function get_start_time( string $format = '', $local = false ) {
214 + $date = $this->get_data( self::KEY_DATA_START_TIME );
215 +
216 + return $this->format_time( $date, $format, $local );
217 + }
218 +
219 + /**
220 + * Set end-time for item.
221 + *
222 + * @param mixed $time
223 + *
224 + * @return $this
225 + */
226 + public function set_end_time( $time = '' ): LP_User_Item {
227 + $this->set_data_date( 'end_time', $time );
228 +
229 + return $this;
230 + }
231 +
232 + /**
233 + * Get end-time.
234 + *
235 + * @param string $format
236 + *
237 + * @return string|LP_Datetime
238 + */
239 + public function get_end_time( string $format = '' ) {
240 + $date = $this->get_data( self::KEY_DATA_END_TIME );
241 +
242 + return $this->format_time( $date, $format );
243 + }
244 +
245 + /**
246 + * @param string|int|LP_Datetime $date
247 + * @param string $format
248 + * @param bool $local
249 + *
250 + * @return bool|float|int|LP_Datetime|string
251 + */
252 + public function format_time( $date, $format = '', $local = false ) {
253 + if ( ! $date ) {
254 + return false;
255 + }
256 +
257 + if ( ! $date instanceof LP_Datetime ) {
258 + $date = new LP_Datetime( $date );
259 + }
260 +
261 + return $format ? $date->format( $format, $local ) : $date;
262 + }
263 +
264 + /**
265 + * Get expiration time.
266 + *
267 + * @return string|LP_Datetime $time
268 + * @since 3.3.0
269 + * @version 3.3.2
270 + */
271 + public function get_expiration_time() {
272 + $duration = get_post_meta( $this->get_item_id(), '_lp_duration', true );
273 + $start_time = $this->get_start_time()->getTimestamp();
274 +
275 + if ( ! absint( $duration ) || ! $start_time ) {
276 + $expire = null;
277 + } else {
278 + // Convert duration from string to seconds.
279 + if ( ! is_numeric( $duration ) ) {
280 + $duration = strtotime( $duration ) - time();
281 + }
282 +
283 + $expire_time = $start_time + $duration;
284 + $expire = new LP_Datetime( $expire_time );
285 + }
286 +
287 + return apply_filters( 'learn-press/user-item/expiration-time', $expire, $duration, $this );
288 + }
289 +
290 + /**
291 + * Set item-status.
292 + *
293 + * @param string $status .
294 + *
295 + * @return $this
296 + */
297 + public function set_status( string $status ): LP_User_Item {
298 + $this->_set_data( 'status', $status );
299 +
300 + return $this;
301 + }
302 +
303 + /**
304 + * Get item status.
305 + *
306 + * @param string $field
307 + * @param bool $force_cache Reset first cache
308 + *
309 + * @version 1.0.1
310 + * @return string
311 + * @editor tungnx
312 + * @modify 4.1.3
313 + */
314 + public function get_status( string $field = 'status', bool $force_cache = false ): string {
315 + $got_status = '';
316 +
317 + try {
318 + // User is Guest
319 + if ( (int) $this->get_user_id() === 0 ) {
320 + return $got_status;
321 + }
322 +
323 + if ( LP_COURSE_CPT === $this->get_type() ) {
324 + return $this->get_data( $field );
325 + }
326 +
327 + /*error_log('status user item id: ' . $this->get_id());
328 + error_log('status user item type: ' . $this->get_type());
329 + error_log('status user course status: ' . $this->get_data( $field ));*/
330 +
331 + $lp_user_item = LP_User_Items_DB::getInstance();
332 + $filter = new LP_User_Items_Filter();
333 +
334 + $filter->user_id = $this->get_user_id();
335 + $filter->item_id = $this->get_item_id();
336 + $filter->ref_id = $this->get_data( 'ref_id' );
337 + $filter->parent_id = $this->get_parent_id();
338 +
339 + $user_item = $lp_user_item->get_user_course_item( $filter, $force_cache );
340 +
341 + if ( ! empty( $user_item ) && isset( $user_item->$field ) ) {
342 + $got_status = $user_item->$field;
343 + }
344 +
345 + $this->set_data( $field, $got_status );
346 + } catch ( Throwable $e ) {
347 + LP_Debug::error_log( $e );
348 + }
349 +
350 + return $got_status;
351 + }
352 +
353 + public function is_exists() {
354 + return ! ! $this->get_user_item_id();
355 + }
356 +
357 + /**
358 + * @param string $return
359 + *
360 + * @return LP_User|int
361 + */
362 + public function get_user( $return = '' ) {
363 + return $this->get_data( 'user_id', 0 );
364 + }
365 +
366 + /**
367 + * Get course.
368 + *
369 + * @param string $return
370 + *
371 + * @return bool|LP_Course|int|mixed
372 + */
373 + public function get_course( string $return = '' ) {
374 + $course_id = $this->get_data( 'ref_id', 0 );
375 + if ( $return == '' ) {
376 + return $course_id ? learn_press_get_course( $course_id ) : false;
377 + }
378 +
379 + return $course_id;
380 + }
381 +
382 + /**
383 + * @return int
384 + */
385 + public function get_user_item_id() {
386 + return intval( $this->get_data( 'user_item_id' ) );
387 + }
388 +
389 + /**
390 + * Change the primary key user_item_id of user-items.
391 + * Only use zero value to force creating new item.
392 + *
393 + * @param int $user_item_id
394 + */
395 + public function set_user_item_id( $user_item_id ) {
396 + $this->_set_data( 'user_item_id', absint( $user_item_id ) );
397 + }
398 +
399 + public function get_item_id() {
400 + return $this->get_data( 'item_id' );
401 + }
402 +
403 + public function get_parent() {
404 + $user = learn_press_get_user( $this->get_user_id() );
405 + $ref_id = $this->get_data( 'ref_id' );
406 +
407 + if ( get_post_type( $ref_id ) === LP_COURSE_CPT ) {
408 + return $user->get_course_data( $ref_id );
409 + }
410 +
411 + return false;
412 + }
413 +
414 + public function get_result( $prop = 'result' ) {
415 + $result = array(
416 + 'result' => $this->is_completed() ? 100 : 0,
417 + 'grade' => $this->is_completed() ? 'passed' : 'failed',
418 + );
419 +
420 + return $prop && array_key_exists( $prop, $result ) ? $result[ $prop ] : $result;
421 + }
422 +
423 + public function read_meta() {
424 + global $wpdb;
425 + $query = $wpdb->prepare(
426 + "
427 + SELECT *
428 + FROM {$wpdb->learnpress_user_itemmeta}
429 + WHERE learnpress_user_item_id = %d
430 + ",
431 + $this->get_user_item_id()
432 + );
433 +
434 + $results = $wpdb->get_results( $query );
435 + if ( $results ) {
436 + foreach ( $results as $result ) {
437 + $result->meta_value = LP_Helper::maybe_unserialize( $result->meta_value );
438 + $this->_meta_data[] = $result;
439 + }
440 + }
441 +
442 + }
443 +
444 + /**
445 + * Get structure of an user item.
446 + *
447 + * @return array
448 + * @since 3.1.0
449 + */
450 + public static function get_empty_item() {
451 + return array(
452 + 'user_item_id' => 0,
453 + 'user_id' => 0,
454 + 'item_id' => 0,
455 + 'start_time' => '',
456 + 'end_time' => '',
457 + 'item_type' => '',
458 + 'status' => '',
459 + 'graduation' => '',
460 + 'access_level' => 50,
461 + 'ref_id' => '',
462 + 'ref_type' => '',
463 + 'parent_id' => 0,
464 + );
465 + }
466 +
467 + /**
468 + * Get user-item meta data.
469 + * Check if meta data does not exist then return FALSE.
470 + *
471 + * @updated 3.1.0
472 + *
473 + * @param string $key
474 + * @param bool $single
475 + *
476 + * @return bool|mixed
477 + */
478 + public function get_meta( $key, $single = true ) {
479 + if ( ! metadata_exists( 'learnpress_user_item', $this->get_user_item_id(), $key ) ) {
480 + return false;
481 + }
482 +
483 + return learn_press_get_user_item_meta( $this->get_user_item_id(), $key, $single );
484 + }
485 +
486 + /**
487 + * Update meta data
488 + *
489 + * @updated 3.1.0
490 + *
491 + * @param string $key
492 + * @param string $value
493 + * @param string $prev_value
494 + *
495 + * @editor tungnx add bk method
496 + */
497 + public function update_meta_bk( $key = '', $value = '', $prev_value = '' ) {
498 + if ( func_num_args() === 0 ) {
499 + if ( $this->_meta_data ) {
500 + foreach ( $this->_meta_data as $meta_data ) {
501 + if ( $meta_data->meta_value ) {
502 + learn_press_update_user_item_meta(
503 + $this->get_user_item_id(),
504 + $meta_data->meta_key,
505 + $meta_data->meta_value
506 + );
507 + } else {
508 + learn_press_delete_user_item_meta( $this->get_user_item_id(), $meta_data->meta_key );
509 + }
510 + }
511 + }
512 + } else {
513 + if ( is_array( $key ) ) {
514 + foreach ( $key as $k => $v ) {
515 + if ( $v === false ) {
516 + learn_press_delete_user_item_meta( $this->get_user_item_id(), $k );
517 + } else {
518 + learn_press_update_user_item_meta( $this->get_user_item_id(), $k, $v );
519 + }
520 + }
521 + } else {
522 + if ( $value === false ) {
523 + learn_press_delete_user_item_meta( $this->get_user_item_id(), $key );
524 + } else {
525 + learn_press_update_user_item_meta( $this->get_user_item_id(), $key, $value, $prev_value );
526 + }
527 + }
528 + }
529 + }
530 +
531 + /**
532 + * Update meta data
533 + *
534 + * @param string $key .
535 + * @param string $value .
536 + * @param string $prev_value .
537 + *
538 + * @return int|bool
539 + * @editor tungnx
540 + */
541 + public function update_meta( $key = '', $value = '', $prev_value = '' ) {
542 + $result = false;
543 +
544 + if ( is_array( $key ) ) {
545 + $result = $this->update_meta_multiple_keys( $key );
546 + } else {
547 + if ( false === $value ) {
548 + $result = learn_press_delete_user_item_meta( $this->get_user_item_id(), $key );
549 + } else {
550 + $result = learn_press_update_user_item_meta( $this->get_user_item_id(), $key, $value, $prev_value );
551 + }
552 + }
553 +
554 + return $result;
555 + }
556 +
557 + /**
558 + * Update metadata with array keys values
559 + *
560 + * @param array $meta_datas .
561 + *
562 + * @return bool|int
563 + */
564 + public function update_meta_multiple_keys( $meta_datas = array() ) {
565 + $result = false;
566 +
567 + foreach ( $meta_datas as $k => $v ) {
568 + if ( false === $v ) {
569 + $result = learn_press_delete_user_item_meta( $this->get_user_item_id(), $k );
570 + } else {
571 + $result = learn_press_update_user_item_meta( $this->get_user_item_id(), $k, $v );
572 + }
573 + }
574 +
575 + return $result;
576 + }
577 +
578 + public function get_mysql_data() {
579 + /**
580 + * @var LP_Datetime $v
581 + */
582 + $columns = array();
583 +
584 + foreach ( $this->get_data() as $k => $v ) {
585 + $columns[ $k ] = $v;
586 + }
587 +
588 + return $columns;
589 + }
590 +
591 + /**
592 + * @param $data
593 + *
594 + * @return LP_User_Item|bool
595 + */
596 + public static function get_item_object( $data ) {
597 + $item_id = 0;
598 +
599 + if ( is_array( $data ) && isset( $data['item_id'] ) ) {
600 + $item_id = $data['item_id'];
601 + } elseif ( is_object( $data ) && isset( $data->item_id ) ) {
602 + $item_id = $data->item_id;
603 + } elseif ( is_numeric( $data ) ) {
604 + $item_id = absint( $data );
605 + } elseif ( $data instanceof LP_User_Item ) {
606 + $item_id = $data->get_id();
607 + }
608 +
609 + $item = false;
610 + $item_type = learn_press_get_post_type( $item_id );
611 +
612 + switch ( $item_type ) {
613 + case LP_LESSON_CPT:
614 + $item = new LP_User_Item( $data );
615 + break;
616 + case LP_QUIZ_CPT:
617 + $item = new LP_User_Item_Quiz( $data );
618 + break;
619 + default:
620 + break;
621 + }
622 +
623 + return apply_filters( 'learn-press/user-item-object', $item, $data, $item_type );
624 + }
625 +
626 + /**
627 + * Set graduation
628 + *
629 + * @param string $graduation .
630 + *
631 + * @return $this
632 + */
633 + public function set_graduation( string $graduation ): LP_User_Item {
634 + $this->_set_data( 'graduation', $graduation );
635 +
636 + return $this;
637 + }
638 +
639 + /**
640 + * Get graduation
641 + *
642 + * @param string $context
643 + *
644 + * @return string
645 + */
646 + public function get_graduation( string $context = '' ): string {
647 + $grade = $this->get_data( 'graduation', '' );
648 + if ( ! $grade ) {
649 + return '';
650 + }
651 + return $context == 'display' ? learn_press_course_grade_html( $grade, false ) : $grade;
652 + }
653 +
654 + /**
655 + * Update data from memory to database.
656 + *
657 + * @updated 3.1.0
658 + *
659 + * @return bool|mixed
660 + */
661 + public function update( $force = false, $wp_error = false ) {
662 + $data = $this->get_mysql_data();
663 + $data = apply_filters( 'learn-press/update-user-item-data', $data, $this->get_user_item_id() );
664 + $where = array();
665 +
666 + if ( $this->get_user_item_id() ) {
667 + $where = array( 'user_item_id' => $this->get_user_item_id() );
668 + }
669 +
670 + $rs = learn_press_update_user_item_field( $data, $where );
671 +
672 + // Clear cache first status
673 + $this->get_status( 'status', true );
674 +
675 + if ( $rs ) {
676 + foreach ( (array) $rs as $k => $v ) {
677 + $this->_set_data( $k, $v );
678 + }
679 + $this->_changes = array();
680 + }
681 +
682 + return $rs;
683 + }
684 +
685 + public function get_status_label( $status = '' ) {
686 + $statuses = array(
687 + LP_COURSE_ENROLLED => esc_html__( 'Enrolled', 'learnpress' ),
688 + LP_COURSE_PURCHASED => esc_html__( 'Purchased', 'learnpress' ),
689 + LP_ITEM_COMPLETED => esc_html__( 'Completed', 'learnpress' ),
690 + LP_ITEM_STARTED => esc_html__( 'Started', 'learnpress' ),
691 + LP_COURSE_FINISHED => esc_html__( 'Finished', 'learnpress' ),
692 + );
693 +
694 + if ( ! $status ) {
695 + $status = $this->get_status();
696 + }
697 +
698 + return ! empty( $statuses[ $status ] ) ? $statuses[ $status ] : esc_html__( 'Not Enrolled', 'learnpress' );
699 + }
700 +
701 + /**
702 + * Get time from user started to ended.
703 + *
704 + * @param string $context
705 + *
706 + * @return bool|int
707 + */
708 + public function get_time_interval( $context = '' ) {
709 + $start = $this->get_start_time();
710 + $end = $this->get_end_time();
711 +
712 + if ( ! $start instanceof LP_Datetime || ! $end instanceof LP_Datetime ) {
713 + return false;
714 + }
715 +
716 + if ( $start->is_null() || $end->is_null() ) {
717 + return false;
718 + }
719 +
720 + return $end->getTimestamp() - $start->getTimestamp();
721 + }
722 +
723 + /**
724 + * Return true of item is completed/finished
725 + *
726 + * @param string $status
727 + *
728 + * @return bool
729 + */
730 + public function is_completed( $status = 'completed' ) {
731 + return $this->get_status() === $status;
732 + }
733 +
734 + /**
735 + * Complete item
736 + *
737 + * @editor tungnx
738 + * @modify 4.1.4.1 - should review to improve
739 + * @version 4.0.1
740 + */
741 + public function complete( $status = 'completed' ) {
742 + try {
743 + $this->set_end_time( time() );
744 + $this->set_status( $status );
745 + $this->update();
746 + } catch ( Throwable $e ) {
747 + error_log( __FUNCTION__ . ':' . $e->getMessage() );
748 + return false;
749 + }
750 +
751 + return true;
752 + }
753 +
754 + /**
755 + * Get post type of item.
756 + *
757 + * @return string
758 + */
759 + public function get_post_type() {
760 + return learn_press_get_post_type( $this->get_item_id() );
761 + }
762 +
763 + /**
764 + * @return bool
765 + */
766 + public function is_passed(): bool {
767 + return LP_COURSE_GRADUATION_PASSED === $this->get_graduation();
768 + }
769 +
770 + /**
771 + * @param int $decimal
772 + *
773 + * @return mixed|null
774 + */
775 + public function get_percent_result( $decimal = 1 ) {
776 + return apply_filters(
777 + 'learn-press/user/item-percent-result',
778 + sprintf( '%s%', round( $this->get_result( 'result' ), $decimal ) ),
779 + $this->get_user_id(),
780 + $this->get_item_id()
781 + );
782 + }
783 +
784 + public function offsetSet( $offset, $value ) {
785 + _deprecated_function( __METHOD__, '4.2.3.5' );
786 + // TODO: Implement offsetSet() method.
787 + }
788 +
789 + public function offsetGet( $offset ) {
790 + _deprecated_function( __METHOD__, '4.2.3.5' );
791 + if ( is_callable( array( $this, 'get_' . $offset ) ) ) {
792 + return call_user_func( array( $this, 'get_' . $offset ) );
793 + }
794 +
795 + return false;
796 + }
797 +
798 + public function offsetUnset( $offset ) {
799 + _deprecated_function( __METHOD__, '4.2.3.5' );
800 + // TODO: Implement offsetUnset() method.
801 + }
802 +
803 + public function offsetExists( $offset ) {
804 + _deprecated_function( __METHOD__, '4.2.3.5' );
805 + // TODO: Implement offsetExists() method.
806 + }
807 +}
808 +