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/user/class-lp-user.php +239 -90 4.2.04.4.8 View file →
@@ -1,6 +1,10 @@
1 1 <?php
2 2
3 +use LearnPress\Filters\FilterBase;
4 +use LearnPress\Filters\UserItemsFilter;
5 +use LearnPress\Models\UserModel;
6 +
3 7 /**
4 8 * Class LP_User
5 9 *
6 10 * @author ThimPress
@@ -23,9 +27,8 @@
23 27 'learnpress'
24 28 );
25 29
26 30 $course = learn_press_get_course( $course_id );
27 -
28 31 if ( ! $course ) {
29 32 return $view;
30 33 }
31 34
@@ -90,9 +93,9 @@
90 93
91 94 /**
92 95 * Check the user can access to an item inside course.
93 96 *
94 - * @param int $item_id Course's item Id.
97 + * @param int $item_id Course's item Id.
95 98 * @param LP_Model_User_Can_View_Course_Item $view Course Id.
96 99 *
97 100 * @author tungnx
98 101 * @return LP_Model_User_Can_View_Course_Item
@@ -121,9 +124,9 @@
121 124 if ( $view_new ) {
122 125 $view = $view_new;
123 126 }
124 127
125 - return apply_filters( 'learnpress/course/item/can-view', $view, $item );
128 + return apply_filters( 'learnpress/course/item/can-view', $view, $item, $this );
126 129 }
127 130
128 131 /**
129 132 * Check if user can retry course.
@@ -130,9 +133,8 @@
130 133 *
131 134 * @param int $course_id .
132 135 *
133 136 * @return int
134 - * @throws Exception .
135 137 * @since 4.0.0
136 138 * @author tungnx
137 139 */
138 140 public function can_retry_course( int $course_id = 0 ): int {
@@ -195,8 +197,9 @@
195 197 * Check course is enrolled
196 198 *
197 199 * @param integer $course_id Course ID
198 200 * @param boolean $return_bool
201 + *
199 202 * @return bool|object
200 203 * @editor tungnx
201 204 * @since 4.1.2
202 205 * @version 1.0.2
@@ -215,9 +218,8 @@
215 218 throw new Exception( esc_html__( 'Order is not completed', 'learnpress' ) );
216 219 }*/
217 220
218 221 $user_course = $this->get_course_data( $course_id );
219 -
220 222 if ( ! $user_course || ! $user_course->is_enrolled() ) {
221 223 throw new Exception( esc_html__( 'The course is not enrolled.', 'learnpress' ) );
222 224 }
223 225 } catch ( Throwable $th ) {
@@ -235,9 +237,9 @@
235 237 *
236 238 * @return bool
237 239 * @throws Exception
238 240 */
239 - public function has_finished_course( int $course_id ) : bool {
241 + public function has_finished_course( int $course_id ): bool {
240 242 $user_course = $this->get_course_data( $course_id );
241 243
242 244 return apply_filters( 'learn-press/user-has-finished-course', $user_course && $user_course->is_finished(), $this->get_id(), $course_id );
243 245 }
@@ -269,10 +271,11 @@
269 271
270 272 /**
271 273 * Check user can enroll course
272 274 *
273 - * @param int $course_id
275 + * @param int $course_id
274 276 * @param bool $return_bool
277 + *
275 278 * @return mixed|object|bool
276 279 */
277 280 public function can_enroll_course( int $course_id, bool $return_bool = true ) {
278 281 $course = learn_press_get_course( $course_id );
@@ -280,35 +283,53 @@
280 283 $output->check = true;
281 284 $output->message = '';
282 285
283 286 try {
287 + $is_no_required_enroll = $course->get_data( 'no_required_enroll', 'no' ) === 'yes';
284 288 if ( ! $course ) {
289 + $output->code = 'course_unavailable';
285 290 throw new Exception( esc_html__( 'No Course or User available', 'learnpress' ) );
286 291 }
287 292
288 293 if ( ! $course->is_publish() ) {
294 + $output->code = 'course_not_publish';
289 295 throw new Exception( esc_html__( 'The course is not public', 'learnpress' ) );
290 296 }
291 297
292 - if ( $course->get_external_link() && ! $this->has_purchased_course( $course_id ) ) {
293 - throw new Exception( esc_html__( 'The course is external', 'learnpress' ) );
298 + if ( $this->has_enrolled_course( $course_id ) ) {
299 + $output->code = 'course_is_enrolled';
300 + throw new Exception( esc_html__( 'This course is already enrolled.', 'learnpress' ) );
294 301 }
295 302
296 - if ( ! $course->is_in_stock() ) {
303 + if ( ! $course->is_in_stock_enroll() && ! $this->has_purchased_course( $course_id )
304 + && ! $this->has_enrolled_or_finished( $course_id ) && ! $is_no_required_enroll ) {
305 + $output->code = 'course_out_of_stock';
297 306 throw new Exception( esc_html__( 'The course is full of students.', 'learnpress' ) );
298 307 }
299 308
300 - if ( $course->is_no_required_enroll() ) {
301 - throw new Exception( esc_html__( 'The course is not required to enroll.', 'learnpress' ) );
309 + if ( $course->get_external_link()
310 + && ! $this->has_purchased_course( $course_id )
311 + && ! $course->is_offline() ) {
312 + $output->code = 'course_is_external';
313 + throw new Exception( esc_html__( 'The course is external', 'learnpress' ) );
302 314 }
303 315
304 - if ( ! $course->is_free() && ! $this->has_purchased_course( $course_id ) ) {
305 - throw new Exception( esc_html__( 'The course is not purchased.', 'learnpress' ) );
316 + if ( $this->can_retry_course( $course_id ) ) {
317 + $output->code = 'course_can_retry';
318 + throw new Exception( esc_html__( 'Course can retake.', 'learnpress' ) );
306 319 }
307 320
308 - if ( $this->has_enrolled_course( $course_id ) ) {
309 - throw new Exception( esc_html__( 'This course is already enrolled.', 'learnpress' ) );
321 + if ( $is_no_required_enroll && ! is_user_logged_in() ) {
322 + $output->code = 'course_is_no_required_enroll_not_login';
323 + throw new Exception(
324 + esc_html__( 'Enrollment in the course is not mandatory. You can access course for learning now.', 'learnpress' )
325 + );
310 326 }
327 +
328 + if ( ! $course->is_free() && ! $is_no_required_enroll && ! $this->has_purchased_course( $course_id ) ) {
329 + $output->code = 'course_is_not_purchased';
330 + throw new Exception( esc_html__( 'The course is not purchased.', 'learnpress' ) );
331 + }
311 332 } catch ( \Throwable $th ) {
312 333 $output->check = false;
313 334 $output->message = $th->getMessage();
314 335 }
@@ -323,92 +344,75 @@
323 344 /**
324 345 * Check can show purchase course button
325 346 *
326 347 * @param int $course_id
327 - * @return bool
328 - * @throws Exception
348 + *
349 + * @return bool|WP_Error
329 350 * @author nhamdv
330 351 * @editor tungnx
331 - * @modify 4.1.4
332 - * @version 1.0.3
352 + * @since 4.0.8
353 + * @version 1.0.6
333 354 */
334 - public function can_purchase_course( int $course_id = 0 ): bool {
355 + public function can_purchase_course( int $course_id = 0 ) {
335 356 $can_purchase = true;
336 357 $course = learn_press_get_course( $course_id );
358 + $code_err = '';
337 359
338 360 try {
339 - if ( ! $course ) {
340 - throw new Exception( 'Course is unavailable' );
361 + $can_enroll_course = $this->can_enroll_course( $course_id, false );
362 + if ( ! $can_enroll_course->check &&
363 + ! in_array( $can_enroll_course->code, [ 'course_is_not_purchased', 'course_is_enrolled' ] ) ) {
364 + $code_err = $can_enroll_course->code;
365 + throw new Exception( $can_enroll_course->message );
341 366 }
342 367
343 - if ( ! $course->is_publish() ) {
344 - throw new Exception( 'Course is not publish' );
345 - }
346 -
347 368 if ( $course->is_free() ) {
348 - throw new Exception( 'Course is free' );
369 + $code_err = 'course_is_free';
370 + throw new Exception( __( 'Course is free, so you can not purchase', 'learnpress' ) );
349 371 }
350 372
351 - if ( $course->get_external_link() ) {
352 - throw new Exception( 'Course is type external, so can not purchase' );
353 - }
354 -
355 373 // Course is not require enrolling.
356 - if ( $course->is_no_required_enroll() ) {
357 - throw new Exception( 'Course is type no required enroll' );
358 - }
359 -
360 - if ( $this->can_retry_course( $course_id ) ) {
361 - throw new Exception( 'Course is has retake' );
362 - }
363 -
364 - // If course is reached limitation.
365 - if ( ! $course->is_in_stock() ) {
366 - $message = apply_filters(
367 - 'learn-press/maximum-students-reach',
368 - esc_html__( 'This course is out of stock', 'learnpress' )
374 + // Not use $course->is_no_required_enroll() because it is not correct, it check with user logged.
375 + if ( $course->get_data( 'no_required_enroll', 'no' ) === 'yes' ) {
376 + $code_err = 'no_required_enroll';
377 + throw new Exception(
378 + __(
379 + 'Enrollment in the course is not mandatory. You can access materials for learning or to take quizzes now.',
380 + 'learnpress'
381 + )
369 382 );
370 -
371 - if ( $message ) {
372 - learn_press_display_message( $message );
373 - }
374 -
375 - throw new Exception( $message );
376 383 }
377 384
378 385 // If the order contains course is processing
379 386 $order = $this->get_course_order( $course_id );
380 - if ( $order && $order->get_status() === 'processing' ) {
381 - $message = apply_filters(
382 - 'learn-press/order-processing-message',
383 - __( 'Your order is waiting for processing', 'learnpress' )
384 - );
385 -
386 - if ( $message ) {
387 - learn_press_display_message( $message );
388 - }
389 -
390 - throw new Exception( $message );
387 + if ( $order && $order->get_status() === LP_ORDER_PROCESSING ) {
388 + $code_err = 'order_processing';
389 + throw new Exception( __( 'Your order is waiting for processing', 'learnpress' ) );
391 390 }
392 391
393 392 if ( $this->has_purchased_course( $course_id ) ) {
394 - throw new Exception( 'Course is purchased' );
393 + $code_err = 'course_purchased';
394 + throw new Exception( __( 'Course is purchased', 'learnpress' ) );
395 395 }
396 396
397 397 $is_blocked_course = 0 === $course->timestamp_remaining_duration();
398 398 $is_enrolled_course = $this->has_enrolled_course( $course_id );
399 - $is_finished_course = $this->has_finished_course( $course_id );
400 -
401 399 if ( $course->allow_repurchase() ) {
402 400 if ( $is_enrolled_course && ! $is_blocked_course ) {
401 + $code_err = 'course_is_enrolled';
403 402 throw new Exception( 'Course is enrolled' );
404 403 }
405 404 } else {
406 405 if ( $this->has_enrolled_or_finished( $course_id ) ) {
407 - throw new Exception( 'Course is enrolled' );
406 + $code_err = 'course_is_enrolled_or_finished';
407 + throw new Exception( __( 'Course is enrolled or finished', 'learnpress' ) );
408 408 }
409 409 }
410 - } catch ( Exception $e ) {
410 + } catch ( Throwable $e ) {
411 + $can_purchase = new WP_Error( $code_err, $e->getMessage() );
412 + }
413 +
414 + if ( $can_purchase instanceof WP_Error ) {
411 415 $can_purchase = false;
412 416 }
413 417
414 418 return apply_filters( 'learn-press/user/can-purchase-course', $can_purchase, $this->get_id(), $course_id );
@@ -417,8 +421,9 @@
417 421 /**
418 422 * Check condition show finish course button
419 423 *
420 424 * @param $course
425 + *
421 426 * @return array
422 427 * @author nhamdv
423 428 * @editor tungnx
424 429 * @version 1.0.2
@@ -482,23 +487,24 @@
482 487
483 488 /**
484 489 * Start quiz for the user.
485 490 *
486 - * @param int $quiz_id
487 - * @param int $course_id
491 + * @param int $quiz_id
492 + * @param int $course_id
488 493 * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false.
489 494 *
490 495 * @return LP_User_Item_Quiz|bool|WP_Error
491 496 * @throws Exception
497 + * @deprecated 4.2.9.1
492 498 */
493 499 public function start_quiz( int $quiz_id, int $course_id = 0, bool $wp_error = false ) {
500 + _deprecated_function( __METHOD__, '4.2.9.1' );
501 + return false;
502 +
494 503 try {
495 - $item_id = learn_press_get_request( 'lp-preview' );
496 -
497 - if ( $item_id ) {
498 - learn_press_add_message( __( 'You cannot start a quiz in preview mode.', 'learnpress' ), 'error' );
499 - wp_safe_redirect( learn_press_get_preview_url( $item_id ) );
500 - exit();
504 + $item_is_preview = learn_press_get_request( 'lp-preview' );
505 + if ( $item_is_preview ) {
506 + throw new Exception( __( 'You cannot start a quiz in preview mode.', 'learnpress' ) );
501 507 }
502 508
503 509 // Validate course and quiz
504 510 $course_id = $this->_verify_course_item( $quiz_id, $course_id );
@@ -509,9 +515,8 @@
509 515 );
510 516 }
511 517
512 518 $course = learn_press_get_course( $course_id );
513 -
514 519 // If user has already finished the course
515 520 if ( $this->has_finished_course( $course_id ) ) {
516 521 throw new Exception(
517 522 __( 'You have already finished the course of this quiz', 'learnpress' ),
@@ -534,11 +539,11 @@
534 539 __( 'The user has started or completed the quiz.', 'learnpress' ),
535 540 LP_QUIZ_HAS_STARTED_OR_COMPLETED
536 541 );
537 542 }
538 - $user = learn_press_get_current_user();
539 543
540 - if ( $user->is_guest() ) {
544 + $user_current = learn_press_get_current_user();
545 + if ( $user_current->is_guest() ) {
541 546 // if course required enroll => print message "You have to login for starting quiz"
542 547 if ( ! $course->is_no_required_enroll() ) {
543 548 throw new Exception( __( 'You have to log in to start the quiz.', 'learnpress' ), LP_REQUIRE_LOGIN );
544 549 }
@@ -549,9 +554,9 @@
549 554 *
550 555 * @see learn_press_hk_before_start_quiz
551 556 */
552 557 $can_start_quiz = apply_filters(
553 - 'learn-press/before-start-quiz',
558 + 'learn-press/can-start-quiz',
554 559 true,
555 560 $quiz_id,
556 561 $course_id,
557 562 $this->get_id()
@@ -560,9 +565,9 @@
560 565 if ( ! $can_start_quiz ) {
561 566 return false;
562 567 }
563 568
564 - $user_quiz = learn_press_user_start_quiz( $quiz_id, false, $course_id, $wp_error );
569 + $user_quiz = false;
565 570
566 571 /**
567 572 * Hook quiz started
568 573 *
@@ -571,9 +576,9 @@
571 576 do_action( 'learn-press/user/quiz-started', $quiz_id, $course_id, $this->get_id() );
572 577
573 578 // $return = $user_quiz->get_mysql_data();
574 579 $return = $user_quiz;
575 - } catch ( Exception $ex ) {
580 + } catch ( Throwable $ex ) {
576 581 $return = $wp_error ? new WP_Error( $ex->getCode(), $ex->getMessage() ) : false;
577 582 }
578 583
579 584 return $return;
@@ -581,10 +586,10 @@
581 586
582 587 /**
583 588 * Finish a quiz for the user and save all data needed
584 589 *
585 - * @param int $quiz_id
586 - * @param int $course_id
590 + * @param int $quiz_id
591 + * @param int $course_id
587 592 * @param bool $wp_error
588 593 *
589 594 * @return LP_User_Item_Quiz|bool|WP_Error
590 595 */
@@ -625,17 +630,18 @@
625 630
626 631 /**
627 632 * Retake a quiz for the user
628 633 *
629 - * @param int $quiz_id
630 - * @param int $course_id
634 + * @param int $quiz_id
635 + * @param int $course_id
631 636 * @param bool $wp_error
632 637 *
633 638 * @return bool|WP_Error|LP_User_Item_Quiz
634 639 *
635 640 * @throws Exception
641 + * @deprecated 4.2.7.2
636 642 */
637 - public function retake_quiz( int $quiz_id, int $course_id, bool $wp_error = false ) {
643 + /*public function retake_quiz( int $quiz_id, int $course_id, bool $wp_error = false ) {
638 644 $return = false;
639 645
640 646 try {
641 647 $course_id = $this->_verify_course_item( $quiz_id, $course_id );
@@ -670,9 +676,9 @@
670 676 // Check if user has already started or completed quiz
671 677 if ( ! $this->has_item_status( array( 'completed' ), $quiz_id, $course_id ) ) {
672 678 throw new Exception(
673 679 sprintf(
674 - __( '%1$s::%2$s - The ser has not completed the quiz.', 'learnpress' ),
680 + __( '%1$s::%2$s - The user has not completed the quiz.', 'learnpress' ),
675 681 __CLASS__,
676 682 __FUNCTION__
677 683 ),
678 684 LP_QUIZ_HAS_STARTED_OR_COMPLETED
@@ -700,18 +706,18 @@
700 706 do_action( 'learn-press/user/retake-quiz-failure', $quiz_id, $course_id, $this->get_id() );
701 707 }
702 708
703 709 return $return;
704 - }
710 + }*/
705 711
706 712 /**
707 713 * Get quiz's user learning or completed
708 714 *
709 - * @param LP_User_Items_Filter $filter
715 + * @param LP_User_Items_Filter|UserItemsFilter $filter
710 716 *
711 717 * @return LP_Query_List_Table
712 718 */
713 - public function get_user_quizzes( LP_User_Items_Filter $filter ): LP_Query_List_Table {
719 + public function get_user_quizzes( $filter ): LP_Query_List_Table {
714 720 $quizzes = [
715 721 'total' => 0,
716 722 'items' => [],
717 723 'pages' => 0,
@@ -787,6 +793,149 @@
787 793 error_log( $e->getMessage() );
788 794 }
789 795
790 796 return $flag;
797 + }
798 +
799 + /**
800 + * Get statistic info of student user
801 + *
802 + * @return array
803 + * @since 4.1.6
804 + * @version 1.0.0
805 + */
806 + public function get_student_statistic(): array {
807 + $user = $this;
808 + $statistic = array(
809 + 'enrolled_courses' => 0,
810 + 'in_progress_course' => 0,
811 + 'finished_courses' => 0,
812 + 'passed_courses' => 0,
813 + 'failed_courses' => 0,
814 + );
815 +
816 + try {
817 + if ( ! $user ) {
818 + throw new Exception( 'The user is invalid' );
819 + }
820 +
821 + $user_id = $user->get_id();
822 + $lp_user_items_db = LP_User_Items_DB::getInstance();
823 +
824 + // Count status
825 + $filter = new LP_User_Items_Filter();
826 + $filter->user_id = $user_id;
827 + $count_status = $lp_user_items_db->count_status_by_items( $filter );
828 + $total_courses_enrolled = intval( $count_status->{LP_COURSE_PURCHASED} ?? 0 )
829 + + intval( $count_status->{LP_COURSE_ENROLLED} ?? 0 )
830 + + intval( $count_status->{LP_COURSE_FINISHED} ?? 0 );
831 +
832 + $statistic['enrolled_courses'] = $total_courses_enrolled;
833 + $statistic['in_progress_course'] = $count_status->{LP_COURSE_GRADUATION_IN_PROGRESS} ?? 0;
834 + $statistic['finished_courses'] = $count_status->{LP_COURSE_FINISHED} ?? 0;
835 + $statistic['passed_courses'] = $count_status->{LP_COURSE_GRADUATION_PASSED} ?? 0;
836 + $statistic['failed_courses'] = $count_status->{LP_COURSE_GRADUATION_FAILED} ?? 0;
837 + } catch ( Throwable $e ) {
838 + error_log( __FUNCTION__ . ': ' . $e->getMessage() );
839 + }
840 +
841 + return apply_filters( 'lp/profile/student/statistic', $statistic, $this );
842 + }
843 +
844 + /**
845 + * Get statistic info of instructor user
846 + *
847 + * @param array $params
848 + *
849 + * @return array
850 + * @since 4.1.6
851 + * @version 1.0.1
852 + */
853 + public function get_instructor_statistic( array $params = [] ): array {
854 + $statistic = array(
855 + 'total_course' => 0,
856 + 'published_course' => 0,
857 + 'pending_course' => 0,
858 + 'total_student' => 0,
859 + 'student_completed' => 0,
860 + 'student_in_progress' => 0,
861 + );
862 +
863 + try {
864 + $user_id = $this->get_id();
865 + $lp_user_items_db = LP_User_Items_DB::getInstance();
866 + $lp_course_db = LP_Course_DB::getInstance();
867 +
868 + if ( ! $this->can_create_course() ) {
869 + throw new Exception( 'The user is not Instructor' );
870 + }
871 +
872 + // Count total user completed course of author
873 + $filter_course = new LP_Course_Filter();
874 + $filter_course->only_fields = array( 'ID' );
875 + $filter_course->post_author = $user_id;
876 + $filter_course->post_status = 'publish';
877 + $filter_course->return_string_query = true;
878 + $query_courses_str = LP_Course_DB::getInstance()->get_courses( $filter_course );
879 +
880 + $filter_count_users = new LP_User_Items_Filter();
881 + $filter_count_users->item_type = LP_COURSE_CPT;
882 + $filter_count_users->where[] = "AND item_id IN ({$query_courses_str})";
883 + $count_student_has_status = $lp_user_items_db->count_status_by_items( $filter_count_users );
884 + // Count total user in progress course of author
885 +
886 + // Get total users attend course of author
887 + $filter_count_users = $lp_user_items_db->count_user_attend_courses_of_author( $user_id );
888 + $count_users_attend_courses_of_author = $lp_user_items_db->get_user_courses( $filter_count_users );
889 +
890 + // Get total courses publish of author
891 + $filter_count_courses = $lp_course_db->count_courses_of_author( $user_id, [ 'publish' ] );
892 + $total_courses_publish_of_author = $lp_course_db->get_courses( $filter_count_courses );
893 +
894 + // Get total courses of author
895 + $filter_count_courses = $lp_course_db->count_courses_of_author( $user_id );
896 + $total_courses_of_author = $lp_course_db->get_courses( $filter_count_courses );
897 +
898 + // Get total courses pending of author
899 + $filter_count_courses = $lp_course_db->count_courses_of_author( $user_id, [ 'pending' ] );
900 + $total_courses_pending_of_author = $lp_course_db->get_courses( $filter_count_courses );
901 +
902 + $statistic['total_course'] = $total_courses_of_author;
903 + $statistic['published_course'] = $total_courses_publish_of_author;
904 + $statistic['pending_course'] = $total_courses_pending_of_author;
905 + $statistic['total_student'] = $count_users_attend_courses_of_author;
906 + $statistic['student_completed'] = $count_student_has_status->{LP_COURSE_FINISHED} ?? 0;
907 + $statistic['student_in_progress'] = $count_student_has_status->{LP_COURSE_GRADUATION_IN_PROGRESS} ?? 0;
908 + } catch ( Throwable $e ) {
909 + error_log( __FUNCTION__ . ': ' . $e->getMessage() );
910 + }
911 +
912 + return apply_filters( 'lp/profile/instructor/statistic', $statistic, $this );
913 + }
914 +
915 + /**
916 + * Get url instructor.
917 + *
918 + * @return string
919 + * @version 1.0.1
920 + * @since 4.2.3
921 + */
922 + public function get_url_instructor(): string {
923 + $single_instructor_link = '';
924 +
925 + try {
926 + $author_id = $this->get_id();
927 + $userModel = UserModel::find( $author_id, true );
928 + if ( ! $userModel ) {
929 + throw new Exception( 'User not found' );
930 + }
931 +
932 + $single_instructor_page_id = learn_press_get_page_id( 'single_instructor' );
933 + $user_slug = $userModel->get_slug_link();
934 + $single_instructor_link = trailingslashit( trailingslashit( get_page_link( $single_instructor_page_id ) ) . $user_slug );
935 + } catch ( Throwable $e ) {
936 + LP_Debug::error_log( $e );
937 + }
938 +
939 + return $single_instructor_link;
791 940 }
792 941 }