PluginProbe
Tutor LMS – eLearning and online course solution / 1.9.10
Tutor LMS – eLearning and online course solution v1.9.10
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
← All changes | classes/Lesson.php +232 -1084 4.0.31.9.10 View file →
@@ -1,655 +1,346 @@
1 1 <?php
2 -/**
3 - * Manage Lesson
4 - *
5 - * @package Tutor
6 - * @author Themeum <support@themeum.com>
7 - * @link https://themeum.com
8 - * @since 1.0.0
9 - */
10 -
11 2 namespace TUTOR;
12 3
13 -defined( 'ABSPATH' ) || exit;
4 +if ( ! defined( 'ABSPATH' ) )
5 + exit;
14 6
15 -use Tutor\Helpers\HttpHelper;
16 -use Tutor\Helpers\QueryHelper;
17 -use Tutor\Helpers\ValidationHelper;
18 -use Tutor\Models\EnrollmentModel;
19 -use Tutor\Models\LessonModel;
20 -use Tutor\Traits\JsonResponse;
21 -use WP_Post;
22 -
23 -/**
24 - * Lesson class
25 - *
26 - * @since 1.0.0
27 - */
28 7 class Lesson extends Tutor_Base {
29 - use JsonResponse;
30 -
31 - /**
32 - * Preview meta key
33 - *
34 - * @since 4.0.0
35 - * @var string
36 - */
37 - const PREVIEW_META_KEY = '_is_preview';
38 -
39 - /**
40 - * Lesson post type
41 - *
42 - * @since 4.0.0
43 - *
44 - * @var string
45 - */
46 - private $post_type;
47 -
48 - /**
49 - * Determine if legacy mode is enabled or not
50 - *
51 - * @since 4.0.0
52 - *
53 - * @var bool
54 - */
55 - private $is_legacy_learning_mode = false;
56 -
57 - /**
58 - * Register hooks
59 - *
60 - * @since 1.0.0
61 - * @since 3.7.0 param register hook added.
62 - *
63 - * @param bool $register_hooks register hooks or not.
64 - *
65 - * @return void
66 - */
67 - public function __construct( $register_hooks = true ) {
8 + public function __construct() {
68 9 parent::__construct();
69 10
70 - $this->post_type = tutor()->lesson_post_type;
11 + add_action( 'add_meta_boxes', array($this, 'register_meta_box') );
12 + add_action('save_post_'.$this->lesson_post_type, array($this, "save_lesson_meta"));
71 13
72 - $this->is_legacy_learning_mode = Options_V2::LEARNING_MODE_LEGACY === tutor_utils()->get_option( 'learning_mode' );
14 + add_action('wp_ajax_tutor_load_edit_lesson_modal', array($this, "tutor_load_edit_lesson_modal"));
15 + add_action('wp_ajax_tutor_modal_create_or_update_lesson', array($this, "tutor_modal_create_or_update_lesson"));
16 + add_action('wp_ajax_tutor_delete_lesson_by_id', array($this, "tutor_delete_lesson_by_id"));
73 17
74 - if ( ! $register_hooks ) {
75 - return;
76 - }
18 + add_filter('get_sample_permalink', array($this, 'change_lesson_permalink'), 10, 2);
19 + add_action('admin_init', array($this, 'flush_rewrite_rules'));
77 20
78 - add_action( 'save_post_' . $this->lesson_post_type, array( $this, 'save_lesson_meta' ) );
79 -
80 - add_action( 'wp_ajax_tutor_lesson_details', array( $this, 'ajax_lesson_details' ) );
81 - add_action( 'wp_ajax_tutor_save_lesson', array( $this, 'ajax_save_lesson' ) );
82 - add_action( 'wp_ajax_tutor_delete_lesson', array( $this, 'ajax_delete_lesson' ) );
83 -
84 - add_filter( 'get_sample_permalink', array( $this, 'change_lesson_permalink' ), 10, 2 );
85 -
86 21 /**
87 - * Frontend Action
22 + * Add Column
88 23 */
89 - add_action( 'template_redirect', array( $this, 'mark_lesson_complete' ) );
90 24
91 - add_action( 'wp_ajax_tutor_render_lesson_content', array( $this, 'tutor_render_lesson_content' ) );
25 + add_filter( "manage_{$this->lesson_post_type}_posts_columns", array($this, 'add_column'), 10,1 );
26 + add_action( "manage_{$this->lesson_post_type}_posts_custom_column" , array($this, 'custom_lesson_column'), 10, 2 );
92 27
93 - /**
94 - * For public course access
95 - */
96 - add_action( 'wp_ajax_nopriv_tutor_render_lesson_content', array( $this, 'tutor_render_lesson_content' ) );
28 + //Frontend Action
29 + add_action('template_redirect', array($this, 'mark_lesson_complete'));
97 30
31 + add_action('wp_ajax_tutor_render_lesson_content', array($this, "tutor_render_lesson_content"));
32 + add_action('wp_ajax_nopriv_tutor_render_lesson_content', array($this, "tutor_render_lesson_content")); // For public course access
33 +
98 34 /**
99 35 * Autoplay next video
100 - *
101 - * @since 1.4.9
36 + * @since v.1.4.9
102 37 */
103 - add_action( 'wp_ajax_autoload_next_course_content', array( $this, 'autoload_next_course_content' ) );
38 + add_action('wp_ajax_autoload_next_course_content', array($this, 'autoload_next_course_content'));
104 39
105 40 /**
106 41 * Load next course item after click complete button
107 - *
108 - * @since 1.5.3
42 + * @since v.1.5.3
109 43 */
110 - add_action( 'tutor_lesson_completed_after', array( $this, 'tutor_lesson_completed_after' ), 999 );
111 -
112 - /**
113 - * Lesson comment & reply ajax handler
114 - *
115 - * @since 2.0.0
116 - */
117 - add_action( 'wp_ajax_tutor_single_course_lesson_load_more', array( $this, 'ajax_single_course_lesson_load_more' ) );
118 - add_action( 'wp_ajax_tutor_create_lesson_comment', array( $this, 'ajax_single_course_lesson_load_more' ) );
119 - add_action( 'wp_ajax_tutor_delete_lesson_comment', array( $this, 'ajax_delete_lesson_comment' ) );
120 - add_action( 'wp_ajax_tutor_update_lesson_comment', array( $this, 'ajax_update_lesson_comment' ) );
121 - add_action( 'wp_ajax_tutor_reply_lesson_comment', array( $this, 'ajax_reply_lesson_comment' ) );
122 - add_action( 'wp_ajax_tutor_load_lesson_comments', array( $this, 'ajax_load_lesson_comments' ) );
123 - add_action( 'wp_ajax_tutor_load_comment_replies', array( $this, 'ajax_load_comment_replies' ) );
124 -
125 - // Add lesson title as nav item & render single content on the learning area.
126 - add_action( "tutor_learning_area_nav_item_{$this->post_type}", array( $this, 'render_nav_item' ), 10, 2 );
127 - add_action( "tutor_single_content_{$this->post_type}", array( $this, 'render_single_content' ) );
44 + add_action('tutor_lesson_completed_after', array($this, 'tutor_lesson_completed_after'), 999);
128 45 }
129 46
130 47 /**
131 - * Manage load more & comment create
132 - *
133 - * @since 2.0.6
134 - *
135 - * @since 4.0.0 different template returned
136 - *
137 - * @return void send wp json data
48 + * Registering metabox
138 49 */
139 - public function ajax_single_course_lesson_load_more() {
140 - tutor_utils()->checking_nonce();
50 + public function register_meta_box(){
51 + $lesson_post_type = $this->lesson_post_type;
141 52
142 - $comment_id = 0;
143 - $comment = Input::post( 'comment', '', Input::TYPE_TEXTAREA );
144 - $lesson_id = Input::post( 'comment_post_ID', 0, Input::TYPE_INT );
53 + add_meta_box( 'tutor-course-select', __( 'Select Course', 'tutor' ), array($this, 'lesson_metabox'), $lesson_post_type );
54 + add_meta_box( 'tutor-lesson-videos', __( 'Lesson Video', 'tutor' ), array($this, 'lesson_video_metabox'), $lesson_post_type );
55 + add_meta_box( 'tutor-lesson-attachments', __( 'Attachments', 'tutor' ), array($this, 'lesson_attachments_metabox'), $lesson_post_type );
56 + }
145 57
146 - if ( ! self::is_comment_enabled_for_lesson( $lesson_id ) ) {
147 - $this->response_bad_request( tutor_utils()->error_message( 'invalid_req' ) );
148 - }
58 + public function lesson_metabox(){
59 + include tutor()->path.'views/metabox/lesson-metabox.php';
60 + }
149 61
150 - if ( 'tutor_create_lesson_comment' === Input::post( 'action' ) && strlen( $comment ) > 0 ) {
151 - if ( ! self::can_post_lesson_comment( $lesson_id ) ) {
152 - wp_send_json_error( tutor_utils()->error_message() );
153 - return;
154 - }
155 -
156 - $comment_data = array(
157 - 'comment_content' => $comment,
158 - 'comment_post_ID' => $lesson_id,
159 - 'comment_parent' => Input::post( 'comment_parent', 0, Input::TYPE_INT ),
160 - );
161 - $comment_id = self::create_comment( $comment_data );
162 - do_action( 'tutor_new_comment_added', $comment_data );
163 - }
164 -
165 - if ( ! $this->is_legacy_learning_mode ) {
166 - $html = '';
167 - if ( $comment_id ) {
168 - ob_start();
169 - tutor_load_template(
170 - 'learning-area.lesson.comment-card',
171 - array(
172 - 'comment_item' => get_comment( $comment_id ),
173 - 'lesson_id' => $lesson_id,
174 - 'user_id' => get_current_user_id(),
175 - )
176 - );
177 - $html = ob_get_clean();
178 - }
179 -
180 - $count = self::get_comments(
181 - array(
182 - 'post_id' => $lesson_id,
183 - 'parent' => 0,
184 - 'count' => true,
185 - )
186 - );
187 -
188 - wp_send_json_success(
189 - array(
190 - 'html' => $html,
191 - 'count' => $count,
192 - )
193 - );
194 - }
195 -
196 - ob_start();
197 - tutor_load_template( 'single.lesson.comment' );
198 - $html = ob_get_clean();
199 - wp_send_json_success( array( 'html' => $html ) );
62 + public function lesson_video_metabox(){
63 + include tutor()->path.'views/metabox/video-metabox.php';
200 64 }
201 65
202 - /**
203 - * Delete lesson comment by AJAX
204 - *
205 - * @since 4.0.0
206 - *
207 - * @return void
208 - */
209 - public function ajax_delete_lesson_comment() {
210 - tutor_utils()->check_nonce();
211 - $comment_id = Input::post( 'comment_id', 0, Input::TYPE_INT );
212 - if ( ! $comment_id ) {
213 - $this->response_bad_request( __( 'Invalid comment ID', 'tutor' ) );
214 - }
215 -
216 - $comment = get_comment( $comment_id );
217 - if ( ! $comment ) {
218 - $this->response_bad_request( __( 'Invalid comment ID', 'tutor' ) );
219 - }
220 -
221 - $lesson_id = $comment->comment_post_ID;
222 - $parent_id = $comment->comment_parent;
223 - $is_reply = $parent_id > 0;
224 -
225 - if ( ! self::is_comment_enabled_for_lesson( $lesson_id ) ) {
226 - $this->response_bad_request( tutor_utils()->error_message( 'invalid_req' ) );
227 - }
228 -
229 - if ( get_current_user_id() === (int) $comment->user_id || tutor_utils()->can_user_manage( 'lesson', $lesson_id ) ) {
230 - wp_delete_comment( $comment_id, true );
231 -
232 - $total_comments = self::get_comments(
233 - array(
234 - 'post_id' => $lesson_id,
235 - 'parent' => 0,
236 - 'count' => true,
237 - )
238 - );
239 -
240 - wp_send_json_success(
241 - array(
242 - 'message' => __( 'Comment deleted successfully', 'tutor' ),
243 - 'count' => $total_comments,
244 - 'is_reply' => $is_reply,
245 - 'parent_id' => $parent_id,
246 - 'comment_id' => $comment_id,
247 - )
248 - );
249 - } else {
250 - $this->response_bad_request( __( 'You are not allowed to delete this comment', 'tutor' ) );
251 - }
66 + public function lesson_attachments_metabox(){
67 + include tutor()->path.'views/metabox/lesson-attachments-metabox.php';
252 68 }
253 69
254 70 /**
255 - * Update lesson comment by AJAX
71 + * @param $post_ID
256 72 *
257 - * @since 4.0.0
258 - *
259 - * @return void
260 - */
261 - public function ajax_update_lesson_comment() {
262 - tutor_utils()->check_nonce();
263 -
264 - $comment_id = Input::post( 'comment_id', 0, Input::TYPE_INT );
265 - if ( ! $comment_id ) {
266 - $this->response_bad_request( __( 'Invalid comment ID', 'tutor' ) );
267 - }
268 -
269 - $comment = get_comment( $comment_id );
270 - if ( ! $comment ) {
271 - $this->response_bad_request( __( 'Invalid comment ID', 'tutor' ) );
272 - }
273 -
274 - $comment_content = Input::post( 'comment', '', Input::TYPE_KSES_POST );
275 - $user_id = get_current_user_id();
276 - $lesson_id = $comment->comment_post_ID;
277 -
278 - if ( ! self::is_comment_enabled_for_lesson( $lesson_id ) ) {
279 - $this->response_bad_request( tutor_utils()->error_message( 'invalid_req' ) );
280 - }
281 -
282 - if ( $user_id === (int) $comment->user_id ) {
283 - wp_update_comment(
284 - array(
285 - 'comment_ID' => $comment_id,
286 - 'comment_content' => $comment_content,
287 - )
288 - );
289 -
290 - $comment->comment_content = $comment_content;
291 - $is_reply = $comment->comment_parent > 0;
292 -
293 - ob_start();
294 - tutor_load_template(
295 - 'learning-area.lesson.comment-card',
296 - array(
297 - 'comment_item' => $comment,
298 - 'lesson_id' => $lesson_id,
299 - 'user_id' => $user_id,
300 - 'is_reply' => $is_reply,
301 - )
302 - );
303 - $html = ob_get_clean();
304 -
305 - wp_send_json_success(
306 - array(
307 - 'html' => $html,
308 - 'is_reply' => $is_reply,
309 - 'parent_id' => $is_reply ? $comment->comment_parent : 0,
310 - 'comment_id' => $comment_id,
311 - )
312 - );
313 - } else {
314 - $this->response_bad_request( tutor_utils()->error_message() );
315 - }
316 - }
317 -
318 - /**
319 73 * Saving lesson meta and assets
320 74 *
321 - * @since 1.0.0
322 - *
323 - * @param integer $post_ID post ID.
324 - *
325 - * @return void
326 75 */
327 - public function save_lesson_meta( $post_ID ) {
328 - $thumbnail_id = Input::post( 'thumbnail_id', 0, Input::TYPE_INT );
329 - if ( $thumbnail_id ) {
330 - update_post_meta( $post_ID, '_thumbnail_id', $thumbnail_id );
331 - } else {
332 - delete_post_meta( $post_ID, '_thumbnail_id' );
76 + public function save_lesson_meta($post_ID){
77 + //Course
78 + if (isset($_POST['selected_course'])) {
79 + $course_id = (int) sanitize_text_field( $_POST['selected_course'] );
80 + if ( $course_id ) {
81 + update_post_meta( $post_ID, '_tutor_course_id_for_lesson', $course_id );
82 + }
333 83 }
334 84
335 - $video_source = sanitize_text_field( tutor_utils()->array_get( 'video.source', $_POST ) ); //phpcs:ignore
336 - if ( '-1' === $video_source ) {
337 - delete_post_meta( $post_ID, '_video' );
338 - } elseif ( $video_source ) {
339 -
340 - // Sanitize data through helper method.
341 - $video = Input::sanitize_array(
342 - $_POST['video'] ?? array(), //phpcs:ignore
343 - array(
344 - 'source_external_url' => 'esc_url',
345 - 'source_embedded' => 'wp_kses_post',
346 - ),
347 - true
348 - );
349 - update_post_meta( $post_ID, '_video', $video );
85 + //Video
86 + $video_source = sanitize_text_field( tutils()->array_get('video.source', $_POST) );
87 + if ( $video_source === '-1'){
88 + delete_post_meta($post_ID, '_video');
89 + }elseif($video_source) {
90 + $video = (array)tutor_utils()->array_get('video', $_POST, array());
91 + update_post_meta($post_ID, '_video', $video);
350 92 }
351 93
352 - // Attachments.
94 + //Attachments
353 95 $attachments = array();
354 - // phpcs:disable WordPress.Security.NonceVerification.Missing
355 - if ( ! empty( $_POST['tutor_attachments'] ) ) {
356 - //phpcs:ignore -- data sanitized through helper method.
357 - $attachments = tutor_utils()->sanitize_array( wp_unslash( $_POST['tutor_attachments'] ) );
358 - $attachments = array_unique( $attachments );
359 - }
96 + if ( ! empty($_POST['tutor_attachments'])){
97 + $attachments = tutor_utils()->sanitize_array($_POST['tutor_attachments']);
98 + $attachments = array_unique($attachments);
99 + }
360 100
361 101 /**
362 - * If !empty attachment then update meta else
363 - * delete meta key to prevent empty data in db
364 - *
102 + * it !empty attachment then update meta else
103 + * delete meta key to prevetn empty data in db
365 104 * @since 1.8.9
366 105 */
367 - if ( ! empty( $attachments ) ) {
368 - update_post_meta( $post_ID, '_tutor_attachments', $attachments );
106 + if( ! empty($attachments) ) {
107 + update_post_meta($post_ID, '_tutor_attachments', $attachments);
369 108 } else {
370 - delete_post_meta( $post_ID, '_tutor_attachments' );
109 + delete_post_meta($post_ID, '_tutor_attachments');
371 110 }
111 +
372 112 }
373 113
374 - /**
375 - * Get lesson details data.
376 - *
377 - * @since 3.0.0
378 - *
379 - * @return void
380 - */
381 - public function ajax_lesson_details() {
382 - if ( ! tutor_utils()->is_nonce_verified() ) {
383 - $this->response_bad_request( tutor_utils()->error_message( 'nonce' ) );
384 - }
114 + public function tutor_load_edit_lesson_modal(){
115 + tutils()->checking_nonce();
385 116
386 - $topic_id = Input::post( 'topic_id', 0, Input::TYPE_INT );
387 - $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
117 + $lesson_id = (int) tutor_utils()->avalue_dot('lesson_id', $_POST);
118 + $topic_id = (int) sanitize_text_field( $_POST['topic_id'] );
388 119
389 - if ( ! $topic_id || ! $lesson_id ) {
390 - $this->response_bad_request( tutor_utils()->error_message( 'invalid_req' ) );
120 + if(!tutils()->can_user_manage('topic', $topic_id)) {
121 + wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
391 122 }
392 123
393 - if ( ! tutor_utils()->can_user_manage( 'topic', $topic_id ) || ! tutor_utils()->can_user_manage( 'lesson', $lesson_id ) ) {
394 - $this->response_bad_request( tutor_utils()->error_message() );
395 - }
124 + /**
125 + * If Lesson Not Exists, provide dummy
126 + */
127 + $post_arr = array(
128 + 'ID' => 0,
129 + 'post_content' => '',
130 + 'post_type' => $this->lesson_post_type,
131 + 'post_title' => __('Draft Lesson', 'tutor'),
132 + 'post_status' => 'publish',
133 + 'post_author' => get_current_user_id(),
134 + 'post_parent' => $topic_id,
135 + );
396 136
397 - $data = LessonModel::get_lesson_details( $lesson_id );
137 + $post = $lesson_id ? get_post($lesson_id) : (object)$post_arr;
138 +
139 + ob_start();
140 + include tutor()->path.'views/modal/edit-lesson.php';
141 + $output = ob_get_clean();
398 142
399 - $this->json_response(
400 - __( 'Lesson data fetched successfully', 'tutor' ),
401 - $data
402 - );
143 + wp_send_json_success(array('output' => $output));
403 144 }
404 145
405 146 /**
406 - * Create or update lesson.
407 - *
408 - * @since 1.0.0
409 - * @since 1.5.1 updated
410 - * @since 3.0.0 refactor and response updated.
411 - *
412 - * @return void
147 + * @since v.1.0.0
148 + * @updated v.1.5.1
413 149 */
414 - public function ajax_save_lesson() {
415 - if ( ! tutor_utils()->is_nonce_verified() ) {
416 - $this->response_bad_request( tutor_utils()->error_message( 'nonce' ) );
417 - }
150 + public function tutor_modal_create_or_update_lesson(){
151 + tutils()->checking_nonce();
418 152
419 - /**
420 - * Allow iframe inside lesson content to support
421 - * embed video & other stuff
422 - *
423 - * @since 2.1.6
424 - */
425 - add_filter( 'wp_kses_allowed_html', Input::class . '::allow_iframe', 10, 2 );
426 -
427 - $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
428 - $topic_id = Input::post( 'topic_id', 0, Input::TYPE_INT );
429 -
430 - if ( ! $topic_id || ! tutor_utils()->can_user_manage( 'topic', $topic_id ) ) {
431 - $this->response_bad_request( tutor_utils()->error_message() );
153 + global $wpdb;
154 +
155 + $lesson_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('lesson_id', $_POST));
156 + $topic_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('current_topic_id', $_POST));
157 + $course_id = tutor_utils()->get_course_id_by('topic', $topic_id);
158 + $_lesson_thumbnail_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('_lesson_thumbnail_id', $_POST));
159 +
160 + if(!tutils()->can_user_manage('topic', $topic_id)) {
161 + wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
432 162 }
433 163
434 - $is_update = $lesson_id > 0;
435 164
436 - $title = Input::post( 'title' );
437 - $description = Input::post( 'description', '', Input::TYPE_KSES_POST );
438 - $is_html_active = Input::post( 'is_html_active' ) === 'true' ? true : false;
439 - $raw_html_content = Input::post( 'tutor_lesson_modal_editor', '', Input::TYPE_KSES_POST );
440 - $post_content = $is_html_active ? $raw_html_content : $description;
165 + $title = sanitize_text_field($_POST['lesson_title']);
166 + $lesson_content = wp_kses_post($_POST['lesson_content']);
441 167
442 - $rules = array(
443 - 'topic_id' => 'required|numeric',
444 - 'lesson_id' => 'if_input|numeric',
168 + $lesson_data = array(
169 + 'post_type' => $this->lesson_post_type,
170 + 'post_title' => $title,
171 + 'post_name' => sanitize_title($title),
172 + 'post_content' => $lesson_content,
173 + 'post_status' => 'publish',
174 + 'post_author' => get_current_user_id(),
175 + 'post_parent' => $topic_id
445 176 );
446 177
447 - //phpcs:ignore WordPress.Security.NonceVerification.Missing
448 - $params = Input::sanitize_array( $_POST, array( 'description' => 'wp_kses_post' ) );
178 + if($lesson_id==0) {
449 179
450 - $validation = ValidationHelper::validate( $rules, $params );
451 - if ( ! $validation->success ) {
452 - $this->json_response(
453 - __( 'Invalid inputs', 'tutor' ),
454 - $validation->errors,
455 - HttpHelper::STATUS_UNPROCESSABLE_ENTITY
456 - );
457 - }
458 -
459 - $lesson_data = array(
460 - 'post_type' => $this->lesson_post_type,
461 - 'post_title' => wp_slash( $title ), // Note: Added wp_slash to support latex syntaxes.
462 - 'post_name' => sanitize_title( $title ),
463 - 'post_content' => wp_slash( $post_content ),
464 - 'post_status' => 'publish',
465 - 'comment_status' => 'open',
466 - 'post_author' => get_current_user_id(),
467 - 'post_parent' => $topic_id,
468 - );
469 -
470 - if ( ! $is_update ) {
471 180 $lesson_data['menu_order'] = tutor_utils()->get_next_course_content_order_id( $topic_id );
472 - $lesson_id = wp_insert_post( $lesson_data );
181 + $lesson_id = wp_insert_post( $lesson_data );
473 182
474 - if ( $lesson_id ) {
475 - do_action( 'tutor/lesson/created', $lesson_id );
183 + if ($lesson_id ) {
184 + do_action('tutor/lesson/created', $lesson_id);
185 + update_post_meta( $lesson_id, '_tutor_course_id_for_lesson', $course_id );
476 186 } else {
477 - $this->json_response(
478 - tutor_utils()->error_message(),
479 - null,
480 - HttpHelper::STATUS_INTERNAL_SERVER_ERROR
481 - );
187 + wp_send_json_error( array('message' => __('Couldn\'t create lesson.', 'tutor')) );
482 188 }
483 189 } else {
484 - $lesson_data['ID'] = $lesson_id;
190 + $lesson_data['ID']=$lesson_id;
485 191
486 - if ( ! tutor_utils()->can_user_manage( 'lesson', $lesson_id ) ) {
487 - $this->json_response(
488 - tutor_utils()->error_message(),
489 - null,
490 - HttpHelper::STATUS_FORBIDDEN
491 - );
192 + do_action('tutor/lesson_update/before', $lesson_id);
193 + wp_update_post($lesson_data);
194 + if ($_lesson_thumbnail_id){
195 + update_post_meta($lesson_id, '_thumbnail_id', $_lesson_thumbnail_id);
196 + } else {
197 + delete_post_meta($lesson_id, '_thumbnail_id');
492 198 }
493 -
494 - do_action( 'tutor/lesson_update/before', $lesson_id );
495 - wp_update_post( $lesson_data );
496 - do_action( 'tutor/lesson_update/after', $lesson_id );
199 + do_action('tutor/lesson_update/after', $lesson_id);
497 200 }
201 +
202 + ob_start();
203 + include tutor()->path.'views/metabox/course-contents.php';
204 + $course_contents = ob_get_clean();
498 205
499 - if ( $is_update ) {
500 - $this->json_response(
501 - __( 'Lesson updated successfully', 'tutor' ),
502 - $lesson_id
503 - );
504 - } else {
505 - $this->json_response(
506 - __( 'Lesson created successfully', 'tutor' ),
507 - $lesson_id,
508 - HttpHelper::STATUS_CREATED
509 - );
510 - }
206 + wp_send_json_success(array('course_contents' => $course_contents));
511 207 }
512 208
513 209 /**
514 - * Delete Lesson from course builder by ID
515 - *
516 - * @since 1.0.0
517 - * @since 3.0.0 refactor and update response.
518 - *
519 - * @return void
210 + * Delete Lesson from course builder
520 211 */
521 - public function ajax_delete_lesson() {
522 - tutor_utils()->check_nonce();
212 + public function tutor_delete_lesson_by_id(){
213 + tutils()->checking_nonce();
523 214
524 - $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
525 - if ( ! $lesson_id ) {
526 - $this->response_bad_request( tutor_utils()->error_message( 'invalid_req' ) );
527 - }
215 + $lesson_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('lesson_id', $_POST));
528 216
529 - if ( ! tutor_utils()->can_user_manage( 'lesson', $lesson_id ) ) {
530 - $this->response_bad_request( tutor_utils()->error_message() );
217 + if(!tutils()->can_user_manage('lesson', $lesson_id)) {
218 + wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
531 219 }
532 220
533 - $content = __( 'Lesson', 'tutor' );
534 - $post_type = get_post_type( $lesson_id );
535 - if ( tutor()->assignment_post_type === $post_type ) {
536 - $content = __( 'Assignment', 'tutor' );
537 - }
538 -
539 - do_action( 'tutor_before_delete_course_content', 0, $lesson_id );
540 -
541 - wp_delete_post( $lesson_id, true );
542 - /* translators: %s refers to the name of the content being deleted */
543 - $this->json_response( sprintf( __( '%s deleted successfully', 'tutor' ), $content ) );
221 + wp_delete_post($lesson_id, true);
222 + delete_post_meta($lesson_id, '_tutor_course_id_for_lesson');
223 + wp_send_json_success();
544 224 }
545 225
546 226
547 227 /**
548 - * Changed the URI based
228 + * @param $uri
229 + * @param $lesson_id
549 230 *
550 - * @since 1.0.0
231 + * @return mixed
551 232 *
552 - * @param string $uri URI.
553 - * @param integer $lesson_id lesson ID.
554 - *
555 - * @return string
233 + * Changed the URI based
556 234 */
557 - public function change_lesson_permalink( $uri, $lesson_id ) {
558 - $post = get_post( $lesson_id );
559 235
560 - if ( $post && $post->post_type === $this->lesson_post_type ) {
561 - $uri_base = trailingslashit( site_url() );
236 + public function change_lesson_permalink($uri, $lesson_id){
237 + $post = get_post($lesson_id);
562 238
563 - $sample_course = 'sample-course';
564 - $is_course = tutor_utils()->get_course_id_by( 'lesson', get_the_ID() );
565 - if ( $is_course ) {
566 - $course = get_post( $is_course );
567 - if ( $course ) {
239 + if ($post && $post->post_type === $this->lesson_post_type){
240 + $uri_base = trailingslashit(site_url());
241 +
242 + $sample_course = "sample-course";
243 + $is_course = tutor_utils()->get_course_id_by('lesson', get_the_ID());
244 + if ($is_course){
245 + $course = get_post($is_course);
246 + if ($course){
568 247 $sample_course = $course->post_name;
569 248 }
570 249 }
571 250
572 - $new_course_base = $uri_base . "course/{$sample_course}/lesson/%pagename%/";
573 - $uri[0] = $new_course_base;
251 + $new_course_base = $uri_base."course/{$sample_course}/lesson/%pagename%/";
252 + $uri[0] = $new_course_base;
574 253 }
575 254
576 255 return $uri;
577 256 }
578 257
258 +
259 + public function flush_rewrite_rules(){
260 + $is_required_flush = get_option('required_rewrite_flush');
261 + if ($is_required_flush){
262 + flush_rewrite_rules();
263 + delete_option( 'required_rewrite_flush' );
264 + }
265 + }
266 +
267 +
268 + public function add_column($columns){
269 + $date_col = $columns['date'];
270 + unset($columns['date']);
271 + $columns['course'] = __('Course', 'tutor');
272 + $columns['date'] = $date_col;
273 +
274 + return $columns;
275 + }
276 +
579 277 /**
580 - * Mark lesson completed
278 + * @param $column
279 + * @param $post_id
581 280 *
582 - * @since 1.0.0
583 - *
584 - * @return void
585 281 */
586 - public function mark_lesson_complete() {
587 - if ( 'tutor_complete_lesson' !== Input::post( 'tutor_action' ) ) {
588 - return;
589 - }
282 + public function custom_lesson_column($column, $post_id ){
283 + if ($column === 'course'){
590 284
591 - tutor_utils()->checking_nonce();
285 + $course_id = tutor_utils()->get_course_id_by('lesson', $post_id);
286 + if ($course_id){
287 + echo '<a href="'.admin_url('post.php?post='.$course_id.'&action=edit').'">'.get_the_title($course_id).'</a>';
288 + }
592 289
593 - $user_id = get_current_user_id();
594 -
595 - if ( ! $user_id ) {
596 - die( esc_html__( 'Please Sign-In', 'tutor' ) );
597 290 }
291 + }
598 292
599 - $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
600 - if ( ! $lesson_id ) {
293 + /**
294 + *
295 + * Mark lesson completed
296 + *
297 + * @since v.1.0.0
298 + */
299 + public function mark_lesson_complete(){
300 + if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_complete_lesson' ){
601 301 return;
602 302 }
303 + //Checking nonce
304 + tutor_utils()->checking_nonce();
603 305
604 - $course_id = tutor_utils()->get_course_id_by( 'lesson', $lesson_id );
605 - if ( ! $course_id ) {
606 - return;
607 - }
306 + $user_id = get_current_user_id();
608 307
609 - if ( ! tutor_utils()->is_enrolled( $course_id ) ) {
610 - die( esc_html( tutor_utils()->error_message() ) );
308 + //TODO: need to show view if not signed_in
309 + if ( ! $user_id){
310 + die(__('Please Sign-In', 'tutor'));
611 311 }
612 312
613 - $validated = apply_filters( 'tutor_validate_lesson_complete', true, $user_id, $lesson_id );
614 - if ( ! $validated ) {
615 - return;
616 - }
313 + $lesson_id = (int) sanitize_text_field($_POST['lesson_id']);
617 314
618 - do_action( 'tutor_lesson_completed_before', $lesson_id );
315 + do_action('tutor_lesson_completed_before', $lesson_id);
619 316 /**
620 317 * Marking lesson at user meta, meta format, _tutor_completed_lesson_id_{id} and value = tutor_time();
621 318 */
622 - LessonModel::mark_lesson_complete( $lesson_id );
319 + tutor_utils()->mark_lesson_complete($lesson_id);
623 320
624 - do_action( 'tutor_lesson_completed_email_after', $lesson_id, $user_id );
625 - do_action( 'tutor_lesson_completed_after', $lesson_id, $user_id );
321 + do_action('tutor_lesson_completed_after', $lesson_id, $user_id);
626 322 }
627 323
628 324 /**
629 325 * Render the lesson content
630 - *
631 - * @since 1.0.0
632 - *
633 - * @return void
634 326 */
635 - public function tutor_render_lesson_content() {
636 - tutor_utils()->checking_nonce();
327 + public function tutor_render_lesson_content(){
328 + tutils()->checking_nonce();
637 329
638 - $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
639 - if ( ! $lesson_id ) {
640 - $this->response_bad_request( tutor_utils()->error_message( 'invalid_req' ) );
641 - }
330 + $lesson_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('lesson_id', $_POST));
642 331
643 - $course_id = tutor_utils()->get_course_id_by( 'lesson', $lesson_id );
332 + $ancestors = get_post_ancestors($lesson_id);
333 + $course_id = !empty($ancestors) ? array_pop($ancestors): $lesson_id;
644 334
645 - // Course must be public or current user must be enrolled to access this lesson.
646 - if ( ! Course_List::is_public( $course_id ) && ! EnrollmentModel::is_enrolled( $course_id ) ) {
335 + // Course must be public or current user must be enrolled to access this lesson
336 + if(get_post_meta($course_id, '_tutor_is_public_course', true)!=='yes' && !tutils()->is_enrolled($course_id)){
337 +
338 + $is_admin = tutor_utils()->has_user_role('administrator');
339 + $allowed = $is_admin ? true : tutor_utils()->is_instructor_of_this_course(get_current_user_id(), $course_id);
647 340
648 - $allowed = User::is_admin() ? true : tutor_utils()->is_instructor_of_this_course( get_current_user_id(), $course_id );
649 -
650 - if ( ! $allowed ) {
651 - $this->response_bad_request( tutor_utils()->error_message() );
341 + if( !$allowed ) {
342 + http_response_code(400);
652 343 exit;
653 344 }
654 345 }
655 346
@@ -655,595 +346,52 @@
655 346
656 347 ob_start();
657 348 global $post;
658 349
659 - $post = get_post( $lesson_id ); //phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
660 - setup_postdata( $post );
350 + $post = get_post($lesson_id);
351 + setup_postdata($post);
661 352 tutor_lesson_content();
662 353 wp_reset_postdata();
663 354
664 355 $html = ob_get_clean();
665 -
666 - wp_send_json_success( array( 'html' => $html ) );
356 + wp_send_json_success(array('html' => $html));
667 357 }
668 358
669 359 /**
670 360 * Load next course item automatically
671 361 *
672 - * @since 1.4.9
673 - *
674 - * @return void
362 + * @since v.1.4.9
675 363 */
676 - public function autoload_next_course_content() {
364 + public function autoload_next_course_content(){
677 365 tutor_utils()->checking_nonce();
678 366
679 - $post_id = Input::post( 'post_id', 0, Input::TYPE_INT );
680 - $course_id = tutor_utils()->get_course_id_by_content( $post_id );
681 - if ( ! $course_id || ! EnrollmentModel::is_enrolled( $course_id ) ) {
682 - wp_send_json_error( tutor_utils()->error_message() );
683 - }
367 + $post_id = sanitize_text_field($_POST['post_id']);
368 + $content_id = tutils()->get_post_id($post_id);
369 + $contents = tutor_utils()->get_course_prev_next_contents_by_id($content_id);
684 370
685 - $content_id = tutor_utils()->get_post_id( $post_id );
686 - $contents = tutor_utils()->get_course_prev_next_contents_by_id( $content_id );
687 -
688 - $autoload_course_content = (bool) UserPreference::get( 'auto_play_next', false, get_current_user_id() );
689 - $next_url = false;
690 - if ( $autoload_course_content && $contents->next_id ) {
691 - $next_url = get_the_permalink( $contents->next_id );
371 + $autoload_course_content = (bool) get_tutor_option('autoload_next_course_content');
372 + $next_url = false;
373 + if($autoload_course_content) {
374 + $next_url = get_the_permalink($contents->next_id);
692 375 }
693 -
694 - wp_send_json_success( array( 'next_url' => $next_url ) );
376 + wp_send_json_success(array('next_url' => $next_url));
695 377 }
696 378
697 379 /**
698 380 * Load next course item after click complete button
699 381 *
700 - * @since 1.5.3
701 - *
702 - * @param integer $content_id content ID.
703 - * @return void
382 + * @since v.1.5.3
704 383 */
705 - public function tutor_lesson_completed_after( $content_id ) {
706 - $contents = tutor_utils()->get_course_prev_next_contents_by_id( $content_id );
707 - $autoload_course_content = (bool) get_tutor_option( 'autoload_next_course_content' );
708 - if ( $autoload_course_content ) {
709 - wp_safe_redirect( get_the_permalink( $contents->next_id ) );
384 + public function tutor_lesson_completed_after($content_id){
385 + $contents = tutor_utils()->get_course_prev_next_contents_by_id($content_id);
386 + $autoload_course_content = (bool) get_tutor_option('autoload_next_course_content');
387 + if($autoload_course_content) {
388 + wp_redirect(get_the_permalink($contents->next_id));
710 389 } else {
711 - wp_safe_redirect( get_the_permalink( $content_id ) );
390 + wp_redirect(get_the_permalink($content_id));
712 391 }
713 392 die();
714 393 }
715 394
716 - /**
717 - * Check user can post lesson comment.
718 - *
719 - * @since 4.0.0
720 - *
721 - * @param int $lesson_id lesson id.
722 - * @param int $user_id user id. default 0 means current user id.
723 - *
724 - * @return bool true if user can post lesson comment, false otherwise.
725 - */
726 - private static function can_post_lesson_comment( $lesson_id, $user_id = 0 ) {
727 - $course_id = tutor_utils()->get_course_id_by( 'lesson', $lesson_id );
728 - if ( ! $course_id ) {
729 - return false;
730 - }
395 +}
731 396
732 - $can_post = EnrollmentModel::is_enrolled( $course_id, $user_id ) || tutor_utils()->can_user_manage( 'course', $course_id, $user_id );
733 - return $can_post;
734 - }
735 397
736 - /**
737 - * Replay lesson comment
738 - *
739 - * @since 1.0.0
740 - *
741 - * @return void|null
742 - */
743 - public function ajax_reply_lesson_comment() {
744 - tutor_utils()->checking_nonce();
745 -
746 - $lesson_id = Input::post( 'comment_post_ID', 0, Input::TYPE_INT );
747 - $comment_parent = Input::post( 'comment_parent', 0, Input::TYPE_INT );
748 - $comment = Input::post( 'comment', '', Input::TYPE_TEXTAREA );
749 -
750 - if ( ! $lesson_id || ! $comment_parent || 0 === strlen( $comment ) ) {
751 - wp_send_json_error( tutor_utils()->error_message( 'invalid_req' ) );
752 - return;
753 - }
754 -
755 - if ( ! self::can_post_lesson_comment( $lesson_id ) ) {
756 - wp_send_json_error( tutor_utils()->error_message() );
757 - return;
758 - }
759 -
760 - $parent_comment = get_comment( $comment_parent );
761 - if ( ! $parent_comment || (int) $parent_comment->comment_post_ID !== $lesson_id ) {
762 - wp_send_json_error( tutor_utils()->error_message( 'invalid_req' ) );
763 - return;
764 - }
765 -
766 - $comment_data = array(
767 - 'comment_content' => $comment,
768 - 'comment_post_ID' => $lesson_id,
769 - 'comment_parent' => $comment_parent,
770 - );
771 -
772 - if ( ! self::is_comment_enabled_for_lesson( $comment_data['comment_post_ID'] ) ) {
773 - $this->response_bad_request( tutor_utils()->error_message( 'invalid_req' ) );
774 - }
775 -
776 - $comment_id = self::create_comment( $comment_data );
777 - if ( false === $comment_id ) {
778 - wp_send_json_error();
779 - return;
780 - }
781 -
782 - $reply = get_comment( $comment_id );
783 - do_action( 'tutor_reply_lesson_comment_thread', $comment_id, $comment_data );
784 -
785 - if ( ! $this->is_legacy_learning_mode ) {
786 - $lesson_id = $comment_data['comment_post_ID'];
787 - $parent_id = $comment_data['comment_parent'];
788 - $comment_item = get_comment( $parent_id );
789 - $user_id = get_current_user_id();
790 -
791 - $replies = self::get_comments(
792 - array(
793 - 'post_id' => $lesson_id,
794 - 'parent' => $parent_id,
795 - 'order' => 'ASC',
796 - )
797 - );
798 -
799 - $is_first_reply = ( is_array( $replies ) ? count( $replies ) : 0 ) === 1;
800 -
801 - ob_start();
802 - if ( $is_first_reply ) {
803 - // For the first reply, we need the wrapper and the toggle button.
804 - tutor_load_template(
805 - 'learning-area.lesson.comment-replies',
806 - array(
807 - 'lesson_id' => $lesson_id,
808 - 'comment_item' => $comment_item,
809 - 'user_id' => $user_id,
810 - 'replies' => $replies,
811 - )
812 - );
813 - } else {
814 - // Just the card for subsequent replies.
815 - tutor_load_template(
816 - 'learning-area.lesson.comment-card',
817 - array(
818 - 'comment_item' => get_comment( $comment_id ),
819 - 'lesson_id' => $lesson_id,
820 - 'user_id' => $user_id,
821 - 'is_reply' => true,
822 - )
823 - );
824 - }
825 - $html = ob_get_clean();
826 -
827 - $total_comments = self::get_comments(
828 - array(
829 - 'post_id' => $lesson_id,
830 - 'parent' => 0,
831 - 'count' => true,
832 - )
833 - );
834 -
835 - wp_send_json_success(
836 - array(
837 - 'html' => $html,
838 - 'count' => $total_comments,
839 - 'is_first_reply' => $is_first_reply,
840 - )
841 - );
842 - }
843 -
844 - ob_start();
845 - ?>
846 - <div class="tutor-comments-list tutor-child-comment tutor-mt-32" id="lesson-comment-<?php echo esc_attr( $reply->comment_ID ); ?>">
847 - <div class="comment-avatar">
848 - <img src="<?php echo esc_url( get_avatar_url( $reply->user_id ) ); ?>" alt="">
849 - </div>
850 - <div class="tutor-single-comment">
851 - <div class="tutor-actual-comment tutor-mb-12">
852 - <div class="tutor-comment-author">
853 - <span class="tutor-fs-6 tutor-fw-bold">
854 - <?php echo esc_html( $reply->comment_author ); ?>
855 - </span>
856 - <span class="tutor-fs-7 tutor-ml-0 tutor-ml-sm-10">
857 - <?php echo esc_html( human_time_diff( strtotime( $reply->comment_date ), tutor_time() ) . __( ' ago', 'tutor' ) ); ?>
858 - </span>
859 - </div>
860 - <div class="tutor-comment-text tutor-fs-6 tutor-mt-4">
861 - <?php echo esc_html( $reply->comment_content ); ?>
862 - </div>
863 - </div>
864 - </div>
865 - </div>
866 - <?php
867 - $html = ob_get_clean();
868 - wp_send_json_success( array( 'html' => $html ) );
869 - }
870 -
871 - /**
872 - * Get comments
873 - *
874 - * @since 2.0.6
875 - * @see Checkout arguments details: https://developer.wordpress.org/reference/classes/wp_comment_query/__construct/
876 - *
877 - * @param array $args arguments.
878 - * @return mixed based on arguments
879 - */
880 - public static function get_comments( array $args ) {
881 - $args['type'] = 'comment';
882 - $comments = get_comments( $args );
883 - return $comments;
884 - }
885 -
886 - /**
887 - * Get comment replies
888 - *
889 - * @since 4.0.0
890 - *
891 - * @param int $comment_id comment id.
892 - * @param string $order order.
893 - *
894 - * @return mixed comment replies on success, false on failure
895 - */
896 - public static function get_comment_replies( int $comment_id, string $order = 'DESC' ) {
897 - return get_comments(
898 - array(
899 - 'parent' => $comment_id,
900 - 'order' => QueryHelper::get_valid_sort_order( $order ),
901 - )
902 - );
903 - }
904 -
905 - /**
906 - * Create comment
907 - *
908 - * @since 1.0.0
909 - *
910 - * @param array $request request.
911 - * @return mixed comment id on success, false on failure
912 - */
913 - public static function create_comment( array $request ) {
914 - $current_user = wp_get_current_user();
915 - $default_data = array(
916 - 'comment_content' => '',
917 - 'comment_post_ID' => '',
918 - 'comment_parent' => '',
919 - 'user_id' => $current_user->ID,
920 - 'comment_author' => $current_user->user_login,
921 - 'comment_author_email' => $current_user->user_email,
922 - 'comment_author_url' => $current_user->user_url,
923 - 'comment_agent' => 'Tutor',
924 - );
925 - $comment_data = wp_parse_args( $request, $default_data );
926 - return wp_insert_comment( $comment_data );
927 - }
928 -
929 - /**
930 - * Check if lesson has content
931 - *
932 - * @since 3.9.0
933 - *
934 - * @param int $lesson_id Lesson ID.
935 - *
936 - * @return bool True if lesson has content, false otherwise.
937 - */
938 - public static function has_lesson_content( $lesson_id ) {
939 - /**
940 - * If lesson has no content, lesson tab will be hidden.
941 - * To enable elementor and SCORM, only admin can see lesson tab.
942 - *
943 - * @since 2.2.2
944 - */
945 - return apply_filters(
946 - 'tutor_has_lesson_content',
947 - User::is_admin() || ! in_array( trim( get_the_content() ), array( null, '', '&nbsp;' ), true ),
948 - $lesson_id
949 - );
950 - }
951 -
952 - /**
953 - * Check if lesson has attachments
954 - *
955 - * @since 3.9.0
956 - *
957 - * @param int $lesson_id Lesson ID.
958 - *
959 - * @return bool True if lesson has attachments, false otherwise.
960 - */
961 - public static function has_lesson_attachment( $lesson_id ) {
962 - return count( tutor_utils()->get_attachments( $lesson_id ) ) > 0;
963 - }
964 -
965 - /**
966 - * Check if comments are enabled for lessons
967 - *
968 - * @since 3.9.0
969 - *
970 - * @return bool True if comments are enabled, false otherwise.
971 - */
972 - public static function is_comment_enabled() {
973 - return tutor_utils()->get_option( 'enable_comment_for_lesson' );
974 - }
975 -
976 - /**
977 - * Check if comments are enabled for lessons
978 - *
979 - * @since 4.0.0
980 - *
981 - * @param int|object $lesson Lesson ID or object. If null, current lesson will be used.
982 - *
983 - * @return bool True if comments are enabled, false otherwise.
984 - */
985 - public static function is_comment_enabled_for_lesson( $lesson = null ) {
986 - return self::is_comment_enabled() && comments_open( $lesson );
987 - }
988 -
989 - /**
990 - * Check if lesson has comments
991 - *
992 - * @since 3.9.0
993 - *
994 - * @param int $lesson_id Lesson ID.
995 - *
996 - * @return int Number of comments for the lesson.
997 - */
998 - public static function has_lesson_comment( $lesson_id ) {
999 - return (int) get_comments_number( $lesson_id );
1000 - }
1001 -
1002 - /**
1003 - * Get navigation items for lesson single page
1004 - *
1005 - * @since 3.9.0
1006 - *
1007 - * @param int $lesson_id Lesson ID.
1008 - *
1009 - * @return array navigation items array
1010 - */
1011 - public static function get_nav_items( $lesson_id ) {
1012 - $is_legacy = ( new self( false ) )->is_legacy_learning_mode;
1013 - $nav_items = array();
1014 -
1015 - $attachments = tutor_utils()->get_attachments( $lesson_id );
1016 -
1017 - $definitions = array(
1018 - 'overview' => array(
1019 - 'condition' => self::has_lesson_content( $lesson_id ),
1020 - 'legacy' => array(
1021 - 'label' => __( 'Overview', 'tutor' ),
1022 - 'value' => 'overview',
1023 - 'icon' => 'document-text',
1024 - 'template' => 'single.lesson.parts.overview',
1025 - ),
1026 - 'default' => array(
1027 - 'id' => 'overview',
1028 - 'label' => __( 'Overview', 'tutor' ),
1029 - 'icon' => Icon::COURSES,
1030 - 'template' => 'learning-area.lesson.overview',
1031 - ),
1032 - ),
1033 - 'files' => array(
1034 - 'condition' => tutor_utils()->count( $attachments ),
1035 - 'legacy' => array(
1036 - 'label' => __( 'Exercise Files', 'tutor' ),
1037 - 'value' => 'files',
1038 - 'icon' => 'paperclip',
1039 - 'template' => 'single.lesson.parts.files',
1040 - ),
1041 - 'default' => array(
1042 - 'id' => 'exercise_files',
1043 - 'label' => __( 'Exercise Files', 'tutor' ),
1044 - 'icon' => Icon::FILE_ATTACHEMENT,
1045 - 'template' => 'learning-area.lesson.exercise-files',
1046 - ),
1047 - ),
1048 - 'comments' => array(
1049 - 'condition' => self::is_comment_enabled_for_lesson( $lesson_id ) && is_user_logged_in(),
1050 - 'legacy' => array(
1051 - 'label' => __( 'Comments', 'tutor' ),
1052 - 'value' => 'comments',
1053 - 'icon' => 'comment',
1054 - 'template' => 'single.lesson.parts.comments',
1055 - ),
1056 - 'default' => array(
1057 - 'id' => 'comments',
1058 - 'label' => __( 'Comments', 'tutor' ),
1059 - 'icon' => Icon::COMMENTS,
1060 - 'template' => 'learning-area.lesson.comments',
1061 - ),
1062 - ),
1063 - );
1064 -
1065 - foreach ( $definitions as $key => $def ) {
1066 - if ( empty( $def['condition'] ) ) {
1067 - continue;
1068 - }
1069 - $item = $is_legacy ? $def['legacy'] : $def['default'];
1070 - if ( null !== $item ) {
1071 - $nav_items[ $key ] = $item;
1072 - }
1073 - }
1074 -
1075 - $nav_items = apply_filters( 'tutor_lesson_single_nav_items', $nav_items );
1076 - $nav_items = array_values( $nav_items );
1077 -
1078 - return $nav_items;
1079 - }
1080 -
1081 - /**
1082 - * Return lesson title as nav item to print on the learning area
1083 - *
1084 - * @since 4.0.0
1085 - *
1086 - * @param WP_Post $lesson Lesson post object.
1087 - * @param bool $can_access Can user access this content.
1088 - *
1089 - * @return void
1090 - */
1091 - public function render_nav_item( $lesson, $can_access ): void {
1092 - tutor_load_template(
1093 - 'learning-area.lesson.nav-item',
1094 - array(
1095 - 'lesson' => $lesson,
1096 - 'can_access' => $can_access,
1097 - )
1098 - );
1099 - }
1100 -
1101 - /**
1102 - * Render content for the a single lesson
1103 - *
1104 - * @since 4.0.0
1105 - *
1106 - * @param WP_Post $lesson Lesson post object.
1107 - *
1108 - * @return void
1109 - */
1110 - public function render_single_content( $lesson ): void {
1111 - tutor_load_template(
1112 - 'learning-area.lesson.content',
1113 - array(
1114 - 'lesson' => $lesson,
1115 - )
1116 - );
1117 - }
1118 -
1119 - /**
1120 - * Load lesson comments
1121 - *
1122 - * @since 4.0.0
1123 - *
1124 - * @return void
1125 - */
1126 - public function ajax_load_lesson_comments() {
1127 - tutor_utils()->check_nonce();
1128 -
1129 - $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
1130 - $current_page = Input::post( 'current_page', 1, Input::TYPE_INT );
1131 - $offset = Input::post( 'offset', -1, Input::TYPE_INT );
1132 - $order = QueryHelper::get_valid_sort_order( Input::post( 'order', 'DESC' ) );
1133 -
1134 - if ( ! self::is_comment_enabled_for_lesson( $lesson_id ) ) {
1135 - $this->response_bad_request( tutor_utils()->error_message( 'invalid_req' ) );
1136 - }
1137 -
1138 - $user_id = get_current_user_id();
1139 - $item_per_page = tutor_utils()->get_option( 'pagination_per_page', 10 );
1140 -
1141 - $query_args = array(
1142 - 'post_id' => $lesson_id,
1143 - 'parent' => 0,
1144 - 'number' => $item_per_page,
1145 - 'order' => $order,
1146 - );
1147 -
1148 - if ( $offset >= 0 ) {
1149 - $query_args['offset'] = $offset;
1150 - } else {
1151 - $query_args['paged'] = $current_page;
1152 - }
1153 -
1154 - $comment_list = self::get_comments( $query_args );
1155 -
1156 - // Get total comment count to determine if there are more pages.
1157 - $total_comments = self::get_comments(
1158 - array(
1159 - 'post_id' => $lesson_id,
1160 - 'parent' => 0,
1161 - 'count' => true,
1162 - )
1163 - );
1164 -
1165 - ob_start();
1166 - tutor_load_template(
1167 - 'learning-area.lesson.comment-list',
1168 - compact( 'comment_list', 'lesson_id', 'user_id' )
1169 - );
1170 - $html = ob_get_clean();
1171 -
1172 - // Calculate if there are more items.
1173 - if ( $offset >= 0 ) {
1174 - $items_loaded = $offset + count( $comment_list );
1175 - } else {
1176 - $items_loaded = $current_page * $item_per_page;
1177 - }
1178 - $has_more = $items_loaded < $total_comments;
1179 -
1180 - wp_send_json_success(
1181 - array(
1182 - 'html' => $html,
1183 - 'has_more' => $has_more,
1184 - 'count' => $total_comments,
1185 - )
1186 - );
1187 - }
1188 -
1189 - /**
1190 - * Load comment replies for dashboard.
1191 - *
1192 - * @since 4.0.0
1193 - *
1194 - * @return void
1195 - */
1196 - public function ajax_load_comment_replies() {
1197 - tutor_utils()->check_nonce();
1198 -
1199 - $comment_id = Input::post( 'comment_id', 0, Input::TYPE_INT );
1200 - $replies_order = Input::post( 'order', 'DESC' );
1201 -
1202 - if ( ! $comment_id ) {
1203 - $this->response_bad_request( __( 'Invalid comment ID', 'tutor' ) );
1204 - }
1205 -
1206 - $user_id = get_current_user_id();
1207 - $replies = self::get_comment_replies( $comment_id, $replies_order );
1208 -
1209 - ob_start();
1210 - tutor_load_template(
1211 - 'dashboard.discussions.comment-replies',
1212 - array(
1213 - 'replies' => $replies,
1214 - 'replies_order' => $replies_order,
1215 - 'user_id' => $user_id,
1216 - )
1217 - );
1218 - $html = ob_get_clean();
1219 -
1220 - wp_send_json_success( array( 'html' => $html ) );
1221 - }
1222 -
1223 - /**
1224 - * Get lesson content type info with video duration
1225 - *
1226 - * @since 4.0.0
1227 - *
1228 - * @param WP_Post $lesson Lesson post.
1229 - *
1230 - * @return string
1231 - */
1232 - public static function get_content_type_info( WP_Post $lesson ) {
1233 - $video_info = tutor_utils()->get_video_info( $lesson->ID );
1234 - $lesson_type = __( 'Reading', 'tutor' );
1235 -
1236 - if ( $video_info ) {
1237 - $lesson_type = __( 'Video', 'tutor' );
1238 - $playtime = $video_info->playtime ?? '';
1239 -
1240 - // Check if the playtime is actually a valid, positive duration.
1241 - if ( ! empty( $playtime ) ) {
1242 - /* translators: %s: duration in minutes */
1243 - $lesson_type = sprintf( __( 'Video - %s mins', 'tutor' ), $playtime );
1244 - }
1245 - }
1246 -
1247 - return $lesson_type;
1248 - }
1249 -}