PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
← All changes | inc/course/class-lp-course.php +297 -71 4.1.7.24.4.8 View file →
@@ -6,8 +6,11 @@
6 6 * @package LearnPress/Classes
7 7 * @version 4.0.1
8 8 */
9 9
10 +use LearnPress\Models\CourseModel;
11 +use LearnPress\Models\CoursePostModel;
12 +
10 13 defined( 'ABSPATH' ) || exit();
11 14
12 15 if ( ! class_exists( 'LP_Course' ) ) {
13 16
@@ -72,8 +75,9 @@
72 75 *
73 76 * @param int $course_id
74 77 *
75 78 * @return mixed|bool|LP_Course
79 + * @Todo - Tungnx review to rewrite this method.
76 80 */
77 81 public static function get_course( int $course_id = 0 ) {
78 82 if ( isset( LP_Global::$courses[ $course_id ] ) ) {
79 83 return LP_Global::$courses[ $course_id ];
@@ -214,9 +218,9 @@
214 218
215 219 $course_start_time = $course_item_data->get_start_time()->get_raw_date();
216 220 $duration = $this->get_data( 'duration' );
217 221 $timestamp_expire = strtotime( $course_start_time . ' +' . $duration );
218 - $timestamp_current = strtotime( current_time( 'mysql' ) );
222 + $timestamp_current = time();
219 223 $timestamp_remaining = $timestamp_expire - $timestamp_current;
220 224
221 225 if ( $timestamp_remaining < 0 ) {
222 226 $timestamp_remaining = 0;
@@ -233,13 +237,13 @@
233 237 public function enable_block_item_when_finish(): bool {
234 238 return 'yes' === $this->get_data( 'block_course_finished' );
235 239 }
236 240
237 - public function allow_repurchase() : bool {
241 + public function allow_repurchase(): bool {
238 242 return 'yes' === $this->get_data( 'allow_repurchase' );
239 243 }
240 244
241 - public function allow_repurchase_course_option() : string {
245 + public function allow_repurchase_course_option(): string {
242 246 return $this->get_data( 'allow_repurchase_course_option', 'reset' );
243 247 }
244 248
245 249 /**
@@ -247,14 +251,17 @@
247 251 *
248 252 * @author tungnx
249 253 * @since 4.0.0
250 254 * @modify 4.1.3
251 - * @version 1.0.1
255 + * @version 1.0.2
252 256 * @return int
253 257 */
254 258 public function get_first_item_id(): int {
255 259 $course_id = $this->get_id();
256 260
261 + $courseModel = CourseModel::find( $course_id, true );
262 + return $courseModel->get_first_item_id();
263 +
257 264 try {
258 265 // Get cache
259 266 $lp_course_cache = LP_Course_Cache::instance();
260 267 $key_cache = "$course_id/first_item_id";
@@ -303,8 +310,9 @@
303 310 * @since 4.1.3
304 311 * @author tungnx
305 312 * @version 1.0.0
306 313 * @return LP_Course_Extra_Info_Fast_Query_Model
314 + * @deprecated 4.2.7.4
307 315 */
308 316 public function get_info_extra_for_fast_query(): LP_Course_Extra_Info_Fast_Query_Model {
309 317 $extra_info = new LP_Course_Extra_Info_Fast_Query_Model();
310 318
@@ -310,19 +318,14 @@
310 318
311 319 try {
312 320 $extra_info_str = get_post_meta( $this->get_id(), $this->key_info_extra_fast_query, true );
313 321
314 - if ( $extra_info_str ) {
315 - $extra_info_stdclass = json_decode( $extra_info_str );
316 -
317 - if ( JSON_ERROR_NONE !== json_last_error() ) {
318 - throw new Exception( 'Error json decode on ' . __METHOD__ );
319 - }
320 -
321 - $extra_info = $extra_info->map_stdclass( $extra_info_stdclass );
322 + if ( ! empty( $extra_info_str ) ) {
323 + $extra_info_stdclass = LP_Helper::json_decode( $extra_info_str );
324 + $extra_info = $extra_info->map_stdclass( $extra_info_stdclass );
322 325 }
323 326 } catch ( Throwable $e ) {
324 - error_log( $e->getMessage() );
327 + error_log( __METHOD__ . ': ' . $e->getMessage() );
325 328 }
326 329
327 330 return $extra_info;
328 331 }
@@ -353,49 +356,36 @@
353 356 * Get info total items of Course
354 357 *
355 358 * @param string $type
356 359 * @param bool $include_preview
360 + *
361 + * @return int
362 + * @throws Exception
363 + * @version 1.0.1
357 364 * @author tungnx
358 365 * @since 4.1.4.1
359 - * @version 1.0.0
360 - * @return int
361 366 */
362 367 public function count_items( string $type = '', bool $include_preview = true ): int {
363 - $course_id = $this->get_id();
368 + $course_id = $this->get_id();
369 + $courseModel = CourseModel::find( $course_id, true );
370 + if ( ! $courseModel ) {
371 + return 0;
372 + }
364 373
365 - // Get cache
366 - $lp_course_cache = LP_Course_Cache::instance();
367 - $key_cache = "$course_id/total_items";
368 - $total_items = $lp_course_cache->get_cache( $key_cache );
369 - $count_items = 0;
370 -
371 - if ( ! $total_items ) {
372 - $extra_info = $this->get_info_extra_for_fast_query();
373 -
374 - if ( ! $extra_info->total_items ) {
375 - $total_items = LP_Course_DB::getInstance()->get_total_items( $course_id );
376 - $extra_info->total_items = $total_items;
377 -
378 - // Save post meta
379 - $this->set_info_extra_for_fast_query( $extra_info );
380 - } else {
381 - $total_items = $extra_info->total_items;
382 - }
383 -
384 - $lp_course_cache->set_cache( $key_cache, $total_items );
374 + $total_items = $courseModel->get_total_items();
375 + if ( empty( $total_items ) ) {
376 + return 0;
385 377 }
386 378
387 - if ( ! empty( $total_items ) ) {
388 - if ( ! empty( $type ) ) {
389 - if ( isset( $total_items->{$type} ) ) {
390 - $count_items = $total_items->{$type};
391 - }
392 - } else {
393 - $count_items = $total_items->count_items;
379 + if ( ! empty( $type ) ) {
380 + if ( isset( $total_items->{$type} ) ) {
381 + return $total_items->{$type};
394 382 }
383 + } else {
384 + return $total_items->count_items ?? 0;
395 385 }
396 386
397 - return apply_filters( 'learn-press/course/count-items', intval( $count_items ), $course_id );
387 + return 0;
398 388 }
399 389
400 390 /**
401 391 * Delete relate data when delete course
@@ -429,8 +419,20 @@
429 419 $filter_user_items->item_id = $this->get_id();
430 420 $user_course_ids = $lp_user_items_db->get_user_items_by_course( $filter_user_items );
431 421
432 422 $this->delete_user_item_and_result( $user_course_ids );
423 +
424 + // Clear cache total students enrolled.
425 + $lp_course_cache = new LP_Course_Cache( true );
426 + $lp_course_cache->clean_total_students_enrolled( $this->get_id() );
427 + $lp_course_cache->clean_total_students_enrolled_or_purchased( $this->get_id() );
428 + // Clear cache count students many courses.
429 + $lp_courses_cache = new LP_Courses_Cache( true );
430 + $lp_courses_cache->clear_cache_on_group( LP_Courses_Cache::KEYS_COUNT_STUDENT_COURSES );
431 + $lp_course_cache->clear_cache_on_group( LP_Courses_Cache::KEYS_COUNT_COURSES_FREE );
432 + // Clear cache user course.
433 + $lp_user_items_cache = new LP_User_Items_Cache();
434 + $lp_user_items_cache->clean_user_items_by_course( $this->get_id() );
433 435 } catch ( Throwable $e ) {
434 436 error_log( __FUNCTION__ . ':' . $e->getMessage() );
435 437 }
436 438 }
@@ -459,8 +461,19 @@
459 461
460 462 // Delete on tb lp_user_items
461 463 $filter_delete = new LP_User_Items_Filter();
462 464 $filter_delete->user_item_ids = $user_item_ids_concat;
465 + $user_items_rs = $lp_user_items_db->get_user_items( $filter_delete );
466 +
467 + // For each to clear cache
468 + foreach ( $user_items_rs as $user_item ) {
469 + $lp_user_items_cache = new LP_User_Items_Cache();
470 + $key_one = "userItemModel/find/{$user_item->user_id}/{$user_item->item_id}/{$user_item->item_type}";
471 + $key_two = "userItemModel/find/{$user_item->user_id}/{$user_item->item_id}/{$user_item->item_type}/{$user_item->ref_id}/{$user_item->ref_type}";
472 + $lp_user_items_cache->clear( $key_one );
473 + $lp_user_items_cache->clear( $key_two );
474 + }
475 +
463 476 $lp_user_items_db->remove_user_item_ids( $filter_delete );
464 477
465 478 // Delete user_itemmeta
466 479 $lp_user_items_db->remove_user_itemmeta( $filter_delete );
@@ -472,8 +485,98 @@
472 485 }
473 486 }
474 487
475 488 /**
489 + * Handle params before query courses
490 + *
491 + * @param array $param
492 + * @param LP_Course_Filter $filter
493 + *
494 + * @return void
495 + * @since 4.2.3.3
496 + * @version 1.0.1
497 + * @deprecated 4.2.7.1
498 + */
499 + public static function handle_params_for_query_courses( LP_Course_Filter &$filter, array $param = [] ) {
500 + //_deprecated_function( __METHOD__, '4.2.7.1', 'Courses::handle_params_for_query_courses' );
501 + //return $filter;
502 +
503 + $filter->page = absint( $param['paged'] ?? 1 );
504 + $filter->post_title = LP_Helper::sanitize_params_submitted( trim( $param['c_search'] ?? '' ) );
505 +
506 + // Get Columns
507 + $fields_str = LP_Helper::sanitize_params_submitted( urldecode( $param['c_fields'] ?? '' ) );
508 + if ( ! empty( $fields_str ) ) {
509 + $fields = explode( ',', $fields_str );
510 + $filter->fields = $fields;
511 + }
512 +
513 + // Exclude Columns
514 + $fields_exclude_str = LP_Helper::sanitize_params_submitted( urldecode( $param['c_exclude_fields'] ?? '' ) );
515 + if ( ! empty( $fields_exclude_str ) ) {
516 + $fields_exclude = explode( ',', $fields_exclude_str );
517 + $filter->exclude_fields = $fields_exclude;
518 + }
519 +
520 + // Author
521 + $filter->post_author = LP_Helper::sanitize_params_submitted( $param['c_author'] ?? 0 );
522 + $author_ids_str = LP_Helper::sanitize_params_submitted( $param['c_authors'] ?? 0 );
523 + if ( ! empty( $author_ids_str ) ) {
524 + $author_ids = explode( ',', $author_ids_str );
525 + $filter->post_authors = $author_ids;
526 + }
527 +
528 + /**
529 + * Sort by
530 + * 1. on_sale
531 + * 2. on_free
532 + * 3. on_paid
533 + * 4. on_feature
534 + */
535 + if ( ! empty( $param['sort_by'] ) ) {
536 + $filter->sort_by[] = $param['sort_by'];
537 + }
538 +
539 + // Sort by level
540 + $levels_str = LP_Helper::sanitize_params_submitted( urldecode( $param['c_level'] ?? '' ) );
541 + if ( ! empty( $levels_str ) ) {
542 + $levels_str = str_replace( 'all', '', $levels_str );
543 + $levels = explode( ',', $levels_str );
544 + $filter->levels = $levels;
545 + }
546 +
547 + // Find by category
548 + $term_ids_str = LP_Helper::sanitize_params_submitted( urldecode( $param['term_id'] ?? '' ) );
549 + if ( ! empty( $term_ids_str ) ) {
550 + $term_ids = explode( ',', $term_ids_str );
551 + $filter->term_ids = $term_ids;
552 + }
553 +
554 + // Find by tag
555 + $tag_ids_str = LP_Helper::sanitize_params_submitted( urldecode( $param['tag_id'] ?? '' ) );
556 + if ( ! empty( $tag_ids_str ) ) {
557 + $tag_ids = explode( ',', $tag_ids_str );
558 + $filter->tag_ids = $tag_ids;
559 + }
560 +
561 + // Order by
562 + $filter->order_by = LP_Helper::sanitize_params_submitted( ! empty( $param['order_by'] ) ? $param['order_by'] : 'post_date', 'key' );
563 + $filter->order = LP_Helper::sanitize_params_submitted( ! empty( $param['order'] ) ? $param['order'] : 'DESC' );
564 + $filter->limit = $param['limit'] ?? LP_Settings::get_option( 'archive_course_limit', 10 );
565 +
566 + // For search suggest courses
567 + if ( ! empty( $param['c_suggest'] ) ) {
568 + $filter->only_fields = [ 'ID', 'post_title' ];
569 + $filter->limit = apply_filters( 'learn-press/rest-api/courses/suggest-limit', 10 );
570 + }
571 +
572 + $return_type = $param['return_type'] ?? 'html';
573 + if ( 'json' !== $return_type ) {
574 + $filter->only_fields = array( 'DISTINCT(ID) AS ID' );
575 + }
576 + }
577 +
578 + /**
476 579 * Get list course
477 580 * Order By: price, title, rating, date ...
478 581 * Order: ASC, DES
479 582 *
@@ -479,31 +582,36 @@
479 582 *
480 583 * @param LP_Course_Filter $filter
481 584 * @param int $total_rows
482 585 *
483 - * @return array|null|string|int
586 + * @return object|null|string|int
484 587 * @author tungnx
485 588 * @version 1.0.0
486 589 * @sicne 4.1.5
590 + * @deprecated 4.2.7.1
487 591 */
488 592 public static function get_courses( LP_Course_Filter $filter, int &$total_rows = 0 ) {
593 + //_deprecated_function( __METHOD__, '4.2.7.1', 'Courses::get_courses' );
594 + //return [];
595 +
489 596 $lp_course_db = LP_Course_DB::getInstance();
490 597
491 598 try {
492 - $key_cache = md5( json_encode( $filter ) );
493 - $key_cache_total_rows = md5( json_encode( $filter ) . 'total_rows' );
494 - $courses_cache = LP_Courses_Cache::instance()->get_cache( $key_cache );
599 + /*$lp_courses_cache = new LP_Courses_Cache( true );
600 + $key_cache = 'query-courses-' . md5( json_encode( $filter ) );
601 + $key_cache_total_rows = 'query-courses-total-' . md5( json_encode( $filter ) );
602 + $courses_cache = $lp_courses_cache->get_cache( $key_cache );
495 603
496 604 if ( false !== $courses_cache ) {
497 - $total_rows = LP_Courses_Cache::instance()->get_cache( $key_cache_total_rows );
498 - return $courses_cache;
499 - }
605 + $total_rows = $lp_courses_cache->get_cache( $key_cache_total_rows );
606 + return LP_Helper::json_decode( $courses_cache );
607 + }*/
500 608
501 609 // Sort by
502 610 $filter->sort_by = (array) $filter->sort_by;
503 611 foreach ( $filter->sort_by as $sort_by ) {
504 612 $filter_tmp = clone $filter;
505 - $filter_tmp->only_fields = array( 'ID' );
613 + $filter_tmp->only_fields = array( 'DISTINCT(ID)' );
506 614 $filter_tmp->return_string_query = true;
507 615
508 616 switch ( $sort_by ) {
509 617 case 'on_sale':
@@ -508,8 +616,14 @@
508 616 switch ( $sort_by ) {
509 617 case 'on_sale':
510 618 $filter_tmp = $lp_course_db->get_courses_sort_by_sale( $filter_tmp );
511 619 break;
620 + case 'on_free':
621 + $filter_tmp = $lp_course_db->get_courses_sort_by_free( $filter_tmp );
622 + break;
623 + case 'on_paid':
624 + $filter_tmp = $lp_course_db->get_courses_sort_by_paid( $filter_tmp );
625 + break;
512 626 case 'on_feature':
513 627 $filter_tmp = $lp_course_db->get_courses_sort_by_feature( $filter_tmp );
514 628 break;
515 629 default:
@@ -536,8 +650,19 @@
536 650 break;
537 651 case 'popular':
538 652 $filter = $lp_course_db->get_courses_order_by_popular( $filter );
539 653 break;
654 + case 'post_title':
655 + $filter->order = 'ASC';
656 + break;
657 + case 'post_title_desc':
658 + $filter->order_by = 'post_title';
659 + $filter->order = 'DESC';
660 + break;
661 + case 'menu_order':
662 + $filter->order_by = 'menu_order';
663 + $filter->order = 'ASC';
664 + break;
540 665 default:
541 666 $filter = apply_filters( 'lp/courses/filter/order_by/' . $filter->order_by, $filter );
542 667 break;
543 668 }
@@ -545,17 +670,10 @@
545 670 // Query get results
546 671 $filter = apply_filters( 'lp/courses/filter', $filter );
547 672 $courses = LP_Course_DB::getInstance()->get_courses( $filter, $total_rows );
548 673
549 - LP_Courses_Cache::instance()->set_cache( $key_cache, $courses );
550 - LP_Courses_Cache::instance()->set_cache( $key_cache_total_rows, $total_rows );
551 -
552 - /**
553 - * Save key cache to array to clear
554 - * @see LP_Background_Single_Course::save_post() - clear cache when save post
555 - */
556 - LP_Courses_Cache::instance()->save_cache_keys( $key_cache );
557 - LP_Courses_Cache::instance()->save_cache_keys( $key_cache_total_rows );
674 + //$lp_courses_cache->set_cache( $key_cache, json_encode( $courses ) );
675 + //$lp_courses_cache->set_cache( $key_cache_total_rows, $total_rows );
558 676 } catch ( Throwable $e ) {
559 677 $courses = [];
560 678 error_log( __FUNCTION__ . ': ' . $e->getMessage() );
561 679 }
@@ -567,16 +685,19 @@
567 685 * Get full sections, items of course via Cache, extra info (if it has)
568 686 *
569 687 * @return array
570 688 * @since 4.1.6.9
571 - * @version 1.0.0
689 + * @version 1.0.1
572 690 * @author tungnx
573 691 */
574 - public function get_full_sections_and_items_course(): array {
692 + public function get_full_sections_and_items_course() {
575 693 $sections_items = [];
576 694 $course_id = $this->get_id();
577 695
578 696 try {
697 + $courseModel = CourseModel::find( $course_id, true );
698 + return $courseModel->get_section_items();
699 +
579 700 // Get cache
580 701 $lp_course_cache = LP_Course_Cache::instance();
581 702 $key_cache = "$course_id/sections_items";
582 703 $sections_items = $lp_course_cache->get_cache( $key_cache );
@@ -636,14 +757,18 @@
636 757 $item->order = $sections_item->item_order;
637 758 $item->type = $sections_item->item_type;
638 759
639 760 if ( $section_new != $section_current ) {
640 - $sections_items[ $section_new ] = new stdClass();
641 - $sections_items[ $section_new ]->id = $section_new;
642 - $sections_items[ $section_new ]->order = $section_order;
643 - $sections_items[ $section_new ]->title = html_entity_decode( $sections_item->section_name );
644 - $sections_items[ $section_new ]->description = html_entity_decode( $sections_item->section_description );
645 - $sections_items[ $section_new ]->items = [];
761 + $sections_items[ $section_new ] = new stdClass();
762 + $sections_items[ $section_new ]->id = $section_new; // old field will be deprecated in future
763 + $sections_items[ $section_new ]->section_id = $section_new; // new field
764 + $sections_items[ $section_new ]->order = $section_order; // old field will be deprecated in future
765 + $sections_items[ $section_new ]->section_order = $section_order; // new field
766 + $sections_items[ $section_new ]->title = html_entity_decode( $sections_item->section_name ); // old field will be deprecated in future
767 + $sections_items[ $section_new ]->section_name = html_entity_decode( $sections_item->section_name ); // new field
768 + $sections_items[ $section_new ]->description = html_entity_decode( $sections_item->section_description ); // old field will be deprecated in future
769 + $sections_items[ $section_new ]->section_description = html_entity_decode( $sections_item->section_description ); // new field
770 + $sections_items[ $section_new ]->items = [];
646 771
647 772 // Sort item by item_order
648 773 if ( $section_current != 0 ) {
649 774 usort(
@@ -705,10 +830,10 @@
705 830
706 831 /**
707 832 * Get sections of course.
708 833 *
709 - * @param string $return - Optional.
710 - * @param int $section_id - Optional.
834 + * @param string $return.
835 + * @param int $section_id.
711 836 *
712 837 * @return array|bool|LP_Course_Section[]|LP_Course_Section
713 838 * @version 4.0.0
714 839 */
@@ -869,7 +994,108 @@
869 994 * @deprecated
870 995 */
871 996 public function get_curriculum_items( $type = '' ) {
872 997 return $this->get_items( $type );
998 + }
999 +
1000 + /**
1001 + * Get evaluation type
1002 + *
1003 + * @since 4.2.1
1004 + * @version 1.0.0
1005 + * @return string
1006 + */
1007 + public function get_evaluation_type(): string {
1008 + $evaluation_type = get_post_meta( $this->get_id(), '_lp_course_result', true );
1009 + if ( ! $evaluation_type ) {
1010 + $evaluation_type = 'evaluate_lesson';
1011 + }
1012 +
1013 + return $evaluation_type;
1014 + }
1015 +
1016 + /**
1017 + * Get categories of course.
1018 + *
1019 + * @since 4.2.3
1020 + * @version 1.0.0
1021 + * @return array|WP_Term[]
1022 + */
1023 + public function get_categories(): array {
1024 + // Todo: set cache.
1025 + $categories = get_the_terms( $this->get_id(), LP_COURSE_CATEGORY_TAX );
1026 + if ( ! $categories ) {
1027 + $categories = array();
1028 + }
1029 +
1030 + return $categories;
1031 + }
1032 +
1033 + /**
1034 + * Get tags of course.
1035 + *
1036 + * @since 4.2.3
1037 + * @version 1.0.0
1038 + * @return array|WP_Term[]
1039 + */
1040 + public function get_tags(): array {
1041 + // Todo: set cache.
1042 + $tags = get_the_terms( $this->get_id(), LP_COURSE_TAXONOMY_TAG );
1043 + if ( ! $tags ) {
1044 + $tags = array();
1045 + }
1046 +
1047 + return $tags;
1048 + }
1049 +
1050 + /**
1051 + * Get all categories.
1052 + *
1053 + * @return array
1054 + */
1055 + public static function get_all_categories(): array {
1056 + // Todo: set cache.
1057 + $categories = get_terms( LP_COURSE_CATEGORY_TAX );
1058 + if ( ! $categories ) {
1059 + $categories = array();
1060 + }
1061 +
1062 + return $categories;
1063 + }
1064 +
1065 + /**
1066 + * Get all curriculum of this course.
1067 + *
1068 + * @return bool|LP_Course_Section
1069 + * @since 4.2.3.5
1070 + */
1071 + public function get_level(): string {
1072 + $level = get_post_meta( $this->get_id(), '_lp_level', true );
1073 + if ( ! $level ) {
1074 + $level = '';
1075 + }
1076 +
1077 + return $level;
1078 + }
1079 +
1080 + /**
1081 + * Get duration of this course.
1082 + *
1083 + * @return bool|LP_Course_Section
1084 + * @since 4.2.3.5
1085 + */
1086 + public function get_duration(): string {
1087 + $duration = get_post_meta( $this->get_id(), '_lp_duration', true );
1088 +
1089 + return $duration;
1090 + }
1091 +
1092 + /**
1093 + * Check if a course is enabled Offline
1094 + *
1095 + * @return bool
1096 + */
1097 + public function is_offline(): bool {
1098 + return get_post_meta( $this->get_id(), CoursePostModel::META_KEY_OFFLINE_COURSE, 'no' ) === 'yes';
873 1099 }
874 1100 }
875 1101 }