PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.2.20
Tutor LMS – eLearning and online course solution v1.2.20
3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / classes / Course.php
tutor / classes Last commit date
Addons.php 7 years ago Admin.php 7 years ago Ajax.php 7 years ago Assets.php 7 years ago Course.php 7 years ago Gutenberg.php 7 years ago Instructor.php 7 years ago Instructors_List.php 7 years ago Lesson.php 7 years ago Options.php 7 years ago Post_types.php 7 years ago Q_and_A.php 7 years ago Question.php 7 years ago Question_Answers_List.php 7 years ago Quiz.php 7 years ago Quiz_Attempts_List.php 7 years ago Rewrite_Rules.php 7 years ago Shortcode.php 7 years ago Student.php 7 years ago Students_List.php 7 years ago Taxonomies.php 7 years ago Template.php 7 years ago Theme_Compatibility.php 7 years ago Tools.php 7 years ago Tutor.php 7 years ago TutorEDD.php 7 years ago Tutor_Base.php 7 years ago Tutor_List_Table.php 7 years ago User.php 7 years ago Utils.php 7 years ago Video_Stream.php 7 years ago Withdraw.php 7 years ago Withdraw_Requests_List.php 7 years ago WooCommerce.php 7 years ago
Course.php
535 lines
1 <?php
2 namespace TUTOR;
3
4 if ( ! defined( 'ABSPATH' ) )
5 exit;
6
7 class Course extends Tutor_Base {
8 public function __construct() {
9 parent::__construct();
10
11 add_action( 'add_meta_boxes', array($this, 'register_meta_box') );
12 add_action('save_post_'.$this->course_post_type, array($this, 'save_course_meta'), 10, 2);
13 add_action('wp_ajax_tutor_add_course_topic', array($this, 'tutor_add_course_topic'));
14 add_action('wp_ajax_tutor_update_topic', array($this, 'tutor_update_topic'));
15
16 //Add Column
17 add_filter( "manage_{$this->course_post_type}_posts_columns", array($this, 'add_column'), 10,1 );
18 add_action( "manage_{$this->course_post_type}_posts_custom_column" , array($this, 'custom_lesson_column'), 10, 2 );
19
20 add_action('admin_action_tutor_delete_topic', array($this, 'tutor_delete_topic'));
21 add_action('admin_action_tutor_delete_announcement', array($this, 'tutor_delete_announcement'));
22
23 //Frontend Action
24 add_action('template_redirect', array($this, 'enroll_now'));
25 add_action('template_redirect', array($this, 'mark_course_complete'));
26
27 //Modal Perform
28 add_action('wp_ajax_tutor_load_instructors_modal', array($this, 'tutor_load_instructors_modal'));
29 add_action('wp_ajax_tutor_add_instructors_to_course', array($this, 'tutor_add_instructors_to_course'));
30 add_action('wp_ajax_detach_instructor_from_course', array($this, 'detach_instructor_from_course'));
31
32 /**
33 * Frontend Dashboard
34 */
35 add_action('wp_ajax_tutor_delete_dashboard_course', array($this, 'tutor_delete_dashboard_course'));
36
37 }
38 /**
39 * Registering metabox
40 */
41 public function register_meta_box(){
42 $coursePostType = tutor()->course_post_type;
43
44 add_meta_box( 'tutor-course-topics', __( 'Course Builder', 'tutor' ), array($this, 'course_meta_box'), $coursePostType );
45 add_meta_box( 'tutor-course-additional-data', __( 'Additional Data', 'tutor' ), array($this, 'course_additional_data_meta_box'), $coursePostType );
46 add_meta_box( 'tutor-course-videos', __( 'Video', 'tutor' ), array($this, 'video_metabox'), $coursePostType );
47 add_meta_box( 'tutor-instructors', __( 'Instructors', 'tutor' ), array($this, 'instructors_metabox'), $coursePostType );
48 add_meta_box( 'tutor-announcements', __( 'Announcements', 'tutor' ), array($this, 'announcements_metabox'), $coursePostType );
49 }
50 public function course_meta_box(){
51 include tutor()->path.'views/metabox/course-topics.php';
52 }
53 public function course_additional_data_meta_box(){
54 include tutor()->path.'views/metabox/course-additional-data.php';
55 }
56 public function video_metabox(){
57 include tutor()->path.'views/metabox/video-metabox.php';
58 }
59
60 public function announcements_metabox(){
61 include tutor()->path.'views/metabox/announcements-metabox.php';
62 }
63
64 public function instructors_metabox(){
65 include tutor()->path.'views/metabox/instructors-metabox.php';
66 }
67
68 /**
69 * @param $post_ID
70 *
71 * Insert Topic and attached it with Course
72 */
73 public function save_course_meta($post_ID, $post){
74 global $wpdb;
75 /**
76 * Insert Topic
77 */
78 if ( ! empty($_POST['topic_title'])) {
79 $topic_title = sanitize_text_field( $_POST['topic_title'] );
80 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
81
82 $post_arr = array(
83 'post_type' => 'topics',
84 'post_title' => $topic_title,
85 'post_content' => $topic_summery,
86 'post_status' => 'publish',
87 'post_author' => get_current_user_id(),
88 'post_parent' => $post_ID,
89 );
90 wp_insert_post( $post_arr );
91 }
92
93 //Course Duration
94 if ( ! empty($_POST['course_duration'])){
95 $video = tutor_utils()->sanitize_array($_POST['course_duration']);
96 update_post_meta($post_ID, '_course_duration', $video);
97 }
98
99 if ( ! empty($_POST['course_level'])){
100 $course_level = sanitize_text_field($_POST['course_level']);
101 update_post_meta($post_ID, '_tutor_course_level', $course_level);
102 }
103
104 if ( ! empty($_POST['course_benefits'])){
105 $course_benefits = wp_kses_post($_POST['course_benefits']);
106 update_post_meta($post_ID, '_tutor_course_benefits', $course_benefits);
107 }
108
109 if ( ! empty($_POST['course_requirements'])){
110 $requirements = wp_kses_post($_POST['course_requirements']);
111 update_post_meta($post_ID, '_tutor_course_requirements', $requirements);
112 }
113
114 if ( ! empty($_POST['course_target_audience'])){
115 $target_audience = wp_kses_post($_POST['course_target_audience']);
116 update_post_meta($post_ID, '_tutor_course_target_audience', $target_audience);
117 }
118
119 if ( ! empty($_POST['course_material_includes'])){
120 $material_includes = wp_kses_post($_POST['course_material_includes']);
121 update_post_meta($post_ID, '_tutor_course_material_includes', $material_includes);
122 }
123 /**
124 * Sorting Topics and lesson
125 */
126 if ( ! empty($_POST['tutor_topics_lessons_sorting'])){
127 $new_order = sanitize_text_field(stripslashes($_POST['tutor_topics_lessons_sorting']));
128 $order = json_decode($new_order, true);
129
130 if (is_array($order) && count($order)){
131 $i = 0;
132 foreach ($order as $topic ){
133 $i++;
134 $wpdb->update(
135 $wpdb->posts,
136 array('menu_order' => $i),
137 array('ID' => $topic['topic_id'])
138 );
139
140 /**
141 * Removing All lesson with topic
142 */
143
144 $wpdb->update(
145 $wpdb->posts,
146 array('post_parent' => 0),
147 array('post_parent' => $topic['topic_id'])
148 );
149
150 /**
151 * Lesson Attaching with topic ID
152 * sorting lesson
153 */
154 if (isset($topic['lesson_ids'])){
155 $lesson_ids = $topic['lesson_ids'];
156 }else{
157 $lesson_ids = array();
158 }
159 if (count($lesson_ids)){
160 foreach ($lesson_ids as $lesson_key => $lesson_id ){
161 $wpdb->update(
162 $wpdb->posts,
163 array('post_parent' => $topic['topic_id'], 'menu_order' => $lesson_key),
164 array('ID' => $lesson_id)
165 );
166 }
167 }
168 }
169 }
170 }
171
172
173 //Video
174 if ( ! empty($_POST['video']['source'])){
175 $video = tutor_utils()->sanitize_array($_POST['video']);
176 update_post_meta($post_ID, '_video', $video);
177 }
178
179 /**
180 * Adding author to instructor automatically
181 */
182
183 $author_id = $post->post_author;
184 $attached = (int) $wpdb->get_var(" SELECT COUNT(umeta_id) FROM {$wpdb->usermeta} WHERE user_id = {$author_id} AND meta_key = '_tutor_instructor_course_id' AND meta_value = {$post_ID} ");
185 if ( ! $attached){
186 add_user_meta($author_id, '_tutor_instructor_course_id', $post_ID);
187 }
188
189 //Announcements
190 $announcement_title = tutor_utils()->avalue_dot('announcements.title', $_POST );
191 if ( ! empty($announcement_title)){
192 $title = sanitize_text_field(tutor_utils()->avalue_dot('announcements.title', $_POST ));
193 $content = wp_kses_post(tutor_utils()->avalue_dot('announcements.content', $_POST ));
194
195 $post_arr = array(
196 'post_type' => 'tutor_announcements',
197 'post_title' => $title,
198 'post_content' => $content,
199 'post_status' => 'publish',
200 'post_author' => get_current_user_id(),
201 'post_parent' => $post_ID,
202 );
203 wp_insert_post( $post_arr );
204 }
205 }
206
207 /**
208 * Tutor add course topic
209 */
210 public function tutor_add_course_topic(){
211 if (empty($_POST['topic_title'])) {
212 wp_send_json_error();
213 }
214 $course_id = (int) tutor_utils()->avalue_dot('tutor_topic_course_ID', $_POST);
215 $next_topic_order_id = tutor_utils()->get_next_topic_order_id($course_id);
216
217 $topic_title = sanitize_text_field( $_POST['topic_title'] );
218 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
219
220 $post_arr = array(
221 'post_type' => 'topics',
222 'post_title' => $topic_title,
223 'post_content' => $topic_summery,
224 'post_status' => 'publish',
225 'post_author' => get_current_user_id(),
226 'post_parent' => $course_id,
227 'menu_order' => $next_topic_order_id,
228 );
229 $current_topic_id = wp_insert_post( $post_arr );
230
231 ob_start();
232 include tutor()->path.'views/metabox/course-contents.php';
233 $course_contents = ob_get_clean();
234
235 wp_send_json_success(array('course_contents' => $course_contents));
236 }
237
238 /**
239 * Update the topic
240 */
241 public function tutor_update_topic(){
242 $topic_id = (int) sanitize_text_field($_POST['topic_id']);
243 $topic_title = sanitize_text_field($_POST['topic_title']);
244 $topic_summery = wp_kses_post($_POST['topic_summery']);
245
246 $topic_attr = array(
247 'ID' => $topic_id,
248 'post_title' => $topic_title,
249 'post_content' => $topic_summery,
250 );
251 wp_update_post( $topic_attr );
252
253 wp_send_json_success(array('msg' => __('Topic has been updated', 'tutor') ));
254 }
255
256
257 /**
258 * @param $columns
259 *
260 * @return mixed
261 *
262 * Add Lesson column
263 */
264
265 public function add_column($columns){
266 $date_col = $columns['date'];
267 unset($columns['date']);
268 $columns['lessons'] = __('Lessons', 'tutor');
269 $columns['students'] = __('Students', 'tutor');
270 $columns['price'] = __('Price', 'tutor');
271 $columns['date'] = $date_col;
272
273 return $columns;
274 }
275
276 /**
277 * @param $column
278 * @param $post_id
279 *
280 */
281 public function custom_lesson_column($column, $post_id ){
282 if ($column === 'lessons'){
283 echo tutor_utils()->get_lesson_count_by_course($post_id);
284 }
285
286 if ($column === 'students'){
287 echo tutor_utils()->count_enrolled_users_by_course($post_id);
288 }
289
290 if ($column === 'price'){
291 $price = tutor_utils()->get_course_price($post_id);
292
293 if ($price){
294 if (function_exists('wc_price')){
295 echo '<span class="tutor-label-success">'.wc_price($price).'</span>';
296 }else{
297 echo '<span class="tutor-label-success">'.$price.'</span>';
298 }
299 }else{
300 echo 'free';
301 }
302 }
303 }
304
305
306 public function tutor_delete_topic(){
307 if (!isset($_GET[tutor()->nonce]) || !wp_verify_nonce($_GET[tutor()->nonce], tutor()->nonce_action)) {
308 exit();
309 }
310 if ( ! isset($_GET['topic_id'])){
311 exit();
312 }
313
314 global $wpdb;
315
316 $topic_id = (int) sanitize_text_field($_GET['topic_id']);
317 $wpdb->update(
318 $wpdb->posts,
319 array('post_parent' => 0),
320 array('post_parent' => $topic_id)
321 );
322
323 $wpdb->delete(
324 $wpdb->postmeta,
325 array('post_id' => $topic_id)
326 );
327
328 wp_delete_post($topic_id);
329 wp_safe_redirect(wp_get_referer());
330 }
331
332 public function tutor_delete_announcement(){
333 tutor_utils()->checking_nonce('get');
334
335 $announcement_id = (int) sanitize_text_field($_GET['topic_id']);
336
337 wp_delete_post($announcement_id);
338 wp_safe_redirect(wp_get_referer());
339 }
340
341 public function enroll_now(){
342 //Checking if action comes from Enroll form
343 if ( ! isset($_POST['tutor_course_action']) || $_POST['tutor_course_action'] !== '_tutor_course_enroll_now' || ! isset($_POST['tutor_course_id']) ){
344 return;
345 }
346 //Checking Nonce
347 tutor_utils()->checking_nonce();
348
349 $user_id = get_current_user_id();
350 if ( ! $user_id){
351 exit(__('Please Sign In first', 'tutor'));
352 }
353
354 $course_id = (int) sanitize_text_field($_POST['tutor_course_id']);
355 $user_id = get_current_user_id();
356
357 /**
358 * TODO: need to check purchase information
359 */
360
361 $is_purchasable = tutor_utils()->is_course_purchasable($course_id);
362
363 /**
364 * If is is not purchasable, it's free, and enroll right now
365 *
366 * if purchasable, then process purchase.
367 *
368 * @since: v.1.0.0
369 */
370 if ($is_purchasable){
371 //process purchase
372
373 }else{
374 //Free enroll
375 tutor_utils()->do_enroll($course_id);
376 }
377
378 $referer_url = wp_get_referer();
379 wp_redirect($referer_url);
380 }
381
382 /**
383 *
384 * Mark complete completed
385 *
386 * @since v.1.0.0
387 */
388 public function mark_course_complete(){
389 if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_complete_course' ){
390 return;
391 }
392 //Checking nonce
393 tutor_utils()->checking_nonce();
394
395 $user_id = get_current_user_id();
396
397 //TODO: need to show view if not signed_in
398 if ( ! $user_id){
399 die(__('Please Sign-In', 'tutor'));
400 }
401
402 $course_id = (int) sanitize_text_field($_POST['course_id']);
403
404 do_action('tutor_course_complete_before', $course_id);
405 /**
406 * Marking course completed at Comment
407 */
408
409 global $wpdb;
410
411 $date = date("Y-m-d H:i:s");
412
413 //Making sure that, hash is unique
414 do{
415 $hash = substr(md5(wp_generate_password(32).$date.$course_id.$user_id), 0, 16);
416 $hasHash = (int) $wpdb->get_var("SELECT COUNT(comment_ID) from {$wpdb->comments} WHERE comment_agent = 'TutorLMSPlugin' AND comment_type = 'course_completed' AND comment_content = '{$hash}' ");
417 }while($hasHash > 0);
418
419 $data = array(
420 'comment_post_ID' => $course_id,
421 'comment_author' => $user_id,
422 'comment_date' => $date,
423 'comment_date_gmt' => get_gmt_from_date($date),
424 'comment_content' => $hash, //Identification Hash
425 'comment_approved' => 'approved',
426 'comment_agent' => 'TutorLMSPlugin',
427 'comment_type' => 'course_completed',
428 'user_id' => $user_id,
429 );
430
431 $wpdb->insert($wpdb->comments, $data);
432
433 do_action('tutor_course_complete_after', $course_id);
434
435 wp_redirect(get_the_permalink($course_id));
436 }
437
438
439 public function tutor_load_instructors_modal(){
440 global $wpdb;
441
442 $course_id = (int) sanitize_text_field($_POST['course_id']);
443 $search_terms = sanitize_text_field(tutor_utils()->avalue_dot('search_terms', $_POST));
444
445 $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
446
447 $instructors = array();
448
449
450 $not_in_sql = apply_filters('tutor_instructor_query_when_exists', " AND ID <1 ");
451
452 if ($saved_instructors){
453 $saved_instructors_ids = wp_list_pluck($saved_instructors, 'ID');
454 $instructor_not_in_ids = implode(',', $saved_instructors_ids);
455 $not_in_sql .= "AND ID NOT IN($instructor_not_in_ids) ";
456 }
457
458 $search_sql = '';
459 if ($search_terms){
460 $search_sql = "AND (user_login like '%{$search_terms}%' or user_nicename like '%{$search_terms}%' or display_name like '%{$search_terms}%') ";
461 }
462
463 $instructors = $wpdb->get_results("select ID, display_name from {$wpdb->users}
464 INNER JOIN {$wpdb->usermeta} ON ID = user_id AND meta_key = '_tutor_instructor_status' AND meta_value = 'approved'
465 WHERE 1=1 {$not_in_sql} {$search_sql} limit 10 ");
466
467 $output = '';
468 if (is_array($instructors) && count($instructors)){
469 $instructor_output = '';
470 foreach ($instructors as $instructor){
471 $instructor_output .= "<p><label><input type='radio' name='tutor_instructor_ids[]' value='{$instructor->ID}' > {$instructor->display_name} </label></p>";
472 }
473
474 $output .= apply_filters('tutor_course_instructors_html', $instructor_output, $instructors);
475 $output .= '<p class="quiz-search-suggest-text">'.__('Search to get the specific instructors', 'tutor').'</p>';
476
477 }else{
478 $output .= __('No instructor available or you have already added maximum instructors', 'tutor');
479 }
480
481
482 if ( ! defined('TUTOR_MT_VERSION')){
483 $output .= '<p class="tutor-notice-warning" style="margin-top: 50px; font-size: 14px;">'. sprintf( __('To add unlimited multiple instructors in your course, get %sTutor LMS Pro%s', 'tutor'), '<a href="https://www.themeum.com/product/tutor-lms" target="_blank">', "</a>" ) .'</p>';
484 }
485
486 wp_send_json_success(array('output' => $output));
487 }
488
489 public function tutor_add_instructors_to_course(){
490 $course_id = (int) sanitize_text_field($_POST['course_id']);
491 $instructor_ids = tutor_utils()->avalue_dot('tutor_instructor_ids', $_POST);
492
493 if (is_array($instructor_ids) && count($instructor_ids)){
494 foreach ($instructor_ids as $instructor_id){
495 add_user_meta($instructor_id, '_tutor_instructor_course_id', $course_id);
496 }
497 }
498
499 $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
500 $output = '';
501
502 if ($saved_instructors){
503 foreach ($saved_instructors as $t){
504
505 $output .= '<div id="added-instructor-id-'.$t->ID.'" class="added-instructor-item added-instructor-item-'.$t->ID.'" data-instructor-id="'.$t->ID.'">
506 <span class="instructor-icon">'.get_avatar($t->ID, 30).'</span>
507 <span class="instructor-name"> '.$t->display_name.' </span>
508 <span class="instructor-control">
509 <a href="javascript:;" class="tutor-instructor-delete-btn"><i class="tutor-icon-garbage"></i></a>
510 </span>
511 </div>';
512 }
513 }
514
515 wp_send_json_success(array('output' => $output));
516 }
517
518 public function detach_instructor_from_course(){
519 global $wpdb;
520
521 $instructor_id = (int) sanitize_text_field($_POST['instructor_id']);
522 $course_id = (int) sanitize_text_field($_POST['course_id']);
523
524 $wpdb->delete($wpdb->usermeta, array('user_id' => $instructor_id, 'meta_key' => '_tutor_instructor_course_id', 'meta_value' => $course_id) );
525 wp_send_json_success();
526 }
527
528 public function tutor_delete_dashboard_course(){
529 $course_id = intval(sanitize_text_field($_POST['course_id']));
530 wp_trash_post($course_id);
531 wp_send_json_success();
532 }
533
534
535 }