PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 2.0.10
Tutor LMS – eLearning and online course solution v2.0.10
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 / Lesson.php
tutor / classes Last commit date
Addons.php 4 years ago Admin.php 4 years ago Ajax.php 3 years ago Announcements.php 4 years ago Assets.php 3 years ago Backend_Page_Trait.php 4 years ago Course.php 3 years ago Course_Embed.php 3 years ago Course_Filter.php 4 years ago Course_List.php 3 years ago Course_Settings_Tabs.php 4 years ago Course_Widget.php 4 years ago Custom_Validation.php 4 years ago Dashboard.php 3 years ago FormHandler.php 4 years ago Frontend.php 3 years ago Gutenberg.php 4 years ago Input.php 3 years ago Instructor.php 4 years ago Instructors_List.php 3 years ago Lesson.php 3 years ago Options_V2.php 3 years ago Post_types.php 4 years ago Private_Course_Access.php 4 years ago Q_and_A.php 3 years ago Question_Answers_List.php 4 years ago Quiz.php 3 years ago Quiz_Attempts_List.php 3 years ago RestAPI.php 4 years ago Reviews.php 4 years ago Rewrite_Rules.php 4 years ago Shortcode.php 4 years ago Student.php 4 years ago Students_List.php 4 years ago Taxonomies.php 4 years ago Template.php 3 years ago Theme_Compatibility.php 5 years ago Tools.php 3 years ago Tools_V2.php 4 years ago Tutor.php 3 years ago TutorEDD.php 4 years ago Tutor_Base.php 5 years ago Tutor_List_Table.php 4 years ago Tutor_Setup.php 3 years ago Upgrader.php 4 years ago User.php 4 years ago Utils.php 3 years ago Video_Stream.php 4 years ago Withdraw.php 3 years ago Withdraw_Requests_List.php 4 years ago WooCommerce.php 3 years ago
Lesson.php
515 lines
1 <?php
2 namespace TUTOR;
3
4 use SebastianBergmann\Environment\Console;
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit;
8 }
9
10 class Lesson extends Tutor_Base {
11 public function __construct() {
12 parent::__construct();
13
14 add_action( 'add_meta_boxes', array( $this, 'register_meta_box' ) );
15 add_action( 'save_post_' . $this->lesson_post_type, array( $this, 'save_lesson_meta' ) );
16
17 add_action( 'wp_ajax_tutor_load_edit_lesson_modal', array( $this, 'tutor_load_edit_lesson_modal' ) );
18 add_action( 'wp_ajax_tutor_modal_create_or_update_lesson', array( $this, 'tutor_modal_create_or_update_lesson' ) );
19 add_action( 'wp_ajax_tutor_delete_lesson_by_id', array( $this, 'tutor_delete_lesson_by_id' ) );
20
21 add_filter( 'get_sample_permalink', array( $this, 'change_lesson_permalink' ), 10, 2 );
22 add_action( 'admin_init', array( $this, 'flush_rewrite_rules' ) );
23
24 /**
25 * Add Column
26 */
27
28 add_filter( "manage_{$this->lesson_post_type}_posts_columns", array( $this, 'add_column' ), 10, 1 );
29 add_action( "manage_{$this->lesson_post_type}_posts_custom_column", array( $this, 'custom_lesson_column' ), 10, 2 );
30
31 // Frontend Action
32 add_action( 'template_redirect', array( $this, 'mark_lesson_complete' ) );
33
34 add_action( 'wp_ajax_tutor_render_lesson_content', array( $this, 'tutor_render_lesson_content' ) );
35 add_action( 'wp_ajax_nopriv_tutor_render_lesson_content', array( $this, 'tutor_render_lesson_content' ) ); // For public course access
36
37 /**
38 * Autoplay next video
39 *
40 * @since v.1.4.9
41 */
42 add_action( 'wp_ajax_autoload_next_course_content', array( $this, 'autoload_next_course_content' ) );
43
44 /**
45 * Load next course item after click complete button
46 *
47 * @since v.1.5.3
48 */
49 add_action( 'tutor_lesson_completed_after', array( $this, 'tutor_lesson_completed_after' ), 999 );
50
51 /**
52 * Lesson comment & reply ajax handler
53 *
54 * @since v2.0.0
55 */
56 add_action( 'wp_ajax_tutor_single_course_lesson_load_more', array( $this, 'tutor_single_course_lesson_load_more' ) );
57 add_action( 'wp_ajax_tutor_create_lesson_comment', array( $this, 'tutor_single_course_lesson_load_more' ) );
58 add_action( 'wp_ajax_tutor_reply_lesson_comment', array( $this, 'reply_lesson_comment' ) );
59 }
60
61 /**
62 * Manage load more & comment create
63 *
64 * @since v2.0.6
65 *
66 * @return void send wp json data
67 */
68 public function tutor_single_course_lesson_load_more() {
69 tutor_utils()->checking_nonce();
70 $action = $_POST['action'] ?? '';
71 if ( 'tutor_create_lesson_comment' === $action ) {
72 $comment_data = array(
73 'comment_content' => $_POST['comment'],
74 'comment_post_ID' => $_POST['comment_post_ID'],
75 'comment_parent' => $_POST['comment_parent'],
76 );
77 self::create_comment( $comment_data);
78 }
79 ob_start();
80 tutor_load_template('single.lesson.comment');
81 $html = ob_get_clean();
82
83 wp_send_json_success( array('html' => $html) );
84 }
85
86 /**
87 * Registering metabox
88 */
89 public function register_meta_box() {
90 $lesson_post_type = $this->lesson_post_type;
91
92 tutor_meta_box_wrapper( 'tutor-course-select', __( 'Select Course', 'tutor' ), array( $this, 'lesson_metabox' ), $lesson_post_type, 'advanced', 'default', 'tutor-admin-post-meta' );
93
94 tutor_meta_box_wrapper( 'tutor-lesson-videos', __( 'Lesson Video', 'tutor' ), array( $this, 'lesson_video_metabox' ), $lesson_post_type, 'advanced', 'default', 'tutor-admin-post-meta' );
95
96 tutor_meta_box_wrapper( 'tutor-lesson-attachments', __( 'Attachments', 'tutor' ), array( $this, 'lesson_attachments_metabox' ), $lesson_post_type, 'advanced', 'default', 'tutor-admin-post-meta' );
97 }
98
99 public function lesson_metabox() {
100 include tutor()->path . 'views/metabox/lesson-metabox.php';
101 }
102
103 public function lesson_video_metabox() {
104 include tutor()->path . 'views/metabox/video-metabox.php';
105 }
106
107 public function lesson_attachments_metabox() {
108 include tutor()->path . 'views/metabox/lesson-attachments-metabox.php';
109 }
110
111 /**
112 * @param $post_ID
113 *
114 * Saving lesson meta and assets
115 */
116 public function save_lesson_meta( $post_ID ) {
117 //Video
118 $video_source = sanitize_text_field( tutor_utils()->array_get('video.source', $_POST) );
119 if ( $video_source === '-1'){
120 delete_post_meta($post_ID, '_video');
121 }elseif($video_source) {
122 $video = (array)tutor_utils()->array_get('video', $_POST, array());
123 update_post_meta($post_ID, '_video', $video);
124 }
125
126 // Attachments
127 $attachments = array();
128 if ( ! empty($_POST['tutor_attachments'])){
129 $attachments = tutor_utils()->sanitize_array($_POST['tutor_attachments']);
130 $attachments = array_unique($attachments);
131 }
132
133 /**
134 * it !empty attachment then update meta else
135 * delete meta key to prevetn empty data in db
136 *
137 * @since 1.8.9
138 */
139 if ( ! empty( $attachments ) ) {
140 update_post_meta( $post_ID, '_tutor_attachments', $attachments );
141 } else {
142 delete_post_meta( $post_ID, '_tutor_attachments' );
143 }
144
145 }
146
147 public function tutor_load_edit_lesson_modal(){
148 tutor_utils()->checking_nonce();
149
150 $lesson_id = (int) tutor_utils()->avalue_dot( 'lesson_id', tutor_sanitize_data($_POST) );
151 $topic_id = (int) $_POST['topic_id'];
152
153 if(!tutor_utils()->can_user_manage('topic', $topic_id)) {
154 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
155 }
156
157 /**
158 * If Lesson Not Exists, provide dummy
159 */
160 $post_arr = array(
161 'ID' => 0,
162 'post_content' => '',
163 'post_type' => $this->lesson_post_type,
164 'post_title' => __( 'Draft Lesson', 'tutor' ),
165 'post_status' => 'publish',
166 'post_author' => get_current_user_id(),
167 'post_parent' => $topic_id,
168 );
169
170 $post = $lesson_id ? get_post($lesson_id) : (object)$post_arr;
171
172 ob_start();
173 include tutor()->path . 'views/modal/edit-lesson.php';
174 $output = ob_get_clean();
175
176 wp_send_json_success( array( 'output' => $output ) );
177 }
178
179 /**
180 * @since v.1.0.0
181 * @updated v.1.5.1
182 */
183 public function tutor_modal_create_or_update_lesson(){
184 tutor_utils()->checking_nonce();
185
186 global $wpdb;
187
188 $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
189 $topic_id = Input::post( 'current_topic_id', 0, Input::TYPE_INT );
190 $current_topic_id = $topic_id;
191 $course_id = tutor_utils()->get_course_id_by( 'topic', $topic_id );
192
193 $_lesson_thumbnail_id = Input::post( '_lesson_thumbnail_id', 0, Input::TYPE_INT );
194 $is_html_active = Input::post('is_html_active') === 'true' ? true : false;
195 $raw_html_content = wp_kses_post( $_POST['tutor_lesson_modal_editor'] );
196 $tmce_content = wp_kses_post( $_POST['lesson_content'] );
197
198 if( ! tutor_utils()->can_user_manage( 'topic', $topic_id ) ) {
199 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
200 }
201
202 $title = Input::post( 'lesson_title' );
203 $lesson_content = $is_html_active ? $raw_html_content : $tmce_content;
204
205 $lesson_data = array(
206 'post_type' => $this->lesson_post_type,
207 'post_title' => $title,
208 'post_name' => sanitize_title($title),
209 'post_content' => $lesson_content,
210 'post_status' => 'publish',
211 'comment_status' => 'open',
212 'post_author' => get_current_user_id(),
213 'post_parent' => $topic_id
214 );
215
216 if ( $lesson_id == 0 ) {
217
218 $lesson_data['menu_order'] = tutor_utils()->get_next_course_content_order_id( $topic_id );
219 $lesson_id = wp_insert_post( $lesson_data );
220
221 if ( $lesson_id ) {
222 do_action( 'tutor/lesson/created', $lesson_id );
223 } else {
224 wp_send_json_error( array( 'message' => __( 'Couldn\'t create lesson.', 'tutor' ) ) );
225 }
226 } else {
227 $lesson_data['ID'] = $lesson_id;
228
229 do_action( 'tutor/lesson_update/before', $lesson_id );
230 wp_update_post( $lesson_data );
231 if ( $_lesson_thumbnail_id ) {
232 update_post_meta( $lesson_id, '_thumbnail_id', $_lesson_thumbnail_id );
233 } else {
234 delete_post_meta( $lesson_id, '_thumbnail_id' );
235 }
236
237 do_action( 'tutor/lesson_update/after', $lesson_id );
238 }
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 * Delete Lesson from course builder
249 */
250 public function tutor_delete_lesson_by_id(){
251 tutor_utils()->checking_nonce();
252
253 $lesson_id = (int) tutor_utils()->avalue_dot( 'lesson_id', $_POST );
254
255 if(!tutor_utils()->can_user_manage('lesson', $lesson_id)) {
256 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
257 }
258
259 wp_delete_post( $lesson_id, true );
260 wp_send_json_success();
261 }
262
263
264 /**
265 * @param $uri
266 * @param $lesson_id
267 *
268 * @return mixed
269 *
270 * Changed the URI based
271 */
272
273 public function change_lesson_permalink( $uri, $lesson_id ) {
274 $post = get_post( $lesson_id );
275
276 if ( $post && $post->post_type === $this->lesson_post_type ) {
277 $uri_base = trailingslashit( site_url() );
278
279 $sample_course = 'sample-course';
280 $is_course = tutor_utils()->get_course_id_by( 'lesson', get_the_ID() );
281 if ( $is_course ) {
282 $course = get_post( $is_course );
283 if ( $course ) {
284 $sample_course = $course->post_name;
285 }
286 }
287
288 $new_course_base = $uri_base . "course/{$sample_course}/lesson/%pagename%/";
289 $uri[0] = $new_course_base;
290 }
291
292 return $uri;
293 }
294
295
296 public function flush_rewrite_rules() {
297 $is_required_flush = get_option( 'required_rewrite_flush' );
298 if ( $is_required_flush ) {
299 flush_rewrite_rules();
300 delete_option( 'required_rewrite_flush' );
301 }
302 }
303
304
305 public function add_column( $columns ) {
306 $date_col = $columns['date'];
307 unset( $columns['date'] );
308 $columns['course'] = __( 'Course', 'tutor' );
309 $columns['date'] = $date_col;
310
311 return $columns;
312 }
313
314 /**
315 * @param $column
316 * @param $post_id
317 */
318 public function custom_lesson_column( $column, $post_id ) {
319 if ( $column === 'course' ) {
320
321 $course_id = tutor_utils()->get_course_id_by( 'lesson', $post_id );
322 if ( $course_id ) {
323 echo '<a href="' . admin_url( 'post.php?post=' . $course_id . '&action=edit' ) . '">' . get_the_title( $course_id ) . '</a>';
324 }
325 }
326 }
327
328 /**
329 *
330 * Mark lesson completed
331 *
332 * @since v.1.0.0
333 */
334 public function mark_lesson_complete() {
335 if ( ! isset( $_POST['tutor_action'] ) || $_POST['tutor_action'] !== 'tutor_complete_lesson' ) {
336 return;
337 }
338 // Checking nonce
339 tutor_utils()->checking_nonce();
340
341 $user_id = get_current_user_id();
342
343 // TODO: need to show view if not signed_in
344 if ( ! $user_id ) {
345 die( __( 'Please Sign-In', 'tutor' ) );
346 }
347
348 $lesson_id = (int) $_POST['lesson_id'];
349
350 do_action( 'tutor_lesson_completed_before', $lesson_id );
351 /**
352 * Marking lesson at user meta, meta format, _tutor_completed_lesson_id_{id} and value = tutor_time();
353 */
354 tutor_utils()->mark_lesson_complete( $lesson_id );
355
356 do_action( 'tutor_lesson_completed_email_after', $lesson_id, $user_id );
357 do_action( 'tutor_lesson_completed_after', $lesson_id, $user_id );
358 }
359
360 /**
361 * Render the lesson content
362 */
363 public function tutor_render_lesson_content(){
364 tutor_utils()->checking_nonce();
365
366 $lesson_id = (int) tutor_utils()->avalue_dot( 'lesson_id', $_POST );
367
368 $ancestors = get_post_ancestors($lesson_id);
369 $course_id = !empty($ancestors) ? array_pop($ancestors): $lesson_id;
370
371 // Course must be public or current user must be enrolled to access this lesson
372 if(get_post_meta($course_id, '_tutor_is_public_course', true)!=='yes' && !tutor_utils()->is_enrolled($course_id)){
373
374 $is_admin = tutor_utils()->has_user_role('administrator');
375 $allowed = $is_admin ? true : tutor_utils()->is_instructor_of_this_course(get_current_user_id(), $course_id);
376
377 if ( ! $allowed ) {
378 http_response_code( 400 );
379 exit;
380 }
381 }
382
383 ob_start();
384 global $post;
385
386 $post = get_post( $lesson_id );
387 setup_postdata( $post );
388 tutor_lesson_content();
389 wp_reset_postdata();
390
391 $html = ob_get_clean();
392
393 wp_send_json_success(array('html' => $html));
394 }
395
396 /**
397 * Load next course item automatically
398 *
399 * @since v.1.4.9
400 */
401 public function autoload_next_course_content() {
402 tutor_utils()->checking_nonce();
403
404 $post_id = sanitize_text_field($_POST['post_id']);
405 $content_id = tutor_utils()->get_post_id($post_id);
406 $contents = tutor_utils()->get_course_prev_next_contents_by_id($content_id);
407
408 $autoload_course_content = (bool) get_tutor_option( 'autoload_next_course_content' );
409 $next_url = false;
410 if ( $autoload_course_content ) {
411 $next_url = get_the_permalink( $contents->next_id );
412 }
413 wp_send_json_success( array( 'next_url' => $next_url ) );
414 }
415
416 /**
417 * Load next course item after click complete button
418 *
419 * @since v.1.5.3
420 */
421 public function tutor_lesson_completed_after( $content_id ) {
422 $contents = tutor_utils()->get_course_prev_next_contents_by_id( $content_id );
423 $autoload_course_content = (bool) get_tutor_option( 'autoload_next_course_content' );
424 if ( $autoload_course_content ) {
425 wp_redirect( get_the_permalink( $contents->next_id ) );
426 } else {
427 wp_redirect( get_the_permalink( $content_id ) );
428 }
429 die();
430 }
431
432 public function reply_lesson_comment() {
433 tutor_utils()->checking_nonce();
434 $comment_data = array(
435 'comment_content' => $_POST['comment'],
436 'comment_post_ID' => $_POST['comment_post_ID'],
437 'comment_parent' => $_POST['comment_parent'],
438 );
439 $comment_id = self::create_comment( $comment_data);
440 if ( false === $comment_id ) {
441 wp_send_json_error();
442 return;
443 }
444 $reply = get_comment( $comment_id );
445 ob_start();
446 ?>
447 <div class="tutor-comments-list tutor-child-comment tutor-mt-32" id="lesson-comment-<?php echo esc_attr($reply->comment_ID) ?>">
448 <div class="comment-avatar">
449 <img src="<?php echo get_avatar_url($reply->user_id); ?>" alt="">
450 </div>
451 <div class="tutor-single-comment">
452 <div class="tutor-actual-comment tutor-mb-12">
453 <div class="tutor-comment-author">
454 <span class="tutor-fs-6 tutor-fw-bold">
455 <?php echo $reply->comment_author; ?>
456 </span>
457 <span class="tutor-fs-7 tutor-ml-0 tutor-ml-sm-10">
458 <?php echo human_time_diff(strtotime($reply->comment_date), tutor_time()) . __(' ago', 'tutor'); ?>
459 </span>
460 </div>
461 <div class="tutor-comment-text tutor-fs-6 tutor-mt-4">
462 <?php echo $reply->comment_content; ?>
463 </div>
464 </div>
465 </div>
466 </div>
467 <?php
468 $html = ob_get_clean();
469 wp_send_json_success( array('html' => $html) );
470 }
471
472 /**
473 * Get comments
474 *
475 * @since v2.0.6
476 *
477 * @param array $args
478 *
479 * ?Checkout arguments details:
480 * ?https://developer.wordpress.org/reference/classes/wp_comment_query/__construct/
481 *
482 * @return mixed based on arguments
483 */
484 public static function get_comments( array $args ) {
485 $comments = get_comments( $args );
486 return $comments;
487 }
488
489 /**
490 * Create comment
491 *
492 * @param array $post
493 *
494 * @return mixed comment id on success, false on failure
495 */
496 public static function create_comment( array $request ) {
497 $current_user = wp_get_current_user();
498 $default_data = array(
499 'comment_content' => '',
500 'comment_post_ID' => '',
501 'comment_parent' => '',
502 'user_id' => $current_user->ID,
503 'comment_author' => $current_user->user_login,
504 'comment_author_email' => $current_user->user_email,
505 'comment_author_url' => $current_user->user_url,
506 'comment_agent' => 'Tutor',
507 );
508 $comment_data = wp_parse_args( $request, $default_data );
509 return wp_insert_comment( $comment_data );
510 }
511
512 }
513
514
515