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 +295 -70 4.2.04.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
@@ -234,13 +237,13 @@
234 237 public function enable_block_item_when_finish(): bool {
235 238 return 'yes' === $this->get_data( 'block_course_finished' );
236 239 }
237 240
238 - public function allow_repurchase() : bool {
241 + public function allow_repurchase(): bool {
239 242 return 'yes' === $this->get_data( 'allow_repurchase' );
240 243 }
241 244
242 - public function allow_repurchase_course_option() : string {
245 + public function allow_repurchase_course_option(): string {
243 246 return $this->get_data( 'allow_repurchase_course_option', 'reset' );
244 247 }
245 248
246 249 /**
@@ -248,14 +251,17 @@
248 251 *
249 252 * @author tungnx
250 253 * @since 4.0.0
251 254 * @modify 4.1.3
252 - * @version 1.0.1
255 + * @version 1.0.2
253 256 * @return int
254 257 */
255 258 public function get_first_item_id(): int {
256 259 $course_id = $this->get_id();
257 260
261 + $courseModel = CourseModel::find( $course_id, true );
262 + return $courseModel->get_first_item_id();
263 +
258 264 try {
259 265 // Get cache
260 266 $lp_course_cache = LP_Course_Cache::instance();
261 267 $key_cache = "$course_id/first_item_id";
@@ -304,8 +310,9 @@
304 310 * @since 4.1.3
305 311 * @author tungnx
306 312 * @version 1.0.0
307 313 * @return LP_Course_Extra_Info_Fast_Query_Model
314 + * @deprecated 4.2.7.4
308 315 */
309 316 public function get_info_extra_for_fast_query(): LP_Course_Extra_Info_Fast_Query_Model {
310 317 $extra_info = new LP_Course_Extra_Info_Fast_Query_Model();
311 318
@@ -311,19 +318,14 @@
311 318
312 319 try {
313 320 $extra_info_str = get_post_meta( $this->get_id(), $this->key_info_extra_fast_query, true );
314 321
315 - if ( $extra_info_str ) {
316 - $extra_info_stdclass = json_decode( $extra_info_str );
317 -
318 - if ( JSON_ERROR_NONE !== json_last_error() ) {
319 - throw new Exception( 'Error json decode on ' . __METHOD__ );
320 - }
321 -
322 - $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 );
323 325 }
324 326 } catch ( Throwable $e ) {
325 - error_log( $e->getMessage() );
327 + error_log( __METHOD__ . ': ' . $e->getMessage() );
326 328 }
327 329
328 330 return $extra_info;
329 331 }
@@ -354,49 +356,36 @@
354 356 * Get info total items of Course
355 357 *
356 358 * @param string $type
357 359 * @param bool $include_preview
360 + *
361 + * @return int
362 + * @throws Exception
363 + * @version 1.0.1
358 364 * @author tungnx
359 365 * @since 4.1.4.1
360 - * @version 1.0.0
361 - * @return int
362 366 */
363 367 public function count_items( string $type = '', bool $include_preview = true ): int {
364 - $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 + }
365 373
366 - // Get cache
367 - $lp_course_cache = LP_Course_Cache::instance();
368 - $key_cache = "$course_id/total_items";
369 - $total_items = $lp_course_cache->get_cache( $key_cache );
370 - $count_items = 0;
371 -
372 - if ( ! $total_items ) {
373 - $extra_info = $this->get_info_extra_for_fast_query();
374 -
375 - if ( ! $extra_info->total_items ) {
376 - $total_items = LP_Course_DB::getInstance()->get_total_items( $course_id );
377 - $extra_info->total_items = $total_items;
378 -
379 - // Save post meta
380 - $this->set_info_extra_for_fast_query( $extra_info );
381 - } else {
382 - $total_items = $extra_info->total_items;
383 - }
384 -
385 - $lp_course_cache->set_cache( $key_cache, $total_items );
374 + $total_items = $courseModel->get_total_items();
375 + if ( empty( $total_items ) ) {
376 + return 0;
386 377 }
387 378
388 - if ( ! empty( $total_items ) ) {
389 - if ( ! empty( $type ) ) {
390 - if ( isset( $total_items->{$type} ) ) {
391 - $count_items = $total_items->{$type};
392 - }
393 - } else {
394 - $count_items = $total_items->count_items;
379 + if ( ! empty( $type ) ) {
380 + if ( isset( $total_items->{$type} ) ) {
381 + return $total_items->{$type};
395 382 }
383 + } else {
384 + return $total_items->count_items ?? 0;
396 385 }
397 386
398 - return apply_filters( 'learn-press/course/count-items', intval( $count_items ), $course_id );
387 + return 0;
399 388 }
400 389
401 390 /**
402 391 * Delete relate data when delete course
@@ -430,8 +419,20 @@
430 419 $filter_user_items->item_id = $this->get_id();
431 420 $user_course_ids = $lp_user_items_db->get_user_items_by_course( $filter_user_items );
432 421
433 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() );
434 435 } catch ( Throwable $e ) {
435 436 error_log( __FUNCTION__ . ':' . $e->getMessage() );
436 437 }
437 438 }
@@ -460,8 +461,19 @@
460 461
461 462 // Delete on tb lp_user_items
462 463 $filter_delete = new LP_User_Items_Filter();
463 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 +
464 476 $lp_user_items_db->remove_user_item_ids( $filter_delete );
465 477
466 478 // Delete user_itemmeta
467 479 $lp_user_items_db->remove_user_itemmeta( $filter_delete );
@@ -473,8 +485,98 @@
473 485 }
474 486 }
475 487
476 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 + /**
477 579 * Get list course
478 580 * Order By: price, title, rating, date ...
479 581 * Order: ASC, DES
480 582 *
@@ -480,31 +582,36 @@
480 582 *
481 583 * @param LP_Course_Filter $filter
482 584 * @param int $total_rows
483 585 *
484 - * @return array|null|string|int
586 + * @return object|null|string|int
485 587 * @author tungnx
486 588 * @version 1.0.0
487 589 * @sicne 4.1.5
590 + * @deprecated 4.2.7.1
488 591 */
489 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 +
490 596 $lp_course_db = LP_Course_DB::getInstance();
491 597
492 598 try {
493 - $key_cache = md5( json_encode( $filter ) );
494 - $key_cache_total_rows = md5( json_encode( $filter ) . 'total_rows' );
495 - $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 );
496 603
497 604 if ( false !== $courses_cache ) {
498 - $total_rows = LP_Courses_Cache::instance()->get_cache( $key_cache_total_rows );
499 - return $courses_cache;
500 - }
605 + $total_rows = $lp_courses_cache->get_cache( $key_cache_total_rows );
606 + return LP_Helper::json_decode( $courses_cache );
607 + }*/
501 608
502 609 // Sort by
503 610 $filter->sort_by = (array) $filter->sort_by;
504 611 foreach ( $filter->sort_by as $sort_by ) {
505 612 $filter_tmp = clone $filter;
506 - $filter_tmp->only_fields = array( 'ID' );
613 + $filter_tmp->only_fields = array( 'DISTINCT(ID)' );
507 614 $filter_tmp->return_string_query = true;
508 615
509 616 switch ( $sort_by ) {
510 617 case 'on_sale':
@@ -509,8 +616,14 @@
509 616 switch ( $sort_by ) {
510 617 case 'on_sale':
511 618 $filter_tmp = $lp_course_db->get_courses_sort_by_sale( $filter_tmp );
512 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;
513 626 case 'on_feature':
514 627 $filter_tmp = $lp_course_db->get_courses_sort_by_feature( $filter_tmp );
515 628 break;
516 629 default:
@@ -537,8 +650,19 @@
537 650 break;
538 651 case 'popular':
539 652 $filter = $lp_course_db->get_courses_order_by_popular( $filter );
540 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;
541 665 default:
542 666 $filter = apply_filters( 'lp/courses/filter/order_by/' . $filter->order_by, $filter );
543 667 break;
544 668 }
@@ -546,17 +670,10 @@
546 670 // Query get results
547 671 $filter = apply_filters( 'lp/courses/filter', $filter );
548 672 $courses = LP_Course_DB::getInstance()->get_courses( $filter, $total_rows );
549 673
550 - LP_Courses_Cache::instance()->set_cache( $key_cache, $courses );
551 - LP_Courses_Cache::instance()->set_cache( $key_cache_total_rows, $total_rows );
552 -
553 - /**
554 - * Save key cache to array to clear
555 - * @see LP_Background_Single_Course::save_post() - clear cache when save post
556 - */
557 - LP_Courses_Cache::instance()->save_cache_keys( $key_cache );
558 - 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 );
559 676 } catch ( Throwable $e ) {
560 677 $courses = [];
561 678 error_log( __FUNCTION__ . ': ' . $e->getMessage() );
562 679 }
@@ -568,16 +685,19 @@
568 685 * Get full sections, items of course via Cache, extra info (if it has)
569 686 *
570 687 * @return array
571 688 * @since 4.1.6.9
572 - * @version 1.0.0
689 + * @version 1.0.1
573 690 * @author tungnx
574 691 */
575 - public function get_full_sections_and_items_course(): array {
692 + public function get_full_sections_and_items_course() {
576 693 $sections_items = [];
577 694 $course_id = $this->get_id();
578 695
579 696 try {
697 + $courseModel = CourseModel::find( $course_id, true );
698 + return $courseModel->get_section_items();
699 +
580 700 // Get cache
581 701 $lp_course_cache = LP_Course_Cache::instance();
582 702 $key_cache = "$course_id/sections_items";
583 703 $sections_items = $lp_course_cache->get_cache( $key_cache );
@@ -637,14 +757,18 @@
637 757 $item->order = $sections_item->item_order;
638 758 $item->type = $sections_item->item_type;
639 759
640 760 if ( $section_new != $section_current ) {
641 - $sections_items[ $section_new ] = new stdClass();
642 - $sections_items[ $section_new ]->id = $section_new;
643 - $sections_items[ $section_new ]->order = $section_order;
644 - $sections_items[ $section_new ]->title = html_entity_decode( $sections_item->section_name );
645 - $sections_items[ $section_new ]->description = html_entity_decode( $sections_item->section_description );
646 - $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 = [];
647 771
648 772 // Sort item by item_order
649 773 if ( $section_current != 0 ) {
650 774 usort(
@@ -706,10 +830,10 @@
706 830
707 831 /**
708 832 * Get sections of course.
709 833 *
710 - * @param string $return - Optional.
711 - * @param int $section_id - Optional.
834 + * @param string $return.
835 + * @param int $section_id.
712 836 *
713 837 * @return array|bool|LP_Course_Section[]|LP_Course_Section
714 838 * @version 4.0.0
715 839 */
@@ -870,7 +994,108 @@
870 994 * @deprecated
871 995 */
872 996 public function get_curriculum_items( $type = '' ) {
873 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';
874 1099 }
875 1100 }
876 1101 }