PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.3.3
Tutor LMS – eLearning and online course solution v1.3.3
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 6 years ago Admin.php 6 years ago Ajax.php 6 years ago Assets.php 6 years ago Course.php 6 years ago Course_Widget.php 6 years ago Gutenberg.php 6 years ago Instructor.php 6 years ago Instructors_List.php 6 years ago Lesson.php 6 years ago Options.php 6 years ago Post_types.php 6 years ago Q_and_A.php 6 years ago Question.php 6 years ago Question_Answers_List.php 6 years ago Quiz.php 6 years ago Quiz_Attempts_List.php 6 years ago Rewrite_Rules.php 6 years ago Shortcode.php 6 years ago Student.php 6 years ago Students_List.php 6 years ago Taxonomies.php 6 years ago Template.php 6 years ago Theme_Compatibility.php 6 years ago Tools.php 6 years ago Tutor.php 6 years ago TutorEDD.php 6 years ago Tutor_Base.php 6 years ago Tutor_List_Table.php 6 years ago Upgrader.php 6 years ago User.php 6 years ago Utils.php 6 years ago Video_Stream.php 6 years ago Withdraw.php 6 years ago Withdraw_Requests_List.php 6 years ago WooCommerce.php 6 years ago
Course.php
566 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 * Gutenberg author support
39 */
40
41 add_filter('wp_insert_post_data', array($this, 'tutor_add_gutenberg_author'), '99', 2);
42 }
43 /**
44 * Registering metabox
45 */
46 public function register_meta_box(){
47 $coursePostType = tutor()->course_post_type;
48 $course_marketplace = tutor_utils()->get_option('enable_course_marketplace');
49
50 add_meta_box( 'tutor-course-topics', __( 'Course Builder', 'tutor' ), array($this, 'course_meta_box'), $coursePostType );
51 add_meta_box( 'tutor-course-additional-data', __( 'Additional Data', 'tutor' ), array($this, 'course_additional_data_meta_box'), $coursePostType );
52 add_meta_box( 'tutor-course-videos', __( 'Video', 'tutor' ), array($this, 'video_metabox'), $coursePostType );
53
54 if ($course_marketplace) {
55 add_meta_box( 'tutor-instructors', __( 'Instructors', 'tutor' ), array( $this, 'instructors_metabox' ), $coursePostType );
56 }
57 add_meta_box( 'tutor-announcements', __( 'Announcements', 'tutor' ), array($this, 'announcements_metabox'), $coursePostType );
58 }
59 public function course_meta_box(){
60 include tutor()->path.'views/metabox/course-topics.php';
61 }
62 public function course_additional_data_meta_box(){
63 include tutor()->path.'views/metabox/course-additional-data.php';
64 }
65 public function video_metabox(){
66 include tutor()->path.'views/metabox/video-metabox.php';
67 }
68
69 public function announcements_metabox(){
70 include tutor()->path.'views/metabox/announcements-metabox.php';
71 }
72
73 public function instructors_metabox(){
74 include tutor()->path . 'views/metabox/instructors-metabox.php';
75 }
76
77 /**
78 * @param $post_ID
79 *
80 * Insert Topic and attached it with Course
81 */
82 public function save_course_meta($post_ID, $post){
83 global $wpdb;
84 /**
85 * Insert Topic
86 */
87 if ( ! empty($_POST['topic_title'])) {
88 $topic_title = sanitize_text_field( $_POST['topic_title'] );
89 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
90
91 $post_arr = array(
92 'post_type' => 'topics',
93 'post_title' => $topic_title,
94 'post_content' => $topic_summery,
95 'post_status' => 'publish',
96 'post_author' => get_current_user_id(),
97 'post_parent' => $post_ID,
98 );
99 wp_insert_post( $post_arr );
100 }
101
102 //Course Duration
103 if ( ! empty($_POST['course_duration'])){
104 $video = tutor_utils()->sanitize_array($_POST['course_duration']);
105 update_post_meta($post_ID, '_course_duration', $video);
106 }
107
108 if ( ! empty($_POST['course_level'])){
109 $course_level = sanitize_text_field($_POST['course_level']);
110 update_post_meta($post_ID, '_tutor_course_level', $course_level);
111 }
112
113 if ( ! empty($_POST['course_benefits'])){
114 $course_benefits = wp_kses_post($_POST['course_benefits']);
115 update_post_meta($post_ID, '_tutor_course_benefits', $course_benefits);
116 }
117
118 if ( ! empty($_POST['course_requirements'])){
119 $requirements = wp_kses_post($_POST['course_requirements']);
120 update_post_meta($post_ID, '_tutor_course_requirements', $requirements);
121 }
122
123 if ( ! empty($_POST['course_target_audience'])){
124 $target_audience = wp_kses_post($_POST['course_target_audience']);
125 update_post_meta($post_ID, '_tutor_course_target_audience', $target_audience);
126 }
127
128 if ( ! empty($_POST['course_material_includes'])){
129 $material_includes = wp_kses_post($_POST['course_material_includes']);
130 update_post_meta($post_ID, '_tutor_course_material_includes', $material_includes);
131 }
132 /**
133 * Sorting Topics and lesson
134 */
135 if ( ! empty($_POST['tutor_topics_lessons_sorting'])){
136 $new_order = sanitize_text_field(stripslashes($_POST['tutor_topics_lessons_sorting']));
137 $order = json_decode($new_order, true);
138
139 if (is_array($order) && count($order)){
140 $i = 0;
141 foreach ($order as $topic ){
142 $i++;
143 $wpdb->update(
144 $wpdb->posts,
145 array('menu_order' => $i),
146 array('ID' => $topic['topic_id'])
147 );
148
149 /**
150 * Removing All lesson with topic
151 */
152
153 $wpdb->update(
154 $wpdb->posts,
155 array('post_parent' => 0),
156 array('post_parent' => $topic['topic_id'])
157 );
158
159 /**
160 * Lesson Attaching with topic ID
161 * sorting lesson
162 */
163 if (isset($topic['lesson_ids'])){
164 $lesson_ids = $topic['lesson_ids'];
165 }else{
166 $lesson_ids = array();
167 }
168 if (count($lesson_ids)){
169 foreach ($lesson_ids as $lesson_key => $lesson_id ){
170 $wpdb->update(
171 $wpdb->posts,
172 array('post_parent' => $topic['topic_id'], 'menu_order' => $lesson_key),
173 array('ID' => $lesson_id)
174 );
175 }
176 }
177 }
178 }
179 }
180
181
182 //Video
183 if ( ! empty($_POST['video']['source'])){
184 $video = tutor_utils()->sanitize_array($_POST['video']);
185 update_post_meta($post_ID, '_video', $video);
186 }
187
188 /**
189 * Adding author to instructor automatically
190 */
191
192 $author_id = $post->post_author;
193 $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} ");
194 if ( ! $attached){
195 add_user_meta($author_id, '_tutor_instructor_course_id', $post_ID);
196 }
197
198 //Announcements
199 $announcement_title = tutor_utils()->avalue_dot('announcements.title', $_POST );
200 if ( ! empty($announcement_title)){
201 $title = sanitize_text_field(tutor_utils()->avalue_dot('announcements.title', $_POST ));
202 $content = wp_kses_post(tutor_utils()->avalue_dot('announcements.content', $_POST ));
203
204 $post_arr = array(
205 'post_type' => 'tutor_announcements',
206 'post_title' => $title,
207 'post_content' => $content,
208 'post_status' => 'publish',
209 'post_author' => get_current_user_id(),
210 'post_parent' => $post_ID,
211 );
212 wp_insert_post( $post_arr );
213 }
214 }
215
216 /**
217 * Tutor add course topic
218 */
219 public function tutor_add_course_topic(){
220 if (empty($_POST['topic_title'])) {
221 wp_send_json_error();
222 }
223 $course_id = (int) tutor_utils()->avalue_dot('tutor_topic_course_ID', $_POST);
224 $next_topic_order_id = tutor_utils()->get_next_topic_order_id($course_id);
225
226 $topic_title = sanitize_text_field( $_POST['topic_title'] );
227 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
228
229 $post_arr = array(
230 'post_type' => 'topics',
231 'post_title' => $topic_title,
232 'post_content' => $topic_summery,
233 'post_status' => 'publish',
234 'post_author' => get_current_user_id(),
235 'post_parent' => $course_id,
236 'menu_order' => $next_topic_order_id,
237 );
238 $current_topic_id = wp_insert_post( $post_arr );
239
240 ob_start();
241 include tutor()->path.'views/metabox/course-contents.php';
242 $course_contents = ob_get_clean();
243
244 wp_send_json_success(array('course_contents' => $course_contents));
245 }
246
247 /**
248 * Update the topic
249 */
250 public function tutor_update_topic(){
251 $topic_id = (int) sanitize_text_field($_POST['topic_id']);
252 $topic_title = sanitize_text_field($_POST['topic_title']);
253 $topic_summery = wp_kses_post($_POST['topic_summery']);
254
255 $topic_attr = array(
256 'ID' => $topic_id,
257 'post_title' => $topic_title,
258 'post_content' => $topic_summery,
259 );
260 wp_update_post( $topic_attr );
261
262 wp_send_json_success(array('msg' => __('Topic has been updated', 'tutor') ));
263 }
264
265
266 /**
267 * @param $columns
268 *
269 * @return mixed
270 *
271 * Add Lesson column
272 */
273
274 public function add_column($columns){
275 $date_col = $columns['date'];
276 unset($columns['date']);
277 $columns['lessons'] = __('Lessons', 'tutor');
278 $columns['students'] = __('Students', 'tutor');
279 $columns['price'] = __('Price', 'tutor');
280 $columns['date'] = $date_col;
281
282 return $columns;
283 }
284
285 /**
286 * @param $column
287 * @param $post_id
288 *
289 */
290 public function custom_lesson_column($column, $post_id ){
291 if ($column === 'lessons'){
292 echo tutor_utils()->get_lesson_count_by_course($post_id);
293 }
294
295 if ($column === 'students'){
296 echo tutor_utils()->count_enrolled_users_by_course($post_id);
297 }
298
299 if ($column === 'price'){
300 $price = tutor_utils()->get_course_price($post_id);
301
302 if ($price){
303 if (function_exists('wc_price')){
304 echo '<span class="tutor-label-success">'.wc_price($price).'</span>';
305 }else{
306 echo '<span class="tutor-label-success">'.$price.'</span>';
307 }
308 }else{
309 echo 'free';
310 }
311 }
312 }
313
314
315 public function tutor_delete_topic(){
316 if (!isset($_GET[tutor()->nonce]) || !wp_verify_nonce($_GET[tutor()->nonce], tutor()->nonce_action)) {
317 exit();
318 }
319 if ( ! isset($_GET['topic_id'])){
320 exit();
321 }
322
323 global $wpdb;
324
325 $topic_id = (int) sanitize_text_field($_GET['topic_id']);
326 $wpdb->update(
327 $wpdb->posts,
328 array('post_parent' => 0),
329 array('post_parent' => $topic_id)
330 );
331
332 $wpdb->delete(
333 $wpdb->postmeta,
334 array('post_id' => $topic_id)
335 );
336
337 wp_delete_post($topic_id);
338 wp_safe_redirect(wp_get_referer());
339 }
340
341 public function tutor_delete_announcement(){
342 tutor_utils()->checking_nonce('get');
343
344 $announcement_id = (int) sanitize_text_field($_GET['topic_id']);
345
346 wp_delete_post($announcement_id);
347 wp_safe_redirect(wp_get_referer());
348 }
349
350 public function enroll_now(){
351 //Checking if action comes from Enroll form
352 if ( ! isset($_POST['tutor_course_action']) || $_POST['tutor_course_action'] !== '_tutor_course_enroll_now' || ! isset($_POST['tutor_course_id']) ){
353 return;
354 }
355 //Checking Nonce
356 tutor_utils()->checking_nonce();
357
358 $user_id = get_current_user_id();
359 if ( ! $user_id){
360 exit(__('Please Sign In first', 'tutor'));
361 }
362
363 $course_id = (int) sanitize_text_field($_POST['tutor_course_id']);
364 $user_id = get_current_user_id();
365
366 /**
367 * TODO: need to check purchase information
368 */
369
370 $is_purchasable = tutor_utils()->is_course_purchasable($course_id);
371
372 /**
373 * If is is not purchasable, it's free, and enroll right now
374 *
375 * if purchasable, then process purchase.
376 *
377 * @since: v.1.0.0
378 */
379 if ($is_purchasable){
380 //process purchase
381
382 }else{
383 //Free enroll
384 tutor_utils()->do_enroll($course_id);
385 }
386
387 $referer_url = wp_get_referer();
388 wp_redirect($referer_url);
389 }
390
391 /**
392 *
393 * Mark complete completed
394 *
395 * @since v.1.0.0
396 */
397 public function mark_course_complete(){
398 if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_complete_course' ){
399 return;
400 }
401 //Checking nonce
402 tutor_utils()->checking_nonce();
403
404 $user_id = get_current_user_id();
405
406 //TODO: need to show view if not signed_in
407 if ( ! $user_id){
408 die(__('Please Sign-In', 'tutor'));
409 }
410
411 $course_id = (int) sanitize_text_field($_POST['course_id']);
412
413 do_action('tutor_course_complete_before', $course_id);
414 /**
415 * Marking course completed at Comment
416 */
417
418 global $wpdb;
419
420 $date = date("Y-m-d H:i:s");
421
422 //Making sure that, hash is unique
423 do{
424 $hash = substr(md5(wp_generate_password(32).$date.$course_id.$user_id), 0, 16);
425 $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}' ");
426 }while($hasHash > 0);
427
428 $data = array(
429 'comment_post_ID' => $course_id,
430 'comment_author' => $user_id,
431 'comment_date' => $date,
432 'comment_date_gmt' => get_gmt_from_date($date),
433 'comment_content' => $hash, //Identification Hash
434 'comment_approved' => 'approved',
435 'comment_agent' => 'TutorLMSPlugin',
436 'comment_type' => 'course_completed',
437 'user_id' => $user_id,
438 );
439
440 $wpdb->insert($wpdb->comments, $data);
441
442 do_action('tutor_course_complete_after', $course_id);
443
444 wp_redirect(get_the_permalink($course_id));
445 }
446
447
448 public function tutor_load_instructors_modal(){
449 global $wpdb;
450
451 $course_id = (int) sanitize_text_field($_POST['course_id']);
452 $search_terms = sanitize_text_field(tutor_utils()->avalue_dot('search_terms', $_POST));
453
454 $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
455
456 $instructors = array();
457
458
459 $not_in_sql = apply_filters('tutor_instructor_query_when_exists', " AND ID <1 ");
460
461 if ($saved_instructors){
462 $saved_instructors_ids = wp_list_pluck($saved_instructors, 'ID');
463 $instructor_not_in_ids = implode(',', $saved_instructors_ids);
464 $not_in_sql .= "AND ID NOT IN($instructor_not_in_ids) ";
465 }
466
467 $search_sql = '';
468 if ($search_terms){
469 $search_sql = "AND (user_login like '%{$search_terms}%' or user_nicename like '%{$search_terms}%' or display_name like '%{$search_terms}%') ";
470 }
471
472 $instructors = $wpdb->get_results("select ID, display_name from {$wpdb->users}
473 INNER JOIN {$wpdb->usermeta} ON ID = user_id AND meta_key = '_tutor_instructor_status' AND meta_value = 'approved'
474 WHERE 1=1 {$not_in_sql} {$search_sql} limit 10 ");
475
476 $output = '';
477 if (is_array($instructors) && count($instructors)){
478 $instructor_output = '';
479 foreach ($instructors as $instructor){
480 $instructor_output .= "<p><label><input type='radio' name='tutor_instructor_ids[]' value='{$instructor->ID}' > {$instructor->display_name} </label></p>";
481 }
482
483 $output .= apply_filters('tutor_course_instructors_html', $instructor_output, $instructors);
484 $output .= '<p class="quiz-search-suggest-text">'.__('Search to get the specific instructors', 'tutor').'</p>';
485
486 }else{
487 $output .= __('No instructor available or you have already added maximum instructors', 'tutor');
488 }
489
490
491 if ( ! defined('TUTOR_MT_VERSION')){
492 $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>';
493 }
494
495 wp_send_json_success(array('output' => $output));
496 }
497
498 public function tutor_add_instructors_to_course(){
499 $course_id = (int) sanitize_text_field($_POST['course_id']);
500 $instructor_ids = tutor_utils()->avalue_dot('tutor_instructor_ids', $_POST);
501
502 if (is_array($instructor_ids) && count($instructor_ids)){
503 foreach ($instructor_ids as $instructor_id){
504 add_user_meta($instructor_id, '_tutor_instructor_course_id', $course_id);
505 }
506 }
507
508 $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
509 $output = '';
510
511 if ($saved_instructors){
512 foreach ($saved_instructors as $t){
513
514 $output .= '<div id="added-instructor-id-'.$t->ID.'" class="added-instructor-item added-instructor-item-'.$t->ID.'" data-instructor-id="'.$t->ID.'">
515 <span class="instructor-icon">'.get_avatar($t->ID, 30).'</span>
516 <span class="instructor-name"> '.$t->display_name.' </span>
517 <span class="instructor-control">
518 <a href="javascript:;" class="tutor-instructor-delete-btn"><i class="tutor-icon-garbage"></i></a>
519 </span>
520 </div>';
521 }
522 }
523
524 wp_send_json_success(array('output' => $output));
525 }
526
527 public function detach_instructor_from_course(){
528 global $wpdb;
529
530 $instructor_id = (int) sanitize_text_field($_POST['instructor_id']);
531 $course_id = (int) sanitize_text_field($_POST['course_id']);
532
533 $wpdb->delete($wpdb->usermeta, array('user_id' => $instructor_id, 'meta_key' => '_tutor_instructor_course_id', 'meta_value' => $course_id) );
534 wp_send_json_success();
535 }
536
537 public function tutor_delete_dashboard_course(){
538 $course_id = intval(sanitize_text_field($_POST['course_id']));
539 wp_trash_post($course_id);
540 wp_send_json_success();
541 }
542
543
544 public function tutor_add_gutenberg_author($data , $postarr){
545 global $wpdb;
546
547 $post_author = (int) tutor_utils()->avalue_dot('post_author', $data);
548
549 if ( ! $post_author){
550 $user_ID = (int) tutor_utils()->avalue_dot('user_ID', $postarr);
551 if ($user_ID){
552 $data['post_author'] = $user_ID;
553 }else{
554 global $wpdb;
555
556 $post_ID = (int) tutor_utils()->avalue_dot('ID', $postarr);
557 $post_author = (int) $wpdb->get_var("SELECT post_author FROM {$wpdb->posts} WHERE ID = {$post_ID} ");
558
559 $data['post_author'] = $post_author;
560 }
561 }
562
563 return $data;
564 }
565
566 }