PluginProbe
Tutor LMS – eLearning and online course solution / 1.0.7
Tutor LMS – eLearning and online course solution v1.0.7
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 3.9.15 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 All 191 releases
tutor / classes / Course.php

Course.php in Tutor LMS – eLearning and online course solution 1.0.7, at classes/Course.php

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