| @@ -9,26 +9,20 @@ | ||
| 9 | 9 | */ |
| 10 | 10 | |
| 11 | 11 | namespace TUTOR; |
| 12 | 12 | |
| 13 | -defined( 'ABSPATH' ) || exit; | |
| 13 | +if ( ! defined( 'ABSPATH' ) ) { | |
| 14 | + exit; | |
| 15 | +} | |
| 14 | 16 | |
| 15 | -use Tutor\Components\Button; | |
| 16 | -use Tutor\Components\Constants\Size; | |
| 17 | -use Tutor\Components\Constants\Variant; | |
| 18 | -use Tutor\Components\Progress; | |
| 19 | -use Tutor\Ecommerce\Tax; | |
| 20 | -use Tutor\Models\QuizModel; | |
| 17 | +use stdClass; | |
| 18 | +use TUTOR\Input; | |
| 21 | 19 | use Tutor\Helpers\HttpHelper; |
| 22 | 20 | use Tutor\Models\CourseModel; |
| 23 | -use Tutor\Components\Tooltip; | |
| 24 | 21 | use Tutor\Ecommerce\Ecommerce; |
| 25 | -use Tutor\Helpers\DateTimeHelper; | |
| 26 | 22 | use Tutor\Traits\JsonResponse; |
| 27 | 23 | use Tutor\Helpers\ValidationHelper; |
| 28 | -use Tutor\Models\EnrollmentModel; | |
| 29 | -use Tutor\Options_V2; | |
| 30 | -use TUTOR_ASSIGNMENTS\Assignments; | |
| 24 | +use TutorPro\CourseBundle\Models\BundleModel; | |
| 31 | 25 | |
| 32 | 26 | /** |
| 33 | 27 | * Course Class |
| 34 | 28 | * |
| @@ -70,16 +64,8 @@ | ||
| 70 | 64 | const SELLING_OPTION_MEMBERSHIP = 'membership'; |
| 71 | 65 | const SELLING_OPTION_ALL = 'all'; |
| 72 | 66 | |
| 73 | 67 | /** |
| 74 | - * Tax collection settings meta | |
| 75 | - * | |
| 76 | - * @since 3.7.0 | |
| 77 | - */ | |
| 78 | - const TAX_ON_SINGLE_META = 'tutor_tax_on_single'; | |
| 79 | - const TAX_ON_SUBSCRIPTION_META = 'tutor_tax_on_subscription'; | |
| 80 | - | |
| 81 | - /** | |
| 82 | 68 | * Additional data meta |
| 83 | 69 | * |
| 84 | 70 | * @since 3.6.0 |
| 85 | 71 | */ |
| @@ -98,15 +84,8 @@ | ||
| 98 | 84 | const PUBLIC_COURSE_META = '_tutor_is_public_course'; |
| 99 | 85 | const COURSE_SETTINGS_META = '_tutor_course_settings'; |
| 100 | 86 | const COURSE_LEVEL_META = '_tutor_course_level'; |
| 101 | 87 | |
| 102 | - /** | |
| 103 | - * Meta keys used to identify and store Tutor course order data. | |
| 104 | - * | |
| 105 | - * @since 4.0.0 | |
| 106 | - */ | |
| 107 | - const IS_TUTOR_ORDER_FOR_COURSE_META = '_is_tutor_order_for_course'; | |
| 108 | - const TUTOR_ORDER_FOR_COURSE_ID_META = '_tutor_order_for_course_id_'; | |
| 109 | 88 | |
| 110 | 89 | /** |
| 111 | 90 | * Additional course meta info |
| 112 | 91 | * |
| @@ -160,8 +139,15 @@ | ||
| 160 | 139 | */ |
| 161 | 140 | add_action( 'save_tutor_course', array( $this, 'attach_product_with_course' ), 10, 2 ); |
| 162 | 141 | |
| 163 | 142 | /** |
| 143 | + * Add course level to course settings | |
| 144 | + * | |
| 145 | + * @since v.1.4.1 | |
| 146 | + */ | |
| 147 | + add_filter( 'tutor_course_settings_tabs', array( $this, 'add_course_level_to_settings' ) ); | |
| 148 | + | |
| 149 | + /** | |
| 164 | 150 | * Enable Disable Course Details Page Feature |
| 165 | 151 | * |
| 166 | 152 | * @since v.1.4.8 |
| 167 | 153 | */ |
| @@ -207,14 +193,9 @@ | ||
| 207 | 193 | * Delete course data after deleted course |
| 208 | 194 | * |
| 209 | 195 | * @since v.1.6.6 |
| 210 | 196 | */ |
| 211 | - add_action( | |
| 212 | - 'deleted_post', | |
| 213 | - function ( $post_id ) { | |
| 214 | - ( new CourseModel() )->delete_course_data( $post_id ); | |
| 215 | - } | |
| 216 | - ); | |
| 197 | + add_action( 'deleted_post', array( new CourseModel(), 'delete_course_data' ) ); | |
| 217 | 198 | |
| 218 | 199 | /** |
| 219 | 200 | * Delete course data after deleted course |
| 220 | 201 | * |
| @@ -257,9 +238,9 @@ | ||
| 257 | 238 | * @since 1.9.8 |
| 258 | 239 | */ |
| 259 | 240 | add_action( 'tutor_do_enroll_after_login_if_attempt', array( $this, 'enroll_after_login_if_attempt' ), 10, 2 ); |
| 260 | 241 | |
| 261 | - add_action( 'wp_ajax_tutor_update_course_content_order', array( $this, 'ajax_update_course_content_order' ) ); | |
| 242 | + add_action( 'wp_ajax_tutor_update_course_content_order', array( $this, 'tutor_update_course_content_order' ) ); | |
| 262 | 243 | |
| 263 | 244 | add_action( 'wp_ajax_tutor_get_wc_product', array( $this, 'get_wc_product' ) ); |
| 264 | 245 | add_action( 'wp_ajax_tutor_get_wc_products', array( $this, 'get_wc_products' ) ); |
| 265 | 246 | |
| @@ -307,13 +288,9 @@ | ||
| 307 | 288 | add_filter( 'tutor_user_list_args', array( $this, 'user_list_args_for_instructor' ) ); |
| 308 | 289 | |
| 309 | 290 | add_filter( 'template_include', array( $this, 'handle_password_protected' ) ); |
| 310 | 291 | add_action( 'login_form_postpass', array( $this, 'handle_password_submit' ) ); |
| 311 | - add_filter( 'post_password_required', array( $this, 'bypass_password_for_enrolled' ), 10, 2 ); | |
| 312 | 292 | add_filter( 'the_preview', array( $this, 'handle_schedule_courses' ) ); |
| 313 | - | |
| 314 | - add_action( 'tutor_course_action_btn', array( $this, 'render_course_action_btn' ) ); | |
| 315 | - add_action( 'wp_ajax_tutor_complete_course', array( $this, 'ajax_tutor_complete_course' ) ); | |
| 316 | 293 | } |
| 317 | 294 | |
| 318 | 295 | /** |
| 319 | 296 | * Handle schedule courses preview for instructors. |
| @@ -355,31 +332,8 @@ | ||
| 355 | 332 | } |
| 356 | 333 | } |
| 357 | 334 | |
| 358 | 335 | /** |
| 359 | - * Bypass password protection for enrolled users. | |
| 360 | - * | |
| 361 | - * @since 4.0.0 | |
| 362 | - * | |
| 363 | - * @param bool $required Whether the password is required. | |
| 364 | - * @param \WP_Post $post The post object. | |
| 365 | - * | |
| 366 | - * @return bool false if the current user is enrolled, original value otherwise. | |
| 367 | - */ | |
| 368 | - public function bypass_password_for_enrolled( $required, $post ) { | |
| 369 | - if ( ! $required ) { | |
| 370 | - return $required; | |
| 371 | - } | |
| 372 | - | |
| 373 | - $post_types = array( tutor()->course_post_type, tutor()->bundle_post_type ); | |
| 374 | - if ( in_array( $post->post_type, $post_types, true ) && EnrollmentModel::is_enrolled( $post->ID ) ) { | |
| 375 | - return false; | |
| 376 | - } | |
| 377 | - | |
| 378 | - return $required; | |
| 379 | - } | |
| 380 | - | |
| 381 | - /** | |
| 382 | 336 | * Handle password protected course/bundle. |
| 383 | 337 | * |
| 384 | 338 | * @since 3.0.0 |
| 385 | 339 | * |
| @@ -803,21 +757,8 @@ | ||
| 803 | 757 | update_post_meta( $post_id, '_tutor_enable_qa', $params['enable_qna'] ?? 'yes' ); |
| 804 | 758 | update_post_meta( $post_id, '_tutor_is_public_course', $params['is_public_course'] ?? 'no' ); |
| 805 | 759 | update_post_meta( $post_id, '_tutor_course_level', $params['course_level'] ); |
| 806 | 760 | |
| 807 | - /** | |
| 808 | - * Save tax collection settings | |
| 809 | - * | |
| 810 | - * @since 3.7.0 | |
| 811 | - */ | |
| 812 | - if ( isset( $params['tax_on_single'] ) ) { | |
| 813 | - update_post_meta( $post_id, self::TAX_ON_SINGLE_META, $params['tax_on_single'] ); | |
| 814 | - } | |
| 815 | - | |
| 816 | - if ( isset( $params['tax_on_subscription'] ) ) { | |
| 817 | - update_post_meta( $post_id, self::TAX_ON_SUBSCRIPTION_META, $params['tax_on_subscription'] ); | |
| 818 | - } | |
| 819 | - | |
| 820 | 761 | do_action( 'tutor_after_prepare_update_post_meta', $post_id, $params ); |
| 821 | 762 | } |
| 822 | 763 | |
| 823 | 764 | /** |
| @@ -917,9 +858,9 @@ | ||
| 917 | 858 | |
| 918 | 859 | update_post_meta( $course_id, self::COURSE_PRICE_TYPE_META, self::PRICE_TYPE_FREE ); |
| 919 | 860 | |
| 920 | 861 | $link = admin_url( 'admin.php?page=create-course' ); |
| 921 | - if ( tutor()->has_pro && Input::post( 'from_dashboard', false, Input::TYPE_BOOL ) ) { | |
| 862 | + if ( Input::post( 'from_dashboard', false, Input::TYPE_BOOL ) ) { | |
| 922 | 863 | $link = tutor_utils()->tutor_dashboard_url( 'create-course' ); |
| 923 | 864 | } |
| 924 | 865 | |
| 925 | 866 | $link = add_query_arg( array( 'course_id' => $course_id ), $link ); |
| @@ -937,14 +878,15 @@ | ||
| 937 | 878 | * Get course list |
| 938 | 879 | * |
| 939 | 880 | * @since 3.0.0 |
| 940 | 881 | * |
| 941 | - * @since 3.2.0 Refactor the arguments & response as per new design. | |
| 882 | + * @since 3.2.0 | |
| 942 | 883 | * |
| 884 | + * Refactor the arguments & response as per new design | |
| 885 | + * | |
| 943 | 886 | * @return void |
| 944 | 887 | */ |
| 945 | 888 | public function ajax_course_list() { |
| 946 | - tutor_utils()->check_nonce(); | |
| 947 | 889 | $this->check_access(); |
| 948 | 890 | |
| 949 | 891 | $limit = Input::post( 'limit', 10, Input::TYPE_INT ); |
| 950 | 892 | $offset = Input::post( 'offset', 0, Input::TYPE_INT ); |
| @@ -964,9 +906,14 @@ | ||
| 964 | 906 | ); |
| 965 | 907 | |
| 966 | 908 | $exclude = Input::post( 'exclude', array(), Input::TYPE_ARRAY ); |
| 967 | 909 | if ( count( $exclude ) ) { |
| 968 | - $exclude = array_filter( $exclude, fn( $id ) => is_numeric( $id ) && $id > 0 ); | |
| 910 | + $exclude = array_filter( | |
| 911 | + $exclude, | |
| 912 | + function ( $id ) { | |
| 913 | + return is_numeric( $id ); | |
| 914 | + } | |
| 915 | + ); | |
| 969 | 916 | $args['post__not_in'] = $exclude; |
| 970 | 917 | } |
| 971 | 918 | |
| 972 | 919 | $courses = CourseModel::get_courses_by_args( $args ); |
| @@ -1102,17 +1049,12 @@ | ||
| 1102 | 1049 | 'course_benefits' => 'sanitize_textarea_field', |
| 1103 | 1050 | 'course_target_audience' => 'sanitize_textarea_field', |
| 1104 | 1051 | 'course_material_includes' => 'sanitize_textarea_field', |
| 1105 | 1052 | 'course_requirements' => 'sanitize_textarea_field', |
| 1106 | - ), | |
| 1107 | - true | |
| 1053 | + ) | |
| 1108 | 1054 | ); |
| 1109 | 1055 | |
| 1110 | 1056 | $course_id = (int) $params['course_id']; |
| 1111 | - if ( ! $course_id ) { | |
| 1112 | - $this->response_bad_request( __( 'Invalid course id', 'tutor' ) ); | |
| 1113 | - } | |
| 1114 | - | |
| 1115 | 1057 | $this->check_access( $course_id ); |
| 1116 | 1058 | |
| 1117 | 1059 | $errors = array(); |
| 1118 | 1060 | $validation = $this->validate_inputs( $params ); |
| @@ -1201,32 +1143,15 @@ | ||
| 1201 | 1143 | public function ajax_unlink_page_builder() { |
| 1202 | 1144 | tutor_utils()->check_nonce(); |
| 1203 | 1145 | |
| 1204 | 1146 | $course_id = Input::post( 'course_id', 0, Input::TYPE_INT ); |
| 1205 | - if ( ! $course_id ) { | |
| 1206 | - $this->response_bad_request( __( 'Invalid course id', 'tutor' ) ); | |
| 1207 | - } | |
| 1208 | - | |
| 1147 | + $builder = Input::post( 'builder' ); | |
| 1209 | 1148 | $this->check_access( $course_id ); |
| 1210 | 1149 | |
| 1211 | - $builder = Input::post( 'builder' ); | |
| 1212 | 1150 | if ( 'elementor' === $builder ) { |
| 1213 | 1151 | delete_post_meta( $course_id, '_elementor_edit_mode' ); |
| 1214 | 1152 | } elseif ( 'droip' === $builder ) { |
| 1215 | 1153 | delete_post_meta( $course_id, 'droip_editor_mode' ); |
| 1216 | - } elseif ( 'divi' === $builder ) { | |
| 1217 | - $old_post_content = get_post_meta( $course_id, '_et_pb_old_content', true ); | |
| 1218 | - $course = get_post( $course_id ); | |
| 1219 | - $course->post_content = $old_post_content; | |
| 1220 | - $result = wp_update_post( $course ); | |
| 1221 | - | |
| 1222 | - if ( $result && ! is_wp_error( $result ) ) { | |
| 1223 | - update_post_meta( $course_id, '_et_pb_use_builder', 'off' ); | |
| 1224 | - update_post_meta( $course_id, '_et_pb_old_content', '' ); | |
| 1225 | - delete_post_meta( $course_id, '_et_dynamic_cached_shortcodes' ); | |
| 1226 | - delete_post_meta( $course_id, '_et_dynamic_cached_attributes' ); | |
| 1227 | - delete_post_meta( $course_id, '_et_builder_module_features_cache' ); | |
| 1228 | - } | |
| 1229 | 1154 | } |
| 1230 | 1155 | |
| 1231 | 1156 | $this->json_response( |
| 1232 | 1157 | __( 'Builder unlinked successfully.', 'tutor' ), |
| @@ -1259,18 +1184,15 @@ | ||
| 1259 | 1184 | |
| 1260 | 1185 | $topic_contents = tutor_utils()->get_course_contents_by_topic( $post->ID, -1 ); |
| 1261 | 1186 | |
| 1262 | 1187 | if ( $topic_contents->have_posts() ) { |
| 1263 | - foreach ( $topic_contents->get_posts() as $content ) { | |
| 1264 | - if ( tutor()->quiz_post_type === $content->post_type ) { | |
| 1265 | - $questions = tutor_utils()->get_questions_by_quiz( $content->ID ); | |
| 1266 | - $content = (object) array_merge( | |
| 1267 | - (array) $content, | |
| 1268 | - array( 'total_question' => is_array( $questions ) ? count( $questions ) : 0 ) | |
| 1269 | - ); | |
| 1188 | + foreach ( $topic_contents->get_posts() as $post ) { | |
| 1189 | + if ( tutor()->quiz_post_type === $post->post_type ) { | |
| 1190 | + $questions = tutor_utils()->get_questions_by_quiz( $post->ID ); | |
| 1191 | + $post->total_question = is_array( $questions ) ? count( $questions ) : 0; | |
| 1270 | 1192 | } |
| 1271 | 1193 | |
| 1272 | - array_push( $current_topic['contents'], $content ); | |
| 1194 | + array_push( $current_topic['contents'], $post ); | |
| 1273 | 1195 | } |
| 1274 | 1196 | } |
| 1275 | 1197 | |
| 1276 | 1198 | $current_topic = apply_filters( 'tutor_filter_course_content', $current_topic ); |
| @@ -1285,23 +1207,20 @@ | ||
| 1285 | 1207 | /** |
| 1286 | 1208 | * Get course contents |
| 1287 | 1209 | * |
| 1288 | 1210 | * @since 3.0.0 |
| 1289 | - * | |
| 1290 | - * @return void | |
| 1291 | 1211 | */ |
| 1292 | 1212 | public function ajax_course_contents() { |
| 1293 | 1213 | tutor_utils()->check_nonce(); |
| 1294 | 1214 | |
| 1295 | - $errors = array(); | |
| 1296 | 1215 | $course_id = Input::post( 'course_id', 0, Input::TYPE_INT ); |
| 1297 | 1216 | |
| 1298 | - if ( ! $course_id || tutor()->course_post_type !== get_post_type( $course_id ) ) { | |
| 1217 | + $this->check_access( $course_id ); | |
| 1218 | + | |
| 1219 | + if ( tutor()->course_post_type !== get_post_type( $course_id ) ) { | |
| 1299 | 1220 | $errors['course_id'] = __( 'Invalid course id', 'tutor' ); |
| 1300 | 1221 | } |
| 1301 | 1222 | |
| 1302 | - $this->check_access( $course_id ); | |
| 1303 | - | |
| 1304 | 1223 | if ( ! empty( $errors ) ) { |
| 1305 | 1224 | $this->json_response( __( 'Invalid input', 'tutor' ), $errors, HttpHelper::STATUS_UNPROCESSABLE_ENTITY ); |
| 1306 | 1225 | } |
| 1307 | 1226 | |
| @@ -1325,14 +1244,14 @@ | ||
| 1325 | 1244 | |
| 1326 | 1245 | $errors = array(); |
| 1327 | 1246 | $course_id = Input::post( 'course_id', 0, Input::TYPE_INT ); |
| 1328 | 1247 | |
| 1329 | - if ( ! $course_id || tutor()->course_post_type !== get_post_type( $course_id ) ) { | |
| 1248 | + $this->check_access( $course_id ); | |
| 1249 | + | |
| 1250 | + if ( tutor()->course_post_type !== get_post_type( $course_id ) ) { | |
| 1330 | 1251 | $errors['course_id'] = __( 'Invalid course id', 'tutor' ); |
| 1331 | 1252 | } |
| 1332 | 1253 | |
| 1333 | - $this->check_access( $course_id ); | |
| 1334 | - | |
| 1335 | 1254 | if ( ! empty( $errors ) ) { |
| 1336 | 1255 | $this->json_response( __( 'Invalid input', 'tutor' ), $errors, HttpHelper::STATUS_UNPROCESSABLE_ENTITY ); |
| 1337 | 1256 | } |
| 1338 | 1257 | |
| @@ -1343,9 +1262,9 @@ | ||
| 1343 | 1262 | $price = 0; |
| 1344 | 1263 | $sale_price = 0; |
| 1345 | 1264 | $product_id = tutor_utils()->get_course_product_id( $course_id ); |
| 1346 | 1265 | |
| 1347 | - if ( WooCommerce::MONETIZE_BY === $monetize_by ) { | |
| 1266 | + if ( 'wc' === $monetize_by ) { | |
| 1348 | 1267 | $product = wc_get_product( $product_id ); |
| 1349 | 1268 | if ( $product ) { |
| 1350 | 1269 | $product_name = $product->get_name(); |
| 1351 | 1270 | $price = $product->get_regular_price(); |
| @@ -1352,9 +1271,9 @@ | ||
| 1352 | 1271 | $sale_price = $product->get_sale_price(); |
| 1353 | 1272 | } |
| 1354 | 1273 | } |
| 1355 | 1274 | |
| 1356 | - if ( Ecommerce::MONETIZE_BY === $monetize_by ) { | |
| 1275 | + if ( 'tutor' === $monetize_by ) { | |
| 1357 | 1276 | $price = get_post_meta( $course_id, self::COURSE_PRICE_META, true ); |
| 1358 | 1277 | $sale_price = get_post_meta( $course_id, self::COURSE_SALE_PRICE_META, true ); |
| 1359 | 1278 | } |
| 1360 | 1279 | |
| @@ -1369,12 +1288,12 @@ | ||
| 1369 | 1288 | $video_intro = get_post_meta( $course_id, '_video', true ); |
| 1370 | 1289 | if ( $video_intro ) { |
| 1371 | 1290 | $source = $video_intro['source'] ?? ''; |
| 1372 | 1291 | if ( 'html5' === $source ) { |
| 1373 | - $poster_url = wp_get_attachment_url( $video_intro['poster'] ?? 0 ); | |
| 1374 | - $source_html5 = wp_get_attachment_url( $video_intro['source_video_id'] ?? 0 ); | |
| 1375 | - $video_intro['poster_url'] = $poster_url; | |
| 1376 | - $video_intro['source_html5'] = $source_html5; | |
| 1292 | + $poster_url = wp_get_attachment_url( $video['poster'] ?? 0 ); | |
| 1293 | + $source_html5 = wp_get_attachment_url( $video['source_video_id'] ?? 0 ); | |
| 1294 | + $video['poster_url'] = $poster_url; | |
| 1295 | + $video['source_html5'] = $source_html5; | |
| 1377 | 1296 | } |
| 1378 | 1297 | } |
| 1379 | 1298 | |
| 1380 | 1299 | $course = get_post( $course_id, ARRAY_A ); |
| @@ -1383,23 +1302,13 @@ | ||
| 1383 | 1302 | } |
| 1384 | 1303 | |
| 1385 | 1304 | $editors = tutor_utils()->get_editor_list( $course_id ); |
| 1386 | 1305 | |
| 1387 | - /** | |
| 1388 | - * Replaced the post_author with current user id if post_author value is 0. | |
| 1389 | - * | |
| 1390 | - * @since 4.0.7 | |
| 1391 | - */ | |
| 1392 | - $post_author = (int) $course['post_author']; | |
| 1393 | - if ( 0 === $post_author && $course_id > 0 ) { | |
| 1394 | - $post_author = get_current_user_id(); | |
| 1395 | - } | |
| 1396 | - | |
| 1397 | 1306 | $data = array( |
| 1398 | 1307 | 'editors' => array_values( $editors ), |
| 1399 | 1308 | 'editor_used' => tutor_utils()->get_editor_used( $course_id ), |
| 1400 | 1309 | 'preview_link' => get_preview_post_link( $course_id ), |
| 1401 | - 'post_author' => tutor_utils()->get_tutor_user( $post_author ), | |
| 1310 | + 'post_author' => tutor_utils()->get_tutor_user( $course['post_author'] ), | |
| 1402 | 1311 | 'course_categories' => wp_get_post_terms( $course_id, CourseModel::COURSE_CATEGORY ), |
| 1403 | 1312 | 'course_tags' => wp_get_post_terms( $course_id, CourseModel::COURSE_TAG ), |
| 1404 | 1313 | 'thumbnail_id' => get_post_meta( $course_id, '_thumbnail_id', true ), |
| 1405 | 1314 | 'thumbnail' => get_the_post_thumbnail_url( $course_id ), |
| @@ -1423,16 +1332,8 @@ | ||
| 1423 | 1332 | 'certificate' => false, |
| 1424 | 1333 | ), |
| 1425 | 1334 | ); |
| 1426 | 1335 | |
| 1427 | - $tax_on_single = get_post_meta( $course_id, self::TAX_ON_SINGLE_META, true ); | |
| 1428 | - $tax_on_subscription = get_post_meta( $course_id, self::TAX_ON_SUBSCRIPTION_META, true ); | |
| 1429 | - | |
| 1430 | - $data['tax_collection'] = array( | |
| 1431 | - 'tax_on_single' => '' === $tax_on_single ? '1' : $tax_on_single, | |
| 1432 | - 'tax_on_subscription' => '' === $tax_on_subscription ? '1' : $tax_on_subscription, | |
| 1433 | - ); | |
| 1434 | - | |
| 1435 | 1336 | $data = apply_filters( 'tutor_course_details_response', array_merge( $course, $data ) ); |
| 1436 | 1337 | |
| 1437 | 1338 | $this->json_response( __( 'Data retrieved successfully!', 'tutor' ), $data ); |
| 1438 | 1339 | } |
| @@ -1539,9 +1440,9 @@ | ||
| 1539 | 1440 | $default_data = ( new Assets( false ) )->get_default_localized_data(); |
| 1540 | 1441 | |
| 1541 | 1442 | if ( isset( $default_data['current_user']['data']['id'] ) ) { |
| 1542 | 1443 | $tutor_user = tutor_utils()->get_tutor_user( $default_data['current_user']['data']['id'] ); |
| 1543 | - $default_data['current_user']['data']['tutor_profile_photo_url'] = is_object( $tutor_user ) ? $tutor_user->tutor_profile_photo_url : ''; | |
| 1444 | + $default_data['current_user']['data']['tutor_profile_photo_url'] = $tutor_user->tutor_profile_photo_url; | |
| 1544 | 1445 | } |
| 1545 | 1446 | |
| 1546 | 1447 | /** |
| 1547 | 1448 | * Localized only options to protect sensitive info like API keys. |
| @@ -1546,9 +1447,8 @@ | ||
| 1546 | 1447 | /** |
| 1547 | 1448 | * Localized only options to protect sensitive info like API keys. |
| 1548 | 1449 | */ |
| 1549 | 1450 | $required_options = array( |
| 1550 | - 'learning_mode', | |
| 1551 | 1451 | 'monetize_by', |
| 1552 | 1452 | 'enable_course_marketplace', |
| 1553 | 1453 | 'course_permalink_base', |
| 1554 | 1454 | 'supported_video_sources', |
| @@ -1568,12 +1468,8 @@ | ||
| 1568 | 1468 | $settings['course_builder_logo_url'] = wp_get_attachment_image_url( $full_settings['tutor_frontend_course_page_logo_id'] ?? 0, 'full' ); |
| 1569 | 1469 | $settings['chatgpt_key_exist'] = tutor()->has_pro && ! empty( $full_settings['chatgpt_api_key'] ?? '' ); |
| 1570 | 1470 | $settings['youtube_api_key_exist'] = ! empty( $full_settings['lesson_video_duration_youtube_api_key'] ?? '' ); |
| 1571 | 1471 | |
| 1572 | - $settings['enable_tax'] = Tax::get_setting( 'enable_tax', true ); | |
| 1573 | - $settings['is_tax_included_in_price'] = Tax::is_tax_included_in_price(); | |
| 1574 | - $settings['enable_individual_tax_control'] = Tax::get_setting( 'enable_individual_tax_control' ); | |
| 1575 | - | |
| 1576 | 1472 | $new_data = array( 'settings' => $settings ); |
| 1577 | 1473 | |
| 1578 | 1474 | $data = array_merge( $default_data, $new_data ); |
| 1579 | 1475 | |
| @@ -1619,15 +1515,10 @@ | ||
| 1619 | 1515 | $data['timezones'] = tutor_global_timezone_lists(); |
| 1620 | 1516 | $data['difficulty_levels'] = $difficulty_levels; |
| 1621 | 1517 | $data['supported_video_sources'] = $supported_video_sources; |
| 1622 | 1518 | $data['wp_rest_nonce'] = wp_create_nonce( 'wp_rest' ); |
| 1519 | + $data['max_upload_size'] = size_format( wp_max_upload_size() ); | |
| 1623 | 1520 | |
| 1624 | - if ( 'en_US' !== $data['local'] ) { | |
| 1625 | - $data['course_builder_basic_locales'] = tutils()->get_script_locale_data( 'tutor-course-builder-basic', $data['local'] ); | |
| 1626 | - $data['course_builder_curriculum_locales'] = tutils()->get_script_locale_data( 'tutor-course-builder-curriculum', $data['local'] ); | |
| 1627 | - $data['course_builder_additional_locales'] = tutils()->get_script_locale_data( 'tutor-course-builder-additional', $data['local'] ); | |
| 1628 | - } | |
| 1629 | - | |
| 1630 | 1521 | $data = apply_filters( 'tutor_course_builder_localized_data', $data ); |
| 1631 | 1522 | |
| 1632 | 1523 | return $data; |
| 1633 | 1524 | } |
| @@ -1750,38 +1641,23 @@ | ||
| 1750 | 1641 | /** |
| 1751 | 1642 | * Update course content order |
| 1752 | 1643 | * |
| 1753 | 1644 | * @since 1.0.0 |
| 1754 | - * @since 3.9.9 Check if user can manage course before updating order. | |
| 1755 | - * | |
| 1756 | 1645 | * @return void |
| 1757 | 1646 | */ |
| 1758 | - public function ajax_update_course_content_order() { | |
| 1647 | + public function tutor_update_course_content_order() { | |
| 1759 | 1648 | tutor_utils()->checking_nonce(); |
| 1760 | 1649 | |
| 1761 | - $sorting_order = Input::post( 'tutor_topics_lessons_sorting', '' ); | |
| 1762 | - $sorting_order = json_decode( $sorting_order, true ) ?? array(); | |
| 1763 | - | |
| 1764 | - if ( ! tutor_utils()->count( $sorting_order ) ) { | |
| 1765 | - wp_send_json_error( __( 'Sorting order is required', 'tutor' ) ); | |
| 1766 | - } | |
| 1767 | - | |
| 1768 | - $topic_id = (int) isset( $sorting_order[0], $sorting_order[0]['topic_id'] ) ? $sorting_order[0]['topic_id'] : 0; | |
| 1769 | - $course_id = wp_get_post_parent_id( $topic_id ); | |
| 1770 | - | |
| 1771 | - if ( ! $topic_id || ! $course_id ) { | |
| 1772 | - $this->response_bad_request( tutor_utils()->error_message( 'invalid_req' ) ); | |
| 1773 | - } | |
| 1774 | - | |
| 1775 | - if ( ! tutor_utils()->can_user_manage( 'course', $course_id ) && ! User::is_admin() ) { | |
| 1776 | - $this->json_response( tutor_utils()->error_message(), null, HttpHelper::STATUS_UNAUTHORIZED ); | |
| 1777 | - } | |
| 1778 | - | |
| 1779 | 1650 | if ( Input::has( 'content_parent' ) ) { |
| 1780 | 1651 | $content_parent = Input::post( 'content_parent', array(), Input::TYPE_ARRAY ); |
| 1781 | 1652 | $topic_id = tutor_utils()->array_get( 'parent_topic_id', $content_parent ); |
| 1782 | 1653 | $content_id = tutor_utils()->array_get( 'content_id', $content_parent ); |
| 1783 | 1654 | |
| 1655 | + if ( ! tutor_utils()->can_user_manage( 'topic', $topic_id ) ) { | |
| 1656 | + wp_send_json_success( array( 'message' => __( 'Access Denied!', 'tutor' ) ) ); | |
| 1657 | + exit; | |
| 1658 | + } | |
| 1659 | + | |
| 1784 | 1660 | // Update the parent topic id of the content. |
| 1785 | 1661 | global $wpdb; |
| 1786 | 1662 | $wpdb->update( $wpdb->posts, array( 'post_parent' => $topic_id ), array( 'ID' => $content_id ) ); |
| 1787 | 1663 | } |
| @@ -1786,11 +1662,11 @@ | ||
| 1786 | 1662 | $wpdb->update( $wpdb->posts, array( 'post_parent' => $topic_id ), array( 'ID' => $content_id ) ); |
| 1787 | 1663 | } |
| 1788 | 1664 | |
| 1789 | 1665 | // Save course content order. |
| 1790 | - $this->save_course_content_order( $sorting_order ); | |
| 1666 | + $this->save_course_content_order(); | |
| 1791 | 1667 | |
| 1792 | - $this->response_success( __( 'Course content order updated successfully!', 'tutor' ) ); | |
| 1668 | + wp_send_json_success(); | |
| 1793 | 1669 | } |
| 1794 | 1670 | |
| 1795 | 1671 | /** |
| 1796 | 1672 | * Restrict new student entry |
| @@ -1815,11 +1691,9 @@ | ||
| 1815 | 1691 | /** |
| 1816 | 1692 | * Restrict media |
| 1817 | 1693 | * |
| 1818 | 1694 | * @since 1.0.0 |
| 1819 | - * | |
| 1820 | 1695 | * @param string $where where clause. |
| 1821 | - * | |
| 1822 | 1696 | * @return string |
| 1823 | 1697 | */ |
| 1824 | 1698 | public function restrict_media( $where ) { |
| 1825 | 1699 | $action = Input::post( 'action' ); |
| @@ -1835,58 +1709,58 @@ | ||
| 1835 | 1709 | /** |
| 1836 | 1710 | * Save course content order |
| 1837 | 1711 | * |
| 1838 | 1712 | * @since 1.0.0 |
| 1839 | - * @since 3.9.8 param $order added. | |
| 1840 | - * | |
| 1841 | - * @param array $sort_order the lesson and topic order array. | |
| 1842 | - * | |
| 1843 | 1713 | * @return void |
| 1844 | 1714 | */ |
| 1845 | - private function save_course_content_order( $sort_order = array() ) { | |
| 1715 | + private function save_course_content_order() { | |
| 1846 | 1716 | global $wpdb; |
| 1847 | 1717 | |
| 1848 | - if ( ! tutor_utils()->count( $sort_order ) ) { | |
| 1849 | - return; | |
| 1850 | - } | |
| 1718 | + $new_order = Input::post( 'tutor_topics_lessons_sorting' ); | |
| 1719 | + if ( ! empty( $new_order ) ) { | |
| 1720 | + $order = json_decode( $new_order, true ); | |
| 1851 | 1721 | |
| 1852 | - $i = 0; | |
| 1853 | - foreach ( $sort_order as $topic ) { | |
| 1854 | - ++$i; | |
| 1855 | - $wpdb->update( | |
| 1856 | - $wpdb->posts, | |
| 1857 | - array( 'menu_order' => $i ), | |
| 1858 | - array( 'ID' => $topic['topic_id'] ) | |
| 1859 | - ); | |
| 1722 | + if ( is_array( $order ) && count( $order ) ) { | |
| 1723 | + $i = 0; | |
| 1724 | + foreach ( $order as $topic ) { | |
| 1725 | + $i++; | |
| 1726 | + $wpdb->update( | |
| 1727 | + $wpdb->posts, | |
| 1728 | + array( 'menu_order' => $i ), | |
| 1729 | + array( 'ID' => $topic['topic_id'] ) | |
| 1730 | + ); | |
| 1860 | 1731 | |
| 1861 | - /** | |
| 1862 | - * Removing All lesson with topic | |
| 1863 | - */ | |
| 1864 | - $wpdb->update( | |
| 1865 | - $wpdb->posts, | |
| 1866 | - array( 'post_parent' => 0 ), | |
| 1867 | - array( 'post_parent' => $topic['topic_id'] ) | |
| 1868 | - ); | |
| 1732 | + /** | |
| 1733 | + * Removing All lesson with topic | |
| 1734 | + */ | |
| 1869 | 1735 | |
| 1870 | - /** | |
| 1871 | - * Lesson Attaching with topic ID | |
| 1872 | - * Sorting lesson | |
| 1873 | - */ | |
| 1874 | - if ( isset( $topic['lesson_ids'] ) ) { | |
| 1875 | - $lesson_ids = $topic['lesson_ids']; | |
| 1876 | - } else { | |
| 1877 | - $lesson_ids = array(); | |
| 1878 | - } | |
| 1879 | - if ( count( $lesson_ids ) ) { | |
| 1880 | - foreach ( $lesson_ids as $lesson_key => $lesson_id ) { | |
| 1881 | 1736 | $wpdb->update( |
| 1882 | 1737 | $wpdb->posts, |
| 1883 | - array( | |
| 1884 | - 'post_parent' => $topic['topic_id'], | |
| 1885 | - 'menu_order' => $lesson_key, | |
| 1886 | - ), | |
| 1887 | - array( 'ID' => $lesson_id ) | |
| 1738 | + array( 'post_parent' => 0 ), | |
| 1739 | + array( 'post_parent' => $topic['topic_id'] ) | |
| 1888 | 1740 | ); |
| 1741 | + | |
| 1742 | + /** | |
| 1743 | + * Lesson Attaching with topic ID | |
| 1744 | + * Sorting lesson | |
| 1745 | + */ | |
| 1746 | + if ( isset( $topic['lesson_ids'] ) ) { | |
| 1747 | + $lesson_ids = $topic['lesson_ids']; | |
| 1748 | + } else { | |
| 1749 | + $lesson_ids = array(); | |
| 1750 | + } | |
| 1751 | + if ( count( $lesson_ids ) ) { | |
| 1752 | + foreach ( $lesson_ids as $lesson_key => $lesson_id ) { | |
| 1753 | + $wpdb->update( | |
| 1754 | + $wpdb->posts, | |
| 1755 | + array( | |
| 1756 | + 'post_parent' => $topic['topic_id'], | |
| 1757 | + 'menu_order' => $lesson_key, | |
| 1758 | + ), | |
| 1759 | + array( 'ID' => $lesson_id ) | |
| 1760 | + ); | |
| 1761 | + } | |
| 1762 | + } | |
| 1889 | 1763 | } |
| 1890 | 1764 | } |
| 1891 | 1765 | } |
| 1892 | 1766 | } |
| @@ -1957,14 +1831,12 @@ | ||
| 1957 | 1831 | } |
| 1958 | 1832 | //phpcs:enable WordPress.Security.NonceVerification.Missing |
| 1959 | 1833 | } |
| 1960 | 1834 | |
| 1961 | - $sorting_order = Input::post( 'tutor_topics_lessons_sorting', '' ); | |
| 1962 | - $sorting_order = json_decode( $sorting_order, true ) ?? array(); | |
| 1963 | 1835 | /** |
| 1964 | 1836 | * Sorting Topics and lesson |
| 1965 | 1837 | */ |
| 1966 | - $this->save_course_content_order( $sorting_order ); | |
| 1838 | + $this->save_course_content_order(); | |
| 1967 | 1839 | |
| 1968 | 1840 | // Additional data like course intro video. |
| 1969 | 1841 | if ( $additional_data_edit ) { |
| 1970 | 1842 | // Sanitize data through helper method. |
| @@ -1975,9 +1847,8 @@ | ||
| 1975 | 1847 | 'source_embedded' => 'wp_kses_post', |
| 1976 | 1848 | ), |
| 1977 | 1849 | true |
| 1978 | 1850 | ); |
| 1979 | - $video = tutor_utils()->filter_video_meta( $video ); | |
| 1980 | 1851 | $video_source = tutor_utils()->array_get( 'source', $video ); |
| 1981 | 1852 | if ( -1 !== $video_source ) { |
| 1982 | 1853 | update_post_meta( $post_ID, '_video', $video ); |
| 1983 | 1854 | } elseif ( ! tutor_is_rest() ) { |
| @@ -1987,23 +1858,12 @@ | ||
| 1987 | 1858 | |
| 1988 | 1859 | /** |
| 1989 | 1860 | * Adding author to instructor automatically |
| 1990 | 1861 | */ |
| 1991 | - $requested_author_id = Input::post( 'post_author_override', 0, Input::TYPE_INT ); | |
| 1992 | 1862 | |
| 1993 | - /** | |
| 1994 | - * Only accept the requested author override if it targets a real,approved instructor or admin | |
| 1995 | - * | |
| 1996 | - * @since 4.0.4 | |
| 1997 | - */ | |
| 1998 | - $author_id = $post->post_author; | |
| 1999 | - if ( $requested_author_id && ( User::is_admin() || User::is_instructor() ) ) { | |
| 2000 | - if ( User::is_admin( $requested_author_id ) || User::is_instructor( $requested_author_id, true ) ) { | |
| 2001 | - $author_id = $requested_author_id; | |
| 2002 | - } | |
| 2003 | - } | |
| 2004 | - | |
| 2005 | - $attached = (int) $wpdb->get_var( | |
| 1863 | + // Override post author id. | |
| 1864 | + $author_id = isset( $_POST['post_author_override'] ) ? $_POST['post_author_override'] : $post->post_author; //phpcs:ignore | |
| 1865 | + $attached = (int) $wpdb->get_var( | |
| 2006 | 1866 | $wpdb->prepare( |
| 2007 | 1867 | "SELECT COUNT(umeta_id) FROM {$wpdb->usermeta} |
| 2008 | 1868 | WHERE user_id = %d |
| 2009 | 1869 | AND meta_key = '_tutor_instructor_course_id' |
| @@ -2028,20 +1888,8 @@ | ||
| 2028 | 1888 | update_post_meta( $post_ID, $key, ( isset( $_POST[ $key ] ) ? 'yes' : 'no' ) ); |
| 2029 | 1889 | } |
| 2030 | 1890 | } |
| 2031 | 1891 | |
| 2032 | - /** | |
| 2033 | - * Update course content if main author is changed and multi-instructor addon is disabled. | |
| 2034 | - * | |
| 2035 | - * @since 4.0.4 | |
| 2036 | - */ | |
| 2037 | - if ( ! $attached && ! tutor_utils()->is_addon_enabled( 'tutor-multi-instructors' ) ) { | |
| 2038 | - CourseModel::update_course_content_author( $post_ID, (int) $author_id ); | |
| 2039 | - // Remove all existing instructors from the course and add the new one. | |
| 2040 | - delete_metadata( 'user', 0, '_tutor_instructor_course_id', $post_ID, true ); | |
| 2041 | - add_user_meta( $author_id, '_tutor_instructor_course_id', $post_ID ); | |
| 2042 | - } | |
| 2043 | - | |
| 2044 | 1892 | do_action( 'tutor_save_course_after', $post_ID, $post ); |
| 2045 | 1893 | } |
| 2046 | 1894 | |
| 2047 | 1895 | /** |
| @@ -2183,14 +2031,8 @@ | ||
| 2183 | 2031 | */ |
| 2184 | 2032 | |
| 2185 | 2033 | $is_purchasable = tutor_utils()->is_course_purchasable( $course_id ); |
| 2186 | 2034 | |
| 2187 | - $course = get_post( $course_id ); | |
| 2188 | - | |
| 2189 | - if ( 'private' === $course->post_status && ! current_user_can( 'read_private_tutor_courses' ) ) { | |
| 2190 | - wp_send_json_error( __( 'You do not have permission to enroll in this course', 'tutor' ) ); | |
| 2191 | - } | |
| 2192 | - | |
| 2193 | 2035 | /** |
| 2194 | 2036 | * If is is not purchasable, it's free, and enroll right now |
| 2195 | 2037 | * If purchasable, then process purchase. |
| 2196 | 2038 | * |
| @@ -2200,9 +2042,9 @@ | ||
| 2200 | 2042 | // Process purchase. |
| 2201 | 2043 | |
| 2202 | 2044 | } else { |
| 2203 | 2045 | // Free enroll. |
| 2204 | - EnrollmentModel::do_enroll( $course_id ); | |
| 2046 | + tutor_utils()->do_enroll( $course_id ); | |
| 2205 | 2047 | } |
| 2206 | 2048 | |
| 2207 | 2049 | $referer_url = wp_get_referer(); |
| 2208 | 2050 | wp_safe_redirect( tutor_utils()->get_nocache_url( $referer_url ) ); |
| @@ -2212,11 +2054,8 @@ | ||
| 2212 | 2054 | /** |
| 2213 | 2055 | * Mark complete completed |
| 2214 | 2056 | * |
| 2215 | 2057 | * @since 1.0.0 |
| 2216 | - * | |
| 2217 | - * @since 3.7.1 Filter hook: tutor_user_can_complete_course added | |
| 2218 | - * | |
| 2219 | 2058 | * @return void |
| 2220 | 2059 | */ |
| 2221 | 2060 | public function mark_course_complete() { |
| 2222 | 2061 | $tutor_action = Input::post( 'tutor_action' ); |
| @@ -2224,10 +2063,8 @@ | ||
| 2224 | 2063 | if ( 'tutor_complete_course' !== $tutor_action || ! $course_id ) { |
| 2225 | 2064 | return; |
| 2226 | 2065 | } |
| 2227 | 2066 | |
| 2228 | - $permalink = get_the_permalink( $course_id ); | |
| 2229 | - | |
| 2230 | 2067 | // Checking nonce. |
| 2231 | 2068 | tutor_utils()->checking_nonce(); |
| 2232 | 2069 | |
| 2233 | 2070 | $user_id = get_current_user_id(); |
| @@ -2236,78 +2073,20 @@ | ||
| 2236 | 2073 | if ( ! $user_id ) { |
| 2237 | 2074 | die( esc_html__( 'Please Sign-In', 'tutor' ) ); |
| 2238 | 2075 | } |
| 2239 | 2076 | |
| 2240 | - if ( ! EnrollmentModel::is_enrolled( $course_id, $user_id ) ) { | |
| 2241 | - die( esc_html__( 'User is not enrolled in course', 'tutor' ) ); | |
| 2242 | - } | |
| 2077 | + CourseModel::mark_course_as_completed( $course_id, $user_id ); | |
| 2243 | 2078 | |
| 2244 | - /** | |
| 2245 | - * Filter hook provided to restrict course completion. This is useful | |
| 2246 | - * for specific cases like prerequisites. WP_Error should be returned | |
| 2247 | - * from the filter value to prevent the completion. | |
| 2248 | - */ | |
| 2249 | - $can_complete = apply_filters( 'tutor_user_can_complete_course', CourseModel::can_complete_course( $course_id, $user_id ), $user_id, $course_id ); | |
| 2079 | + $permalink = get_the_permalink( $course_id ); | |
| 2250 | 2080 | |
| 2251 | - if ( is_wp_error( $can_complete ) ) { | |
| 2252 | - tutor_utils()->redirect_to( $permalink, $can_complete->get_error_message(), 'error' ); | |
| 2253 | - } elseif ( ! $can_complete ) { | |
| 2254 | - tutor_utils()->redirect_to( $permalink, __( 'You do not have permission to complete this course.', 'tutor' ), 'error' ); | |
| 2255 | - } else { | |
| 2256 | - CourseModel::mark_course_as_completed( $course_id, $user_id ); | |
| 2257 | - // Set temporary identifier to show review pop up. | |
| 2258 | - self::set_review_popup_data( $user_id, $course_id ); | |
| 2081 | + // Set temporary identifier to show review pop up. | |
| 2082 | + self::set_review_popup_data( $user_id, $course_id, $permalink ); | |
| 2259 | 2083 | |
| 2260 | - wp_safe_redirect( $permalink ); | |
| 2261 | - exit; | |
| 2262 | - } | |
| 2084 | + wp_safe_redirect( $permalink ); | |
| 2085 | + exit; | |
| 2263 | 2086 | } |
| 2264 | 2087 | |
| 2265 | 2088 | /** |
| 2266 | - * Ajax course complete handler | |
| 2267 | - * | |
| 2268 | - * @since 4.0.0 | |
| 2269 | - * | |
| 2270 | - * @return void | |
| 2271 | - */ | |
| 2272 | - public function ajax_tutor_complete_course() { | |
| 2273 | - $course_id = Input::post( 'course_id', 0, Input::TYPE_INT ); | |
| 2274 | - | |
| 2275 | - // Checking nonce. | |
| 2276 | - if ( ! tutor_utils()->is_nonce_verified() ) { | |
| 2277 | - $this->response_bad_request( tutor_utils()->error_message( 'nonce' ) ); | |
| 2278 | - } | |
| 2279 | - | |
| 2280 | - if ( ! $course_id ) { | |
| 2281 | - $this->response_bad_request( __( 'Invalid course', 'tutor' ) ); | |
| 2282 | - } | |
| 2283 | - | |
| 2284 | - $user_id = get_current_user_id(); | |
| 2285 | - if ( ! EnrollmentModel::is_enrolled( $course_id, $user_id ) ) { | |
| 2286 | - $this->response_bad_request( __( 'You are not enrolled in this course', 'tutor' ) ); | |
| 2287 | - } | |
| 2288 | - | |
| 2289 | - /** | |
| 2290 | - * Filter hook provided to restrict course completion. This is useful | |
| 2291 | - * for specific cases like prerequisites. WP_Error should be returned | |
| 2292 | - * from the filter value to prevent the completion. | |
| 2293 | - */ | |
| 2294 | - $can_complete = apply_filters( 'tutor_user_can_complete_course', CourseModel::can_complete_course( $course_id, $user_id ), $user_id, $course_id ); | |
| 2295 | - | |
| 2296 | - if ( is_wp_error( $can_complete ) ) { | |
| 2297 | - $this->response_bad_request( $can_complete->get_error_message() ); | |
| 2298 | - } elseif ( ! $can_complete ) { | |
| 2299 | - $this->response_bad_request( __( 'You do not have permission to complete this course.', 'tutor' ) ); | |
| 2300 | - } else { | |
| 2301 | - CourseModel::mark_course_as_completed( $course_id, $user_id ); | |
| 2302 | - // Set temporary identifier to show review pop up. | |
| 2303 | - self::set_review_popup_data( $user_id, $course_id ); | |
| 2304 | - | |
| 2305 | - $this->response_success( __( 'Course completed successfully', 'tutor' ) ); | |
| 2306 | - } | |
| 2307 | - } | |
| 2308 | - | |
| 2309 | - /** | |
| 2310 | 2089 | * Set data for review popup. |
| 2311 | 2090 | * |
| 2312 | 2091 | * @since 2.2.5 |
| 2313 | 2092 | * @since 2.4.0 removed $permalink param. store user meta instead of option data. |
| @@ -2333,34 +2112,18 @@ | ||
| 2333 | 2112 | * @since 1.0.0 |
| 2334 | 2113 | * @return void |
| 2335 | 2114 | */ |
| 2336 | 2115 | public function popup_review_form() { |
| 2337 | - if ( ! is_user_logged_in() ) { | |
| 2338 | - return; | |
| 2339 | - } | |
| 2116 | + if ( is_user_logged_in() ) { | |
| 2117 | + $user_id = get_current_user_id(); | |
| 2118 | + $course_id = get_the_ID(); | |
| 2119 | + $meta_key = User::get_review_popup_meta( $course_id ); | |
| 2120 | + $review_course_id = (int) get_user_meta( $user_id, $meta_key, true ); | |
| 2340 | 2121 | |
| 2341 | - $is_learning_area = tutor_utils()->is_learning_area(); | |
| 2342 | - $is_legacy_learning = tutor_utils()->is_legacy_learning_mode(); | |
| 2343 | - if ( $is_legacy_learning && $is_learning_area ) { | |
| 2344 | - return; | |
| 2122 | + if ( is_single() && $course_id === $review_course_id ) { | |
| 2123 | + include tutor()->path . 'views/modal/review.php'; | |
| 2124 | + } | |
| 2345 | 2125 | } |
| 2346 | - | |
| 2347 | - $course_id = get_the_ID(); | |
| 2348 | - | |
| 2349 | - if ( $is_learning_area && ! Input::has( 'subpage' ) ) { | |
| 2350 | - $course_id = wp_get_post_parent_id( wp_get_post_parent_id( get_the_ID() ) ); | |
| 2351 | - } | |
| 2352 | - | |
| 2353 | - if ( empty( $course_id ) ) { | |
| 2354 | - return; | |
| 2355 | - } | |
| 2356 | - | |
| 2357 | - $user_id = get_current_user_id(); | |
| 2358 | - $meta_key = User::get_review_popup_meta( $course_id ); | |
| 2359 | - $review_course_id = (int) get_user_meta( $user_id, $meta_key, true ); | |
| 2360 | - if ( is_single() && $course_id === $review_course_id ) { | |
| 2361 | - include tutor()->path . 'views/modal/review.php'; | |
| 2362 | - } | |
| 2363 | 2126 | } |
| 2364 | 2127 | |
| 2365 | 2128 | /** |
| 2366 | 2129 | * Review popup data clear |
| @@ -2388,9 +2151,8 @@ | ||
| 2388 | 2151 | /** |
| 2389 | 2152 | * Delete course delete from frontend dashboard |
| 2390 | 2153 | * |
| 2391 | 2154 | * @since 2.0.0 |
| 2392 | - * | |
| 2393 | 2155 | * @return void |
| 2394 | 2156 | */ |
| 2395 | 2157 | public function tutor_delete_dashboard_course() { |
| 2396 | 2158 | tutor_utils()->checking_nonce(); |
| @@ -2409,9 +2171,9 @@ | ||
| 2409 | 2171 | wp_send_json_error( array( 'message' => __( 'Only main instructor can delete this course', 'tutor' ) ) ); |
| 2410 | 2172 | } |
| 2411 | 2173 | |
| 2412 | 2174 | // Check if user is only an instructor. |
| 2413 | - if ( ! User::is_admin() ) { | |
| 2175 | + if ( ! current_user_can( 'administrator' ) ) { | |
| 2414 | 2176 | // Check if instructor can trash course. |
| 2415 | 2177 | $can_trash_post = tutor_utils()->get_option( 'instructor_can_delete_course' ); |
| 2416 | 2178 | |
| 2417 | 2179 | if ( ! $can_trash_post ) { |
| @@ -2421,9 +2183,9 @@ | ||
| 2421 | 2183 | |
| 2422 | 2184 | $trash_course = wp_update_post( |
| 2423 | 2185 | array( |
| 2424 | 2186 | 'ID' => $course_id, |
| 2425 | - 'post_status' => CourseModel::STATUS_TRASH, | |
| 2187 | + 'post_status' => 'trash', | |
| 2426 | 2188 | ) |
| 2427 | 2189 | ); |
| 2428 | 2190 | |
| 2429 | 2191 | if ( $trash_course ) { |
| @@ -2538,19 +2300,23 @@ | ||
| 2538 | 2300 | update_post_meta( $product_id, '_subscription_price', $course_price ); |
| 2539 | 2301 | } |
| 2540 | 2302 | |
| 2541 | 2303 | // Set course regular & sale price. |
| 2542 | - self::set_course_regular_and_sale_price( $post_ID, $product_obj->get_regular_price(), $product_obj->get_sale_price() ); | |
| 2304 | + update_post_meta( $post_ID, self::COURSE_PRICE_META, $product_obj->get_regular_price() ); | |
| 2305 | + update_post_meta( $post_ID, self::COURSE_SALE_PRICE_META, $product_obj->get_sale_price() ); | |
| 2543 | 2306 | } else { |
| 2544 | 2307 | // Create new WC product name with course title. |
| 2545 | 2308 | $product_id = self::create_wc_product( $course->post_title, $course_price, $sale_price ); |
| 2546 | 2309 | if ( $product_id ) { |
| 2547 | 2310 | $product_obj = wc_get_product( $product_id ); |
| 2311 | + update_post_meta( $post_ID, self::COURSE_PRODUCT_ID_META, $product_id ); | |
| 2312 | + // Mark product for woocommerce. | |
| 2313 | + update_post_meta( $product_id, '_virtual', 'yes' ); | |
| 2314 | + update_post_meta( $product_id, '_tutor_product', 'yes' ); | |
| 2548 | 2315 | |
| 2549 | - self::sync_course_with_wc_product( $post_ID, $product_id ); | |
| 2550 | - | |
| 2551 | 2316 | // Set course regular & sale price. |
| 2552 | - self::set_course_regular_and_sale_price( $post_ID, $product_obj->get_regular_price(), $product_obj->get_sale_price() ); | |
| 2317 | + update_post_meta( $post_ID, self::COURSE_PRICE_META, $product_obj->get_regular_price() ); | |
| 2318 | + update_post_meta( $post_ID, self::COURSE_SALE_PRICE_META, $product_obj->get_sale_price() ); | |
| 2553 | 2319 | } |
| 2554 | 2320 | } |
| 2555 | 2321 | |
| 2556 | 2322 | $course_post_thumbnail = Input::post( 'thumbnail_id', 0, Input::TYPE_INT ); |
| @@ -2598,8 +2364,33 @@ | ||
| 2598 | 2364 | } |
| 2599 | 2365 | } |
| 2600 | 2366 | |
| 2601 | 2367 | /** |
| 2368 | + * Add Course level to course settings | |
| 2369 | + * | |
| 2370 | + * @since 1.4.1 | |
| 2371 | + * | |
| 2372 | + * @param array $args arguments. | |
| 2373 | + * @return array | |
| 2374 | + */ | |
| 2375 | + public function add_course_level_to_settings( $args ) { | |
| 2376 | + $course_id = get_the_ID(); | |
| 2377 | + $levels = tutor_utils()->course_levels(); | |
| 2378 | + $course_level = get_post_meta( $course_id, '_tutor_course_level', true ); | |
| 2379 | + | |
| 2380 | + $args['general']['fields']['_tutor_course_level'] = array( | |
| 2381 | + 'type' => 'select', | |
| 2382 | + 'label' => __( 'Difficulty Level', 'tutor' ), | |
| 2383 | + 'label_title' => __( 'Enable', 'tutor' ), | |
| 2384 | + 'options' => $levels, | |
| 2385 | + 'value' => $course_level ? $course_level : 'intermediate', | |
| 2386 | + 'desc' => __( 'Course difficulty level', 'tutor' ), | |
| 2387 | + ); | |
| 2388 | + | |
| 2389 | + return $args; | |
| 2390 | + } | |
| 2391 | + | |
| 2392 | + /** | |
| 2602 | 2393 | * Check if course starting |
| 2603 | 2394 | * |
| 2604 | 2395 | * @since 1.4.8 |
| 2605 | 2396 | * @return void |
| @@ -2619,9 +2410,8 @@ | ||
| 2619 | 2410 | /** |
| 2620 | 2411 | * Add Course level to course settings |
| 2621 | 2412 | * |
| 2622 | 2413 | * @since 1.4.8 |
| 2623 | - * | |
| 2624 | 2414 | * @return void |
| 2625 | 2415 | */ |
| 2626 | 2416 | public function course_elements_enable_disable() { |
| 2627 | 2417 | add_filter( 'tutor_course/single/completing-progress-bar', array( $this, 'enable_disable_course_progress_bar' ) ); |
| @@ -2654,13 +2444,12 @@ | ||
| 2654 | 2444 | * |
| 2655 | 2445 | * @since 1.4.8 |
| 2656 | 2446 | * |
| 2657 | 2447 | * @param string $html HTML string. |
| 2658 | - * | |
| 2659 | 2448 | * @return string |
| 2660 | 2449 | */ |
| 2661 | 2450 | public function enable_disable_material_includes( $html ) { |
| 2662 | - $disable_option = ! (bool) get_tutor_option( 'enable_course_material', true ); | |
| 2451 | + $disable_option = ! (bool) get_tutor_option( 'enable_course_material', true, true ); | |
| 2663 | 2452 | if ( $disable_option ) { |
| 2664 | 2453 | return ''; |
| 2665 | 2454 | } |
| 2666 | 2455 | return $html; |
| @@ -2671,9 +2460,8 @@ | ||
| 2671 | 2460 | * |
| 2672 | 2461 | * @since 1.4.8 |
| 2673 | 2462 | * |
| 2674 | 2463 | * @param string $html HTML string. |
| 2675 | - * | |
| 2676 | 2464 | * @return string |
| 2677 | 2465 | */ |
| 2678 | 2466 | public function enable_disable_course_content( $html ) { |
| 2679 | 2467 | $disable_option = ! (bool) tutor_utils()->get_option( 'enable_course_description', true, true ); |
| @@ -2688,9 +2476,8 @@ | ||
| 2688 | 2476 | * |
| 2689 | 2477 | * @since 1.4.8 |
| 2690 | 2478 | * |
| 2691 | 2479 | * @param string $html HTML string. |
| 2692 | - * | |
| 2693 | 2480 | * @return string |
| 2694 | 2481 | */ |
| 2695 | 2482 | public function enable_disable_course_benefits( $html ) { |
| 2696 | 2483 | $disable_option = ! (bool) tutor_utils()->get_option( 'enable_course_benefits', true, true ); |
| @@ -2705,9 +2492,8 @@ | ||
| 2705 | 2492 | * |
| 2706 | 2493 | * @since 1.4.8 |
| 2707 | 2494 | * |
| 2708 | 2495 | * @param string $html HTML string. |
| 2709 | - * | |
| 2710 | 2496 | * @return string |
| 2711 | 2497 | */ |
| 2712 | 2498 | public function enable_disable_course_requirements( $html ) { |
| 2713 | 2499 | $disable_option = ! (bool) tutor_utils()->get_option( 'enable_course_requirements', true, true ); |
| @@ -2722,9 +2508,8 @@ | ||
| 2722 | 2508 | * |
| 2723 | 2509 | * @since 1.4.8 |
| 2724 | 2510 | * |
| 2725 | 2511 | * @param string $html HTML string. |
| 2726 | - * | |
| 2727 | 2512 | * @return string |
| 2728 | 2513 | */ |
| 2729 | 2514 | public function enable_disable_course_target_audience( $html ) { |
| 2730 | 2515 | $disable_option = ! (bool) tutor_utils()->get_option( 'enable_course_target_audience', true, true ); |
| @@ -2769,9 +2554,9 @@ | ||
| 2769 | 2554 | unset( $items['reviews'] ); |
| 2770 | 2555 | } |
| 2771 | 2556 | |
| 2772 | 2557 | // Whether enrollment require. |
| 2773 | - $is_enrolled = EnrollmentModel::is_enrolled(); | |
| 2558 | + $is_enrolled = tutor_utils()->is_enrolled(); | |
| 2774 | 2559 | |
| 2775 | 2560 | return array_filter( |
| 2776 | 2561 | $items, |
| 2777 | 2562 | function ( $item ) use ( $is_enrolled ) { |
| @@ -2786,9 +2571,8 @@ | ||
| 2786 | 2571 | /** |
| 2787 | 2572 | * Filter product in shop page |
| 2788 | 2573 | * |
| 2789 | 2574 | * @since 1.4.9 |
| 2790 | - * | |
| 2791 | 2575 | * @return void|null |
| 2792 | 2576 | */ |
| 2793 | 2577 | public function filter_product_in_shop_page() { |
| 2794 | 2578 | $hide_course_from_shop_page = (bool) get_tutor_option( 'hide_course_from_shop_page' ); |
| @@ -2794,11 +2578,11 @@ | ||
| 2794 | 2578 | $hide_course_from_shop_page = (bool) get_tutor_option( 'hide_course_from_shop_page' ); |
| 2795 | 2579 | if ( ! $hide_course_from_shop_page ) { |
| 2796 | 2580 | return; |
| 2797 | 2581 | } |
| 2798 | - add_filter( 'woocommerce_product_query', array( $this, 'filter_woocommerce_product_query' ) ); | |
| 2799 | - add_filter( 'edd_downloads_query', array( $this, 'filter_edd_downloads_query' ), 10 ); | |
| 2800 | - add_filter( 'pre_get_posts', array( $this, 'filter_archive_meta_query' ), 1 ); | |
| 2582 | + add_action( 'woocommerce_product_query', array( $this, 'filter_woocommerce_product_query' ) ); | |
| 2583 | + add_filter( 'edd_downloads_query', array( $this, 'filter_edd_downloads_query' ), 10, 2 ); | |
| 2584 | + add_action( 'pre_get_posts', array( $this, 'filter_archive_meta_query' ), 1 ); | |
| 2801 | 2585 | } |
| 2802 | 2586 | |
| 2803 | 2587 | |
| 2804 | 2588 | /** |
| @@ -2804,9 +2588,8 @@ | ||
| 2804 | 2588 | /** |
| 2805 | 2589 | * Tutor product meta query |
| 2806 | 2590 | * |
| 2807 | 2591 | * @since 1.4.9 |
| 2808 | - * | |
| 2809 | 2592 | * @return array |
| 2810 | 2593 | */ |
| 2811 | 2594 | public function tutor_product_meta_query() { |
| 2812 | 2595 | $meta_query = array( |
| @@ -2821,9 +2604,8 @@ | ||
| 2821 | 2604 | * |
| 2822 | 2605 | * @since 1.4.9 |
| 2823 | 2606 | * |
| 2824 | 2607 | * @param \WP_Query $wp_query WP Query instance. |
| 2825 | - * | |
| 2826 | 2608 | * @return \WP_Query |
| 2827 | 2609 | */ |
| 2828 | 2610 | public function filter_woocommerce_product_query( $wp_query ) { |
| 2829 | 2611 | $product_ids = $this->get_connected_wc_product_ids(); |
| @@ -2865,9 +2647,8 @@ | ||
| 2865 | 2647 | * |
| 2866 | 2648 | * @since 1.4.9 |
| 2867 | 2649 | * |
| 2868 | 2650 | * @param \WP_Query $query WP Query instance. |
| 2869 | - * | |
| 2870 | 2651 | * @return \WP_Query |
| 2871 | 2652 | */ |
| 2872 | 2653 | public function filter_edd_downloads_query( $query ) { |
| 2873 | 2654 | $query['meta_query'][] = $this->tutor_product_meta_query(); |
| @@ -2879,9 +2660,8 @@ | ||
| 2879 | 2660 | * |
| 2880 | 2661 | * @since 1.4.9 |
| 2881 | 2662 | * |
| 2882 | 2663 | * @param \WP_Query $wp_query WP Query instance. |
| 2883 | - * | |
| 2884 | 2664 | * @return \WP_Query |
| 2885 | 2665 | */ |
| 2886 | 2666 | public function filter_archive_meta_query( $wp_query ) { |
| 2887 | 2667 | if ( ! is_admin() && $wp_query->is_archive && $wp_query->get( 'post_type' ) === 'download' ) { |
| @@ -2895,9 +2675,8 @@ | ||
| 2895 | 2675 | * |
| 2896 | 2676 | * @since 1.5.8 |
| 2897 | 2677 | * |
| 2898 | 2678 | * @param string $html HTML string. |
| 2899 | - * | |
| 2900 | 2679 | * @return string |
| 2901 | 2680 | */ |
| 2902 | 2681 | public function remove_price_if_enrolled( $html ) { |
| 2903 | 2682 | $should_removed = apply_filters( 'should_remove_price_if_enrolled', true ); |
| @@ -2903,9 +2682,9 @@ | ||
| 2903 | 2682 | $should_removed = apply_filters( 'should_remove_price_if_enrolled', true ); |
| 2904 | 2683 | |
| 2905 | 2684 | if ( $should_removed ) { |
| 2906 | 2685 | $course_id = get_the_ID(); |
| 2907 | - $enrolled = EnrollmentModel::is_enrolled( $course_id ); | |
| 2686 | + $enrolled = tutor_utils()->is_enrolled( $course_id ); | |
| 2908 | 2687 | if ( $enrolled ) { |
| 2909 | 2688 | $html = ''; |
| 2910 | 2689 | } |
| 2911 | 2690 | } |
| @@ -2912,119 +2691,112 @@ | ||
| 2912 | 2691 | return $html; |
| 2913 | 2692 | } |
| 2914 | 2693 | |
| 2915 | 2694 | /** |
| 2916 | - * Get course completion missing requirements message. | |
| 2695 | + * Check if all lessons and quizzes done before mark course complete. | |
| 2917 | 2696 | * |
| 2918 | - * @since 4.0.0 | |
| 2697 | + * @since 1.5.8 | |
| 2919 | 2698 | * |
| 2920 | - * @param int $course_id Course ID. | |
| 2921 | - * @param int $user_id User ID. | |
| 2922 | - * | |
| 2923 | - * @return string|null | |
| 2699 | + * @param string $html HTML string. | |
| 2700 | + * @return string | |
| 2924 | 2701 | */ |
| 2925 | - public static function get_course_completion_restrict_msg( $course_id = 0, $user_id = 0 ) { | |
| 2926 | - $course_id = tutor_utils()->get_post_id( $course_id ); | |
| 2927 | - $user_id = tutor_utils()->get_user_id( $user_id ); | |
| 2702 | + public function tutor_lms_hide_course_complete_btn( $html ) { | |
| 2928 | 2703 | |
| 2929 | - if ( 'strict' !== tutor_utils()->get_option( 'course_completion_process' ) ) { | |
| 2930 | - return null; | |
| 2704 | + $completion_mode = tutor_utils()->get_option( 'course_completion_process' ); | |
| 2705 | + if ( 'strict' !== $completion_mode ) { | |
| 2706 | + return $html; | |
| 2931 | 2707 | } |
| 2932 | 2708 | |
| 2933 | - $completed_lessons = tutor_utils()->get_completed_lesson_count_by_course( $course_id, $user_id ); | |
| 2934 | - $total_lessons = tutor_utils()->get_lesson_count_by_course( $course_id ); // @phpstan-ignore method.notFound | |
| 2709 | + $completed_lesson = tutor_utils()->get_completed_lesson_count_by_course(); | |
| 2710 | + $lesson_count = tutor_utils()->get_lesson_count_by_course(); | |
| 2935 | 2711 | |
| 2936 | - if ( $completed_lessons < $total_lessons ) { | |
| 2937 | - return __( 'Complete all lessons to mark this course as complete', 'tutor' ); | |
| 2712 | + if ( $completed_lesson < $lesson_count ) { | |
| 2713 | + return '<div class="tutor-alert tutor-warning tutor-mt-28"> | |
| 2714 | + <div class="tutor-alert-text"> | |
| 2715 | + <span class="tutor-alert-icon tutor-fs-4 tutor-icon-circle-info tutor-mr-12"></span> | |
| 2716 | + <span>' . __( 'Complete all lessons to mark this course as complete', 'tutor' ) . '</span> | |
| 2717 | + </div> | |
| 2718 | + </div>'; | |
| 2938 | 2719 | } |
| 2939 | 2720 | |
| 2940 | - $course_contents = tutor_utils()->get_course_contents_by_id( $course_id ); | |
| 2721 | + $quizzes = array(); | |
| 2722 | + $assignments = array(); | |
| 2941 | 2723 | |
| 2942 | - $required_quiz_pass_count = 0; | |
| 2943 | - $required_assignment_pass_count = 0; | |
| 2724 | + $course_contents = tutor_utils()->get_course_contents_by_id(); | |
| 2725 | + if ( tutor_utils()->count( $course_contents ) ) { | |
| 2726 | + foreach ( $course_contents as $content ) { | |
| 2727 | + if ( 'tutor_quiz' === $content->post_type ) { | |
| 2728 | + $quizzes[] = $content; | |
| 2729 | + } | |
| 2730 | + if ( 'tutor_assignments' === $content->post_type ) { | |
| 2731 | + $assignments[] = $content; | |
| 2732 | + } | |
| 2733 | + } | |
| 2734 | + } | |
| 2944 | 2735 | |
| 2945 | - $is_assignment_addon_enabled = tutor_utils()->is_addon_enabled( 'tutor-assignments' ); | |
| 2736 | + $required_assignment_pass = 0; | |
| 2946 | 2737 | |
| 2947 | - foreach ( $course_contents as $content ) { | |
| 2738 | + foreach ( $assignments as $row ) { | |
| 2948 | 2739 | |
| 2949 | - if ( tutor()->quiz_post_type === $content->post_type ) { | |
| 2950 | - if ( ! QuizModel::is_quiz_passed( $content->ID, $user_id ) ) { | |
| 2951 | - ++$required_quiz_pass_count; | |
| 2952 | - } | |
| 2953 | - } | |
| 2740 | + $submitted_assignment = tutor_utils()->is_assignment_submitted( $row->ID ); | |
| 2741 | + $is_reviewed_by_instructor = null === $submitted_assignment | |
| 2742 | + ? false | |
| 2743 | + : get_comment_meta( $submitted_assignment->comment_ID, 'evaluate_time', true ); | |
| 2954 | 2744 | |
| 2955 | - if ( $is_assignment_addon_enabled && tutor()->assignment_post_type === $content->post_type ) { | |
| 2956 | - if ( ! Assignments::is_assignment_passed( $content->ID, $user_id ) ) { | |
| 2957 | - ++$required_assignment_pass_count; | |
| 2745 | + if ( $submitted_assignment && $is_reviewed_by_instructor ) { | |
| 2746 | + $pass_mark = tutor_utils()->get_assignment_option( $submitted_assignment->comment_post_ID, 'pass_mark' ); | |
| 2747 | + $given_mark = get_comment_meta( $submitted_assignment->comment_ID, 'assignment_mark', true ); | |
| 2748 | + | |
| 2749 | + if ( $given_mark < $pass_mark ) { | |
| 2750 | + $required_assignment_pass++; | |
| 2958 | 2751 | } |
| 2752 | + } else { | |
| 2753 | + $required_assignment_pass++; | |
| 2959 | 2754 | } |
| 2960 | 2755 | } |
| 2961 | 2756 | |
| 2962 | - if ( ! $required_quiz_pass_count && ! $required_assignment_pass_count ) { | |
| 2963 | - return null; | |
| 2964 | - } | |
| 2757 | + $is_quiz_pass = true; | |
| 2758 | + $required_quiz_pass = 0; | |
| 2965 | 2759 | |
| 2966 | - return self::get_course_completion_requirement_message( | |
| 2967 | - $required_quiz_pass_count, | |
| 2968 | - $required_assignment_pass_count | |
| 2969 | - ); | |
| 2970 | - } | |
| 2760 | + if ( tutor_utils()->count( $quizzes ) ) { | |
| 2761 | + foreach ( $quizzes as $quiz ) { | |
| 2971 | 2762 | |
| 2972 | - /** | |
| 2973 | - * Build missing course completion requirements message. | |
| 2974 | - * | |
| 2975 | - * @since 4.0.0 | |
| 2976 | - * | |
| 2977 | - * @param int $quiz_count Total quiz count. | |
| 2978 | - * @param int $assignment_count Total assignment count. | |
| 2979 | - * | |
| 2980 | - * @return string | |
| 2981 | - */ | |
| 2982 | - private static function get_course_completion_requirement_message( $quiz_count, $assignment_count ) { | |
| 2983 | - $quiz_label = _n( 'quiz', 'quizzes', $quiz_count, 'tutor' ); | |
| 2984 | - $assignment_label = _n( 'assignment', 'assignments', $assignment_count, 'tutor' ); | |
| 2763 | + $attempt = tutor_utils()->get_quiz_attempt( $quiz->ID ); | |
| 2764 | + if ( $attempt ) { | |
| 2765 | + $passing_grade = tutor_utils()->get_quiz_option( $quiz->ID, 'passing_grade', 0 ); | |
| 2766 | + $earned_percentage = $attempt->earned_marks > 0 ? ( number_format( ( $attempt->earned_marks * 100 ) / $attempt->total_marks ) ) : 0; | |
| 2985 | 2767 | |
| 2986 | - if ( $quiz_count && ! $assignment_count ) { | |
| 2987 | - return sprintf( | |
| 2988 | - /* translators: %1$s: item count; %2$s: item label */ | |
| 2989 | - __( 'You have to pass %1$s %2$s to complete this course.', 'tutor' ), | |
| 2990 | - $quiz_count, | |
| 2991 | - $quiz_label | |
| 2992 | - ); | |
| 2768 | + if ( $earned_percentage < $passing_grade ) { | |
| 2769 | + $required_quiz_pass++; | |
| 2770 | + $is_quiz_pass = false; | |
| 2771 | + } | |
| 2772 | + } else { | |
| 2773 | + $required_quiz_pass++; | |
| 2774 | + $is_quiz_pass = false; | |
| 2775 | + } | |
| 2776 | + } | |
| 2993 | 2777 | } |
| 2994 | 2778 | |
| 2995 | - if ( ! $quiz_count && $assignment_count ) { | |
| 2996 | - return sprintf( | |
| 2997 | - /* translators: %1$s: item count; %2$s: item label */ | |
| 2998 | - __( 'You have to pass %1$s %2$s to complete this course.', 'tutor' ), | |
| 2999 | - $assignment_count, | |
| 3000 | - $assignment_label | |
| 3001 | - ); | |
| 3002 | - } | |
| 2779 | + if ( ! $is_quiz_pass || $required_assignment_pass > 0 ) { | |
| 2780 | + $_msg = ''; | |
| 2781 | + $quiz_str = _n( 'quiz', 'quizzes', $required_quiz_pass, 'tutor' ); | |
| 2782 | + $assignment_str = _n( 'assignment', 'assignments', $required_assignment_pass, 'tutor' ); | |
| 3003 | 2783 | |
| 3004 | - return sprintf( | |
| 3005 | - /* translators: %1$s: quiz count; %2$s: quiz label; %3$s: assignment count; %4$s: assignment label */ | |
| 3006 | - __( 'You have to pass %1$s %2$s and %3$s %4$s to complete this course.', 'tutor' ), | |
| 3007 | - $quiz_count, | |
| 3008 | - $quiz_label, | |
| 3009 | - $assignment_count, | |
| 3010 | - $assignment_label | |
| 3011 | - ); | |
| 3012 | - } | |
| 2784 | + if ( ! $is_quiz_pass && 0 == $required_assignment_pass ) { | |
| 2785 | + /* translators: %1$s: number of quiz/assignment pass required; %2$s: quiz/assignment string */ | |
| 2786 | + $_msg = sprintf( __( 'You have to pass %1$s %2$s to complete this course.', 'tutor' ), $required_quiz_pass, $quiz_str ); | |
| 2787 | + } | |
| 3013 | 2788 | |
| 3014 | - /** | |
| 3015 | - * Check if all lessons and quizzes done before mark course complete. | |
| 3016 | - * | |
| 3017 | - * @since 1.5.8 | |
| 3018 | - * | |
| 3019 | - * @param string $html HTML string. | |
| 3020 | - * | |
| 3021 | - * @return string | |
| 3022 | - */ | |
| 3023 | - public function tutor_lms_hide_course_complete_btn( $html ) { | |
| 3024 | - $_msg = self::get_course_completion_restrict_msg(); | |
| 2789 | + if ( $is_quiz_pass && $required_assignment_pass > 0 ) { | |
| 2790 | + //phpcs:ignore | |
| 2791 | + $_msg = sprintf( __( 'You have to pass %1$s %2$s to complete this course.', 'tutor' ), $required_assignment_pass, $assignment_str ); | |
| 2792 | + } | |
| 3025 | 2793 | |
| 3026 | - if ( $_msg ) { | |
| 2794 | + if ( ! $is_quiz_pass && $required_assignment_pass > 0 ) { | |
| 2795 | + /* translators: %1$s: number of quiz pass required; %2$s: quiz string; %3$s: number of assignment pass required; %4$s: assignment string */ | |
| 2796 | + $_msg = sprintf( __( 'You have to pass %1$s %2$s and %3$s %4$s to complete this course.', 'tutor' ), $required_quiz_pass, $quiz_str, $required_assignment_pass, $assignment_str ); | |
| 2797 | + } | |
| 2798 | + | |
| 3027 | 2799 | return '<div class="tutor-alert tutor-warning tutor-mt-28"> |
| 3028 | 2800 | <div class="tutor-alert-text"> |
| 3029 | 2801 | <span class="tutor-alert-icon tutor-fs-4 tutor-icon-circle-info tutor-mr-12"></span> |
| 3030 | 2802 | <span>' . $_msg . '</span> |
| @@ -3040,9 +2812,8 @@ | ||
| 3040 | 2812 | * |
| 3041 | 2813 | * @since 1.5.8 |
| 3042 | 2814 | * |
| 3043 | 2815 | * @param string $html HTML string. |
| 3044 | - * | |
| 3045 | 2816 | * @return string |
| 3046 | 2817 | */ |
| 3047 | 2818 | public function get_generate_greadbook( $html ) { |
| 3048 | 2819 | if ( ! tutor_utils()->is_completed_course() ) { |
| @@ -3054,9 +2825,8 @@ | ||
| 3054 | 2825 | /** |
| 3055 | 2826 | * Add social share content in header |
| 3056 | 2827 | * |
| 3057 | 2828 | * @since 1.6.3 |
| 3058 | - * | |
| 3059 | 2829 | * @return void |
| 3060 | 2830 | */ |
| 3061 | 2831 | public function social_share_content() { |
| 3062 | 2832 | global $wp_query, $post; |
| @@ -3080,9 +2850,8 @@ | ||
| 3080 | 2850 | * |
| 3081 | 2851 | * @since 1.8.2 |
| 3082 | 2852 | * |
| 3083 | 2853 | * @param integer $post_id post ID. |
| 3084 | - * | |
| 3085 | 2854 | * @return void |
| 3086 | 2855 | */ |
| 3087 | 2856 | public function delete_associated_enrollment( $post_id ) { |
| 3088 | 2857 | global $wpdb; |
| @@ -3093,12 +2862,11 @@ | ||
| 3093 | 2862 | post_id |
| 3094 | 2863 | FROM |
| 3095 | 2864 | {$wpdb->postmeta} |
| 3096 | 2865 | WHERE |
| 3097 | - meta_key=%s | |
| 2866 | + meta_key='_tutor_enrolled_by_order_id' | |
| 3098 | 2867 | AND meta_value = %d |
| 3099 | 2868 | ", |
| 3100 | - EnrollmentModel::ENROLLMENT_ORDER_ID_META, | |
| 3101 | 2869 | $post_id |
| 3102 | 2870 | ) |
| 3103 | 2871 | ); |
| 3104 | 2872 | |
| @@ -3114,35 +2882,21 @@ | ||
| 3114 | 2882 | /** |
| 3115 | 2883 | * Reset course progress. |
| 3116 | 2884 | * |
| 3117 | 2885 | * @since 1.5.8 |
| 3118 | - * | |
| 3119 | 2886 | * @return void |
| 3120 | 2887 | */ |
| 3121 | 2888 | public function tutor_reset_course_progress() { |
| 3122 | 2889 | tutor_utils()->checking_nonce(); |
| 3123 | - $course_id = Input::post( 'course_id', 0, Input::TYPE_INT ); | |
| 3124 | - $context = Input::post( 'context', '' ); | |
| 3125 | - $course_reset_progress = tutor_utils()->get_option( 'course_reset_progress', false ); | |
| 3126 | - $course_retake_feature = tutor_utils()->get_option( 'course_retake_feature', false ); | |
| 2890 | + $course_id = Input::post( 'course_id' ); | |
| 3127 | 2891 | |
| 3128 | - if ( ! $course_reset_progress && 'learning-area-sidebar' === $context ) { | |
| 3129 | - $this->response_bad_request( __( 'You do not have permission to reset this course.', 'tutor' ) ); | |
| 2892 | + if ( ! $course_id || ! is_numeric( $course_id ) || ! tutor_utils()->is_enrolled( $course_id ) ) { | |
| 2893 | + wp_send_json_error( array( 'message' => __( 'Invalid Course ID or Access Denied.', 'tutor' ) ) ); | |
| 3130 | 2894 | return; |
| 3131 | 2895 | } |
| 3132 | 2896 | |
| 3133 | - if ( ! $course_retake_feature && ( 'course-landing' === $context || 'learning-area' === $context ) ) { | |
| 3134 | - $this->response_bad_request( __( 'You do not have permission to retake this course.', 'tutor' ) ); | |
| 3135 | - return; | |
| 3136 | - } | |
| 3137 | - | |
| 3138 | - if ( ! $course_id || ! is_numeric( $course_id ) || ! EnrollmentModel::is_enrolled( $course_id ) ) { | |
| 3139 | - $this->response_bad_request( __( 'Invalid Course ID or Access Denied.', 'tutor' ) ); | |
| 3140 | - return; | |
| 3141 | - } | |
| 3142 | - | |
| 3143 | 2897 | tutor_utils()->delete_course_progress( $course_id ); |
| 3144 | - $this->json_response( '', array( 'redirect_to' => tutor_utils()->get_course_first_lesson( $course_id ) ) ); | |
| 2898 | + wp_send_json_success( array( 'redirect_to' => tutor_utils()->get_course_first_lesson( $course_id ) ) ); | |
| 3145 | 2899 | } |
| 3146 | 2900 | |
| 3147 | 2901 | /** |
| 3148 | 2902 | * Do enroll if guest attempt to enroll and course is free |
| @@ -3150,9 +2904,9 @@ | ||
| 3150 | 2904 | * @since 1.9.8 |
| 3151 | 2905 | * |
| 3152 | 2906 | * @param integer $course_id course ID. |
| 3153 | 2907 | * @param integer $user_id user ID. |
| 3154 | - * | |
| 2908 | + | |
| 3155 | 2909 | * @return void |
| 3156 | 2910 | */ |
| 3157 | 2911 | public function enroll_after_login_if_attempt( int $course_id, int $user_id ) { |
| 3158 | 2912 | $course_id = sanitize_text_field( $course_id ); |
| @@ -3160,9 +2914,9 @@ | ||
| 3160 | 2914 | |
| 3161 | 2915 | if ( $course_id && $is_allowed ) { |
| 3162 | 2916 | $is_purchasable = tutor_utils()->is_course_purchasable( $course_id ); |
| 3163 | 2917 | if ( ! $is_purchasable ) { |
| 3164 | - EnrollmentModel::do_enroll( $course_id, $order_id = 0, $user_id ); | |
| 2918 | + tutor_utils()->do_enroll( $course_id, $order_id = 0, $user_id ); | |
| 3165 | 2919 | do_action( 'guest_attempt_after_enrollment', $course_id ); |
| 3166 | 2920 | } |
| 3167 | 2921 | } |
| 3168 | 2922 | } |
| @@ -3170,9 +2924,8 @@ | ||
| 3170 | 2924 | /** |
| 3171 | 2925 | * Handle course enrollment |
| 3172 | 2926 | * |
| 3173 | 2927 | * @since 2.1.0 |
| 3174 | - * | |
| 3175 | 2928 | * @return void |
| 3176 | 2929 | */ |
| 3177 | 2930 | public function course_enrollment() { |
| 3178 | 2931 | tutor_utils()->checking_nonce(); |
| @@ -3179,46 +2932,21 @@ | ||
| 3179 | 2932 | |
| 3180 | 2933 | $course_id = Input::post( 'course_id', 0, Input::TYPE_INT ); |
| 3181 | 2934 | $user_id = get_current_user_id(); |
| 3182 | 2935 | |
| 3183 | - if ( ! $course_id || ! $user_id ) { | |
| 3184 | - wp_send_json_error( tutor_utils()->error_message( 'invalid_req' ) ); | |
| 3185 | - } | |
| 3186 | - | |
| 3187 | - $password_protected = post_password_required( $course_id ); | |
| 3188 | - if ( $password_protected ) { | |
| 3189 | - wp_send_json_error( __( 'This course is password protected', 'tutor' ) ); | |
| 3190 | - } | |
| 3191 | - | |
| 3192 | - $course = get_post( $course_id ); | |
| 3193 | - | |
| 3194 | - if ( CourseModel::STATUS_PRIVATE === $course->post_status && ! current_user_can( 'read_private_tutor_courses' ) ) { | |
| 3195 | - wp_send_json_error( __( 'You do not have permission to enroll in this course', 'tutor' ) ); | |
| 3196 | - } | |
| 3197 | - | |
| 3198 | - /** | |
| 3199 | - * This check was added to address a security issue where users could | |
| 3200 | - * enroll in a course via an AJAX call without purchasing it. | |
| 3201 | - * | |
| 3202 | - * To prevent this, we now verify whether the course is paid. | |
| 3203 | - * Additionally, we check if the user is already enrolled, since | |
| 3204 | - * Tutor's default behavior enrolls users automatically upon purchase. | |
| 3205 | - * | |
| 3206 | - * @since 3.9.4 | |
| 3207 | - */ | |
| 3208 | - if ( tutor_utils()->is_course_purchasable( $course_id ) ) { | |
| 3209 | - $is_enrolled = (bool) EnrollmentModel::is_enrolled( $course_id, $user_id ); | |
| 3210 | - | |
| 3211 | - if ( ! $is_enrolled ) { | |
| 3212 | - wp_send_json_error( __( 'Please purchase the course before enrolling', 'tutor' ) ); | |
| 2936 | + if ( $course_id ) { | |
| 2937 | + $password_protected = post_password_required( $course_id ); | |
| 2938 | + if ( $password_protected ) { | |
| 2939 | + wp_send_json_error( __( 'This course is password protected', 'tutor' ) ); | |
| 3213 | 2940 | } |
| 3214 | - } | |
| 3215 | - | |
| 3216 | - $enroll = EnrollmentModel::do_enroll( $course_id, 0, $user_id ); | |
| 3217 | - if ( $enroll ) { | |
| 3218 | - wp_send_json_success( __( 'Enrollment successfully done!', 'tutor' ) ); | |
| 2941 | + $enroll = tutor_utils()->do_enroll( $course_id, 0, $user_id ); | |
| 2942 | + if ( $enroll ) { | |
| 2943 | + wp_send_json_success( __( 'Enrollment successfully done!', 'tutor' ) ); | |
| 2944 | + } else { | |
| 2945 | + wp_send_json_error( __( 'Enrollment failed, please try again!', 'tutor' ) ); | |
| 2946 | + } | |
| 3219 | 2947 | } else { |
| 3220 | - wp_send_json_error( __( 'Enrollment failed, please try again!', 'tutor' ) ); | |
| 2948 | + wp_send_json_error( __( 'Invalid course ID', 'tutor' ) ); | |
| 3221 | 2949 | } |
| 3222 | 2950 | } |
| 3223 | 2951 | |
| 3224 | 2952 | /** |
| @@ -3305,10 +3033,14 @@ | ||
| 3305 | 3033 | 'regular_price' => $regular_price, |
| 3306 | 3034 | 'sale_price' => $sale_price, |
| 3307 | 3035 | ); |
| 3308 | 3036 | |
| 3309 | - $card_data = apply_filters( 'tutor_course_mini_info', $info, $post ); | |
| 3037 | + if ( 'course-bundle' === $post->post_type && tutor_utils()->is_addon_enabled( 'tutor-pro/addons/course-bundle/course-bundle.php' ) ) { | |
| 3038 | + $info['total_course'] = count( BundleModel::get_bundle_course_ids( $post->ID ) ); | |
| 3039 | + } | |
| 3310 | 3040 | |
| 3041 | + $card_data = apply_filters( 'tutor_add_course_plan_info', $info, $post ); | |
| 3042 | + | |
| 3311 | 3043 | return $card_data; |
| 3312 | 3044 | } |
| 3313 | 3045 | |
| 3314 | 3046 | /** |
| @@ -3329,9 +3061,9 @@ | ||
| 3329 | 3061 | $info['last_updated'] = tutor_i18n_get_formated_date( $post->post_modified_at ); |
| 3330 | 3062 | $info['course_duration'] = tutor_utils()->get_course_duration( $post->ID, false ); |
| 3331 | 3063 | $info['total_enrolled'] = tutor_utils()->count_enrolled_users_by_course( $post->ID ); |
| 3332 | 3064 | |
| 3333 | - $card_data = apply_filters( 'tutor_course_card_data', $info, $post ); | |
| 3065 | + $card_data = apply_filters( 'tutor_add_course_plan_info', $info, $post ); | |
| 3334 | 3066 | |
| 3335 | 3067 | return $card_data; |
| 3336 | 3068 | } |
| 3337 | 3069 | |
| @@ -3388,199 +3120,6 @@ | ||
| 3388 | 3120 | 'trash', |
| 3389 | 3121 | 'pending', |
| 3390 | 3122 | 'future', |
| 3391 | 3123 | ); |
| 3392 | - } | |
| 3393 | - | |
| 3394 | - /** | |
| 3395 | - * Link a course/bundle post to a WooCommerce product. | |
| 3396 | - * | |
| 3397 | - * @since 3.8.2 | |
| 3398 | - * | |
| 3399 | - * @param int $post_ID The WordPress post ID of the course. | |
| 3400 | - * @param int $product_id The WooCommerce product ID to associate with the course. | |
| 3401 | - * | |
| 3402 | - * @return void | |
| 3403 | - */ | |
| 3404 | - public static function sync_course_with_wc_product( $post_ID, $product_id ) { | |
| 3405 | - | |
| 3406 | - update_post_meta( $post_ID, self::COURSE_PRODUCT_ID_META, $product_id ); | |
| 3407 | - | |
| 3408 | - // Mark product for woocommerce. | |
| 3409 | - update_post_meta( $product_id, '_virtual', 'yes' ); | |
| 3410 | - update_post_meta( $product_id, '_tutor_product', 'yes' ); | |
| 3411 | - } | |
| 3412 | - | |
| 3413 | - /** | |
| 3414 | - * Map Tutor's course prices to WooCommerce. | |
| 3415 | - * | |
| 3416 | - * @since 3.8.2 | |
| 3417 | - * | |
| 3418 | - * @param int $post_ID The WordPress post ID of the course. | |
| 3419 | - * @param string|int|float $regular_price The regular price. | |
| 3420 | - * @param string|int|float $sale_price The sale price. | |
| 3421 | - * @return void | |
| 3422 | - */ | |
| 3423 | - private static function set_course_regular_and_sale_price( $post_ID, $regular_price, $sale_price ) { | |
| 3424 | - | |
| 3425 | - // Set course regular & sale price. | |
| 3426 | - update_post_meta( $post_ID, self::COURSE_PRICE_META, $regular_price ); | |
| 3427 | - update_post_meta( $post_ID, self::COURSE_SALE_PRICE_META, $sale_price ); | |
| 3428 | - } | |
| 3429 | - | |
| 3430 | - /** | |
| 3431 | - * Render start/resume button in enrolled course action btn. | |
| 3432 | - * | |
| 3433 | - * @since 4.0.0 | |
| 3434 | - * | |
| 3435 | - * @param int $course_id course id. | |
| 3436 | - * | |
| 3437 | - * @return void | |
| 3438 | - */ | |
| 3439 | - public function render_course_action_btn( int $course_id ) { | |
| 3440 | - $is_completed = tutor_utils()->is_completed_course( $course_id ); | |
| 3441 | - if ( $is_completed ) { | |
| 3442 | - $certificate_addon_active = tutor_utils()->is_addon_enabled( 'tutor-certificate' ); | |
| 3443 | - if ( ! $certificate_addon_active ) { | |
| 3444 | - Button::make() | |
| 3445 | - ->tag( 'a' ) | |
| 3446 | - ->label( __( 'Completed', 'tutor' ) ) | |
| 3447 | - ->icon( Icon::COMPLETED_CIRCLE ) | |
| 3448 | - ->variant( Variant::PRIMARY ) | |
| 3449 | - ->size( Size::X_SMALL ) | |
| 3450 | - ->attr( 'href', esc_url( get_the_permalink( $course_id ) ) ) | |
| 3451 | - ->render(); | |
| 3452 | - } | |
| 3453 | - return; | |
| 3454 | - } | |
| 3455 | - | |
| 3456 | - $course_progress = tutor_utils()->get_course_completed_percent( $course_id, 0, true ); | |
| 3457 | - $button_text = $course_progress['completed_percent'] > 0 ? __( 'Resume', 'tutor' ) : __( 'Start', 'tutor' ); | |
| 3458 | - $button_url = tutor_utils()->get_course_first_lesson( $course_id ); | |
| 3459 | - | |
| 3460 | - if ( ! $button_url ) { | |
| 3461 | - $button_url = get_the_permalink( $course_id ); | |
| 3462 | - } | |
| 3463 | - | |
| 3464 | - Button::make() | |
| 3465 | - ->tag( 'a' ) | |
| 3466 | - ->label( $button_text ) | |
| 3467 | - ->icon( Icon::PLAY_2 ) | |
| 3468 | - ->variant( Variant::PRIMARY ) | |
| 3469 | - ->size( Size::X_SMALL ) | |
| 3470 | - ->attr( 'href', esc_url( $button_url ) ) | |
| 3471 | - ->render(); | |
| 3472 | - } | |
| 3473 | - | |
| 3474 | - /** | |
| 3475 | - * Get the content for the course completion modal. | |
| 3476 | - * | |
| 3477 | - * This method returns HTML for displaying a modal that informs the user | |
| 3478 | - * that they have not completed all required lessons and assessments. It includes | |
| 3479 | - * the user's current progress shown as a percentage and a progress bar. | |
| 3480 | - * | |
| 3481 | - * @since 4.0.0 | |
| 3482 | - * | |
| 3483 | - * @param float $course_progress The completion percentage of the course. | |
| 3484 | - * | |
| 3485 | - * @return string The rendered HTML content for the modal. | |
| 3486 | - */ | |
| 3487 | - public static function get_complete_modal_content( float $course_progress = 0 ): string { | |
| 3488 | - ob_start(); | |
| 3489 | - ?> | |
| 3490 | - <div> | |
| 3491 | - <p class="tutor-p3 tutor-text-secondary tutor-text-center tutor-mb-7 tutor-px-11"> | |
| 3492 | - <?php esc_html_e( 'You have not completed all required lessons and assessments. ', 'tutor' ); ?> | |
| 3493 | - </p> | |
| 3494 | - <div class="tutor-finish-course-progress tutor-border tutor-p-5 tutor-flex tutor-flex-column tutor-gap-4 tutor-surface-base tutor-rounded-md"> | |
| 3495 | - <div class="tutor-flex tutor-items-center tutor-justify-between"> | |
| 3496 | - <div class="tutor-p3 tutor-text-secondary"> | |
| 3497 | - <?php esc_html_e( 'Your Progress', 'tutor' ); ?> | |
| 3498 | - </div> | |
| 3499 | - <div class="tutor-p1 tutor-font-bold"> | |
| 3500 | - <?php echo esc_html( number_format_i18n( $course_progress ) . '%' ); ?> | |
| 3501 | - </div> | |
| 3502 | - </div> | |
| 3503 | - <?php | |
| 3504 | - Progress::make()->type( 'bar' )->value( $course_progress )->render(); | |
| 3505 | - ?> | |
| 3506 | - </div> | |
| 3507 | - </div> | |
| 3508 | - <?php | |
| 3509 | - return ob_get_clean(); | |
| 3510 | - } | |
| 3511 | - | |
| 3512 | - /** | |
| 3513 | - * Render the course complete button. | |
| 3514 | - * | |
| 3515 | - * Displays a button that allows the user to complete the course. If the course | |
| 3516 | - * progress is less than 100%, clicking the button shows a modal informing the user | |
| 3517 | - * that not all requirements are fulfilled. If the course progress is 100%, | |
| 3518 | - * clicking the button attempts to complete the course. | |
| 3519 | - * | |
| 3520 | - * @since 4.0.0 | |
| 3521 | - * | |
| 3522 | - * @param string $modal_id The HTML ID of the modal to display if not complete. | |
| 3523 | - * @param int $course_id The ID of the course. | |
| 3524 | - * @param float $course_progress The current completion percentage of the course. | |
| 3525 | - * @param string $size The button size. | |
| 3526 | - * @param string $tooltip Optional. Tooltip message. | |
| 3527 | - * @param bool $block Optional. Whether the button is full-width. | |
| 3528 | - * | |
| 3529 | - * @return void | |
| 3530 | - */ | |
| 3531 | - public static function render_course_complete_btn( string $modal_id, int $course_id, float $course_progress = 0, string $size = Size::MEDIUM, string $tooltip = '', bool $block = false ): void { | |
| 3532 | - $button = Button::make() | |
| 3533 | - ->variant( Variant::SECONDARY ) | |
| 3534 | - ->label( __( 'Complete the Course', 'tutor' ) ) | |
| 3535 | - ->icon( Icon::TICK_MARK ) | |
| 3536 | - ->size( $size ) | |
| 3537 | - ->block( $block ) | |
| 3538 | - ->attr( 'type', 'button' ); | |
| 3539 | - | |
| 3540 | - if ( ! empty( $tooltip ) ) { | |
| 3541 | - $button->disabled(); | |
| 3542 | - } | |
| 3543 | - | |
| 3544 | - if ( $course_progress < 100 ) { | |
| 3545 | - $button->attr( '@click', "TutorCore.modal.showModal('{$modal_id}')" ); | |
| 3546 | - } else { | |
| 3547 | - $button->attr( '@click', "handleCourseComplete({$course_id})" ); | |
| 3548 | - $button->attr( ':class', "courseCompleteMutation?.isPending ? 'tutor-btn-loading' : ''" ); | |
| 3549 | - $button->attr( ':disabled', 'courseCompleteMutation?.isPending' ); | |
| 3550 | - } | |
| 3551 | - | |
| 3552 | - if ( ! empty( $tooltip ) ) { | |
| 3553 | - Tooltip::make() | |
| 3554 | - ->content( $tooltip ) | |
| 3555 | - ->placement( Tooltip::PLACEMENT_BOTTOM ) | |
| 3556 | - ->arrow( Tooltip::ARROW_CENTER ) | |
| 3557 | - ->trigger_element( $button->get() ) | |
| 3558 | - ->render(); | |
| 3559 | - } else { | |
| 3560 | - $button->render(); | |
| 3561 | - } | |
| 3562 | - } | |
| 3563 | - | |
| 3564 | - /** | |
| 3565 | - * Render course retake button | |
| 3566 | - * | |
| 3567 | - * @since 4.0.0 | |
| 3568 | - * | |
| 3569 | - * @param string $modal_id Modal id. | |
| 3570 | - * @param string $size The button size. | |
| 3571 | - * @param bool $block Optional. Whether the button is full-width. | |
| 3572 | - * | |
| 3573 | - * @return void | |
| 3574 | - */ | |
| 3575 | - public static function render_course_retake_btn( string $modal_id, string $size = Size::MEDIUM, bool $block = false ): void { | |
| 3576 | - Button::make() | |
| 3577 | - ->variant( Variant::SECONDARY ) | |
| 3578 | - ->label( __( 'Retake this Course', 'tutor' ) ) | |
| 3579 | - ->icon( Icon::RELOAD_4 ) | |
| 3580 | - ->size( $size ) | |
| 3581 | - ->block( $block ) | |
| 3582 | - ->attr( 'type', 'button' ) | |
| 3583 | - ->attr( '@click', "TutorCore.modal.showModal('{$modal_id}')" ) | |
| 3584 | - ->render(); | |
| 3585 | 3124 | } |
| 3586 | 3125 | } |