From 98052a166a44cae2af088b24dbec856f76d9510b Mon Sep 17 00:00:00 2001 From: Jobayer Al Madmud Tuser <43468537+Jobayer-Tuser@users.noreply.github.com> Date: Mon, 15 May 2023 18:13:30 +0600 Subject: [PATCH 01/78] Date formate showing wrong after translation The announcement publish date format is showing wrong if someone translating the tutor. I have modified the code now the translation will work in a proper format. --- templates/single/course/enrolled/announcements.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/single/course/enrolled/announcements.php b/templates/single/course/enrolled/announcements.php index c3ea028c3a..3950085d13 100644 --- a/templates/single/course/enrolled/announcements.php +++ b/templates/single/course/enrolled/announcements.php @@ -36,7 +36,7 @@
- post_date_gmt ) ) . __(' ago', 'tutor' ) ); ?> + post_date_gmt ) ) ) ); ?>
From a035d4469cc572bb7294fa97530acedca087f3ee Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Fri, 28 Jul 2023 15:41:27 +0600 Subject: [PATCH 02/78] remove key sanitize --- views/options/field-types/text.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/options/field-types/text.php b/views/options/field-types/text.php index 1321110549..a79532eb7d 100644 --- a/views/options/field-types/text.php +++ b/views/options/field-types/text.php @@ -9,7 +9,7 @@ * @since 2.0.0 */ -$field_key = sanitize_key( $field['key'] ); +$field_key = $field['key']; $default = isset( $field['default'] ) ? $field['default'] : false; $value = $this->get( $field_key, $default ); $field_id = esc_attr( 'field_' . $field_key ); From 02e2b8817f67b26ce408a3af8621fca48189bec8 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Fri, 28 Jul 2023 15:42:36 +0600 Subject: [PATCH 03/78] new course enrollment email issue fix --- classes/WooCommerce.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/classes/WooCommerce.php b/classes/WooCommerce.php index 765dcae09a..4d497f90b4 100644 --- a/classes/WooCommerce.php +++ b/classes/WooCommerce.php @@ -359,17 +359,14 @@ public function enrolled_courses_status_change( $order_id, $status_from, $status * @since v2.0.5 */ if ( self::should_order_auto_complete( $order_id ) ) { + // Mark enrollment as completed. tutor_utils()->course_enrol_status_change( $enrolled_id, 'completed' ); - // Mark complete only from client side. - $mark_completed = self::mark_order_complete( $order_id ); - if ( $mark_completed ) { - $user_id = get_post_field( 'post_author', $enrolled_id ); - $course_id = get_post_field( 'post_parent', $enrolled_id ); - do_action( 'tutor_after_enrolled', $course_id, $user_id, $enrolled_id ); - } + // Mark WC order as completed. + self::mark_order_complete( $order_id ); } else { tutor_utils()->course_enrol_status_change( $enrolled_id, $status_to ); } + // Invoke enrolled hook. if ( 'completed' === $status_to ) { $user_id = get_post_field( 'post_author', $enrolled_id ); From 23d4bcb121b3eaf4f1a0e82d291909d7973735cc Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Fri, 28 Jul 2023 16:20:09 +0600 Subject: [PATCH 04/78] Force lost password to tutor has removed --- classes/FormHandler.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/classes/FormHandler.php b/classes/FormHandler.php index 6fca91055e..657eacccc1 100644 --- a/classes/FormHandler.php +++ b/classes/FormHandler.php @@ -33,7 +33,6 @@ public function __construct() { add_action( 'tutor_reset_password_notification', array( $this, 'reset_password_notification' ), 10, 2 ); add_filter( 'tutor_lostpassword_url', array( $this, 'lostpassword_url' ) ); - add_filter( 'lostpassword_url', array( $this, 'lostpassword_url' ), 99 ); } /** @@ -44,10 +43,10 @@ public function __construct() { */ public function tutor_retrieve_password() { tutils()->checking_nonce(); - + /** * To check spam or other logic before form process. - * + * * @since 2.1.10 */ $before_form_process = apply_filters( 'tutor_before_retrieve_password_form_process', null ); From d341ec2c62fe85abb3692e5abf621afeaf7db049 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 31 Jul 2023 12:00:02 +0600 Subject: [PATCH 05/78] WP admin tutor table auto height adjust for context menu --- assets/react/admin-dashboard/tutor-admin.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/assets/react/admin-dashboard/tutor-admin.js b/assets/react/admin-dashboard/tutor-admin.js index c86a976a58..2c7dffef02 100644 --- a/assets/react/admin-dashboard/tutor-admin.js +++ b/assets/react/admin-dashboard/tutor-admin.js @@ -503,5 +503,15 @@ jQuery(document).ready(function($) { } }); } - + + /** + * Fix - Table last row context menu hidden. + * + * @since 2.2.4 + */ + let tableDropdown = jQuery('.tutor-table-responsive .tutor-table .tutor-dropdown') + if (tableDropdown.length) { + let tableHeight = jQuery('.tutor-table-responsive .tutor-table').height() + jQuery('.tutor-table-responsive').css('min-height', tableHeight + 110) + } }); From 4108dfdc93067838226cc4b21f495d7c871b4732 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 31 Jul 2023 12:00:38 +0600 Subject: [PATCH 06/78] Tutor dashboard tutor table auto height adjust for context menu --- assets/react/front/dashboard/index.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/assets/react/front/dashboard/index.js b/assets/react/front/dashboard/index.js index 6f554b1ca8..9973641f8b 100644 --- a/assets/react/front/dashboard/index.js +++ b/assets/react/front/dashboard/index.js @@ -47,4 +47,15 @@ document.addEventListener('DOMContentLoaded', function() { document.getElementById('tutor-frontend-course-builder').submit(); }; } + + /** + * Fix - Table last row context menu hidden for frontend dashboard. + * + * @since 2.2.4 + */ + let tableDropdown = jQuery('.tutor-table-responsive .tutor-table .tutor-dropdown') + if (tableDropdown.length) { + let tableHeight = jQuery('.tutor-table-responsive .tutor-table').height() + jQuery('.tutor-table-responsive').css('min-height', tableHeight + 110) + } }); \ No newline at end of file From 4f10f9778c8f40c8b8b38512616173bcf97be801 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 31 Jul 2023 12:03:26 +0600 Subject: [PATCH 07/78] Moved pagination inside responsive table wrapper --- views/pages/course-list.php | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/views/pages/course-list.php b/views/pages/course-list.php index db3909e4d7..5b03f4783b 100644 --- a/views/pages/course-list.php +++ b/views/pages/course-list.php @@ -149,6 +149,7 @@
+ @@ -360,23 +361,25 @@
+ +
+ found_posts > $limit ) { + $pagination_data = array( + 'total_items' => $the_query->found_posts, + 'per_page' => $limit, + 'paged' => $paged_filter, + ); + $pagination_template = tutor()->path . 'views/elements/pagination.php'; + tutor_load_template_from_custom_path( $pagination_template, $pagination_data ); + } + ?> +
-
-
- found_posts > $limit ) { - $pagination_data = array( - 'total_items' => $the_query->found_posts, - 'per_page' => $limit, - 'paged' => $paged_filter, - ); - $pagination_template = tutor()->path . 'views/elements/pagination.php'; - tutor_load_template_from_custom_path( $pagination_template, $pagination_data ); - } - ?> +
From 57da234c5b4705d28dbe8e38beb88e420bb29c72 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 31 Jul 2023 12:03:51 +0600 Subject: [PATCH 08/78] Moved pagination inside responsive table wrapper --- views/fragments/announcement-list.php | 38 +++++++++++++++------------ 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/views/fragments/announcement-list.php b/views/fragments/announcement-list.php index 2d1ad3715d..c91d29ef6f 100644 --- a/views/fragments/announcement-list.php +++ b/views/fragments/announcement-list.php @@ -350,28 +350,32 @@ class="tutor-form-check-input tutor-bulk-checkbox" - -
- "> + get_option( 'pagination_per_page' ); - if ( $the_query->found_posts > $limit ) { - $pagination_data = array( - 'total_items' => $the_query->found_posts, - 'per_page' => $limit, - 'paged' => $paged, - ); + if ( $the_query->found_posts > $limit ) { + $pagination_data = array( + 'total_items' => $the_query->found_posts, + 'per_page' => $limit, + 'paged' => $paged, + ); - $pagination_template = tutor()->path . 'views/elements/pagination.php'; - if ( is_admin() ) { - tutor_load_template_from_custom_path( $pagination_template, $pagination_data ); - } else { - $pagination_template_frontend = tutor()->path . 'templates/dashboard/elements/pagination.php'; - tutor_load_template_from_custom_path( $pagination_template_frontend, $pagination_data ); + $pagination_template = tutor()->path . 'views/elements/pagination.php'; + if ( is_admin() ) { + tutor_load_template_from_custom_path( $pagination_template, $pagination_data ); + } else { + $pagination_template_frontend = tutor()->path . 'templates/dashboard/elements/pagination.php'; + tutor_load_template_from_custom_path( $pagination_template_frontend, $pagination_data ); + } } - } - ?> + ?> +
+ + + + From a97f584b5f51bf517029d0f757d8b88568ba25ac Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 31 Jul 2023 12:04:38 +0600 Subject: [PATCH 09/78] Moved pagination inside responsive table wrapper --- views/qna/qna-table.php | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/views/qna/qna-table.php b/views/qna/qna-table.php index 85f415a234..d3ea628445 100644 --- a/views/qna/qna-table.php +++ b/views/qna/qna-table.php @@ -30,7 +30,7 @@ comment_ID; $row_id = 'tutor_qna_row_' . $qna->comment_ID; @@ -191,22 +191,23 @@ + + $qna_pagination['per_page'] ) : ?> +
+ ! empty( $qna_pagination['base'] ) ? $qna_pagination['base'] : null, + 'total_items' => $qna_pagination['total_items'], + 'per_page' => $qna_pagination['per_page'], + 'paged' => $qna_pagination['paged'], + ); + $pagination_template = tutor()->path . 'views/elements/pagination.php'; + tutor_load_template_from_custom_path( $pagination_template, $pagination_data ); + ?> +
+ + tutor_empty_state( tutor_utils()->not_found_text() ); ?> - - $qna_pagination['per_page'] ) : ?> -
- ! empty( $qna_pagination['base'] ) ? $qna_pagination['base'] : null, - 'total_items' => $qna_pagination['total_items'], - 'per_page' => $qna_pagination['per_page'], - 'paged' => $qna_pagination['paged'], - ); - $pagination_template = tutor()->path . 'views/elements/pagination.php'; - tutor_load_template_from_custom_path( $pagination_template, $pagination_data ); - ?> -
- From 157d0f803bce533df6267acbc64af4346f77bc5c Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Tue, 1 Aug 2023 15:17:07 +0600 Subject: [PATCH 10/78] Schedule and private data added to course list --- classes/Course_List.php | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/classes/Course_List.php b/classes/Course_List.php index 85a6cc1a45..9c84799c49 100644 --- a/classes/Course_List.php +++ b/classes/Course_List.php @@ -118,6 +118,8 @@ public function tabs_key_value( $category_slug, $course_id, $date, $search ): ar $draft = self::count_course( 'draft', $category_slug, $course_id, $date, $search ); $pending = self::count_course( 'pending', $category_slug, $course_id, $date, $search ); $trash = self::count_course( 'trash', $category_slug, $course_id, $date, $search ); + $private = self::count_course( 'private', $category_slug, $course_id, $date, $search ); + $future = self::count_course( 'future', $category_slug, $course_id, $date, $search ); $tabs = array( array( @@ -150,6 +152,18 @@ public function tabs_key_value( $category_slug, $course_id, $date, $search ): ar 'value' => $pending, 'url' => $url . '&data=pending', ), + array( + 'key' => 'future', + 'title' => __( 'Scheduled', 'tutor' ), + 'value' => $future, + 'url' => $url . '&data=future', + ), + array( + 'key' => 'private', + 'title' => __( 'Private', 'tutor' ), + 'value' => $private, + 'url' => $url . '&data=private', + ), array( 'key' => 'trash', 'title' => __( 'Trash', 'tutor' ), @@ -187,7 +201,7 @@ protected static function count_course( string $status, $category_slug = '', $co ); if ( 'all' === $status || 'mine' === $status ) { - $args['post_status'] = array( 'publish', 'pending', 'draft', 'private' ); + $args['post_status'] = array( 'publish', 'pending', 'draft', 'private', 'future' ); } else { $args['post_status'] = array( $status ); } @@ -311,13 +325,24 @@ public static function tutor_change_course_status() { $status = Input::post( 'status' ); $id = Input::post( 'id' ); + $course = get_post( $id ); + + if ( CourseModel::POST_TYPE !== $course->post_type ) { + wp_send_json_error( tutor_utils()->error_message() ); + } $args = array( 'ID' => $id, 'post_status' => $status, ); - wp_update_post( $args ); + if ( CourseModel::STATUS_SCHEDULE === $course->post_status && CourseModel::STATUS_PUBLISH === $status ) { + $args['post_status'] = CourseModel::STATUS_PUBLISH; + $args['post_date'] = current_time( 'mysql' ); + $args['post_date_gmt'] = current_time( 'mysql', 1 ); + } + + wp_update_post( $args ); wp_send_json_success(); exit; } From 20cd94b0c366bccada450d226fac0573cdd44719 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Tue, 1 Aug 2023 15:17:33 +0600 Subject: [PATCH 11/78] Schedule and private constant added --- models/CourseModel.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/models/CourseModel.php b/models/CourseModel.php index 717fe2a130..2ff577eccb 100644 --- a/models/CourseModel.php +++ b/models/CourseModel.php @@ -29,6 +29,8 @@ class CourseModel { const STATUS_DRAFT = 'draft'; const STATUS_AUTO_DRAFT = 'auto-draft'; const STATUS_PENDING = 'pending'; + const STATUS_PRIVATE = 'private'; + const STATUS_SCHEDULE = 'future'; /** * Course mapped with the product using this meta key From aefd76ed6c019fc8eb045a49ea2a1718c6fd7065 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Tue, 1 Aug 2023 15:30:06 +0600 Subject: [PATCH 12/78] Schedule and private course added in course list --- views/pages/course-list.php | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/views/pages/course-list.php b/views/pages/course-list.php index 5b03f4783b..88c7fbd28e 100644 --- a/views/pages/course-list.php +++ b/views/pages/course-list.php @@ -13,7 +13,6 @@ } use TUTOR\Input; -use TUTOR\Course_List; $courses = \TUTOR\Tutor::instance()->course_list; @@ -73,7 +72,7 @@ ); if ( 'all' === $active_tab || 'mine' === $active_tab ) { - $args['post_status'] = array( 'publish', 'pending', 'draft', 'private' ); + $args['post_status'] = array( 'publish', 'pending', 'draft', 'private', 'future' ); } else { $status = 'published' === $active_tab ? 'publish' : $active_tab; $args['post_status'] = array( $status ); @@ -134,6 +133,10 @@ 'private' => array( __( 'Private', 'tutor' ), 'select-default' ), ); +$future_list = array( + 'publish' => array( __( 'Publish', 'tutor' ), 'select-success' ), + 'future' => array( __( 'Schedule', 'tutor' ), 'select-default' ), +); ?>
@@ -318,11 +321,20 @@
From 13007b94ae99246f39c1d56cc2fdfd4ed3a8ab9e Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 2 Aug 2023 12:06:26 +0600 Subject: [PATCH 13/78] Const name updated --- classes/Course_List.php | 2 +- models/CourseModel.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/classes/Course_List.php b/classes/Course_List.php index 9c84799c49..d44d1f02a2 100644 --- a/classes/Course_List.php +++ b/classes/Course_List.php @@ -336,7 +336,7 @@ public static function tutor_change_course_status() { 'post_status' => $status, ); - if ( CourseModel::STATUS_SCHEDULE === $course->post_status && CourseModel::STATUS_PUBLISH === $status ) { + if ( CourseModel::STATUS_FUTURE === $course->post_status && CourseModel::STATUS_PUBLISH === $status ) { $args['post_status'] = CourseModel::STATUS_PUBLISH; $args['post_date'] = current_time( 'mysql' ); $args['post_date_gmt'] = current_time( 'mysql', 1 ); diff --git a/models/CourseModel.php b/models/CourseModel.php index 2ff577eccb..159e99a955 100644 --- a/models/CourseModel.php +++ b/models/CourseModel.php @@ -30,7 +30,7 @@ class CourseModel { const STATUS_AUTO_DRAFT = 'auto-draft'; const STATUS_PENDING = 'pending'; const STATUS_PRIVATE = 'private'; - const STATUS_SCHEDULE = 'future'; + const STATUS_FUTURE = 'future'; /** * Course mapped with the product using this meta key From c5a6ec2fbece98c3077f13f378c83e2d969a56dc Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 2 Aug 2023 12:12:18 +0600 Subject: [PATCH 14/78] fix translation issue on reset button template --- views/options/template/common/reset-button-template.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/views/options/template/common/reset-button-template.php b/views/options/template/common/reset-button-template.php index 75b8bdd310..a0a3583088 100644 --- a/views/options/template/common/reset-button-template.php +++ b/views/options/template/common/reset-button-template.php @@ -17,8 +17,8 @@ From 6e50a9796c661cb1bb5814db990205c5c6629d1c Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 2 Aug 2023 12:18:32 +0600 Subject: [PATCH 15/78] fix translation issue on add new instructor page --- views/pages/add_new_instructor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/pages/add_new_instructor.php b/views/pages/add_new_instructor.php index 995e4b4967..07e6a4c714 100644 --- a/views/pages/add_new_instructor.php +++ b/views/pages/add_new_instructor.php @@ -147,7 +147,7 @@
+
From 544415f0323cd6bf72e5b6a506ea3ff54b3c887d Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 2 Aug 2023 12:19:46 +0600 Subject: [PATCH 16/78] Remove unwanted escaping and echo of constant value --- views/pages/withdraw_requests.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/views/pages/withdraw_requests.php b/views/pages/withdraw_requests.php index a2b6ec4db5..ce10859bd9 100644 --- a/views/pages/withdraw_requests.php +++ b/views/pages/withdraw_requests.php @@ -361,8 +361,8 @@ - - + +
From 03ac7eabf67a0dcc80560ed7ff6e8e35111190b8 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 2 Aug 2023 16:21:51 +0600 Subject: [PATCH 17/78] Pending withdrawal info added --- models/WithdrawModel.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/models/WithdrawModel.php b/models/WithdrawModel.php index 9507834275..5d5b3046bb 100644 --- a/models/WithdrawModel.php +++ b/models/WithdrawModel.php @@ -40,9 +40,11 @@ public static function get_withdraw_summary( $instructor_id ) { $data = $wpdb->get_row( $wpdb->prepare( "SELECT ID, display_name, - total_income,total_withdraw, + total_income, + total_withdraw, (total_income-total_withdraw) current_balance, total_matured, + total_pending, greatest(0, total_matured - total_withdraw) available_for_withdraw FROM ( @@ -55,7 +57,14 @@ public static function get_withdraw_summary( $instructor_id ) { GROUP BY user_id HAVING user_id=u.ID ),0) total_withdraw, - + + COALESCE(( + SELECT sum(amount) total_pending FROM {$wpdb->prefix}tutor_withdraws + WHERE status='pending' + GROUP BY user_id + HAVING user_id=u.ID + ),0) total_pending, + COALESCE(( SELECT SUM(instructor_amount) FROM( SELECT user_id, instructor_amount, created_at, DATEDIFF(NOW(),created_at) AS days_old FROM {$wpdb->prefix}tutor_earnings WHERE order_status='%s' From bc025cedd1aad6c22dfd886650b0cf8731080f02 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 2 Aug 2023 16:22:45 +0600 Subject: [PATCH 18/78] Prevent withdrawal request more than withdrawable balance --- classes/Withdraw.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/classes/Withdraw.php b/classes/Withdraw.php index fbd1adb0f9..ad487a93d0 100644 --- a/classes/Withdraw.php +++ b/classes/Withdraw.php @@ -232,6 +232,18 @@ public function tutor_make_an_withdraw() { $earning_summary = WithdrawModel::get_withdraw_summary( $user_id ); $min_withdraw = tutor_utils()->get_option( 'min_withdraw_amount' ); + if ( ( $earning_summary->total_pending + $withdraw_amount ) > $earning_summary->available_for_withdraw ) { + wp_send_json_error( + array( + 'msg' => wp_sprintf( + __( "You have total %1\$s pending withdraw request. You can't make more than %2\$s withdraw request at a time", 'tutor' ), + $earning_summary->total_pending, + $earning_summary->available_for_withdraw + ), + ) + ); + } + $saved_withdraw_account = WithdrawModel::get_user_withdraw_method(); $formatted_min_withdraw_amount = tutor_utils()->tutor_price( $min_withdraw ); @@ -241,6 +253,7 @@ public function tutor_make_an_withdraw() { } if ( ( ! is_numeric( $withdraw_amount ) && ! is_float( $withdraw_amount ) ) || $withdraw_amount < $min_withdraw ) { + //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment $required_min_withdraw = apply_filters( 'tutor_required_min_amount_msg', sprintf( __( 'Minimum withdrawal amount is %1$s %2$s %3$s ', 'tutor' ), '', $formatted_min_withdraw_amount, '' ) ); wp_send_json_error( array( 'msg' => $required_min_withdraw ) ); } From 7f792e89b72a196179111088a9b17600f09f5095 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 2 Aug 2023 16:37:46 +0600 Subject: [PATCH 19/78] Prevent withdrawal request more than withdrawable balance on withdrawal page --- templates/dashboard/withdraw.php | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/templates/dashboard/withdraw.php b/templates/dashboard/withdraw.php index b79de26a29..a23faae29b 100644 --- a/templates/dashboard/withdraw.php +++ b/templates/dashboard/withdraw.php @@ -12,6 +12,7 @@ use TUTOR\Input; use Tutor\Models\WithdrawModel; +//phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited $per_page = tutor_utils()->get_option( 'statement_show_per_page', 20 ); $current_page = max( 1, Input::get( 'current_page', 1, Input::TYPE_INT ) ); $offset = ( $current_page - 1 ) * $per_page; @@ -46,8 +47,9 @@ } $summary_data = WithdrawModel::get_withdraw_summary( $user_id ); -$is_balance_sufficient = $summary_data->available_for_withdraw >= $min_withdraw; -$available_for_withdraw_formatted = tutor_utils()->tutor_price( $summary_data->available_for_withdraw ); +$available_for_withdraw = $summary_data->available_for_withdraw - $summary_data->total_pending; +$is_balance_sufficient = $available_for_withdraw >= $min_withdraw; +$available_for_withdraw_formatted = tutor_utils()->tutor_price( $available_for_withdraw ); $current_balance_formated = tutor_utils()->tutor_price( $summary_data->current_balance ); ?> @@ -62,6 +64,7 @@ +
@@ -73,6 +76,9 @@ } ?>
+ total_pending > 0 ) : ?> +
tutor_price( $summary_data->total_pending ) ) ); ?>
+
nonce_action, tutor()->nonce ); ?> - +
@@ -261,15 +267,17 @@ Date: Wed, 2 Aug 2023 16:46:12 +0600 Subject: [PATCH 20/78] esc_html_e to esc_html --- views/pages/add_new_instructor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/pages/add_new_instructor.php b/views/pages/add_new_instructor.php index 07e6a4c714..f0f68aa707 100644 --- a/views/pages/add_new_instructor.php +++ b/views/pages/add_new_instructor.php @@ -134,7 +134,7 @@
- +
From 7d890faf6e990c480eac2157c45dee9e8498da7c Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 2 Aug 2023 16:48:14 +0600 Subject: [PATCH 21/78] wpcs fix --- views/pages/withdraw_requests.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/views/pages/withdraw_requests.php b/views/pages/withdraw_requests.php index ce10859bd9..13e0b906a9 100644 --- a/views/pages/withdraw_requests.php +++ b/views/pages/withdraw_requests.php @@ -18,9 +18,7 @@ use TUTOR\Withdraw_Requests_List; $withdraw = new Withdraw_Requests_List(); -/** - * Short able params - */ +//phpcs:disable WordPress.WP.GlobalVariablesOverride.Prohibited $order = Input::get( 'order', 'DESC' ); $date = Input::has( 'date' ) ? tutor_get_formated_date( 'Y-m-d', Input::get( 'date' ) ) : ''; $search_term = Input::get( 'search', '' ); @@ -65,6 +63,7 @@ 'course_filter' => false, ); +//phpcs:enable WordPress.WP.GlobalVariablesOverride.Prohibited ?>
From 113ff6c1cb4c4a1defb5bcefbaa291e02943b22a Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Thu, 3 Aug 2023 16:21:06 +0600 Subject: [PATCH 22/78] Hook added for extend tutor functionality --- views/pages/instructors.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/views/pages/instructors.php b/views/pages/instructors.php index 63663c7930..4e15c43d05 100644 --- a/views/pages/instructors.php +++ b/views/pages/instructors.php @@ -116,14 +116,17 @@ - + - + - + + + + @@ -175,6 +178,9 @@ ?> + + ID ); ?> +
+ + From 5b91256d7bfd207f555cddc6201befa1bd96dca5 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Fri, 4 Aug 2023 17:48:07 +0600 Subject: [PATCH 23/78] Quiz attempt list fix --- models/QuizModel.php | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/models/QuizModel.php b/models/QuizModel.php index 0bf74b75a8..107a64d922 100644 --- a/models/QuizModel.php +++ b/models/QuizModel.php @@ -270,7 +270,19 @@ public static function get_total_quiz_attempts( $search_term = '', int $course_i } // Set query based on action tab. - $pass_mark = "(((SUBSTRING_INDEX(SUBSTRING_INDEX(quiz_attempts.attempt_info, '\"passing_grade\";s:2:\"', -1), '\"', 1))/100)*quiz_attempts.total_marks)"; + $pass_mark = "((( SUBSTRING_INDEX( + SUBSTRING_INDEX( + attempt_info, + CONCAT( + '\"passing_grade\";s:', + SUBSTRING_INDEX(SUBSTRING_INDEX(attempt_info, '\"passing_grade\";s:', -1), ':\"', 1), + ':\"' + ), + -1 + ), + '\"', + 1 + ))/100) * quiz_attempts.total_marks)"; $pending_count = "(SELECT COUNT(DISTINCT attempt_answer_id) FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE quiz_attempt_id=quiz_attempts.attempt_id AND is_correct IS NULL)"; $tab_join = ''; @@ -287,8 +299,7 @@ public static function get_total_quiz_attempts( $search_term = '', int $course_i case 'fail': // Check if earned marks is less than pass mark and there is no pending question. - $tab_clause = " AND quiz_attempts.earned_marks < {$pass_mark} - AND {$pending_count} = 0 "; + $tab_clause = " AND quiz_attempts.earned_marks < {$pass_mark} AND {$pending_count} < 1 "; break; case 'pending': $tab_clause = " AND {$pending_count} > 0 "; @@ -392,7 +403,19 @@ public static function get_quiz_attempts( $start = 0, $limit = 10, $search_filte $select_columns = $count_only ? 'COUNT(DISTINCT quiz_attempts.attempt_id)' : 'DISTINCT quiz_attempts.*, quiz.post_title, users.user_email, users.user_login, users.display_name'; $limit_offset = $count_only ? '' : ' LIMIT ' . $limit . ' OFFSET ' . $start; - $pass_mark = "(((SUBSTRING_INDEX(SUBSTRING_INDEX(quiz_attempts.attempt_info, '\"passing_grade\";s:2:\"', -1), '\"', 1))/100)*quiz_attempts.total_marks)"; + $pass_mark = "((( SUBSTRING_INDEX( + SUBSTRING_INDEX( + attempt_info, + CONCAT( + '\"passing_grade\";s:', + SUBSTRING_INDEX(SUBSTRING_INDEX(attempt_info, '\"passing_grade\";s:', -1), ':\"', 1), + ':\"' + ), + -1 + ), + '\"', + 1 + ))/100) * quiz_attempts.total_marks)"; $pending_count = "(SELECT COUNT(DISTINCT attempt_answer_id) FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE quiz_attempt_id=quiz_attempts.attempt_id AND is_correct IS NULL)"; // Get attempts by instructor ID. @@ -418,8 +441,7 @@ public static function get_quiz_attempts( $start = 0, $limit = 10, $search_filte case 'fail': // Check if earned marks is less than pass mark and there is no pending question. - $result_clause = " AND quiz_attempts.earned_marks<{$pass_mark} - AND {$pending_count}=0 "; + $result_clause = " AND quiz_attempts.earned_marks<{$pass_mark} AND {$pending_count} < 1 "; break; case 'pending': From 43d01dccd3d116304c584e4fbe4a8ba88ba4e925 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Fri, 4 Aug 2023 17:53:40 +0600 Subject: [PATCH 24/78] WPCS fix --- models/QuizModel.php | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/models/QuizModel.php b/models/QuizModel.php index 107a64d922..7c8bc0501d 100644 --- a/models/QuizModel.php +++ b/models/QuizModel.php @@ -862,21 +862,29 @@ public static function get_quiz_count_by_course( $course_id ) { $and_clause = is_array( $course_id ) && count( $course_id ) ? ' AND post_parent IN (' . QueryHelper::prepare_in_clause( $course_id ) . ')' : "AND post_parent = $course_id"; + //phpcs:disable $count = $wpdb->get_var( - "SELECT - COUNT(ID) - FROM {$wpdb->posts} - WHERE post_parent IN - (SELECT - ID - FROM {$wpdb->posts} - WHERE post_type='topics' - {$and_clause} - AND post_status = 'publish' - ) - AND post_type ='tutor_quiz' - AND post_status = 'publish'" + $wpdb->prepare( + "SELECT + COUNT(ID) + FROM {$wpdb->posts} + WHERE post_parent IN + (SELECT + ID + FROM {$wpdb->posts} + WHERE post_type = %s + {$and_clause} + AND post_status = %s + ) + AND post_type = %s + AND post_status = %s", + 'topics', + 'publish', + 'tutor_quiz', + 'publish' + ) ); + //phpcs:enable return $count ? $count : 0; } } From 1878ef72d46ad6a6df6a2b644d6565a04a6e1f82 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 7 Aug 2023 11:32:20 +0600 Subject: [PATCH 25/78] Enable save button after remove image --- assets/react/lib/media-chooser.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/assets/react/lib/media-chooser.js b/assets/react/lib/media-chooser.js index d94769c9ff..65c2300ce0 100644 --- a/assets/react/lib/media-chooser.js +++ b/assets/react/lib/media-chooser.js @@ -49,21 +49,24 @@ window.jQuery(document).ready(function ($) { }); frame.open(); }); + /** * Thumbnail Delete - * @since v.1.5.6 + * @since 1.5.6 */ $(document).on('click', '.tutor-thumbnail-uploader .delete-btn', function (e) { e.preventDefault(); - var $that = $(this); - var wrapper = $that.closest('.tutor-thumbnail-uploader'); - var img = wrapper.find('img'); - var placeholder = img.data('placeholder') || ''; + let $that = $(this), + wrapper = $that.closest('.tutor-thumbnail-uploader'), + img = wrapper.find('img'), + placeholder = img.data('placeholder') || ''; wrapper.find('input[type="hidden"].tutor-tumbnail-id-input').val(''); img.attr('src', placeholder); - $that.hide(); + + // Enable save button after thumbnail remove. + $('#save_tutor_option').prop('disabled', false); }); }); \ No newline at end of file From 56a91ae605ba63fa219a65dd4ddc60b7b7b042fe Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 7 Aug 2023 16:13:27 +0600 Subject: [PATCH 26/78] Missing white space bewteen label and value --- .../header-context/course-single-previous-attempts.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/views/quiz/header-context/course-single-previous-attempts.php b/views/quiz/header-context/course-single-previous-attempts.php index 98f05dfe35..0dc02487d0 100644 --- a/views/quiz/header-context/course-single-previous-attempts.php +++ b/views/quiz/header-context/course-single-previous-attempts.php @@ -26,26 +26,27 @@
+
-
+
:
-
+
:
-
+
:
-
+
: Date: Mon, 7 Aug 2023 16:14:16 +0600 Subject: [PATCH 27/78] Latex expression inline support --- assets/scss/front/course-spotlight/index.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/assets/scss/front/course-spotlight/index.scss b/assets/scss/front/course-spotlight/index.scss index b5aeef4ad9..0d9ad67b6a 100644 --- a/assets/scss/front/course-spotlight/index.scss +++ b/assets/scss/front/course-spotlight/index.scss @@ -160,6 +160,14 @@ } @import './quiz'; } + + /** + * Latex disply inline support. + * @since 2.2.4 + */ + mjx-container, .MathJax_Display { + display: inline!important; + } } @import './spotlight'; From b108f6e79d8de80a67567e3d798e51560b6b25e8 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Tue, 8 Aug 2023 14:57:54 +0600 Subject: [PATCH 28/78] Util helper added to get profile bio config --- classes/Utils.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/classes/Utils.php b/classes/Utils.php index 2545fa8a13..f8dc07d737 100644 --- a/classes/Utils.php +++ b/classes/Utils.php @@ -9060,6 +9060,28 @@ public function text_editor_config( $args = array() ) { return wp_parse_args( $args, $default_args ); } + /** + * Get config for profile bio editor. + * + * @since 2.2.4 + * + * @param string $textarea_name textarea name for post request. + * + * @return array + */ + public function get_profile_bio_editor_config( $textarea_name = 'tutor_profile_bio' ) { + return $this->text_editor_config( + array( + 'textarea_name' => $textarea_name, + 'tinymce' => array( + 'toolbar1' => 'bold,italic,underline,blockquote,bullist,numlist,alignleft,aligncenter,alignright,undo,redo,removeformat', + 'toolbar2' => '', + 'toolbar3' => '', + ), + ) + ); + } + /** * Get video sources. * From 848711ba64af6a62dd65506aafaf248c482c50d9 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Tue, 8 Aug 2023 14:58:43 +0600 Subject: [PATCH 29/78] profile bio input kses sanitize --- classes/Student.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/Student.php b/classes/Student.php index 29dc4abdb0..7b96f04929 100644 --- a/classes/Student.php +++ b/classes/Student.php @@ -194,7 +194,7 @@ public function update_profile() { $first_name = sanitize_text_field( tutor_utils()->input_old( 'first_name' ) ); $last_name = sanitize_text_field( tutor_utils()->input_old( 'last_name' ) ); $phone_number = sanitize_text_field( tutor_utils()->input_old( 'phone_number' ) ); - $tutor_profile_bio = wp_kses_post( tutor_utils()->input_old( 'tutor_profile_bio' ) ); + $tutor_profile_bio = Input::post( 'tutor_profile_bio', '', Input::TYPE_KSES_POST ); $tutor_profile_job_title = sanitize_text_field( tutor_utils()->input_old( 'tutor_profile_job_title' ) ); $display_name = sanitize_text_field( tutor_utils()->input_old( 'display_name' ) ); From 45edf203cbedf361e12693e7269fc8f887939c48 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Tue, 8 Aug 2023 14:59:29 +0600 Subject: [PATCH 30/78] Tinymce content post to save profile bio --- assets/react/front/dashboard/settings/profile.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/assets/react/front/dashboard/settings/profile.js b/assets/react/front/dashboard/settings/profile.js index 14914d9103..26ce1dbed5 100644 --- a/assets/react/front/dashboard/settings/profile.js +++ b/assets/react/front/dashboard/settings/profile.js @@ -233,6 +233,15 @@ window.jQuery(document).ready(($) => { var data = form.serializeObject(); let phone = document.querySelector('[name=phone_number]'); + /** + * Basic markup for profile bio + * @since 2.2.4 + */ + if (window.tinyMCE !== undefined) { + let editor = tinyMCE.get('tutor_profile_bio'); + data.tutor_profile_bio = editor.getContent({ format: 'html' }); + } + if (data.phone_number && !data.phone_number.match(/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/im)) { phone.classList.add('invalid'); tutor_toast('Invalid', 'Invalid phone number', 'error'); From 03edeb2861f4c6ef804bdc3eece4caadb06b7bb7 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Tue, 8 Aug 2023 15:00:20 +0600 Subject: [PATCH 31/78] basic profile bio editor added to frontend dashboard --- templates/dashboard/settings/profile.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/templates/dashboard/settings/profile.php b/templates/dashboard/settings/profile.php index a5ed1215e5..414c5f9b46 100644 --- a/templates/dashboard/settings/profile.php +++ b/templates/dashboard/settings/profile.php @@ -104,10 +104,10 @@
    '; - foreach ( $errors as $error_key => $error_value ) { + foreach ( $error_list as $error_key => $error_value ) { echo '
  • ' . esc_html( $error_value ) . '
  • '; } echo '
'; @@ -162,7 +162,10 @@ - + ID, '_tutor_profile_bio', true ); + wp_editor( $profile_bio, 'tutor_profile_bio', tutor_utils()->get_profile_bio_editor_config() ); + ?>
@@ -174,7 +177,7 @@
From 93a8a627deaff03355d277fa1cc61b16a5a42089 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Thu, 17 Aug 2023 12:58:47 +0600 Subject: [PATCH 39/78] value cast --- templates/single/lesson/content.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/single/lesson/content.php b/templates/single/lesson/content.php index f4794644f5..56600b2ea4 100644 --- a/templates/single/lesson/content.php +++ b/templates/single/lesson/content.php @@ -75,7 +75,7 @@ $completion_mode = tutor_utils()->get_option( 'course_completion_process' ); $json_data['strict_mode'] = ( 'strict' === $completion_mode ); $json_data['control_video_lesson_completion'] = (bool) tutor_utils()->get_option( 'control_video_lesson_completion', false ); - $json_data['required_percentage'] = tutor_utils()->get_option( 'required_percentage_to_complete_video_lesson', 80 ); + $json_data['required_percentage'] = (int) tutor_utils()->get_option( 'required_percentage_to_complete_video_lesson', 80 ); ?> From db51b22612c4508e9706a4e5117bde90c3fafa4b Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Thu, 17 Aug 2023 12:59:31 +0600 Subject: [PATCH 40/78] block lesson key added --- classes/Options_V2.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/Options_V2.php b/classes/Options_V2.php index 4ab2a0f0a1..e67dc4b5f9 100644 --- a/classes/Options_V2.php +++ b/classes/Options_V2.php @@ -702,7 +702,7 @@ public function get_setting_fields() { ), ), ), - array( + 'block_lesson' => array( 'label' => __( 'Lesson', 'tutor' ), 'slug' => 'lesson', 'block_type' => 'uniform', From 821cf916cfb94d12dfa70da988339c27437f67af Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Fri, 18 Aug 2023 11:02:41 +0600 Subject: [PATCH 41/78] Control video lesson completion functions added to video player --- assets/react/front/tutor-front.js | 79 ++++++++++++++++++++++++++--- templates/single/lesson/content.php | 1 + 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/assets/react/front/tutor-front.js b/assets/react/front/tutor-front.js index 06a1edbd4b..6157caaa6d 100644 --- a/assets/react/front/tutor-front.js +++ b/assets/react/front/tutor-front.js @@ -136,16 +136,31 @@ jQuery(document).ready(function($) { track_player: function() { const that = this; if (typeof Plyr !== 'undefined') { - const player = new Plyr(this.player_DOM); const video_data = that.video_data(); + const player = new Plyr(this.player_DOM, { + keyboard: { + focused: that.isRequiredPercentage() ? false : true, + global: false, + }, + listeners: { + ...(that.isRequiredPercentage() && { + seek(e) { + e.preventDefault(); + tutor_toast(__('Warning', 'tutor'), __(`You have to complete ${video_data.required_percentage}% of the lesson.`, 'tutor'), 'error'); + return false; + }, + }), + } + }); player.on('ready', function(event) { const instance = event.detail.plyr; const { best_watch_time = 0 } = video_data || {}; - if ( - best_watch_time > 0 && - instance.duration > Math.round(best_watch_time) - ) { - instance.media.currentTime = best_watch_time; + if (best_watch_time > 0) { + if (instance.provider === 'youtube') { + instance.embed.seekTo(best_watch_time); + }else { + instance.media.currentTime = best_watch_time; + } } that.sync_time(instance); }); @@ -182,13 +197,21 @@ jQuery(document).ready(function($) { } }, sync_time: function(instance, options) { - const post_id = this.video_data().post_id; + const video_data = this.video_data(); + if (!video_data) { + return; + } + + if (this.isRequiredPercentage()) { + this.enable_complete_lesson_btn(instance); + } + //TUTOR is sending about video playback information to server. let data = { action: 'sync_video_playback', currentTime: instance.currentTime, duration: instance.duration, - post_id, + post_id: video_data.post_id, }; data[this.nonce_key] = _tutorobject[this.nonce_key]; let data_send = data; @@ -209,9 +232,49 @@ jQuery(document).ready(function($) { } }); }, + isRequiredPercentage: function() { + const video_data = this.video_data(); + if (!video_data) { + return false; + } + + const { strict_mode, control_video_lesson_completion } = video_data; + if (_tutorobject.tutor_pro_url && strict_mode && control_video_lesson_completion) { + return true; + } + return false; + }, + enable_complete_lesson_btn: function(instance) { + const complete_lesson_btn = $('button[name="complete_lesson_btn"]'); + const video_data = this.video_data(); + const completedPercentage = (instance.currentTime / instance.duration) * 100; + + if (completedPercentage >= video_data.required_percentage) { + complete_lesson_btn.attr('disabled', false); + complete_lesson_btn.next().remove(); + } + }, + disable_complete_lesson_btn: function() { + const video_data = this.video_data(); + if (!video_data) { + return; + } + + const { best_watch_time, video_duration, required_percentage } = video_data; + const completedPercentage = (Number(best_watch_time) / Number(video_duration)) * 100; + + if (completedPercentage < required_percentage) { + const complete_lesson_btn = $('button[name="complete_lesson_btn"]'); + complete_lesson_btn.attr('disabled', true); + complete_lesson_btn.wrap('
').after(`You have to complete ${video_data.required_percentage}% of the lesson.`); + } + }, init: function(element) { this.player_DOM = element; this.track_player(); + if (this.isRequiredPercentage()) { + this.disable_complete_lesson_btn(); + } }, }; diff --git a/templates/single/lesson/content.php b/templates/single/lesson/content.php index 56600b2ea4..81e9ba1ad6 100644 --- a/templates/single/lesson/content.php +++ b/templates/single/lesson/content.php @@ -76,6 +76,7 @@ $json_data['strict_mode'] = ( 'strict' === $completion_mode ); $json_data['control_video_lesson_completion'] = (bool) tutor_utils()->get_option( 'control_video_lesson_completion', false ); $json_data['required_percentage'] = (int) tutor_utils()->get_option( 'required_percentage_to_complete_video_lesson', 80 ); + $json_data['video_duration'] = $video_info->duration_sec ?? 0; ?> From ab94c8436e3ab2d7bfabcdf3b3d279050eca47a7 Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Fri, 18 Aug 2023 12:07:24 +0600 Subject: [PATCH 42/78] Add getPercentage function --- assets/react/front/tutor-front.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/assets/react/front/tutor-front.js b/assets/react/front/tutor-front.js index 6157caaa6d..f78c56cf31 100644 --- a/assets/react/front/tutor-front.js +++ b/assets/react/front/tutor-front.js @@ -247,7 +247,7 @@ jQuery(document).ready(function($) { enable_complete_lesson_btn: function(instance) { const complete_lesson_btn = $('button[name="complete_lesson_btn"]'); const video_data = this.video_data(); - const completedPercentage = (instance.currentTime / instance.duration) * 100; + const completedPercentage = getPercentage(Number(instance.currentTime), Number(instance.duration)); if (completedPercentage >= video_data.required_percentage) { complete_lesson_btn.attr('disabled', false); @@ -261,7 +261,7 @@ jQuery(document).ready(function($) { } const { best_watch_time, video_duration, required_percentage } = video_data; - const completedPercentage = (Number(best_watch_time) / Number(video_duration)) * 100; + const completedPercentage = this.getPercentage(Number(best_watch_time), Number(video_duration)); if (completedPercentage < required_percentage) { const complete_lesson_btn = $('button[name="complete_lesson_btn"]'); @@ -269,6 +269,12 @@ jQuery(document).ready(function($) { complete_lesson_btn.wrap('
').after(`You have to complete ${video_data.required_percentage}% of the lesson.`); } }, + getPercentage: function(value, total) { + if (value > 0 && total > 0) { + return Math.round((value / total) * 100);; + } + return 0; + }, init: function(element) { this.player_DOM = element; this.track_player(); From 95becc35ca4fd8344df89e9b3f5faa136aa0241b Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Fri, 18 Aug 2023 13:53:52 +0600 Subject: [PATCH 43/78] Fix typos in get percentage function --- assets/react/front/tutor-front.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/react/front/tutor-front.js b/assets/react/front/tutor-front.js index f78c56cf31..d11322de5b 100644 --- a/assets/react/front/tutor-front.js +++ b/assets/react/front/tutor-front.js @@ -247,7 +247,7 @@ jQuery(document).ready(function($) { enable_complete_lesson_btn: function(instance) { const complete_lesson_btn = $('button[name="complete_lesson_btn"]'); const video_data = this.video_data(); - const completedPercentage = getPercentage(Number(instance.currentTime), Number(instance.duration)); + const completedPercentage = this.getPercentage(Number(instance.currentTime), Number(instance.duration)); if (completedPercentage >= video_data.required_percentage) { complete_lesson_btn.attr('disabled', false); @@ -271,7 +271,7 @@ jQuery(document).ready(function($) { }, getPercentage: function(value, total) { if (value > 0 && total > 0) { - return Math.round((value / total) * 100);; + return Math.round((value / total) * 100); } return 0; }, From 1ed57c6e5670a52fcb52fb5b5881a4d91989dd1b Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Fri, 18 Aug 2023 15:31:07 +0600 Subject: [PATCH 44/78] Hide youtube information from tutor player videos --- assets/scss/front/course-spotlight/_players.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/assets/scss/front/course-spotlight/_players.scss b/assets/scss/front/course-spotlight/_players.scss index 0ef10849c5..0aa59d9912 100644 --- a/assets/scss/front/course-spotlight/_players.scss +++ b/assets/scss/front/course-spotlight/_players.scss @@ -51,5 +51,10 @@ height: 100%; border: none; } + + .plyr--youtube iframe { + top: -50%; + height: 200%; + } } } From bcbd7848f92922f4090b31bea8e09129a2d903fd Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Fri, 18 Aug 2023 15:31:29 +0600 Subject: [PATCH 45/78] Update warning message --- assets/react/front/tutor-front.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/react/front/tutor-front.js b/assets/react/front/tutor-front.js index d11322de5b..cfd953f4cf 100644 --- a/assets/react/front/tutor-front.js +++ b/assets/react/front/tutor-front.js @@ -146,7 +146,7 @@ jQuery(document).ready(function($) { ...(that.isRequiredPercentage() && { seek(e) { e.preventDefault(); - tutor_toast(__('Warning', 'tutor'), __(`You have to complete ${video_data.required_percentage}% of the lesson.`, 'tutor'), 'error'); + tutor_toast(__('Warning', 'tutor'), __(`You have to watch ${video_data.required_percentage}% of this video lesson.`, 'tutor'), 'error'); return false; }, }), @@ -266,7 +266,7 @@ jQuery(document).ready(function($) { if (completedPercentage < required_percentage) { const complete_lesson_btn = $('button[name="complete_lesson_btn"]'); complete_lesson_btn.attr('disabled', true); - complete_lesson_btn.wrap('
').after(`You have to complete ${video_data.required_percentage}% of the lesson.`); + complete_lesson_btn.wrap('
').after(`You have to watch ${video_data.required_percentage}% of this video lesson.`); } }, getPercentage: function(value, total) { From a6d3f61e34a82c9d49dd86d37b0fdd61610a37a0 Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Fri, 18 Aug 2023 15:32:25 +0600 Subject: [PATCH 46/78] Filter hook added to validate lesson completion --- classes/Lesson.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/classes/Lesson.php b/classes/Lesson.php index bbadce3b4e..9b72290cd8 100644 --- a/classes/Lesson.php +++ b/classes/Lesson.php @@ -454,6 +454,15 @@ public function mark_lesson_complete() { $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT ); + if ( ! $lesson_id ) { + return; + } + + $validated = apply_filters( 'tutor_validate_lesson_complete', true, $user_id, $lesson_id ); + if ( ! $validated ) { + return; + } + do_action( 'tutor_lesson_completed_before', $lesson_id ); /** * Marking lesson at user meta, meta format, _tutor_completed_lesson_id_{id} and value = tutor_time(); From a437d1919524e912380209b40545e48c1806799a Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Fri, 18 Aug 2023 16:29:36 +0600 Subject: [PATCH 47/78] PHPcbf fix --- classes/Lesson.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/Lesson.php b/classes/Lesson.php index 9b72290cd8..c2f203ddf4 100644 --- a/classes/Lesson.php +++ b/classes/Lesson.php @@ -458,7 +458,7 @@ public function mark_lesson_complete() { return; } - $validated = apply_filters( 'tutor_validate_lesson_complete', true, $user_id, $lesson_id ); + $validated = apply_filters( 'tutor_validate_lesson_complete', true, $user_id, $lesson_id ); if ( ! $validated ) { return; } From 804b3816aff4aa066d700e9aea3769366c517c22 Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Fri, 18 Aug 2023 16:50:25 +0600 Subject: [PATCH 48/78] Hide youtube information from all tutor player videos --- assets/scss/front/course-spotlight/_players.scss | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/assets/scss/front/course-spotlight/_players.scss b/assets/scss/front/course-spotlight/_players.scss index 0aa59d9912..405d84a8c7 100644 --- a/assets/scss/front/course-spotlight/_players.scss +++ b/assets/scss/front/course-spotlight/_players.scss @@ -7,6 +7,11 @@ margin-left: -25px; } } + + .plyr--youtube iframe { + top: -50%; + height: 200%; + } } .tutor-video-player-wrapper { @@ -51,10 +56,5 @@ height: 100%; border: none; } - - .plyr--youtube iframe { - top: -50%; - height: 200%; - } } } From e6180aa9daa440a4430617f03aa4dff2f62199f2 Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Wed, 23 Aug 2023 12:20:40 +0600 Subject: [PATCH 49/78] Fix tutor player design and seeking issue --- assets/react/front/tutor-front.js | 39 +++++++++++++++---- .../scss/front/course-spotlight/_players.scss | 2 +- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/assets/react/front/tutor-front.js b/assets/react/front/tutor-front.js index cfd953f4cf..940aa9122a 100644 --- a/assets/react/front/tutor-front.js +++ b/assets/react/front/tutor-front.js @@ -145,9 +145,15 @@ jQuery(document).ready(function($) { listeners: { ...(that.isRequiredPercentage() && { seek(e) { - e.preventDefault(); - tutor_toast(__('Warning', 'tutor'), __(`You have to watch ${video_data.required_percentage}% of this video lesson.`, 'tutor'), 'error'); - return false; + var currentTime = player.currentTime; + var newTime = that.getTargetTime(player, e); + // Disallow moving forward + if (newTime > currentTime) { + e.preventDefault(); + tutor_toast(__('Warning', 'tutor'), __(`Forward seeking is not allowed for this video lesson.`, 'tutor'), 'error'); + return false; + } + return true; }, }), } @@ -156,11 +162,18 @@ jQuery(document).ready(function($) { const instance = event.detail.plyr; const { best_watch_time = 0 } = video_data || {}; if (best_watch_time > 0) { - if (instance.provider === 'youtube') { - instance.embed.seekTo(best_watch_time); - }else { - instance.media.currentTime = best_watch_time; - } + var previous_duration = Math.round(best_watch_time); + var previousTimeSetter = setInterval(function(){ + if (player.playing !== true && player.currentTime != previous_duration) { + if (instance.provider === 'youtube') { + instance.embed.seekTo(best_watch_time); + } else { + instance.media.currentTime = previous_duration; + } + } else{ + clearInterval(previousTimeSetter); + } + }, 800); } that.sync_time(instance); }); @@ -275,6 +288,16 @@ jQuery(document).ready(function($) { } return 0; }, + getTargetTime: function(player, input) { + if ( + typeof input === "object" && + (input.type === "input" || input.type === "change") + ) { + return input.target.value / input.target.max * player.media.duration; + } else { + return Number(input); + } + }, init: function(element) { this.player_DOM = element; this.track_player(); diff --git a/assets/scss/front/course-spotlight/_players.scss b/assets/scss/front/course-spotlight/_players.scss index 405d84a8c7..6a87388e4a 100644 --- a/assets/scss/front/course-spotlight/_players.scss +++ b/assets/scss/front/course-spotlight/_players.scss @@ -10,7 +10,7 @@ .plyr--youtube iframe { top: -50%; - height: 200%; + height: 200%!important; } } From c44871a56b0f2b4a481b5ec7932cb6492d7b7d3c Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Wed, 23 Aug 2023 12:48:29 +0600 Subject: [PATCH 50/78] Use setTimeout instead of setInterval --- assets/react/front/tutor-front.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/assets/react/front/tutor-front.js b/assets/react/front/tutor-front.js index 940aa9122a..56e9b3f698 100644 --- a/assets/react/front/tutor-front.js +++ b/assets/react/front/tutor-front.js @@ -163,17 +163,17 @@ jQuery(document).ready(function($) { const { best_watch_time = 0 } = video_data || {}; if (best_watch_time > 0) { var previous_duration = Math.round(best_watch_time); - var previousTimeSetter = setInterval(function(){ - if (player.playing !== true && player.currentTime != previous_duration) { + var previousTimeSetter = setTimeout(function(){ + if (player.playing !== true && player.currentTime !== previous_duration) { if (instance.provider === 'youtube') { instance.embed.seekTo(best_watch_time); } else { instance.media.currentTime = previous_duration; } - } else{ - clearInterval(previousTimeSetter); + } else { + clearTimeout(previousTimeSetter); } - }, 800); + }); } that.sync_time(instance); }); From f455a0a6e17af6e6278d5be17fb1c897ccf7f7ef Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 23 Aug 2023 12:58:48 +0600 Subject: [PATCH 51/78] custom js event register on media selected for tutor settings --- assets/react/lib/media-chooser.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/assets/react/lib/media-chooser.js b/assets/react/lib/media-chooser.js index 65c2300ce0..e27dc2b284 100644 --- a/assets/react/lib/media-chooser.js +++ b/assets/react/lib/media-chooser.js @@ -39,13 +39,24 @@ window.jQuery(document).ready(function ($) { multiple: false, // Set to true to allow multiple files to be selected }); frame.on('select', function () { - var attachment = frame.state().get('selection').first().toJSON(); + let attachment = frame.state().get('selection').first().toJSON(), + inputEl = wrapper.find('input[type="hidden"].tutor-tumbnail-id-input'); wrapper.find('img').attr('src', attachment.url); - wrapper.find('input[type="hidden"].tutor-tumbnail-id-input').val(attachment.id); + inputEl.val(attachment.id); wrapper.find('.delete-btn').show(); $('#save_tutor_option').prop('disabled', false); + + document.querySelector('.tutor-option-form .tutor-thumbnail-uploader') + .dispatchEvent(new CustomEvent('tutor_settings_media_selected', { + detail: { + wrapper: wrapper, + settingsName: inputEl.attr('name').replace(/.*\[(.*?)\]/, '$1'), + attachment: attachment + } + })); + }); frame.open(); }); From 556974ebf19e3342eb4846210b1aa4eb7df37e1a Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 23 Aug 2023 14:58:32 +0600 Subject: [PATCH 52/78] whats new style --- assets/scss/admin-dashboard/_tutor-admin.scss | 164 +++++++++++++++++- 1 file changed, 162 insertions(+), 2 deletions(-) diff --git a/assets/scss/admin-dashboard/_tutor-admin.scss b/assets/scss/admin-dashboard/_tutor-admin.scss index 253ce1eecc..f9acf47a72 100644 --- a/assets/scss/admin-dashboard/_tutor-admin.scss +++ b/assets/scss/admin-dashboard/_tutor-admin.scss @@ -965,8 +965,15 @@ span.filled_dash_unser { height: auto; } -.tutor-get-pro-text { - color: #e02424; +a:has(> span.tutor-get-pro-text ) { + background-color: orange; + font-weight: 600; + color: #000 !important; + + &:hover{ + background-color: orange!important; + color: #000 !important; + } } .updating-icon:before { @@ -1766,4 +1773,157 @@ h2.tutor-page-heading { .mce-branding { display: none; } +} + +.tutor-pro-badge{ + background: #e5803c; + color: #fff; + font-weight: 400; + border-radius: 16px; + padding: 1px 6px; + font-size: 11px; + display: inline-block; + line-height: 15px; +} + +.tutor-whats-new-wrapper{ + max-width: 1080px; + background-color: white; + margin: 25px auto; + border-radius: 8px; + + padding: 40px 0; + + .tutor-whats-new-header{ + text-align: center; + background-size: contain; + background-repeat: no-repeat; + min-height: 200px; + border-bottom: 1px solid #f0eaea; + position: relative; + + h1{ + font-size: 40px; + font-weight:700; + } + + p{ + font-size: 14px; + } + + .tutor-logo-head{ + position: absolute; + left: 0; + right: 0; + width: 40px; + bottom: -40px; + margin: 0 auto; + background: #FFF; + padding: 10px; + } + + .tutor-whats-new-header-symbols { + position: absolute; + + &.tutor-symbol-left-top { + top: 75px; + left: 100px; + height: 20px; + width: 20px; + } + &.tutor-symbol-left-bottom { + width: 60px; + left: 0; + bottom: 20px; + } + &.tutor-symbol-right-top { + top: 0; + right: 0; + width: 60px; + } + &.tutor-symbol-right-bottom { + height: 30px; + width: 30px; + right: 90px; + bottom: 60px; + } + + } + + @include breakpoint-max(tablet) { + h1{ + font-size: 34px; + } + } + + @include breakpoint-max(mobile) { + h1{ + font-size: 28px; + } + } + } + + .tutor-changelog-wrapper{ + width: 75%; + margin: 0 auto; + margin-top: 100px; + + h4{ + font-size: 16px; + } + + .tutor-changelog-list{ + list-style: disc; + padding-left: 20px; + } + } + + .tutor-whats-new-pro-section{ + width: 75%; + margin: 0 auto; + margin-top: 100px; + text-align: center; + + h2{ + max-width: 50%; + margin: 0 auto 40px; + font-size: 22px; + line-height: 1.3; + } + + @include breakpoint-max(992) { + h2{ + max-width: 100%; + } + } + + .tutor-whats-new-pro-banner{ + border-radius: 8px; + overflow: hidden; + display: flex; + img{ + width: 100%; + } + } + + .tutor-whats-new-action-btn{ + display: inline-block; + font-size: 15px; + padding: 10px 30px; + background: #0049F8; + border-radius: 6px; + text-decoration: none; + color: #fff; + margin-top: 36px; + margin-bottom: 30px; + &:hover{ + background: #0b51f3; + } + + .tutor-icon-crown { + color: #ED9700; + margin-right: 5px; + } + } + } } \ No newline at end of file From 614179135575dce00ea76f3dac2c665459643002 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 23 Aug 2023 14:59:13 +0600 Subject: [PATCH 53/78] Whats new menu added --- classes/Admin.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/classes/Admin.php b/classes/Admin.php index e936a9692b..27a189340e 100644 --- a/classes/Admin.php +++ b/classes/Admin.php @@ -134,11 +134,26 @@ public function register_menu() { add_submenu_page( 'tutor', __( 'Settings', 'tutor' ), __( 'Settings', 'tutor' ), 'manage_tutor', 'tutor_settings', array( new \TUTOR\Options_V2(), 'load_settings_page' ) ); + do_action( 'tutor_after_settings_menu' ); + + add_submenu_page( 'tutor', __( "What's New", 'tutor' ), __( "What's New", 'tutor' ), 'manage_options', 'tutor-whats-new', array( $this, 'whats_new_page' ) ); + if ( ! $has_pro ) { - add_submenu_page( 'tutor', __( 'Get Pro', 'tutor' ), __( ' Get Pro', 'tutor' ), 'manage_options', 'tutor-get-pro', array( $this, 'tutor_get_pro' ) ); + add_submenu_page( 'tutor', __( 'Upgrade to Pro', 'tutor' ), __( 'Upgrade to Pro', 'tutor' ), 'manage_options', 'tutor-get-pro', array( $this, 'tutor_get_pro' ) ); } } + /** + * What's new page. + * + * @since 2.2.4 + * + * @return void + */ + public function whats_new_page() { + include tutor()->path . 'views/pages/whats-new.php'; + } + /** * Show Course Bundle Page For Free User. * From 78146dde654fc8f40b6aea8e0825714dced0fb1e Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 23 Aug 2023 14:59:33 +0600 Subject: [PATCH 54/78] Whats new page --- views/pages/whats-new.php | 170 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 views/pages/whats-new.php diff --git a/views/pages/whats-new.php b/views/pages/whats-new.php new file mode 100644 index 0000000000..7bab6edd98 --- /dev/null +++ b/views/pages/whats-new.php @@ -0,0 +1,170 @@ + + * @link https://themeum.com + * @since 2.2.4 + */ + +$changelogs = array( + 'new' => array( + array( + 'title' => 'E-mail background image change support added.', + 'is_pro' => true, + ), + array( + 'title' => 'Basic editor support for profile bio change.', + ), + array( + 'title' => 'Instructor\'s earning summary on instructor list.', + 'is_pro' => true, + ), + array( + 'title' => 'Latex support to lesson and quiz editor.', + ), + array( + 'title' => 'Delete cancelled enrollment from enrollment list.', + 'is_pro' => true, + ), + array( + 'title' => 'Private and Schedule filter tab in courses and course bundle listing page.', + ), + ), + 'update' => array( + array( + 'title' => 'Email address also added to Analytics CSV data along with display name.', + ), + array( + 'title' => 'Remove force password reset form to tutor.', + ), + ), + 'fix' => array( + array( + 'title' => 'Quiz attempt list showing wrong.', + ), + array( + 'title' => "Some strings aren't translatable.", + ), + array( + 'title' => 'In the Course List page of WP Admin, the Edit menu had design issue.', + ), + array( + 'title' => 'Instructors can make withdrawal requests greater than their available balance.', + ), + array( + 'title' => 'Invalid or no google client ID found for Google login.', + ), + array( + 'title' => 'Course enrollment email to student issue.', + ), + array( + 'title' => 'HTML code appearing on the course details page enrollment box, if user use the Restrict Content Pro.', + ), + array( + 'title' => 'Student can complete course without passing the quiz.', + ), + ), +); + +function tutor_whatnew_item( $type, $log ) { + $obj = (object) $log; + ?> +
  • : title ); ?> + is_pro ) && $obj->is_pro ) : + ?> + Pro
  • + + +
    + +
    + +
    +
    + + + +
    + +
    + + + + +
    + +
    + + + +
    + +
    + + + +
    + +

    What's New 🥳 in Tutor LMS

    +

    Congratulations! You have successfully upgraded to
    + the latest version of Tutor LMS (v) +

    +
    + + + + + +
    +
    + + +
    +

    Changelog (v)

    +
      + +
    +
    + + + has_pro ) : ?> + +
    +

    You are not only missing these features, you are missing your revenues too!

    + +
    + course bundle banner +
    + + + Get Tutor Pro +
    + + +
    +
    + + From e60ba85d5f8dcc0c8906010ccab0d5d647e18182 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Wed, 23 Aug 2023 15:37:42 +0600 Subject: [PATCH 55/78] Rearrange addons order --- classes/Addons.php | 118 ++++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/classes/Addons.php b/classes/Addons.php index 671ebaaeae..3883a92349 100644 --- a/classes/Addons.php +++ b/classes/Addons.php @@ -38,89 +38,97 @@ public function __construct() { */ public function tutor_addons_lists_to_show() { $addons = array( - 'buddypress' => array( - 'name' => __( 'BuddyPress', 'tutor' ), - 'description' => 'Discuss about course and share your knowledge with your friends through BuddyPress', + 'course-bundle' => array( + 'name' => __( 'Course Bundle', 'tutor' ), + 'description' => __( 'Group multiple courses to sell together.', 'tutor' ), ), - 'gradebook' => array( - 'name' => __( 'Gradebook', 'tutor' ), - 'description' => 'Shows student progress from assignment and quiz', + 'social-login' => array( + 'name' => __( 'Social Login', 'tutor' ), + 'description' => __( 'Let users register & login through social network like Facebook, Google, etc.', 'tutor' ), ), 'content-drip' => array( 'name' => __( 'Content Drip', 'tutor' ), 'description' => 'Unlock lessons by schedule or when the student meets specific condition.', ), - 'enrollments' => array( - 'name' => __( 'Enrollment', 'tutor' ), - 'description' => 'Take advanced control on enrollment. Enroll the student manually.', - ), - 'wc-subscriptions' => array( - 'name' => __( 'WooCommerce Subscriptions', 'tutor' ), - 'description' => 'Capture Residual Revenue with Recurring Payments.', - ), - 'pmpro' => array( - 'name' => __( 'Paid Memberships Pro', 'tutor' ), - 'description' => 'Maximize revenue by selling membership access to all of your courses.', - ), - 'restrict-content-pro' => array( - 'name' => __( 'Restrict Content Pro', 'tutor' ), - 'description' => 'Unlock Course depending on Restrict Content Pro Plugin Permission.', + 'tutor-multi-instructors' => array( + 'name' => __( 'Tutor Multi Instructors', 'tutor' ), + 'description' => 'Start a course with multiple instructors by Tutor Multi Instructors', ), 'tutor-assignments' => array( 'name' => __( 'Tutor Assignments', 'tutor' ), 'description' => 'Tutor assignments is a great way to assign tasks to students.', ), - 'tutor-certificate' => array( - 'name' => __( 'Tutor Certificate', 'tutor' ), - 'description' => 'Students will be able to download a certificate after course completion.', + 'tutor-course-preview' => array( + 'name' => __( 'Tutor Course Preview', 'tutor' ), + 'description' => 'Unlock some lessons for students before enrollment.', ), 'tutor-course-attachments' => array( 'name' => __( 'Tutor Course Attachments', 'tutor' ), 'description' => 'Add unlimited attachments/ private files to any Tutor course', ), - 'tutor-course-preview' => array( - 'name' => __( 'Tutor Course Preview', 'tutor' ), - 'description' => 'Unlock some lessons for students before enrollment.', + 'google-meet' => array( + 'name' => __( 'Tutor Google Meet Integration', 'tutor' ), + 'description' => __( 'Connect Tutor LMS with Google Meet to host live online classes. Students can attend live classes right from the lesson page.', 'tutor' ), + ), + 'tutor-report' => array( + 'name' => __( 'Tutor Report', 'tutor' ), + 'description' => 'Check your course performance through Tutor Report stats.', ), 'tutor-email' => array( 'name' => __( 'Tutor E-Mail', 'tutor' ), 'description' => 'Send email on various tutor events', ), - 'tutor-multi-instructors' => array( - 'name' => __( 'Tutor Multi Instructors', 'tutor' ), - 'description' => 'Start a course with multiple instructors by Tutor Multi Instructors', + 'tutor-calendar' => array( + 'name' => 'Calendar', + 'description' => 'Allow students to see everything in a calendar view in the front dashboard.', ), - 'tutor-prerequisites' => array( - 'name' => __( 'Tutor Prerequisites', 'tutor' ), - 'description' => 'Specific course you must complete before you can enroll new course by Tutor Prerequisites', + 'tutor-notifications' => array( + 'name' => 'Notifications', + 'description' => 'Get On Site and Push Notifications on specified tutor events.', ), - 'tutor-report' => array( - 'name' => __( 'Tutor Report', 'tutor' ), - 'description' => 'Check your course performance through Tutor Report stats.', + 'google-classroom' => array( + 'name' => __( 'Google Classroom Integration', 'tutor' ), + 'description' => __( 'Helps connect Google Classrooms with Tutor LMS courses, allowing you to use features like Classroom streams and files directly from the Tutor LMS course.', 'tutor' ), + ), + 'tutor-zoom' => array( + 'name' => __( 'Tutor Zoom Integration', 'tutor' ), + 'description' => __( 'Connect Tutor LMS with Zoom to host live online classes. Students can attend live classes right from the lesson page.', 'tutor' ), ), 'quiz-import-export' => array( 'name' => __( 'Quiz Export/Import', 'tutor' ), 'description' => __( 'Save time by exporting/importing quiz data with easy options.', 'tutor' ), ), - 'tutor-zoom' => array( - 'name' => __( 'Tutor Zoom Integration', 'tutor' ), - 'description' => __( 'Connect Tutor LMS with Zoom to host live online classes. Students can attend live classes right from the lesson page.', 'tutor' ), + 'enrollments' => array( + 'name' => __( 'Enrollment', 'tutor' ), + 'description' => 'Take advanced control on enrollment. Enroll the student manually.', ), - 'google-meet' => array( - 'name' => __( 'Tutor Google Meet Integration', 'tutor' ), - 'description' => __( 'Connect Tutor LMS with Google Meet to host live online classes. Students can attend live classes right from the lesson page.', 'tutor' ), + 'tutor-certificate' => array( + 'name' => __( 'Tutor Certificate', 'tutor' ), + 'description' => 'Students will be able to download a certificate after course completion.', ), - 'google-classroom' => array( - 'name' => __( 'Google Classroom Integration', 'tutor' ), - 'description' => __( 'Helps connect Google Classrooms with Tutor LMS courses, allowing you to use features like Classroom streams and files directly from the Tutor LMS course.', 'tutor' ), + 'gradebook' => array( + 'name' => __( 'Gradebook', 'tutor' ), + 'description' => 'Shows student progress from assignment and quiz', ), - 'tutor-calendar' => array( - 'name' => 'Calendar', - 'description' => 'Allow students to see everything in a calendar view in the front dashboard.', + 'tutor-prerequisites' => array( + 'name' => __( 'Tutor Prerequisites', 'tutor' ), + 'description' => 'Specific course you must complete before you can enroll new course by Tutor Prerequisites', ), - 'tutor-notifications' => array( - 'name' => 'Notifications', - 'description' => 'Get On Site and Push Notifications on specified tutor events.', + 'buddypress' => array( + 'name' => __( 'BuddyPress', 'tutor' ), + 'description' => 'Discuss about course and share your knowledge with your friends through BuddyPress', + ), + 'wc-subscriptions' => array( + 'name' => __( 'WooCommerce Subscriptions', 'tutor' ), + 'description' => 'Capture Residual Revenue with Recurring Payments.', + ), + 'pmpro' => array( + 'name' => __( 'Paid Memberships Pro', 'tutor' ), + 'description' => 'Maximize revenue by selling membership access to all of your courses.', + ), + 'restrict-content-pro' => array( + 'name' => __( 'Restrict Content Pro', 'tutor' ), + 'description' => 'Unlock Course depending on Restrict Content Pro Plugin Permission.', ), 'tutor-weglot' => array( 'name' => 'Weglot', @@ -130,14 +138,6 @@ public function tutor_addons_lists_to_show() { 'name' => __( 'WPML Multilingual CMS', 'tutor' ), 'description' => __( 'Create multilingual courses, lessons, dashboard and more for a global audience.', 'tutor' ), ), - 'social-login' => array( - 'name' => __( 'Social Login', 'tutor' ), - 'description' => __( 'Let users register & login through social network like Facebook, Google, etc.', 'tutor' ), - ), - 'course-bundle' => array( - 'name' => __( 'Course Bundle', 'tutor' ), - 'description' => __( 'Group multiple courses to sell together.', 'tutor' ), - ), ); return $addons; From ba5ce3786a8fa327111212c535eaa6aa6e25004d Mon Sep 17 00:00:00 2001 From: Mohammad Ibrahim Date: Wed, 23 Aug 2023 23:01:47 +0600 Subject: [PATCH 56/78] Update TutorEDD.php EDD issue fixed --- classes/TutorEDD.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/TutorEDD.php b/classes/TutorEDD.php index 8c8bfa2021..60d698a239 100644 --- a/classes/TutorEDD.php +++ b/classes/TutorEDD.php @@ -198,7 +198,7 @@ public function tutor_course_sell_by() { * @return void */ public function edd_update_payment_status( $payment_id, $new_status, $old_status ) { - if ( 'publish' !== $new_status ) { + if ( 'complete' !== $new_status ) { return; } From e14c48a4731f36dc44dff36c27efd3b3f99c575a Mon Sep 17 00:00:00 2001 From: Mohammad Ibrahim Date: Thu, 24 Aug 2023 14:05:22 +0600 Subject: [PATCH 57/78] Update TutorEDD.php edd not installed shows fatal issue fixed --- classes/TutorEDD.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/classes/TutorEDD.php b/classes/TutorEDD.php index 60d698a239..8fc1568a68 100644 --- a/classes/TutorEDD.php +++ b/classes/TutorEDD.php @@ -173,8 +173,10 @@ public function is_course_purchasable( $bool, $course_id ) { */ public function get_tutor_course_price( $price, $course_id ) { $product_id = tutor_utils()->get_course_product_id( $course_id ); - - return edd_price( $product_id, false ); + if( tutils()->has_edd() ){ + return edd_price( $product_id, false ); + } + } /** From 906e5efbfedf1169fc40387e85632188b9c1fe5f Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Thu, 24 Aug 2023 15:17:06 +0600 Subject: [PATCH 58/78] css rules removed --- assets/scss/front/course-spotlight/_players.scss | 5 ----- 1 file changed, 5 deletions(-) diff --git a/assets/scss/front/course-spotlight/_players.scss b/assets/scss/front/course-spotlight/_players.scss index 6a87388e4a..0ef10849c5 100644 --- a/assets/scss/front/course-spotlight/_players.scss +++ b/assets/scss/front/course-spotlight/_players.scss @@ -7,11 +7,6 @@ margin-left: -25px; } } - - .plyr--youtube iframe { - top: -50%; - height: 200%!important; - } } .tutor-video-player-wrapper { From a7c99310f8337186bf9384b25235dbfb3d841466 Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Thu, 24 Aug 2023 15:17:24 +0600 Subject: [PATCH 59/78] Update require course complete condition --- assets/react/front/tutor-front.js | 11 ++++++----- templates/single/lesson/content.php | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/assets/react/front/tutor-front.js b/assets/react/front/tutor-front.js index 56e9b3f698..d7edcc6146 100644 --- a/assets/react/front/tutor-front.js +++ b/assets/react/front/tutor-front.js @@ -129,6 +129,7 @@ jQuery(document).ready(function($) { ajaxurl: window._tutorobject.ajaxurl, nonce_key: window._tutorobject.nonce_key, played_once: false, + max_seek_time: 0, video_data: function() { const video_track_data = $('#tutor_video_tracking_information').val(); return video_track_data ? JSON.parse(video_track_data) : {}; @@ -145,10 +146,9 @@ jQuery(document).ready(function($) { listeners: { ...(that.isRequiredPercentage() && { seek(e) { - var currentTime = player.currentTime; var newTime = that.getTargetTime(player, e); // Disallow moving forward - if (newTime > currentTime) { + if (newTime > that.max_seek_time) { e.preventDefault(); tutor_toast(__('Warning', 'tutor'), __(`Forward seeking is not allowed for this video lesson.`, 'tutor'), 'error'); return false; @@ -161,7 +161,7 @@ jQuery(document).ready(function($) { player.on('ready', function(event) { const instance = event.detail.plyr; const { best_watch_time = 0 } = video_data || {}; - if (best_watch_time > 0) { + if (_tutorobject.tutor_pro_url && best_watch_time > 0) { var previous_duration = Math.round(best_watch_time); var previousTimeSetter = setTimeout(function(){ if (player.playing !== true && player.currentTime !== previous_duration) { @@ -232,6 +232,7 @@ jQuery(document).ready(function($) { data_send = Object.assign(data, options); } $.post(this.ajaxurl, data_send); + this.max_seek_time = video_data.best_watch_time > instance.currentTime ? video_data.best_watch_time : instance.currentTime; }, autoload_content: function() { console.log('Autoloader called'); @@ -251,8 +252,8 @@ jQuery(document).ready(function($) { return false; } - const { strict_mode, control_video_lesson_completion } = video_data; - if (_tutorobject.tutor_pro_url && strict_mode && control_video_lesson_completion) { + const { strict_mode, control_video_lesson_completion, lesson_completed, is_enrolled } = video_data; + if (_tutorobject.tutor_pro_url && is_enrolled && !lesson_completed && strict_mode && control_video_lesson_completion) { return true; } return false; diff --git a/templates/single/lesson/content.php b/templates/single/lesson/content.php index 81e9ba1ad6..00e060c398 100644 --- a/templates/single/lesson/content.php +++ b/templates/single/lesson/content.php @@ -77,6 +77,8 @@ $json_data['control_video_lesson_completion'] = (bool) tutor_utils()->get_option( 'control_video_lesson_completion', false ); $json_data['required_percentage'] = (int) tutor_utils()->get_option( 'required_percentage_to_complete_video_lesson', 80 ); $json_data['video_duration'] = $video_info->duration_sec ?? 0; + $json_data['lesson_completed'] = tutor_utils()->is_completed_lesson( $content_id, get_current_user_id() ) !== false; + $json_data['is_enrolled'] = tutor_utils()->is_enrolled( $course_id, get_current_user_id() ) !== false; ?> From 4367edc6582e12ff976c5de7629f23995511632a Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Thu, 24 Aug 2023 15:17:29 +0600 Subject: [PATCH 60/78] whats new menu re-position --- classes/Admin.php | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/classes/Admin.php b/classes/Admin.php index 27a189340e..8395110146 100644 --- a/classes/Admin.php +++ b/classes/Admin.php @@ -50,6 +50,7 @@ public function __construct() { // Handle flash toast message for redirect_to util helper. add_action( 'admin_head', array( new Utils(), 'handle_flash_message' ), 999 ); + add_action( 'tutor_after_settings_menu', array( $this, 'whats_new_menu' ), 11 ); } /** @@ -136,8 +137,6 @@ public function register_menu() { do_action( 'tutor_after_settings_menu' ); - add_submenu_page( 'tutor', __( "What's New", 'tutor' ), __( "What's New", 'tutor' ), 'manage_options', 'tutor-whats-new', array( $this, 'whats_new_page' ) ); - if ( ! $has_pro ) { add_submenu_page( 'tutor', __( 'Upgrade to Pro', 'tutor' ), __( 'Upgrade to Pro', 'tutor' ), 'manage_options', 'tutor-get-pro', array( $this, 'tutor_get_pro' ) ); } @@ -150,8 +149,29 @@ public function register_menu() { * * @return void */ - public function whats_new_page() { - include tutor()->path . 'views/pages/whats-new.php'; + public function whats_new_menu() { + $plugin_info = tutils()->get_remote_plugin_info(); + $remote_version = $plugin_info->version ?? TUTOR_VERSION; + $installed_version = '1.0.0'; + // $installed_version = TUTOR_VERSION; + $update_required = version_compare( $remote_version, $installed_version, '>' ); + + + $menu_text = __( "What's New", 'tutor' ); + if ( $update_required ) { + $menu_text .= ' 1'; + } + + add_submenu_page( + 'tutor', + __( "What's New", 'tutor' ), + $menu_text, + 'manage_options', + 'tutor-whats-new', + function() use ( $remote_version, $installed_version, $update_required ) { + include tutor()->path . 'views/pages/whats-new.php'; + } + ); } /** From 5b699836d4690d302a4e9f35fe118ea4bfc7b2bc Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Thu, 24 Aug 2023 15:18:03 +0600 Subject: [PATCH 61/78] Button text changed --- views/pages/course-bundle.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/pages/course-bundle.php b/views/pages/course-bundle.php index a4a965dfe2..2f2567419d 100644 --- a/views/pages/course-bundle.php +++ b/views/pages/course-bundle.php @@ -18,7 +18,7 @@
    From 9f7e72850008156418dcf449e399f46c42d8b86a Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Thu, 24 Aug 2023 15:19:09 +0600 Subject: [PATCH 62/78] whats new page css update --- assets/scss/admin-dashboard/_tutor-admin.scss | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/assets/scss/admin-dashboard/_tutor-admin.scss b/assets/scss/admin-dashboard/_tutor-admin.scss index f9acf47a72..f29a1245a1 100644 --- a/assets/scss/admin-dashboard/_tutor-admin.scss +++ b/assets/scss/admin-dashboard/_tutor-admin.scss @@ -1791,8 +1791,49 @@ h2.tutor-page-heading { background-color: white; margin: 25px auto; border-radius: 8px; + padding: 0 0 40px 0; - padding: 40px 0; + .tutor-update-available{ + background: #FFF5E0; + margin-bottom: 25px; + border-top-left-radius: 8px; + border-top-right-radius: 8px; + padding: 25px; + + .tutor-version-alert{ + display: flex; + gap: 15px; + justify-content: center; + align-items: center; + margin-bottom: 10px; + p{ + margin: 0; + } + } + + .tutor-update-version{ + border-radius: 6px; + background-color: #fff; + padding: 20px 25px; + display: flex; + gap: 25px; + align-items: center; + width: 200px; + margin: 0 auto; + + >div:nth-child(2) { + h3,p{ + margin: 0; + } + p{ + margin-top: 5px; + } + a{ + text-decoration: none; + } + } + } + } .tutor-whats-new-header{ text-align: center; From 9e047e58b29876960f2985b563e90c94378e6ca9 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Thu, 24 Aug 2023 15:19:56 +0600 Subject: [PATCH 63/78] changelog added --- views/pages/whats-new.php | 158 ++++++++++++++++++++++++-------------- 1 file changed, 99 insertions(+), 59 deletions(-) diff --git a/views/pages/whats-new.php b/views/pages/whats-new.php index 7bab6edd98..91a286edbb 100644 --- a/views/pages/whats-new.php +++ b/views/pages/whats-new.php @@ -8,66 +8,77 @@ * @since 2.2.4 */ -$changelogs = array( - 'new' => array( - array( - 'title' => 'E-mail background image change support added.', + $changelogs = array( + 'new' => array( + array( + 'title' => 'Option to control when students can skip lessons on Tutor LMS Player', 'is_pro' => true, - ), - array( - 'title' => 'Basic editor support for profile bio change.', - ), - array( - 'title' => 'Instructor\'s earning summary on instructor list.', + ), + array( + 'title' => 'Hide video branding (YouTube) in Tutor LMS Player', 'is_pro' => true, - ), - array( - 'title' => 'Latex support to lesson and quiz editor.', - ), - array( - 'title' => 'Delete cancelled enrollment from enrollment list.', + ), + array( + 'title' => 'Let students resume lessons where they left off (Tutor LMS Player)', 'is_pro' => true, - ), - array( - 'title' => 'Private and Schedule filter tab in courses and course bundle listing page.', - ), - ), - 'update' => array( - array( - 'title' => 'Email address also added to Analytics CSV data along with display name.', - ), - array( - 'title' => 'Remove force password reset form to tutor.', - ), - ), - 'fix' => array( - array( - 'title' => 'Quiz attempt list showing wrong.', - ), - array( - 'title' => "Some strings aren't translatable.", - ), - array( - 'title' => 'In the Course List page of WP Admin, the Edit menu had design issue.', - ), - array( - 'title' => 'Instructors can make withdrawal requests greater than their available balance.', - ), - array( - 'title' => 'Invalid or no google client ID found for Google login.', - ), - array( - 'title' => 'Course enrollment email to student issue.', - ), - array( - 'title' => 'HTML code appearing on the course details page enrollment box, if user use the Restrict Content Pro.', - ), + ), + array( + 'title' => 'Option to change background image in email Template', + 'is_pro' => true, + ), + array( + 'title' => 'WP editor support on the frontend instructor profile-bio field' + ), + array( + 'title' => "Showcase instructor's earning summary on the instructor list", + 'is_pro' => true, + ), + array( + 'title' => 'Latex support to lesson and quiz editor' + ), + array( + 'title' => 'Deletion of canceled enrollment from the enrollment list', + 'is_pro' => true, + ), array( - 'title' => 'Student can complete course without passing the quiz.', - ), - ), + 'title' => 'Private and Schedule filter tabs in course bundle listing page', + 'is_pro' => true, + ), + array( + 'title' => 'Private and Schedule filter tabs in course listing page' + ), + ), + 'update' => array( + array( + 'title' => 'Email address to Analytics CSV data' + ), + array( + 'title' => 'Tutor LMS password reset form only works for Tutor LMS login page' + ), + ), + 'fix' => array( + array( + 'title' => 'Incorrect information on the quiz attempt list' + ), + array( + 'title' => 'Instructors making withdrawal requests exceeding available balance' + ), + array( + 'title' => 'Invalid or missing Google client ID for Google login' + ), + array( + 'title' => 'Course enrollment email to students' + ), + array( + 'title' => 'Error on completing a course when the Certificate addon is disabled' + ), + array( + 'title' => 'Several known bugs' + ), + ), ); + function tutor_whatnew_item( $type, $log ) { $obj = (object) $log; ?> @@ -84,6 +95,29 @@ function tutor_whatnew_item( $type, $log ) {
    + +
    +
    + + + +

    New version available.

    +
    + +
    + + + + + +
    +

    Tutor LMS v

    +

    Update Now

    +
    +
    +
    + +
    @@ -111,9 +145,11 @@ function tutor_whatnew_item( $type, $log ) {

    What's New 🥳 in Tutor LMS

    -

    Congratulations! You have successfully upgraded to
    - the latest version of Tutor LMS (v) + +

    You are using Tutor LMS (v)
    + Here are features and improvements made to this version!

    +
    @@ -125,7 +161,7 @@ function tutor_whatnew_item( $type, $log ) {
    -

    Changelog (v)

    +

    Changelog (v)

    From 03cf2a49d602d8c81e7d8f9b824d57899e92fe10 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Thu, 24 Aug 2023 15:20:47 +0600 Subject: [PATCH 64/78] new util helper added --- classes/Utils.php | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/classes/Utils.php b/classes/Utils.php index 43b6e7bb11..2563b16973 100644 --- a/classes/Utils.php +++ b/classes/Utils.php @@ -9065,7 +9065,7 @@ public function text_editor_config( $args = array() ) { * Get config for profile bio editor. * * @since 2.2.4 - * + * * @param string $textarea_name textarea name for post request. * * @return array @@ -9074,7 +9074,7 @@ public function get_profile_bio_editor_config( $textarea_name = 'tutor_profile_b return $this->text_editor_config( array( 'textarea_name' => $textarea_name, - 'tinymce' => array( + 'tinymce' => array( 'toolbar1' => 'bold,italic,underline,blockquote,bullist,numlist,alignleft,aligncenter,alignright,undo,redo,removeformat', 'toolbar2' => '', 'toolbar3' => '', @@ -9792,4 +9792,22 @@ public function error_message( $key = '401' ) { return $error_message; } + /** + * Get remote plugin information by plugin slug. + * + * @since 2.2.4 + * + * @param string $plugin_slug + * + * @return object|bool if success return object otherwise return false; + */ + public function get_remote_plugin_info( $plugin_slug = 'tutor' ) { + $response = wp_remote_get( "https://api.wordpress.org/plugins/info/1.0/{$plugin_slug}.json" ); + if ( is_wp_error( $response ) ) { + return false; + } + + return (object) json_decode( $response['body'], true ); + } + } From 2bfe6f2acee91b7e4732bdf896b12e687859509d Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Thu, 24 Aug 2023 15:32:20 +0600 Subject: [PATCH 65/78] image url changed --- views/pages/whats-new.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/views/pages/whats-new.php b/views/pages/whats-new.php index 91a286edbb..49f503299d 100644 --- a/views/pages/whats-new.php +++ b/views/pages/whats-new.php @@ -186,17 +186,17 @@ function tutor_whatnew_item( $type, $log ) {

    You are not only missing these features, you are missing your revenues too!

    - pro features + pro features
    - pro features + pro features
    - Get Tutor Pro + Get Tutor LMS Pro
    From 56299100619cf77f26f7e4c21cf7eb19409e1ac9 Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Thu, 24 Aug 2023 15:49:26 +0600 Subject: [PATCH 66/78] Update video seek time condition --- assets/react/front/tutor-front.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/assets/react/front/tutor-front.js b/assets/react/front/tutor-front.js index d7edcc6146..0f30d4eaba 100644 --- a/assets/react/front/tutor-front.js +++ b/assets/react/front/tutor-front.js @@ -232,7 +232,11 @@ jQuery(document).ready(function($) { data_send = Object.assign(data, options); } $.post(this.ajaxurl, data_send); - this.max_seek_time = video_data.best_watch_time > instance.currentTime ? video_data.best_watch_time : instance.currentTime; + + const seekTime = video_data.best_watch_time > instance.currentTime ? video_data.best_watch_time : instance.currentTime; + if (seekTime > this.max_seek_time) { + this.max_seek_time = seekTime; + } }, autoload_content: function() { console.log('Autoloader called'); From 228eea8a631b4da4633d22087a2e8d7a5235188e Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Thu, 24 Aug 2023 16:13:16 +0600 Subject: [PATCH 67/78] data cached for 1 hour --- classes/Admin.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/classes/Admin.php b/classes/Admin.php index 8395110146..64c2901480 100644 --- a/classes/Admin.php +++ b/classes/Admin.php @@ -150,18 +150,26 @@ public function register_menu() { * @return void */ public function whats_new_menu() { - $plugin_info = tutils()->get_remote_plugin_info(); + $transient_key = 'tutor_plugin_info'; + $plugin_info = get_transient( $transient_key ); + + if ( false === $plugin_info ) { + $plugin_info = tutils()->get_remote_plugin_info(); + $hour_in_seconds = 1800; + set_transient( $transient_key, $plugin_info, $hour_in_seconds ); + } + $remote_version = $plugin_info->version ?? TUTOR_VERSION; $installed_version = '1.0.0'; + // TODO need to change. // $installed_version = TUTOR_VERSION; $update_required = version_compare( $remote_version, $installed_version, '>' ); - $menu_text = __( "What's New", 'tutor' ); if ( $update_required ) { $menu_text .= ' 1'; } - + add_submenu_page( 'tutor', __( "What's New", 'tutor' ), From d362f32f65f143225c21b75fd3b5dcf29d75b356 Mon Sep 17 00:00:00 2001 From: Mohammad Ibrahim Date: Thu, 24 Aug 2023 16:35:57 +0600 Subject: [PATCH 68/78] Update TutorEDD.php wpcs updated --- classes/TutorEDD.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/TutorEDD.php b/classes/TutorEDD.php index 8fc1568a68..e0df42626b 100644 --- a/classes/TutorEDD.php +++ b/classes/TutorEDD.php @@ -173,7 +173,7 @@ public function is_course_purchasable( $bool, $course_id ) { */ public function get_tutor_course_price( $price, $course_id ) { $product_id = tutor_utils()->get_course_product_id( $course_id ); - if( tutils()->has_edd() ){ + if ( tutils()->has_edd() ) { return edd_price( $product_id, false ); } From 19d9772b89cacfa2cfe96e1f765a6d2090f4219e Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Fri, 25 Aug 2023 13:57:21 +0600 Subject: [PATCH 69/78] readme changelog added --- readme.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/readme.txt b/readme.txt index db81173cc5..e08dbbbb92 100644 --- a/readme.txt +++ b/readme.txt @@ -225,6 +225,29 @@ Looking for the best LMS for WordPress? Get Tutor and start your e-learning webs == Changelog == += 2.2.4 - August 28, 2023 + +New: Added Video Lesson Completion Control when using Tutor Player. +New: Added ability to hide video branding in Tutor Player. +New: Implemented automatic video lesson resume feature in Tutor Player. +New: Added support for changing the Email Template background image. +New: Added WP editor support on the frontend instructor profile-bio field. +New: Added instructor’s earning summary on the instructor list. +New: Added Latex support to lesson and quiz editor. +New: Added deletion of canceled enrollment from the enrollment list. +New: Added Private and Schedule filter tabs in courses and course bundle listing page. +Update: Added email address to Analytics CSV data. +Update: Removed Tutor LMS's force password reset form. +Fix: Fixed issue with displaying incorrect information on the quiz attempt list. +Fix: Fixed issue with untranslated strings. +Fix: Resolved design problem with the Edit menu on the Course List page. +Fix: Fixed issue with instructors making withdrawal requests exceeding available balance. +Fix: Fixed issue with invalid or missing Google client ID for Google login. +Fix: Fixed issue with course enrollment email to students. +Fix: Removed the appearance of HTML code in the course details page enrollment box when using Restrict Content Pro. +Fix: Fixed issue with missing space in quiz attempt table headings. +Fix: Resolved fatal error on completing a course when the Certificate addon is disabled. + = 2.2.3 - July 20, 2023 New: Quiz question description section now has WP Editor support. From df376e5d3397728042ec2008c016154a84a9c56d Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Fri, 25 Aug 2023 14:01:39 +0600 Subject: [PATCH 70/78] Update tutor player seek time condition --- assets/react/front/tutor-front.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/assets/react/front/tutor-front.js b/assets/react/front/tutor-front.js index 0f30d4eaba..b97edb66b9 100644 --- a/assets/react/front/tutor-front.js +++ b/assets/react/front/tutor-front.js @@ -146,11 +146,13 @@ jQuery(document).ready(function($) { listeners: { ...(that.isRequiredPercentage() && { seek(e) { - var newTime = that.getTargetTime(player, e); + const newTime = that.getTargetTime(player, e); + const currentTime = player.currentTime; + const max_seek_time = currentTime > that.max_seek_time ? currentTime : that.max_seek_time; // Disallow moving forward - if (newTime > that.max_seek_time) { + if (newTime > max_seek_time) { e.preventDefault(); - tutor_toast(__('Warning', 'tutor'), __(`Forward seeking is not allowed for this video lesson.`, 'tutor'), 'error'); + tutor_toast(__('Warning', 'tutor'), __(`Forward seeking is not allowed.`, 'tutor'), 'error'); return false; } return true; @@ -179,7 +181,7 @@ jQuery(document).ready(function($) { }); let tempTimeNow = 0; - let intervalSeconds = 30; //Send to tutor backend about video playing time in this interval + let intervalSeconds = 10; //Send to tutor backend about video playing time in this interval player.on('timeupdate', function(event) { const instance = event.detail.plyr; const tempTimeNowInSec = tempTimeNow / 4; //timeupdate firing 250ms interval @@ -284,7 +286,7 @@ jQuery(document).ready(function($) { if (completedPercentage < required_percentage) { const complete_lesson_btn = $('button[name="complete_lesson_btn"]'); complete_lesson_btn.attr('disabled', true); - complete_lesson_btn.wrap('
    ').after(`You have to watch ${video_data.required_percentage}% of this video lesson.`); + complete_lesson_btn.wrap('
    ').after(`Watch at least ${video_data.required_percentage}% to complete the lesson.`); } }, getPercentage: function(value, total) { From a20a679988bea966ac000e8ac3b24528be261eba Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 28 Aug 2023 12:49:48 +0600 Subject: [PATCH 71/78] css update --- assets/scss/admin-dashboard/_tutor-admin.scss | 70 +++++++++++++------ 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/assets/scss/admin-dashboard/_tutor-admin.scss b/assets/scss/admin-dashboard/_tutor-admin.scss index f29a1245a1..5358a9bcf0 100644 --- a/assets/scss/admin-dashboard/_tutor-admin.scss +++ b/assets/scss/admin-dashboard/_tutor-admin.scss @@ -1791,11 +1791,9 @@ h2.tutor-page-heading { background-color: white; margin: 25px auto; border-radius: 8px; - padding: 0 0 40px 0; .tutor-update-available{ background: #FFF5E0; - margin-bottom: 25px; border-top-left-radius: 8px; border-top-right-radius: 8px; padding: 25px; @@ -1807,6 +1805,7 @@ h2.tutor-page-heading { align-items: center; margin-bottom: 10px; p{ + font-weight: 500; margin: 0; } } @@ -1818,7 +1817,7 @@ h2.tutor-page-heading { display: flex; gap: 25px; align-items: center; - width: 200px; + width: 410px; margin: 0 auto; >div:nth-child(2) { @@ -1829,9 +1828,32 @@ h2.tutor-page-heading { margin-top: 5px; } a{ + color: #00F; text-decoration: none; } } + + .tutor-whats-new-update-now { + align-items: center; + display: flex; + gap: 8px; + font-size: 14px; + padding: 8px 20px; + background: #0049f8; + border-radius: 6px; + text-decoration: none; + color: #fff; + margin-left: auto; + + &:focus { + box-shadow: none; + outline: none; + } + + &:hover{ + background: #0849e1; + } + } } } @@ -1842,6 +1864,7 @@ h2.tutor-page-heading { min-height: 200px; border-bottom: 1px solid #f0eaea; position: relative; + padding-top: 50px; h1{ font-size: 40px; @@ -1878,7 +1901,7 @@ h2.tutor-page-heading { bottom: 20px; } &.tutor-symbol-right-top { - top: 0; + top: 30px; right: 0; width: 60px; } @@ -1907,7 +1930,7 @@ h2.tutor-page-heading { .tutor-changelog-wrapper{ width: 75%; margin: 0 auto; - margin-top: 100px; + padding: 100px 0px 80px 0px; h4{ font-size: 16px; @@ -1915,27 +1938,35 @@ h2.tutor-page-heading { .tutor-changelog-list{ list-style: disc; - padding-left: 20px; + padding-left: 16px; } } .tutor-whats-new-pro-section{ - width: 75%; - margin: 0 auto; - margin-top: 100px; + padding: 80px 0px; text-align: center; + + &.tutor-pro-section-top { + background-color: rgba(204, 219, 254, 0.1); + } + + & > div { + max-width: 75%; + margin: 0 auto; + } h2{ - max-width: 50%; - margin: 0 auto 40px; - font-size: 22px; + margin-top: 0; + margin-bottom: 30px; + font-size: 30px; line-height: 1.3; } - @include breakpoint-max(992) { - h2{ - max-width: 100%; - } + p { + font-size: 18px; + font-weight: 500; + margin-top: 20px; + margin-bottom: 0px; } .tutor-whats-new-pro-banner{ @@ -1950,15 +1981,14 @@ h2.tutor-page-heading { .tutor-whats-new-action-btn{ display: inline-block; font-size: 15px; - padding: 10px 30px; + padding: 12px 30px; background: #0049F8; border-radius: 6px; text-decoration: none; color: #fff; - margin-top: 36px; - margin-bottom: 30px; + margin-top: 30px; &:hover{ - background: #0b51f3; + background: #0849e1; } .tutor-icon-crown { From 134241bcb42d56da76e55b785ef6948d95c5e35d Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 28 Aug 2023 12:50:28 +0600 Subject: [PATCH 72/78] manual version removed --- classes/Admin.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/classes/Admin.php b/classes/Admin.php index 64c2901480..1e2249ba2e 100644 --- a/classes/Admin.php +++ b/classes/Admin.php @@ -160,10 +160,8 @@ public function whats_new_menu() { } $remote_version = $plugin_info->version ?? TUTOR_VERSION; - $installed_version = '1.0.0'; - // TODO need to change. - // $installed_version = TUTOR_VERSION; - $update_required = version_compare( $remote_version, $installed_version, '>' ); + $installed_version = TUTOR_VERSION; + $update_required = version_compare( $remote_version, $installed_version, '>' ); $menu_text = __( "What's New", 'tutor' ); if ( $update_required ) { From 619cc349ff4b75c672f7ebbf47efb31e3da0d475 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 28 Aug 2023 12:51:50 +0600 Subject: [PATCH 73/78] whats new changelog updated and design change --- views/pages/whats-new.php | 54 ++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/views/pages/whats-new.php b/views/pages/whats-new.php index 49f503299d..25616f5496 100644 --- a/views/pages/whats-new.php +++ b/views/pages/whats-new.php @@ -11,7 +11,11 @@ $changelogs = array( 'new' => array( array( - 'title' => 'Option to control when students can skip lessons on Tutor LMS Player', + 'title' => 'Restrict students from completing video lessons until reaching a certain length', + 'is_pro' => true, + ), + array( + 'title' => 'Restrict forward seeking within the defined video length', 'is_pro' => true, ), array( @@ -19,7 +23,7 @@ 'is_pro' => true, ), array( - 'title' => 'Let students resume lessons where they left off (Tutor LMS Player)', + 'title' => 'Let students automatically resume video lessons where they left off', 'is_pro' => true, ), array( @@ -49,6 +53,9 @@ ), ), 'update' => array( + array( + 'title' => 'WordPress 6.3 compatibility' + ), array( 'title' => 'Email address to Analytics CSV data' ), @@ -101,7 +108,7 @@ function tutor_whatnew_item( $type, $log ) { -

    New version available.

    +

    New version available. You didn't update yet!

    @@ -112,8 +119,14 @@ function tutor_whatnew_item( $type, $log ) {

    Tutor LMS v

    -

    Update Now

    +

    More info...

    + + + + + Update Now +
    @@ -182,21 +195,32 @@ function tutor_whatnew_item( $type, $log ) { has_pro ) : ?> -
    -

    You are not only missing these features, you are missing your revenues too!

    +
    +
    +

    Upgrade to Tutor LMS Pro and Maximize
    Your Revenue Potential!

    -
    - pro features +
    + pro features +
    +
    -
    - pro features -
    +
    +
    +

    Users love Tutor LMS Pro,
    you will love it too!

    - - Get Tutor LMS Pro +
    + pro features +
    + +

    Get access to plenty of functional addons, useful integrations,
    new exciting features and much more, so why wait!

    + + + Get Tutor LMS Pro + +
    From 29c1be3c391a5f90c4ac0847749c8d92768e76e2 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 28 Aug 2023 12:52:17 +0600 Subject: [PATCH 74/78] warning message updated --- assets/react/front/tutor-front.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/react/front/tutor-front.js b/assets/react/front/tutor-front.js index b97edb66b9..606b4c17b6 100644 --- a/assets/react/front/tutor-front.js +++ b/assets/react/front/tutor-front.js @@ -152,7 +152,7 @@ jQuery(document).ready(function($) { // Disallow moving forward if (newTime > max_seek_time) { e.preventDefault(); - tutor_toast(__('Warning', 'tutor'), __(`Forward seeking is not allowed.`, 'tutor'), 'error'); + tutor_toast(__('Warning', 'tutor'), __(`Forward seeking is disabled.`, 'tutor'), 'error'); return false; } return true; From c85fc65d68662dd6795539483ca348b4a8f2fd8e Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 28 Aug 2023 13:05:18 +0600 Subject: [PATCH 75/78] esc_html js helper added --- assets/react/lib/tutor.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/assets/react/lib/tutor.js b/assets/react/lib/tutor.js index f8a0d9da1c..91f8dfb079 100644 --- a/assets/react/lib/tutor.js +++ b/assets/react/lib/tutor.js @@ -432,6 +432,28 @@ window.tutor_toast = function( title, description, type, autoClose = true ) { } }; +/** + * Escape HTML and return safe HTML + * + * @since 2.2.4 + * + * @param {string} unsafeText HTML string + * @returns string + */ +window.tutor_esc_html = function (unsafeText) { + let safeHTML = '' + let div = document.createElement('div'); + /** + * When set an HTML string to an element's innerText + * the browser automatically escapes any HTML tags and + * treats the content as plain text. + */ + div.innerText = unsafeText; + safeHTML = div.innerHTML; + div.remove() + + return safeHTML; +} // enable custom selector when modal opens window.addEventListener('tutor_modal_shown', (e) => { From d156d6fb59da374f33e0cb1afc88dc1f8a3e3597 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 28 Aug 2023 13:05:50 +0600 Subject: [PATCH 76/78] fix - xss security on tutor dropdown select --- assets/react/front/_select_dd_search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/react/front/_select_dd_search.js b/assets/react/front/_select_dd_search.js index 4af7f18023..d8cb8219f9 100644 --- a/assets/react/front/_select_dd_search.js +++ b/assets/react/front/_select_dd_search.js @@ -143,7 +143,7 @@ window.selectSearchField = (selectElement) => { Array.from(options).forEach((item) => { optionsList += `
    - ${item.text} + ${tutor_esc_html(item.text)}
    `; }); From 6206b1bd78d175d2fb8c06a6b24cdfb11c6030a5 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 28 Aug 2023 13:32:32 +0600 Subject: [PATCH 77/78] readme changelog updated --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index e08dbbbb92..f96ea15962 100644 --- a/readme.txt +++ b/readme.txt @@ -236,6 +236,7 @@ New: Added instructor’s earning summary on the instructor list. New: Added Latex support to lesson and quiz editor. New: Added deletion of canceled enrollment from the enrollment list. New: Added Private and Schedule filter tabs in courses and course bundle listing page. +Update: WordPress 6.3 compatibility. Update: Added email address to Analytics CSV data. Update: Removed Tutor LMS's force password reset form. Fix: Fixed issue with displaying incorrect information on the quiz attempt list. From 578434fd1990f8321ab74029dd0a702c02252de6 Mon Sep 17 00:00:00 2001 From: "Md.Harun-Ur-Rashid" Date: Mon, 28 Aug 2023 15:02:38 +0600 Subject: [PATCH 78/78] removed tutor_esc_html helper call --- assets/react/front/_select_dd_search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/react/front/_select_dd_search.js b/assets/react/front/_select_dd_search.js index d8cb8219f9..4af7f18023 100644 --- a/assets/react/front/_select_dd_search.js +++ b/assets/react/front/_select_dd_search.js @@ -143,7 +143,7 @@ window.selectSearchField = (selectElement) => { Array.from(options).forEach((item) => { optionsList += `
    - ${tutor_esc_html(item.text)} + ${item.text}
    `; });