PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 3.9.13
Tutor LMS – eLearning and online course solution v3.9.13
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 11 months ago Admin.php 2 months ago Ajax.php 9 months ago Announcements.php 1 year ago Assets.php 2 months ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Config.php 11 months ago Container.php 11 months ago Course.php 2 months ago Course_Embed.php 3 years ago Course_Filter.php 1 year ago Course_List.php 5 months ago Course_Settings_Tabs.php 1 year ago Course_Widget.php 1 year ago Custom_Validation.php 3 years ago Dashboard.php 1 year ago Earnings.php 9 months ago FormHandler.php 2 years ago Frontend.php 1 year ago Gutenberg.php 1 year ago Icon.php 8 months ago Input.php 1 year ago Instructor.php 2 months ago Instructors_List.php 2 months ago Lesson.php 2 weeks ago Options_V2.php 7 months ago Permalink.php 2 years ago Post_types.php 1 year ago Private_Course_Access.php 1 year ago Q_And_A.php 10 months ago Question_Answers_List.php 11 months ago Quiz.php 2 weeks ago QuizBuilder.php 2 weeks ago Quiz_Attempts_List.php 9 months ago RestAPI.php 2 years ago Reviews.php 9 months ago Rewrite_Rules.php 2 years ago Shortcode.php 9 months ago Singleton.php 1 year ago Student.php 2 months ago Students_List.php 1 year ago Taxonomies.php 1 year ago Template.php 9 months ago Theme_Compatibility.php 3 years ago Tools.php 1 year ago Tools_V2.php 3 weeks ago Tutor.php 2 months ago TutorEDD.php 1 year ago Tutor_Base.php 2 years ago Tutor_Setup.php 8 months ago Upgrader.php 9 months ago User.php 4 months ago Utils.php 3 weeks ago Video_Stream.php 3 years ago WhatsNew.php 9 months ago Withdraw.php 1 year ago Withdraw_Requests_List.php 11 months ago WooCommerce.php 7 months ago
Lesson.php
771 lines
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 namespace TUTOR;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 use Tutor\Helpers\HttpHelper;
18 use Tutor\Helpers\ValidationHelper;
19 use Tutor\Models\LessonModel;
20 use Tutor\Traits\JsonResponse;
21
22 /**
23 * Lesson class
24 *
25 * @since 1.0.0
26 */
27 class Lesson extends Tutor_Base {
28 use JsonResponse;
29
30 /**
31 * Register hooks
32 *
33 * @since 1.0.0
34 * @since 3.7.0 param register hook added.
35 *
36 * @param bool $register_hooks register hooks or not.
37 *
38 * @return void
39 */
40 public function __construct( $register_hooks = true ) {
41 parent::__construct();
42
43 if ( ! $register_hooks ) {
44 return;
45 }
46
47 add_action( 'save_post_' . $this->lesson_post_type, array( $this, 'save_lesson_meta' ) );
48
49 add_action( 'wp_ajax_tutor_lesson_details', array( $this, 'ajax_lesson_details' ) );
50 add_action( 'wp_ajax_tutor_save_lesson', array( $this, 'ajax_save_lesson' ) );
51 add_action( 'wp_ajax_tutor_delete_lesson', array( $this, 'ajax_delete_lesson' ) );
52
53 add_filter( 'get_sample_permalink', array( $this, 'change_lesson_permalink' ), 10, 2 );
54
55 /**
56 * Frontend Action
57 */
58 add_action( 'template_redirect', array( $this, 'mark_lesson_complete' ) );
59
60 add_action( 'wp_ajax_tutor_render_lesson_content', array( $this, 'tutor_render_lesson_content' ) );
61
62 /**
63 * For public course access
64 */
65 add_action( 'wp_ajax_nopriv_tutor_render_lesson_content', array( $this, 'tutor_render_lesson_content' ) );
66
67 /**
68 * Autoplay next video
69 *
70 * @since 1.4.9
71 */
72 add_action( 'wp_ajax_autoload_next_course_content', array( $this, 'autoload_next_course_content' ) );
73
74 /**
75 * Load next course item after click complete button
76 *
77 * @since 1.5.3
78 */
79 add_action( 'tutor_lesson_completed_after', array( $this, 'tutor_lesson_completed_after' ), 999 );
80
81 /**
82 * Lesson comment & reply ajax handler
83 *
84 * @since 2.0.0
85 */
86 add_action( 'wp_ajax_tutor_single_course_lesson_load_more', array( $this, 'tutor_single_course_lesson_load_more' ) );
87 add_action( 'wp_ajax_tutor_create_lesson_comment', array( $this, 'tutor_single_course_lesson_load_more' ) );
88 add_action( 'wp_ajax_tutor_reply_lesson_comment', array( $this, 'reply_lesson_comment' ) );
89 }
90
91 /**
92 * Manage load more & comment create
93 *
94 * @since 2.0.6
95 * @return void send wp json data
96 */
97 public function tutor_single_course_lesson_load_more() {
98 tutor_utils()->checking_nonce();
99
100 $comment = Input::post( 'comment', '', Input::TYPE_TEXTAREA );
101 $lesson_id = Input::post( 'comment_post_ID', 0, Input::TYPE_INT );
102
103 if ( 'tutor_create_lesson_comment' === Input::post( 'action' ) && strlen( $comment ) > 0 ) {
104 $course_id = tutor_utils()->get_course_id_by( 'lesson', $lesson_id );
105 if ( ! tutor_utils()->is_enrolled( $course_id ) ) {
106 wp_send_json_error( __( 'You must be enrolled to comment', 'tutor' ) );
107 }
108
109 $comment_data = array(
110 'comment_content' => $comment,
111 'comment_post_ID' => $lesson_id,
112 'comment_parent' => Input::post( 'comment_parent', 0, Input::TYPE_INT ),
113 );
114 self::create_comment( $comment_data );
115 do_action( 'tutor_new_comment_added', $comment_data );
116 }
117 ob_start();
118 tutor_load_template( 'single.lesson.comment' );
119 $html = ob_get_clean();
120 wp_send_json_success( array( 'html' => $html ) );
121 }
122
123 /**
124 * Saving lesson meta and assets
125 *
126 * @since 1.0.0
127 *
128 * @param integer $post_ID post ID.
129 *
130 * @return void
131 */
132 public function save_lesson_meta( $post_ID ) {
133 $thumbnail_id = Input::post( 'thumbnail_id', 0, Input::TYPE_INT );
134 if ( $thumbnail_id ) {
135 update_post_meta( $post_ID, '_thumbnail_id', $thumbnail_id );
136 } else {
137 delete_post_meta( $post_ID, '_thumbnail_id' );
138 }
139
140 $video_source = sanitize_text_field( tutor_utils()->array_get( 'video.source', $_POST ) ); //phpcs:ignore
141 if ( '-1' === $video_source ) {
142 delete_post_meta( $post_ID, '_video' );
143 } elseif ( $video_source ) {
144
145 // Sanitize data through helper method.
146 $video = Input::sanitize_array(
147 $_POST['video'] ?? array(), //phpcs:ignore
148 array(
149 'source_external_url' => 'esc_url',
150 'source_embedded' => 'wp_kses_post',
151 ),
152 true
153 );
154 update_post_meta( $post_ID, '_video', $video );
155 }
156
157 // Attachments.
158 $attachments = array();
159 // phpcs:disable WordPress.Security.NonceVerification.Missing
160 if ( ! empty( $_POST['tutor_attachments'] ) ) {
161 //phpcs:ignore -- data sanitized through helper method.
162 $attachments = tutor_utils()->sanitize_array( wp_unslash( $_POST['tutor_attachments'] ) );
163 $attachments = array_unique( $attachments );
164 }
165
166 /**
167 * If !empty attachment then update meta else
168 * delete meta key to prevent empty data in db
169 *
170 * @since 1.8.9
171 */
172 if ( ! empty( $attachments ) ) {
173 update_post_meta( $post_ID, '_tutor_attachments', $attachments );
174 } else {
175 delete_post_meta( $post_ID, '_tutor_attachments' );
176 }
177 }
178
179 /**
180 * Get lesson details data.
181 *
182 * @since 3.0.0
183 *
184 * @return void
185 */
186 public function ajax_lesson_details() {
187 if ( ! tutor_utils()->is_nonce_verified() ) {
188 $this->json_response( tutor_utils()->error_message( 'nonce' ), null, HttpHelper::STATUS_BAD_REQUEST );
189 }
190
191 $topic_id = Input::post( 'topic_id', 0, Input::TYPE_INT );
192 $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
193
194 if ( ! tutor_utils()->can_user_manage( 'topic', $topic_id ) ) {
195 $this->json_response(
196 tutor_utils()->error_message(),
197 null,
198 HttpHelper::STATUS_FORBIDDEN
199 );
200 }
201
202 if ( 0 !== $lesson_id ) {
203 if ( ! tutor_utils()->can_user_manage( 'lesson', $lesson_id ) ) {
204 $this->json_response(
205 tutor_utils()->error_message(),
206 null,
207 HttpHelper::STATUS_FORBIDDEN
208 );
209 }
210 }
211
212 $data = LessonModel::get_lesson_details( $lesson_id );
213
214 $this->json_response(
215 __( 'Lesson data fetched successfully', 'tutor' ),
216 $data
217 );
218 }
219
220 /**
221 * Create or update lesson.
222 *
223 * @since 1.0.0
224 * @since 1.5.1 updated
225 * @since 3.0.0 refactor and response updated.
226 *
227 * @return void
228 */
229 public function ajax_save_lesson() {
230 if ( ! tutor_utils()->is_nonce_verified() ) {
231 $this->json_response( tutor_utils()->error_message( 'nonce' ), null, HttpHelper::STATUS_BAD_REQUEST );
232 }
233
234 /**
235 * Allow iframe inside lesson content to support
236 * embed video & other stuff
237 *
238 * @since 2.1.6
239 */
240 add_filter( 'wp_kses_allowed_html', Input::class . '::allow_iframe', 10, 2 );
241
242 $is_update = false;
243
244 $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
245 $topic_id = Input::post( 'topic_id', 0, Input::TYPE_INT );
246
247 if ( $lesson_id ) {
248 $is_update = true;
249 }
250
251 if ( ! tutor_utils()->can_user_manage( 'topic', $topic_id ) ) {
252 $this->json_response(
253 tutor_utils()->error_message(),
254 null,
255 HttpHelper::STATUS_FORBIDDEN
256 );
257 }
258
259 $title = Input::post( 'title' );
260 $description = Input::post( 'description', '', Input::TYPE_KSES_POST );
261 $is_html_active = Input::post( 'is_html_active' ) === 'true' ? true : false;
262 $raw_html_content = Input::post( 'tutor_lesson_modal_editor', '', Input::TYPE_KSES_POST );
263 $post_content = $is_html_active ? $raw_html_content : $description;
264
265 $rules = array(
266 'topic_id' => 'required|numeric',
267 'lesson_id' => 'if_input|numeric',
268 );
269
270 //phpcs:ignore WordPress.Security.NonceVerification.Missing
271 $params = Input::sanitize_array( $_POST, array( 'description' => 'wp_kses_post' ) );
272
273 $validation = ValidationHelper::validate( $rules, $params );
274 if ( ! $validation->success ) {
275 $this->json_response(
276 __( 'Invalid inputs', 'tutor' ),
277 $validation->errors,
278 HttpHelper::STATUS_UNPROCESSABLE_ENTITY
279 );
280 }
281
282 $lesson_data = array(
283 'post_type' => $this->lesson_post_type,
284 'post_title' => wp_slash( $title ), // Note: Added wp_slash to support latex syntaxes.
285 'post_name' => sanitize_title( $title ),
286 'post_content' => wp_slash( $post_content ),
287 'post_status' => 'publish',
288 'comment_status' => 'open',
289 'post_author' => get_current_user_id(),
290 'post_parent' => $topic_id,
291 );
292
293 if ( ! $is_update ) {
294 $lesson_data['menu_order'] = tutor_utils()->get_next_course_content_order_id( $topic_id );
295 $lesson_id = wp_insert_post( $lesson_data );
296
297 if ( $lesson_id ) {
298 do_action( 'tutor/lesson/created', $lesson_id );
299 } else {
300 $this->json_response(
301 tutor_utils()->error_message(),
302 null,
303 HttpHelper::STATUS_INTERNAL_SERVER_ERROR
304 );
305 }
306 } else {
307 $lesson_data['ID'] = $lesson_id;
308
309 if ( ! tutor_utils()->can_user_manage( 'lesson', $lesson_id ) ) {
310 $this->json_response(
311 tutor_utils()->error_message(),
312 null,
313 HttpHelper::STATUS_FORBIDDEN
314 );
315 }
316
317 do_action( 'tutor/lesson_update/before', $lesson_id );
318 wp_update_post( $lesson_data );
319 do_action( 'tutor/lesson_update/after', $lesson_id );
320 }
321
322 if ( $is_update ) {
323 $this->json_response(
324 __( 'Lesson updated successfully', 'tutor' ),
325 $lesson_id
326 );
327 } else {
328 $this->json_response(
329 __( 'Lesson created successfully', 'tutor' ),
330 $lesson_id,
331 HttpHelper::STATUS_CREATED
332 );
333 }
334 }
335
336 /**
337 * Delete Lesson from course builder by ID
338 *
339 * @since 1.0.0
340 * @since 3.0.0 refactor and update response.
341 *
342 * @return void
343 */
344 public function ajax_delete_lesson() {
345 tutor_utils()->check_nonce();
346
347 $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
348
349 if ( ! tutor_utils()->can_user_manage( 'lesson', $lesson_id ) ) {
350 $this->json_response(
351 tutor_utils()->error_message(),
352 null,
353 HttpHelper::STATUS_FORBIDDEN
354 );
355 }
356
357 $content = __( 'Lesson', 'tutor' );
358 $post_type = get_post_type( $lesson_id );
359 if ( tutor()->assignment_post_type === $post_type ) {
360 $content = __( 'Assignment', 'tutor' );
361 }
362
363 do_action( 'tutor_before_delete_course_content', 0, $lesson_id );
364
365 wp_delete_post( $lesson_id, true );
366 /* translators: %s refers to the name of the content being deleted */
367 $this->json_response( sprintf( __( '%s deleted successfully', 'tutor' ), $content ) );
368 }
369
370
371 /**
372 * Changed the URI based
373 *
374 * @since 1.0.0
375 *
376 * @param string $uri URI.
377 * @param integer $lesson_id lesson ID.
378 *
379 * @return string
380 */
381 public function change_lesson_permalink( $uri, $lesson_id ) {
382 $post = get_post( $lesson_id );
383
384 if ( $post && $post->post_type === $this->lesson_post_type ) {
385 $uri_base = trailingslashit( site_url() );
386
387 $sample_course = 'sample-course';
388 $is_course = tutor_utils()->get_course_id_by( 'lesson', get_the_ID() );
389 if ( $is_course ) {
390 $course = get_post( $is_course );
391 if ( $course ) {
392 $sample_course = $course->post_name;
393 }
394 }
395
396 $new_course_base = $uri_base . "course/{$sample_course}/lesson/%pagename%/";
397 $uri[0] = $new_course_base;
398 }
399
400 return $uri;
401 }
402
403 /**
404 * Mark lesson completed
405 *
406 * @since 1.0.0
407 *
408 * @return void
409 */
410 public function mark_lesson_complete() {
411 if ( 'tutor_complete_lesson' !== Input::post( 'tutor_action' ) ) {
412 return;
413 }
414 // Checking nonce.
415 tutor_utils()->checking_nonce();
416
417 $user_id = get_current_user_id();
418
419 // TODO: need to show view if not signed_in.
420 if ( ! $user_id ) {
421 die( esc_html__( 'Please Sign-In', 'tutor' ) );
422 }
423
424 $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
425
426 if ( ! $lesson_id ) {
427 return;
428 }
429
430 $validated = apply_filters( 'tutor_validate_lesson_complete', true, $user_id, $lesson_id );
431 if ( ! $validated ) {
432 return;
433 }
434
435 do_action( 'tutor_lesson_completed_before', $lesson_id );
436 /**
437 * Marking lesson at user meta, meta format, _tutor_completed_lesson_id_{id} and value = tutor_time();
438 */
439 LessonModel::mark_lesson_complete( $lesson_id );
440
441 do_action( 'tutor_lesson_completed_email_after', $lesson_id, $user_id );
442 do_action( 'tutor_lesson_completed_after', $lesson_id, $user_id );
443 }
444
445 /**
446 * Render the lesson content
447 *
448 * @since 1.0.0
449 *
450 * @return void
451 */
452 public function tutor_render_lesson_content() {
453 tutor_utils()->checking_nonce();
454
455 $lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
456
457 $ancestors = get_post_ancestors( $lesson_id );
458 $course_id = ! empty( $ancestors ) ? array_pop( $ancestors ) : $lesson_id;
459
460 // Course must be public or current user must be enrolled to access this lesson.
461 if ( get_post_meta( $course_id, '_tutor_is_public_course', true ) !== 'yes' && ! tutor_utils()->is_enrolled( $course_id ) ) {
462
463 $is_admin = tutor_utils()->has_user_role( 'administrator' );
464 $allowed = $is_admin ? true : tutor_utils()->is_instructor_of_this_course( get_current_user_id(), $course_id );
465
466 if ( ! $allowed ) {
467 http_response_code( 400 );
468 exit;
469 }
470 }
471
472 ob_start();
473 global $post;
474
475 $post = get_post( $lesson_id ); //phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
476 setup_postdata( $post );
477 tutor_lesson_content();
478 wp_reset_postdata();
479
480 $html = ob_get_clean();
481
482 wp_send_json_success( array( 'html' => $html ) );
483 }
484
485 /**
486 * Load next course item automatically
487 *
488 * @since 1.4.9
489 *
490 * @return void
491 */
492 public function autoload_next_course_content() {
493 tutor_utils()->checking_nonce();
494
495 $post_id = Input::post( 'post_id', 0, Input::TYPE_INT );
496 $content_id = tutor_utils()->get_post_id( $post_id );
497 $contents = tutor_utils()->get_course_prev_next_contents_by_id( $content_id );
498
499 $autoload_course_content = (bool) get_tutor_option( 'autoload_next_course_content' );
500 $next_url = false;
501 if ( $autoload_course_content ) {
502 $next_url = get_the_permalink( $contents->next_id );
503 }
504 wp_send_json_success( array( 'next_url' => $next_url ) );
505 }
506
507 /**
508 * Load next course item after click complete button
509 *
510 * @since 1.5.3
511 *
512 * @param integer $content_id content ID.
513 * @return void
514 */
515 public function tutor_lesson_completed_after( $content_id ) {
516 $contents = tutor_utils()->get_course_prev_next_contents_by_id( $content_id );
517 $autoload_course_content = (bool) get_tutor_option( 'autoload_next_course_content' );
518 if ( $autoload_course_content ) {
519 wp_safe_redirect( get_the_permalink( $contents->next_id ) );
520 } else {
521 wp_safe_redirect( get_the_permalink( $content_id ) );
522 }
523 die();
524 }
525
526 /**
527 * Replay lesson comment
528 *
529 * @since 1.0.0
530 *
531 * @return void|null
532 */
533 public function reply_lesson_comment() {
534 tutor_utils()->checking_nonce();
535 $comment = Input::post( 'comment', '', Input::TYPE_TEXTAREA );
536 if ( 0 === strlen( $comment ) ) {
537 wp_send_json_error();
538 return;
539 }
540
541 $lesson_id = Input::post( 'comment_post_ID', 0, Input::TYPE_INT );
542 $course_id = tutor_utils()->get_course_id_by( 'lesson', $lesson_id );
543 if ( ! tutor_utils()->is_enrolled( $course_id ) ) {
544 wp_send_json_error( __( 'You must be enrolled to comment', 'tutor' ) );
545 return;
546 }
547
548 $comment_data = array(
549 'comment_content' => $comment,
550 'comment_post_ID' => $lesson_id,
551 'comment_parent' => Input::post( 'comment_parent', 0, Input::TYPE_INT ),
552 );
553
554 $comment_id = self::create_comment( $comment_data );
555 if ( false === $comment_id ) {
556 wp_send_json_error();
557 return;
558 }
559 $reply = get_comment( $comment_id );
560 do_action( 'tutor_reply_lesson_comment_thread', $comment_id, $comment_data );
561
562 ob_start();
563 ?>
564 <div class="tutor-comments-list tutor-child-comment tutor-mt-32" id="lesson-comment-<?php echo esc_attr( $reply->comment_ID ); ?>">
565 <div class="comment-avatar">
566 <img src="<?php echo esc_url( get_avatar_url( $reply->user_id ) ); ?>" alt="">
567 </div>
568 <div class="tutor-single-comment">
569 <div class="tutor-actual-comment tutor-mb-12">
570 <div class="tutor-comment-author">
571 <span class="tutor-fs-6 tutor-fw-bold">
572 <?php echo esc_html( $reply->comment_author ); ?>
573 </span>
574 <span class="tutor-fs-7 tutor-ml-0 tutor-ml-sm-10">
575 <?php echo esc_html( human_time_diff( strtotime( $reply->comment_date ), tutor_time() ) . __( ' ago', 'tutor' ) ); ?>
576 </span>
577 </div>
578 <div class="tutor-comment-text tutor-fs-6 tutor-mt-4">
579 <?php echo esc_html( $reply->comment_content ); ?>
580 </div>
581 </div>
582 </div>
583 </div>
584 <?php
585 $html = ob_get_clean();
586 wp_send_json_success( array( 'html' => $html ) );
587 }
588
589 /**
590 * Get comments
591 *
592 * @since 2.0.6
593 * @see Checkout arguments details: https://developer.wordpress.org/reference/classes/wp_comment_query/__construct/
594 *
595 * @param array $args arguments.
596 * @return mixed based on arguments
597 */
598 public static function get_comments( array $args ) {
599 $args['type'] = 'comment';
600 $comments = get_comments( $args );
601 return $comments;
602 }
603
604 /**
605 * Create comment
606 *
607 * @since 1.0.0
608 *
609 * @param array $request request.
610 * @return mixed comment id on success, false on failure
611 */
612 public static function create_comment( array $request ) {
613 $current_user = wp_get_current_user();
614 $default_data = array(
615 'comment_content' => '',
616 'comment_post_ID' => '',
617 'comment_parent' => '',
618 'user_id' => $current_user->ID,
619 'comment_author' => $current_user->user_login,
620 'comment_author_email' => $current_user->user_email,
621 'comment_author_url' => $current_user->user_url,
622 'comment_agent' => 'Tutor',
623 );
624 $comment_data = wp_parse_args( $request, $default_data );
625 return wp_insert_comment( $comment_data );
626 }
627
628 /**
629 * Check if lesson has content
630 *
631 * @since 3.9.0
632 *
633 * @param int $lesson_id Lesson ID.
634 *
635 * @return bool True if lesson has content, false otherwise.
636 */
637 public static function has_lesson_content( $lesson_id ) {
638 /**
639 * If lesson has no content, lesson tab will be hidden.
640 * To enable elementor and SCORM, only admin can see lesson tab.
641 *
642 * @since 2.2.2
643 */
644 return apply_filters(
645 'tutor_has_lesson_content',
646 User::is_admin() || ! in_array( trim( get_the_content() ), array( null, '', '&nbsp;' ), true ),
647 $lesson_id
648 );
649 }
650
651 /**
652 * Check if lesson has attachments
653 *
654 * @since 3.9.0
655 *
656 * @param int $lesson_id Lesson ID.
657 *
658 * @return bool True if lesson has attachments, false otherwise.
659 */
660 public static function has_lesson_attachment( $lesson_id ) {
661 return count( tutor_utils()->get_attachments( $lesson_id ) ) > 0;
662 }
663
664 /**
665 * Check if comments are enabled for lessons
666 *
667 * @since 3.9.0
668 *
669 * @return bool True if comments are enabled, false otherwise.
670 */
671 public static function is_comment_enabled() {
672 return tutor_utils()->get_option( 'enable_comment_for_lesson' ) && comments_open() && is_user_logged_in();
673 }
674
675 /**
676 * Check if lesson has comments
677 *
678 * @since 3.9.0
679 *
680 * @param int $lesson_id Lesson ID.
681 *
682 * @return int Number of comments for the lesson.
683 */
684 public static function has_lesson_comment( $lesson_id ) {
685 return (int) get_comments_number( $lesson_id );
686 }
687
688 /**
689 * Get navigation items for lesson single page
690 *
691 * @since 3.9.0
692 *
693 * @param int $lesson_id Lesson ID.
694 *
695 * @return array navigation items array
696 */
697 public static function get_nav_items( $lesson_id ) {
698 $nav_items = array();
699
700 if ( self::has_lesson_content( $lesson_id ) ) {
701 $nav_items['overview'] = array(
702 'label' => __( 'Overview', 'tutor' ),
703 'value' => 'overview',
704 'icon' => 'document-text',
705 );
706 }
707
708 if ( self::has_lesson_attachment( $lesson_id ) ) {
709 $nav_items['files'] = array(
710 'label' => __( 'Exercise Files', 'tutor' ),
711 'value' => 'files',
712 'icon' => 'paperclip',
713 );
714 }
715
716 if ( self::is_comment_enabled() ) {
717 $nav_items['comments'] = array(
718 'label' => __( 'Comments', 'tutor' ),
719 'value' => 'comments',
720 'icon' => 'comment',
721 );
722 }
723
724 $nav_items = apply_filters( 'tutor_lesson_single_nav_items', $nav_items );
725 $nav_items = array_values( $nav_items );
726
727 return $nav_items;
728 }
729
730 /**
731 * Get navigation contents for lesson single page
732 *
733 * @since 3.9.0
734 *
735 * @param int $lesson_id Lesson ID.
736 *
737 * @return array navigation contents array
738 */
739 public static function get_nav_contents( $lesson_id ) {
740 $nav_contents = array();
741
742 if ( self::has_lesson_content( $lesson_id ) ) {
743 $nav_contents['overview'] = array(
744 'label' => __( 'Overview', 'tutor' ),
745 'value' => 'overview',
746 'template_path' => 'single.lesson.parts.overview',
747 );
748 }
749
750 if ( self::has_lesson_attachment( $lesson_id ) ) {
751 $nav_contents['files'] = array(
752 'label' => __( 'Files', 'tutor' ),
753 'value' => 'files',
754 'template_path' => 'single.lesson.parts.files',
755 );
756 }
757
758 if ( self::is_comment_enabled() ) {
759 $nav_contents['comments'] = array(
760 'label' => __( 'Comments', 'tutor' ),
761 'value' => 'comments',
762 'template_path' => 'single.lesson.parts.comments',
763 );
764 }
765
766 $nav_contents = apply_filters( 'tutor_lesson_single_nav_contents', $nav_contents );
767
768 return $nav_contents;
769 }
770 }
771