PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.1.7
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.1.7
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 4.2.1 All 138 releases
learnpress / inc / course / abstract-course.php

abstract-course.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.1.7, at inc/course/abstract-course.php

1,438 lines 35.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class LP_Abstract_Course.
4 *
5 * @author ThimPress
6 * @package LearnPress/Classes
7 * @version 4.0.0
8 */
9
10 defined( 'ABSPATH' ) || exit();
11
12 if ( ! function_exists( 'LP_Abstract_Course' ) ) {
13
14 /**
15 * Class LP_Abstract_Course.
16 */
17 abstract class LP_Abstract_Course extends LP_Abstract_Post_Data {
18 /**
19 * Course type
20 *
21 * @var string .
22 */
23 public $course_type = null;
24
25 /**
26 * @var LP_Course_CURD|null
27 */
28 protected $_curd = null;
29
30 /**
31 * Post type
32 *
33 * @var string
34 */
35 protected $_post_type = LP_COURSE_CPT;
36
37 /**
38 * @var array
39 */
40 protected $_data = array(
41 'status' => '',
42 'require_enrollment' => '',
43 'price' => '',
44 'regular_price' => '',
45 'sale_price' => '',
46 'sale_start' => '',
47 'sale_end' => '',
48 'duration' => 0,
49 'max_students' => 0,
50 'students' => 0,
51 'retake_count' => 0,
52 'featured' => '',
53 'course_result' => '',
54 'passing_conditional' => '',
55 'external_link' => '',
56 'payment' => '',
57 );
58
59 protected $_loaded = false;
60
61 /**
62 * @var int
63 */
64 protected $user_id = 0;
65
66 public function set_user( $user ) {
67 if ( is_numeric( $user ) ) {
68 $this->user_id = absint( $user );
69 } elseif ( $user instanceof LP_User ) {
70 $this->user_id = $user->get_id();
71 }
72 }
73
74 public function get_user( $return = 'id' ) {
75 if ( $return === 'id' ) {
76 return $this->user_id;
77 }
78
79 if ( $this->user_id ) {
80 return learn_press_get_user( $this->user_id );
81 }
82
83 return false;
84 }
85
86 /**
87 * Constructor gets the post object and sets the ID for the loaded course.
88 *
89 * @param mixed $the_course Course ID, post object, or course object
90 * @param mixed $deprecated Deprecated
91 */
92 public function __construct( $the_course, $deprecated = '' ) {
93
94 $this->_curd = new LP_Course_CURD();
95
96 if ( is_numeric( $the_course ) && $the_course > 0 ) {
97 $this->set_id( $the_course );
98 } elseif ( $the_course instanceof self ) {
99 $this->set_id( absint( $the_course->get_id() ) );
100 } elseif ( ! empty( $the_course->ID ) ) {
101 $this->set_id( absint( $the_course->ID ) );
102 }
103
104 if ( $this->get_id() > 0 ) {
105
106 }
107 }
108
109 public function refresh() {
110 $this->_loaded = false;
111 if ( $this->get_id() > 0 ) {
112 $this->load();
113 }
114 }
115
116 /**
117 * Read course data.
118 * - Curriculum: sections, items, etc...
119 *
120 * Todo: optimize this function
121 *
122 * @since 3.0.0
123 * @editor tungnx
124 * @version 1.0.1
125 */
126 public function load() {
127 if ( $this->_loaded ) {
128 return;
129 }
130
131 $this->load_data();
132
133 /*$can_load_curriculum = false;
134 // Check if edit course, single course, single item can be load
135 if ( in_array( LP_Page_Controller::page_current(), array( LP_PAGE_SINGLE_COURSE, LP_PAGE_SINGLE_COURSE_CURRICULUM ) ) ) {
136 $can_load_curriculum = true;
137 } elseif ( is_admin() && is_callable( 'get_current_screen' ) ) {
138 $current_screen = get_current_screen();
139 if ( $current_screen && LP_COURSE_CPT === $current_screen->id ) {
140 $can_load_curriculum = true;
141 }
142 } elseif ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
143 if ( isset( $_REQUEST['sectionID'] ) || isset( $_REQUEST['sectionId'] ) ) {
144 $can_load_curriculum = true;
145 }
146 }
147
148 if ( $can_load_curriculum ) {
149 $this->load_curriculum();
150 }*/
151
152 $this->_loaded = true;
153 }
154
155 public function load_data() {
156 $id = $this->get_id();
157 $post_object = get_post( $id );
158
159 // Regular price
160 $regular_price = get_post_meta( $id, '_lp_price', true ); // For LP version < 1.4.1.2
161 if ( metadata_exists( 'post', $this->get_id(), '_lp_regular_price' ) ) {
162 $regular_price = get_post_meta( $id, '_lp_regular_price', true );
163 }
164
165 $this->_set_data(
166 array(
167 'status' => $post_object->post_status,
168 'no_required_enroll' => get_post_meta( $id, '_lp_no_required_enroll', true ),
169 'price' => get_post_meta( $id, '_lp_price', true ),
170 'regular_price' => $regular_price,
171 'sale_price' => get_post_meta( $id, '_lp_sale_price', true ),
172 'sale_start' => get_post_meta( $id, '_lp_sale_start', true ),
173 'sale_end' => get_post_meta( $id, '_lp_sale_end', true ),
174 'duration' => get_post_meta( $id, '_lp_duration', true ),
175 'max_students' => get_post_meta( $id, '_lp_max_students', true ),
176 'students' => false,
177 'fake_students' => get_post_meta( $id, '_lp_students', true ),
178 'retake_count' => get_post_meta( $id, '_lp_retake_count', true ),
179 'featured' => get_post_meta( $id, '_lp_featured', true ),
180 'course_result' => get_post_meta( $id, '_lp_course_result', true ),
181 'passing_condition' => get_post_meta( $id, '_lp_passing_condition', true ),
182 'final_quiz' => get_post_meta( $id, '_lp_final_quiz', true ),
183 'external_link' => get_post_meta( $id, '_lp_external_link_buy_course', true ),
184 'block_course_duration_expire' => get_post_meta(
185 $id,
186 '_lp_block_expire_duration',
187 true
188 ),
189 'block_course_finished' => get_post_meta(
190 $id,
191 '_lp_block_finished',
192 true
193 ),
194 'allow_repurchase' => get_post_meta( $id, '_lp_allow_course_repurchase', true ),
195 'allow_repurchase_course_option' => get_post_meta( $id, '_lp_course_repurchase_option', true ),
196 )
197 );
198 }
199
200 /**
201 * Load course curriculum.
202 *
203 * @depecated 4.1.6.9
204 */
205 public function load_curriculum() {
206 _deprecated_function( __FUNCTION__, '4.1.6.9' );
207 /*$item_ids = array();
208 $item_types = array();
209 $item_by_types = array();
210 $section_items = array();
211
212 $items = $this->_curd->read_course_curriculum( $this->get_id() );
213 if ( $items ) {
214 foreach ( $items as $item ) {
215 $item_ids[] = $item->id;
216
217 // Group items by it type
218 if ( empty( $item_types[ $item->type ] ) ) {
219 $item_types[ $item->type ] = array();
220 }
221
222 $item_types[ $item->type ][] = $item->id;
223
224 // Group items by it section
225 if ( empty( $section_items[ $item->section_id ] ) ) {
226 $section_items[ $item->section_id ] = array();
227 }
228
229 $section_items[ $item->section_id ][] = $item->id;
230 $item_by_types[ $item->id ] = $item->type;
231
232 }
233 }
234
235 LP_Course_Utils::set_course_items( $this->get_id(), $item_ids );
236 LP_Course_Utils::set_course_item_types( $this->get_id(), $item_by_types );
237 LP_Course_Utils::set_course_items_group_types( $this->get_id(), $item_types );
238
239 foreach ( $section_items as $section_id => $its ) {
240 LP_Course_Utils::set_section_items( $section_id, $its );
241 }*/
242 }
243
244 /**
245 * __isset function.
246 *
247 * @param mixed $key
248 *
249 * @return bool
250 */
251 public function __isset( $key ) {
252 return metadata_exists( 'post', $this->get_id(), '_' . $key );
253 }
254
255 /**
256 * __get function.
257 *
258 * @param string $key
259 *
260 * @return mixed
261 */
262 public function __get( $key ) {
263 _deprecated_argument( __CLASS__ . '::' . $key, '3.0.11' );
264
265 return false;
266 }
267
268 /**
269 * Get course thumbnail, return placeholder if it does not exists
270 *
271 * @param string $size
272 * @param array $attr
273 *
274 * @return string
275 */
276 public function get_image( string $size = 'course_thumbnail', array $attr = array() ): string {
277 $image = LP_Thumbnail_Helper::instance()->get_course_image( $this->get_id(), $size, $attr );
278
279 return apply_filters( 'learn-press/course/image', $image, $this->get_id(), $size, $attr );
280 }
281
282 /**
283 * Get course thumbnail, return placeholder if it does not exists
284 *
285 * @param string $size
286 *
287 * @return string
288 */
289 public function get_image_url( $size = 'course_thumbnail' ) {
290 $course_id = $this->get_id();
291 $url = '';
292 $parent_id = wp_get_post_parent_id( $course_id );
293
294 if ( has_post_thumbnail( $course_id ) ) {
295 $url = get_the_post_thumbnail_url( $course_id, $size );
296 } elseif ( $parent_id && has_post_thumbnail( $parent_id ) ) {
297 $url = get_the_post_thumbnail_url( $parent_id, $size );
298 }
299
300 if ( ! $url ) {
301 if ( 'course_thumbnail' == $size ) {
302 $url = LP()->image( 'no-image.png' );
303 } else {
304 $url = LP()->image( 'placeholder-500x300' );
305 }
306 }
307
308 return apply_filters( 'learn-press/course-thumbnail-url', $url, $this->get_id(), $size );
309 }
310
311 /**
312 * @return false|string
313 */
314 public function get_permalink() {
315 return get_the_permalink( $this->get_id() );
316 }
317
318 /**
319 * Course is exists if the post is not empty
320 *
321 * @return bool
322 */
323 public function exists() {
324 return LP_COURSE_CPT === learn_press_get_post_type( $this->get_id() );
325 }
326
327 /**
328 * @return bool
329 */
330 public function is_publish() {
331 return 'publish' === get_post_status( $this->get_id() );
332 }
333
334 /**
335 * Check if this course is required enroll or not.
336 *
337 * @param mixed
338 *
339 * @return bool
340 * @depecated 4.0.0
341 */
342 public function is_required_enroll() {
343
344 // $return = $this->get_data( 'required_enroll' ) == 'yes';
345 // @deprecated
346 // $return = apply_filters( 'learn_press_course_required_enroll', $return, $this );
347
348 /**
349 * Since version 4.0.0 feature 'no require enroll' has deprecated
350 */
351 $return = true;
352
353 return apply_filters( 'learn-press/course-require-enrollment', $return, $this->get_id() );
354 }
355 /**
356 * Check if this course is required enroll or not.
357 *
358 * @param mixed
359 * @author hungkv
360 * @since 4.0.5
361 * @return bool
362 * @version 1.0.0
363 */
364 public function is_no_required_enroll(): bool {
365 $return = false;
366 if ( $this->get_data( 'no_required_enroll', 'no' ) == 'yes' && ! is_user_logged_in() ) {
367 $return = true;
368 }
369 return apply_filters( 'learn-press/course/require-enrollment', $return, $this->get_id() );
370 }
371
372 /**
373 * @return mixed
374 * @deprecated
375 */
376 public function is_require_enrollment() {
377 return $this->is_required_enroll();
378 }
379
380 /**
381 * @depecated 4.1.6.9
382 */
383 /*public function get_item_types( $group = false ) {
384 $cache_key = $group ? 'course-item-group-types' : 'course-item-types';
385 $items = LP_Object_Cache::get( 'course-' . $this->get_id(), "learn-press/{$cache_key}" );
386 $items = false;
387
388 if ( false === $items ) {
389 $item_types = array();
390 $items = array();
391 $sections = array();
392 $all_items = $this->_curd->read_course_items( $this->get_id() );
393
394 if ( $all_items ) {
395 foreach ( $all_items as $item ) {
396 if ( empty( $item_types[ $item->type ] ) ) {
397 $item_types[ $item->type ] = array();
398 }
399 $item_types[ $item->type ][] = $item->id;
400 $items[ $item->id ] = $item->type;
401
402 if ( empty( $sections[ $item->section_id ] ) ) {
403 $sections[ $item->section_id ] = array();
404 }
405 $sections[ $item->section_id ][] = $item->id;
406 }
407 }
408
409 LP_Object_Cache::set( 'course-' . $this->get_id(), $item_types, 'learn-press/course-item-group-types' );
410 LP_Object_Cache::set( 'course-' . $this->get_id(), $items, 'learn-press/course-item-types' );
411
412 foreach ( $sections as $section_id => $section_items ) {
413 LP_Object_Cache::set( 'section-' . $section_id, $section_items, 'learn-press/section-items' );
414 }
415
416 $items = $group ? $item_types : $items;
417 }
418
419 return apply_filters( "learn-press/{$cache_key}", $items, $this->get_id() );
420 }*/
421
422 /**
423 * Get all item's ids in a course.
424 *
425 * @param int $section_id
426 *
427 * @return array
428 * @version 4.0.1
429 * @modify 4.1.6.9 tungnx
430 */
431 public function get_item_ids( int $section_id = 0 ): array {
432 $item_ids = array();
433
434 $sections_items = $this->get_full_sections_and_items_course();
435 foreach ( $sections_items as $section_items ) {
436 foreach ( $section_items->items as $item ) {
437 if ( $section_id ) {
438 if ( $section_id == $section_items->id ) {
439 $item_ids[] = $item->id;
440 }
441
442 continue;
443 }
444
445 $item_ids[] = $item->id;
446 }
447 }
448
449 return apply_filters( 'learn-press/course-item-ids', $item_ids, $this->get_id() );
450 }
451
452 /**
453 * Get item is viewing in single course.
454 *
455 * @return LP_Course_Item
456 * @depecated 4.1.6.9
457 */
458 public function get_viewing_item() {
459 _deprecated_function( __FUNCTION__, '4.1.6.9' );
460 //return apply_filters( 'learn-press/single-course-viewing-item', $this->_viewing_item, $this->get_id() );
461 }
462
463 /**
464 * Get total students fake.
465 *
466 * @return int
467 */
468 public function get_fake_students() : int {
469 return absint( $this->get_data( 'fake_students', 0 ) );
470 }
471
472 /**
473 * Count the real users has enrolled
474 *
475 * @return int
476 */
477 public function get_users_enrolled() {
478 $enrolled = $this->get_data( 'students' );
479
480 if ( false === $enrolled ) {
481 $enrolled = $this->count_students();
482
483 $this->_set_data( 'students', $enrolled );
484 }
485
486 $enrolled = absint( $enrolled );
487
488 return apply_filters( 'learn-press/course/users-enrolled', $enrolled, $this );
489 }
490
491 /**
492 * Output html for students enrolled counter
493 *
494 * @return string
495 * @editor tungnx
496 * @modify 4.1.3
497 */
498 /*public function get_students_html() {
499 $output = '';
500 $count = $this->get_users_enrolled();
501
502 if ( $count ) {
503 $user = learn_press_get_current_user();
504
505 if ( $user->has_enrolled_course( $this->get_id() ) ) {
506 if ( $count == 1 ) {
507 $output .= esc_html__( 'You enrolled', 'learnpress' );
508 } else {
509 $output .= sprintf(
510 _nx(
511 'You and one student enrolled',
512 'You and <span class="course-students-number">%1$s</span> students enrolled',
513 intval( $count - 1 ),
514 'students-html',
515 'learnpress'
516 ),
517 $count - 1
518 );
519 }
520 } else {
521 $output = sprintf(
522 _nx(
523 'One student enrolled',
524 '<span class="course-students-number">%1$s</span> students enrolled',
525 $count,
526 'students-html',
527 'learnpress'
528 ),
529 $count
530 );
531 }
532 } else {
533 $output = esc_html__( 'No student enrolled', 'learnpress' );
534 }
535
536 return apply_filters( 'learn-press/students-enrolled-html', $output, $this->get_id() );
537 }*/
538
539 /**
540 * @param string $field
541 *
542 * @return LP_User|mixed
543 */
544 public function get_instructor( $field = '' ) {
545 $user = learn_press_get_user( get_post_field( 'post_author', $this->get_id() ) );
546
547 return $field ? $user->get_data( $field ) : $user;
548 }
549
550 /**
551 * @return mixed
552 */
553 public function get_instructor_name() {
554 $instructor = $this->get_instructor();
555 $name = '';
556
557 if ( $instructor ) {
558 if ( $instructor->get_data( 'display_name' ) ) {
559 $name = $instructor->get_data( 'display_name' );
560 } elseif ( $instructor->get_data( 'user_nicename' ) ) {
561 $name = $instructor->get_data( 'user_nicename' );
562 } elseif ( $instructor->get_data( 'user_login' ) ) {
563 $name = $instructor->get_data( 'user_login' );
564 }
565 }
566
567 return apply_filters( 'learn-press/course/instructor-name', $name, $this->get_id() );
568 }
569
570 /**
571 * @param int|bool $with_avatar
572 * @param string $link_class
573 *
574 * @return string
575 */
576 public function get_instructor_html( $with_avatar = false, $link_class = '' ) {
577 $instructor = $this->get_instructor_name();
578
579 $html = sprintf(
580 '<a href="%s"%s>%s<span>%s</span></a>',
581 learn_press_user_profile_link( get_post_field( 'post_author', $this->get_id() ) ),
582 $link_class ? sprintf( 'class="%s"', $link_class ) : '',
583 $with_avatar ? get_avatar(
584 $this->get_instructor( 'id' ),
585 $with_avatar === true ? 48 : $with_avatar
586 ) : '',
587 $instructor
588 );
589
590 return apply_filters(
591 'learn_press_course_instructor_html',
592 $html,
593 get_post_field( 'post_author', $this->get_id() ),
594 $this->get_id()
595 );
596 }
597
598 /**
599 * Check if a course is Free
600 *
601 * @return bool
602 */
603 public function is_free(): bool {
604 return apply_filters( 'learn-press/course/is-free', $this->get_price() == 0, $this->get_id() );
605 }
606
607 /**
608 * Get the sale price of course. Check if sale price is set
609 * and the dates are valid.
610 *
611 * @return string|float
612 */
613 public function get_sale_price() {
614 $sale_price_value = $this->get_data( 'sale_price', '' );
615
616 if ( '' !== $sale_price_value ) {
617 return floatval( $sale_price_value );
618 }
619
620 return $sale_price_value;
621 }
622
623 /**
624 * Check course has 'sale price'
625 *
626 * @return mixed
627 */
628 public function has_sale_price() {
629 $has_sale_price = false;
630 $regular_price = $this->get_regular_price();
631 $sale_price = $this->get_sale_price();
632 $start_date = $this->get_data( 'sale_start', '' );
633 $end_date = $this->get_data( 'sale_end', '' );
634
635 if ( $regular_price > $sale_price && is_float( $sale_price ) ) {
636 $has_sale_price = true;
637 }
638
639 // Check in days sale
640 if ( $has_sale_price && '' !== $start_date && '' !== $end_date ) {
641 $now = strtotime( get_date_from_gmt( gmdate( 'Y-m-d H:i:s', time() ), 'Y-m-d H:i:s' ) );
642 $end = strtotime( $end_date );
643 $start = strtotime( $start_date );
644
645 $has_sale_price = $now >= $start && $now <= $end;
646 }
647
648 return apply_filters( 'learn-press/course/has-sale-price', $has_sale_price, $this->get_id() );
649 }
650
651 /**
652 * Get the regular price of course.
653 *
654 * @return float
655 */
656 public function get_regular_price(): float {
657 $price = floatval( $this->get_data( 'regular_price', 0 ) );
658
659 return apply_filters( 'learn-press/course/regular-price', $price, $this->get_id() );
660 }
661
662 /**
663 * Get the regular price format of course.
664 *
665 * @since 4.1.5
666 * @version 1.0.0
667 * @author tungnx
668 * @return mixed
669 */
670 public function get_regular_price_html() {
671 $price = learn_press_format_price( $this->get_regular_price(), true );
672
673 return apply_filters( 'learn-press/course/regular-price', $price, $this->get_id() );
674 }
675
676 /**
677 * Get the price of course.
678 *
679 * @return mixed
680 */
681 public function get_price() {
682 $key_cache = "{$this->get_id()}/price";
683 $price = LP_Course_Cache::cache_load_first( 'get', $key_cache );
684
685 if ( false === $price ) {
686 if ( $this->has_sale_price() ) {
687 $price = $this->get_sale_price();
688 // Add key _lp_course_is_sale for query
689 update_post_meta( $this->get_id(), '_lp_course_is_sale', 1 );
690 } else {
691 // Delete key _lp_course_is_sale
692 delete_post_meta( $this->get_id(), '_lp_course_is_sale' );
693 $price = $this->get_regular_price();
694 }
695
696 // For case set sale by days range
697 update_post_meta( $this->get_id(), '_lp_price', $price );
698
699 LP_Course_Cache::cache_load_first( 'set', $key_cache, $price );
700 }
701
702 return apply_filters( 'learn-press/course/price', $price, $this->get_id() );
703 }
704
705 /**
706 * Get html course price
707 *
708 * @author tungnx
709 * @since 4.1.5
710 * @version 1.0.0
711 * @return mixed|void
712 */
713 public function get_course_price_html() {
714 $price_html = '';
715
716 if ( $this->is_free() ) {
717 if ( is_float( $this->get_sale_price() ) ) {
718 $price_html .= sprintf( '<span class="origin-price">%s</span>', $this->get_regular_price_html() );
719 }
720
721 $price_html .= sprintf( '<span class="free">%s</span>', esc_html__( 'Free', 'learnpress' ) );
722 $price_html = apply_filters( 'learn_press_course_price_html_free', $price_html, $this );
723 } else {
724 if ( $this->has_sale_price() ) {
725 $price_html .= sprintf( '<span class="origin-price">%s</span>', $this->get_regular_price_html() );
726 }
727
728 $price_html .= sprintf( '<span class="price">%s</span>', learn_press_format_price( $this->get_price(), true ) );
729 $price_html = apply_filters( 'learn_press_course_price_html', $price_html, $this->has_sale_price(), $this->get_id() );
730 }
731
732 return $price_html;
733 }
734
735 /**
736 * Get the price of course with html
737 *
738 * @editor tungnx
739 * @modify 4.1.5
740 * @version 1.0.1
741 * @return mixed
742 * @deprecated 4.1.5
743 */
744 public function get_price_html() {
745 $price_html = '';
746
747 if ( $this->is_free() ) {
748 $price_html = apply_filters(
749 'learn_press_course_price_html_free',
750 esc_html__( 'Free', 'learnpress' ),
751 $this
752 );
753 } else {
754 $price_html .= learn_press_format_price( $this->get_price() );
755 $price_html = apply_filters( 'learn_press_course_price_html', $price_html, $this->has_sale_price(), $this->get_id() );
756 }
757
758 return $price_html;
759 }
760
761 /**
762 * Get the origin price of course
763 *
764 * @return float
765 * @deprecated 4.1.5
766 */
767 public function get_origin_price() {
768 return $this->get_regular_price();
769 }
770
771 /**
772 * Get the price of course with html
773 *
774 * @return mixed
775 * @deprecated 4.1.5
776 */
777 public function get_origin_price_html() {
778 return $this->get_regular_price_html();
779 }
780
781 /**
782 * @param bool $item_id
783 *
784 * @return bool|mixed
785 */
786 public function is_viewing_item( $item_id = false ) {
787 $item = LP_Global::course_item();
788
789 if ( empty( $item ) ) {
790 return false;
791 }
792
793 return apply_filters(
794 'learn-press/is-viewing-item',
795 false !== $item_id ? $item_id == $item->get_id() : $item->get_id(),
796 $item_id,
797 $this->get_id()
798 );
799 }
800
801 /**
802 * @param $item_id
803 *
804 * @return bool|mixed
805 */
806 public function is_current_item( $item_id ) {
807 return $this->is_viewing_item( $item_id );
808 }
809
810 /**
811 * Check if the course has 'feature'
812 * This function call to a function with prefix 'has'
813 *
814 * @param string
815 *
816 * @return mixed
817 * @throws Exception
818 */
819 public function has( $tag ) {
820 _deprecated_function( __FUNCTION__, '3.0.8' );
821
822 $args = func_get_args();
823 unset( $args[0] );
824 $method = 'has_' . preg_replace( '!-!', '_', $tag );
825 $callback = array( $this, $method );
826
827 if ( is_callable( $callback ) ) {
828 return call_user_func_array( $callback, $args );
829 } else {
830 throw new Exception( sprintf( __( 'The function %s doesn\'t exist', 'learnpress' ), $tag ) );
831 }
832 }
833
834 /**
835 * @param string
836 *
837 * @return mixed
838 * @throws Exception
839 */
840 public function is( $tag ) {
841 _deprecated_function( __FUNCTION__, '3.0.8' );
842 $args = func_get_args();
843 unset( $args[0] );
844 $method = 'is_' . preg_replace( '!-!', '_', $tag );
845 $callback = array( $this, $method );
846
847 if ( is_callable( $callback ) ) {
848 return call_user_func_array( $callback, $args );
849 } else {
850 throw new Exception( sprintf( __( 'The function %s doesn\'t exist', 'learnpress' ), $tag ) );
851 }
852 }
853
854 /**
855 * Return true if this course can be purchasable.
856 * Required enroll.
857 * Status is publish.
858 *
859 * @return mixed
860 */
861 public function is_purchasable() {
862 $is_purchasable = $this->exists() && $this->is_required_enroll() && get_post_status( $this->get_id() ) == 'publish';
863
864 // @deprecated
865 $is_purchasable = apply_filters( 'learn_press_item_is_purchasable', $is_purchasable, $this->get_id() );
866
867 return apply_filters( 'learn-press/is-purchasable', $is_purchasable, $this->get_id() );
868 }
869
870 /**
871 * Check if students have enrolled or purchased course is reached.
872 *
873 * @return mixed
874 */
875 public function is_in_stock() {
876 $in_stock = true;
877 $max_allowed = $this->get_max_students();
878
879 if ( $max_allowed ) {
880 $in_stock = $max_allowed > $this->get_total_user_enrolled_or_purchased();
881 }
882
883 return apply_filters( 'learn-press/is-in-stock', $in_stock, $this->get_id() );
884 }
885
886 /**
887 * Get max students can enroll to course.
888 *
889 * @return int
890 *
891 * @since 3.0.0
892 */
893 public function get_max_students() {
894 return apply_filters(
895 'learn-press/max-students',
896 absint( $this->get_data( 'max_students' ) ),
897 $this->get_id()
898 );
899 }
900
901 /**
902 * Count number of students enrolled course.
903 * Check global settings `enrolled_students_number`
904 * and add the fake value if both are set.
905 *
906 * @return int
907 * @editor tungnx
908 * @Todo: view and rewrite this function
909 */
910 public function count_students(): int {
911 $key_cache = "{$this->get_id()}/total-students";
912 $total = LP_Course_Cache::instance()->get_cache( $key_cache );
913
914 if ( $total ) {
915 return $total;
916 }
917
918 $lp_course_db = LP_Course_DB::getInstance();
919 $total = $lp_course_db->get_total_user_enrolled( $this->get_id() );
920 $total += $this->get_fake_students();
921
922 LP_Course_Cache::instance()->set_cache( $key_cache, $total, 6 * HOUR_IN_SECONDS );
923
924 return $total;
925 }
926
927 /**
928 * Get total user enrolled
929 *
930 * @return int
931 */
932 public function get_total_user_enrolled(): int {
933 $lp_course_db = LP_Course_DB::getInstance();
934 return $lp_course_db->get_total_user_enrolled( $this->get_id() );
935 }
936
937 /**
938 * Get total user enrolled or finished
939 *
940 * @return int
941 */
942 public function get_total_user_enrolled_or_purchased(): int {
943 $key_cache = "{$this->get_id()}/total-students-attended";
944 $total_user_enrolled = LP_Course_Cache::cache_load_first( 'get', $key_cache );
945
946 if ( false === $total_user_enrolled ) {
947 $lp_course_db = LP_Course_DB::getInstance();
948 $total_user_enrolled = $lp_course_db->get_total_user_enrolled_or_purchased( $this->get_id() );
949
950 LP_Course_Cache::cache_load_first( 'set', $key_cache, $total_user_enrolled );
951 }
952
953 return $total_user_enrolled;
954 }
955
956 /**
957 * @param string|array $statuses
958 *
959 * @return mixed
960 */
961 public function count_in_order( $statuses = 'completed' ) {
962 settype( $statuses, 'array' );
963 $count = 0;
964
965 foreach ( $statuses as $status ) {
966 $orders = get_post_meta( $this->get_id(), 'order-' . $status, true );
967
968 if ( $orders ) {
969 $count += sizeof( $orders );
970 }
971 }
972
973 return $count;
974 }
975
976 /**
977 * @editor tungnx
978 * @modify 4.1.4 - comment - not use
979 */
980 /*public function count_completed_orders() {
981 $orders = $this->get_meta( 'order-completed' );
982
983 if ( $orders ) {
984 $count = sizeof( $orders );
985 } else {
986 $count = 0;
987 }
988
989 return $count;
990 }*/
991
992 /**
993 * Check if course contain an item in curriculum.
994 * Actually, find the item in each section inside curriculum.
995 *
996 * @param $item_id
997 *
998 * @return bool
999 */
1000 public function has_item( $item_id ) {
1001 $found = false;
1002 $items = $this->get_item_ids();
1003
1004 if ( $items ) {
1005 $found = in_array( $item_id, $items );
1006 }
1007
1008 return apply_filters( 'learn-press/course-has-item', $found, $item_id, $this->get_id() );
1009 }
1010
1011 /**
1012 * Get course's item (lesson/quiz/etc...).
1013 *
1014 * @param int $item_id Course's item Id.
1015 *
1016 * @return LP_Lesson|LP_Quiz|boolean
1017 */
1018 public function get_item( $item_id ) {
1019 $item = LP_Course_Item::get_item( $item_id );
1020 if ( $item instanceof LP_Course_Item ) {
1021 $item->set_course( $this->get_id() );
1022 }
1023
1024 return apply_filters( 'learn-press/course-item', $item, $item_id, $this->get_id() );
1025 }
1026
1027 /**
1028 * Get course passing condition value.
1029 *
1030 * @param bool $format
1031 * @param string $context
1032 *
1033 * @return array|mixed|string
1034 */
1035 public function get_passing_condition( $format = false, $context = '' ) {
1036 $value = absint( $this->get_data( 'passing_condition' ) );
1037
1038 if ( $format ) {
1039 $value = "{$value}%";
1040 }
1041
1042 return 'edit' === $context ? $value : apply_filters(
1043 'learn-press/course-passing-condition',
1044 $value,
1045 $format,
1046 $this->get_id()
1047 );
1048 }
1049
1050 /**
1051 * Get item's link
1052 *
1053 * @param int $item_id
1054 *
1055 * @editor tungnx
1056 * @since 3.0.0
1057 * @version 1.0.1
1058 * @return string
1059 */
1060 public function get_item_link( int $item_id ): string {
1061 $item_link = '';
1062 $item_type = get_post_type( $item_id );
1063
1064 $course_permalink = trailingslashit( $this->get_permalink() );
1065 $item_slug = get_post_field( 'post_name', $item_id );
1066
1067 $slug_prefixes = apply_filters(
1068 'learn-press/course/custom-item-prefixes',
1069 array(
1070 LP_QUIZ_CPT => sanitize_title_with_dashes( LP_Settings::instance()->get( 'quiz_slug', 'quizzes' ) ),
1071 LP_LESSON_CPT => sanitize_title_with_dashes( LP_Settings::instance()->get( 'lesson_slug', 'lessons' ) ),
1072 ),
1073 $this->get_id()
1074 );
1075
1076 $slug_prefix = trailingslashit( $slug_prefixes[ $item_type ] ?? '' );
1077
1078 $item_link = $course_permalink . $slug_prefix . $item_slug;
1079
1080 return apply_filters( 'learn-press/course/item-link', $item_link, $item_id, $this );
1081 }
1082
1083 /**
1084 * Get course's item at a position.
1085 *
1086 * @param int $at
1087 *
1088 * @return bool|mixed
1089 * @editor tungnx
1090 * @modify 4.1.3 - comment - not use
1091 */
1092 /*public function get_item_at( $at ) {
1093 $items = $this->get_items();
1094
1095 if ( ! $items ) {
1096 return false;
1097 }
1098
1099 return ! empty( $items[ $at ] ) ? $items[ $at ] : false;
1100 }*/
1101
1102 /**
1103 * Get position of an item in course curriculum.
1104 *
1105 * @param LP_Course_Item|LP_User_Item|int $item
1106 *
1107 * @return mixed
1108 * @depecated 4.1.6.9
1109 */
1110 /*public function get_item_position( $item ) {
1111 $items = $this->get_items();
1112
1113 if ( ! $items ) {
1114 return false;
1115 }
1116
1117 $item_id = is_a( $item, 'LP_User_Item' ) || is_a(
1118 $item,
1119 'LP_Course_Item'
1120 ) ? $item->get_id() : absint( $item );
1121
1122 return array_search( $item_id, $items );
1123 }*/
1124
1125 /**
1126 * @return bool|mixed
1127 */
1128 public function get_current_item() {
1129 return $this->is_viewing_item();
1130 }
1131
1132 /**
1133 * Get item standing after the item is viewing.
1134 *
1135 * @param array $args
1136 *
1137 * @return int
1138 */
1139 public function get_next_item( $args = null ) {
1140 $item_nav = $this->get_item_nav();
1141
1142 return apply_filters( 'learn-press/course/next-item', $item_nav[2], $this->get_id(), $args );
1143 }
1144
1145 /**
1146 * Get item standing before the item is viewing.
1147 *
1148 * @param array $args
1149 *
1150 * @return int
1151 */
1152 public function get_prev_item( $args = null ) {
1153 $item_nav = $this->get_item_nav();
1154
1155 return apply_filters( 'learn-press/course/prev-item', $item_nav[0], $this->get_id(), $args );
1156 }
1157
1158 /**
1159 * Get item standing before and after an item.
1160 * If the item is not passed consider it is item viewing.
1161 *
1162 * @param bool $current_item
1163 * @param bool $viewable - Optional. TRUE will get next item is viewable.
1164 *
1165 * @return array|bool
1166 * @since 3.1.0
1167 */
1168 public function get_item_nav( $current_item = false, $viewable = false ) {
1169 if ( false === $current_item ) {
1170 $current_item = $this->get_current_item();
1171 }
1172
1173 if ( false === $current_item ) {
1174 return false;
1175 }
1176
1177 $prev_id = $next_id = 0;
1178 $item_ids = $this->get_item_ids();
1179
1180 if ( $item_ids ) {
1181 $pos = array_search( $current_item, $item_ids );
1182
1183 if ( false !== $pos ) {
1184 $max = sizeof( $item_ids ) - 1;
1185 $user = learn_press_get_current_user();
1186 $pos_tmp = $pos;
1187
1188 while ( $pos_tmp < $max ) {
1189 $pos_tmp ++;
1190
1191 if ( ! $viewable ) {
1192 $next_id = $item_ids[ $pos_tmp ];
1193
1194 break;
1195 }
1196 }
1197
1198 $pos_tmp = $pos;
1199
1200 while ( $pos_tmp > 0 ) {
1201 $pos_tmp --;
1202
1203 if ( ! $viewable ) {
1204 $prev_id = $item_ids[ $pos_tmp ];
1205
1206 break;
1207 }
1208 }
1209 }
1210 }
1211
1212 return array( $prev_id, $current_item, $next_id );
1213 }
1214
1215 /**
1216 * Get link of item is standing after the item is viewing.
1217 *
1218 * @param array $args
1219 *
1220 * @return string
1221 */
1222 public function get_next_item_html( $args = null ) {
1223 $args = wp_parse_args(
1224 $args,
1225 array(
1226 'current_item' => false,
1227 'viewable' => null,
1228 'dir' => 'next',
1229 )
1230 );
1231
1232 $next_item = $this->get_next_item( $args );
1233
1234 if ( $next_item ) {
1235 ob_start();
1236
1237 learn_press_get_template(
1238 'content-lesson/next-button.php',
1239 array(
1240 'item' => $next_item,
1241 'course' => $this,
1242 )
1243 );
1244
1245 return ob_get_clean();
1246 }
1247
1248 return false;
1249 }
1250
1251 public function get_prev_item_html( $args = null ) {
1252
1253 }
1254
1255 public function get_preview_items() {
1256 return LP_Object_Cache::get( 'course-' . $this->get_id(), 'learn-press/course-preview-items' );
1257 }
1258
1259 /**
1260 * Check a quiz is a final quiz in this course
1261 *
1262 * @param $quiz_id
1263 *
1264 * @return mixed
1265 */
1266 public function is_final_quiz( $quiz_id ) {
1267 return apply_filters( 'learn_press_is_final_quiz', $this->get_final_quiz() == $quiz_id, $quiz_id, $this->get_id() );
1268 }
1269
1270 public function get_final_quiz() {
1271 $final_quiz = $this->get_data( 'final_quiz' );
1272
1273 return apply_filters( 'learn-press/course-final-quiz', $final_quiz, $this->get_id() );
1274 }
1275
1276 public function set_final_quiz( $id ) {
1277 $this->_set_data( 'final_quiz', $id );
1278 }
1279
1280 /**
1281 * Get course duration in seconds
1282 *
1283 * @return int
1284 */
1285 public function get_duration() {
1286 /**
1287 * Duration is in string such as 10 week, 4 hour, etc...
1288 * So we can use strtotime('+10 week') to convert it to seconds
1289 */
1290 return strtotime( '+' . $this->get_data( 'duration' ), 0 );
1291 }
1292
1293
1294 /**
1295 * Get course remaining time message
1296 *
1297 * @param $user_id
1298 *
1299 * @return string
1300 */
1301 public function get_user_duration_html( $user_id = 0 ) {
1302 if ( ! $user_id ) {
1303 $user_id = get_current_user_id();
1304 }
1305
1306 $duration = $this->get_duration();
1307 $user = learn_press_get_user( $user_id );
1308 $course_info = $user->get_course_info( $this->get_id() );
1309 $html = '';
1310
1311 if ( $course_info ) {
1312 $now = current_time( 'timestamp' );
1313 $start_time = intval( strtotime( $course_info['start'] ) );
1314
1315 if ( $start_time + $duration > $now ) {
1316 $remain = $start_time + $duration - $now;
1317 $remain = learn_press_seconds_to_weeks( $remain );
1318 $html = sprintf( __( 'This course will end within next %s', 'learnpress' ), $remain );
1319 }
1320 }
1321
1322 return $html;
1323 }
1324
1325 /**
1326 * Output params for single course page
1327 *
1328 * @param null $args
1329 *
1330 * @return mixed
1331 */
1332 public function output_args( $args = null ) {
1333 return array();
1334 }
1335
1336 /**
1337 * Get external link of "Buy this course" button
1338 *
1339 * @return mixed
1340 */
1341 public function get_external_link() {
1342 return apply_filters( 'learn-press/course-external-link', $this->get_data( 'external_link', '' ), $this->get_id() );
1343 }
1344
1345 public function get_external_link_text() {
1346 return apply_filters( 'learn-press/course-external-link-text', _x( 'More Info', 'External Link button text', 'learnpress' ), $this->get_id() );
1347 }
1348
1349 /**
1350 * Get main author of course.
1351 *
1352 * @param string $field
1353 *
1354 * @return LP_User|int
1355 */
1356 public function get_author( string $field = '' ) {
1357 $author_id = absint( get_post_field( 'post_author', $this->get_id() ) );
1358
1359 return strtolower( $field ) === 'id' ? $author_id : learn_press_get_user( $author_id );
1360 }
1361
1362 /**
1363 * Get author's display name
1364 *
1365 * @return string
1366 * @since 3.0.9
1367 */
1368 public function get_author_display_name() {
1369 $display_name = '';
1370 $user = $this->get_author();
1371
1372 if ( $user ) {
1373 $display_name = $user->get_display_name();
1374 }
1375
1376 return $display_name;
1377 }
1378
1379 /**
1380 * @return mixed
1381 */
1382 public function get_tags() {
1383 return apply_filters( 'learn-press/course-tags', get_the_term_list( $this->get_id(), 'course_tag', __( 'Tags: ', 'learnpress' ), ' ', '' ) );
1384 }
1385
1386 /**
1387 * Get extra info of course.
1388 * Target Audience, Key Features, Requirements, etc...
1389 *
1390 * @param string $type [target_audience, key_features, requirements]
1391 *
1392 * @return string|array
1393 * @since 3.x.x
1394 */
1395 public function get_extra_info( $type ) {
1396 $extra_info_meta = get_post_meta( $this->get_id(), '_lp_' . $type, true );
1397
1398 return apply_filters( 'learn-press/course-extra-info', $extra_info_meta, $type, $this->get_id() );
1399 }
1400
1401 /**
1402 * Get FAQs in Tab metabox.
1403 *
1404 * @return array
1405 * @since 4.0.0
1406 */
1407 public function get_faqs(): array {
1408 $faqs = array();
1409 $data = get_post_meta( $this->get_id(), '_lp_faqs', true );
1410
1411 if ( $data ) {
1412 foreach ( $data as $faq ) {
1413 $faqs[] = array(
1414 'question' => $faq[0],
1415 'answer' => $faq[1],
1416 );
1417 }
1418 }
1419
1420 return apply_filters( 'learn-press/course-faqs', $faqs, $this->get_id() );
1421 }
1422
1423 /**
1424 * Get course is set featured
1425 *
1426 * @return bool
1427 */
1428 public function is_featured(): bool {
1429 return apply_filters(
1430 'learn-press/course-is-featured',
1431 get_post_meta( $this->get_id(), '_lp_featured', true ) === 'yes',
1432 $this->get_id(),
1433 $this
1434 );
1435 }
1436 }
1437 }
1438