PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 3.0.0
Tutor LMS – eLearning and online course solution v3.0.0
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 / Ajax.php
tutor / classes Last commit date
Addons.php 1 year ago Admin.php 1 year ago Ajax.php 1 year ago Announcements.php 1 year ago Assets.php 1 year ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Course.php 1 year ago Course_Embed.php 3 years ago Course_Filter.php 1 year ago Course_List.php 1 year ago Course_Settings_Tabs.php 1 year ago Course_Widget.php 3 years ago Custom_Validation.php 3 years ago Dashboard.php 1 year ago Earnings.php 1 year ago FormHandler.php 2 years ago Frontend.php 1 year ago Gutenberg.php 1 year ago Input.php 1 year ago Instructor.php 1 year ago Instructors_List.php 1 year ago Lesson.php 1 year ago Options_V2.php 1 year ago Permalink.php 2 years ago Post_types.php 2 years ago Private_Course_Access.php 1 year ago Q_And_A.php 1 year ago Question_Answers_List.php 3 years ago Quiz.php 1 year ago QuizBuilder.php 1 year ago Quiz_Attempts_List.php 1 year ago RestAPI.php 2 years ago Reviews.php 3 years ago Rewrite_Rules.php 2 years ago Shortcode.php 1 year ago Singleton.php 1 year ago Student.php 1 year ago Students_List.php 3 years ago Taxonomies.php 3 years ago Template.php 1 year ago Theme_Compatibility.php 3 years ago Tools.php 3 years ago Tools_V2.php 1 year ago Tutor.php 1 year ago TutorEDD.php 1 year ago Tutor_Base.php 2 years ago Tutor_Setup.php 1 year ago Upgrader.php 1 year ago User.php 1 year ago Utils.php 1 year ago Video_Stream.php 3 years ago WhatsNew.php 2 years ago Withdraw.php 1 year ago Withdraw_Requests_List.php 3 years ago WooCommerce.php 1 year ago
Ajax.php
633 lines
1 <?php
2 /**
3 * Handle Ajax Request
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\Models\LessonModel;
19 use Tutor\Traits\JsonResponse;
20
21 /**
22 * Ajax Class
23 *
24 * @since 1.0.0
25 */
26 class Ajax {
27 use JsonResponse;
28
29 const LOGIN_ERRORS_TRANSIENT_KEY = 'tutor_login_errors';
30 /**
31 * Constructor
32 *
33 * @since 1.0.0
34 * @since 2.6.2 added allow_hooks param.
35 *
36 * @param bool $allow_hooks default value true.
37 *
38 * @return void
39 */
40 public function __construct( $allow_hooks = true ) {
41 if ( $allow_hooks ) {
42 add_action( 'wp_ajax_sync_video_playback', array( $this, 'sync_video_playback' ) );
43 add_action( 'wp_ajax_nopriv_sync_video_playback', array( $this, 'sync_video_playback_noprev' ) );
44 add_action( 'wp_ajax_tutor_place_rating', array( $this, 'tutor_place_rating' ) );
45 add_action( 'wp_ajax_delete_tutor_review', array( $this, 'delete_tutor_review' ) );
46
47 add_action( 'wp_ajax_tutor_course_add_to_wishlist', array( $this, 'tutor_course_add_to_wishlist' ) );
48 add_action( 'wp_ajax_nopriv_tutor_course_add_to_wishlist', array( $this, 'tutor_course_add_to_wishlist' ) );
49
50 /**
51 * Ajax login
52 *
53 * @since v.1.6.3
54 */
55 add_action( 'tutor_action_tutor_user_login', array( $this, 'process_tutor_login' ) );
56
57 /**
58 * Announcement
59 *
60 * @since v.1.7.9
61 */
62 add_action( 'wp_ajax_tutor_announcement_create', array( $this, 'create_or_update_annoucement' ) );
63 add_action( 'wp_ajax_tutor_announcement_delete', array( $this, 'delete_annoucement' ) );
64
65 add_action( 'wp_ajax_tutor_youtube_video_duration', array( $this, 'ajax_youtube_video_duration' ) );
66 }
67 }
68
69
70
71 /**
72 * Update video information and data when necessary
73 *
74 * @since 1.0.0
75 * @return void
76 */
77 public function sync_video_playback() {
78 tutor_utils()->checking_nonce();
79
80 $user_id = get_current_user_id();
81 $post_id = Input::post( 'post_id', 0, Input::TYPE_INT );
82 $duration = Input::post( 'duration' );
83 $current_time = Input::post( 'currentTime' );
84
85 if ( ! tutor_utils()->has_enrolled_content_access( 'lesson', $post_id ) ) {
86 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
87 exit;
88 }
89
90 /**
91 * Update posts attached video
92 */
93 $video = tutor_utils()->get_video( $post_id );
94
95 if ( $duration ) {
96 $video['duration_sec'] = $duration; // Duration in sec.
97 $video['playtime'] = tutor_utils()->playtime_string( $duration );
98 $video['runtime'] = tutor_utils()->playtime_array( $duration );
99 }
100 tutor_utils()->update_video( $post_id, $video );
101
102 /**
103 * Sync Lesson Reading Info by Users
104 */
105
106 $best_watch_time = tutor_utils()->get_lesson_reading_info( $post_id, $user_id, 'video_best_watched_time' );
107 if ( $best_watch_time < $current_time ) {
108 LessonModel::update_lesson_reading_info( $post_id, $user_id, 'video_best_watched_time', $current_time );
109 }
110
111 if ( Input::post( 'is_ended', false, Input::TYPE_BOOL ) ) {
112 LessonModel::mark_lesson_complete( $post_id );
113 }
114 exit();
115 }
116
117 /**
118 * Video playback callback for noprev
119 *
120 * @since 1.0.0
121 * @return void
122 */
123 public function sync_video_playback_noprev() {
124 }
125
126 /**
127 * Place rating
128 *
129 * @since 1.0.0
130 * @return void
131 */
132 public function tutor_place_rating() {
133 tutor_utils()->checking_nonce();
134
135 $user_id = get_current_user_id();
136 $course_id = Input::post( 'course_id' );
137 $rating = Input::post( 'tutor_rating_gen_input', 0, Input::TYPE_INT );
138 $review = Input::post( 'review', '', Input::TYPE_TEXTAREA );
139
140 $rating <= 0 ? $rating = 1 : 0;
141 $rating > 5 ? $rating = 5 : 0;
142
143 $this->add_or_update_review( $user_id, $course_id, $rating, $review );
144 }
145
146 /**
147 * Add/Update rating
148 *
149 * @param int $user_id the user id.
150 * @param int $course_id the course id.
151 * @param int $rating rating star number.
152 * @param string $review review description.
153 * @param int $review_id review id needed for api update.
154 *
155 * @return void|string
156 */
157 public function add_or_update_review( $user_id, $course_id, $rating, $review, $review_id = 0 ) {
158 global $wpdb;
159
160 $moderation = tutor_utils()->get_option( 'enable_course_review_moderation', false, true, true );
161 $user = get_userdata( $user_id );
162 $date = date( 'Y-m-d H:i:s', tutor_time() ); //phpcs:ignore
163
164 if ( ! tutor_is_rest() && ! tutor_utils()->has_enrolled_content_access( 'course', $course_id ) ) {
165 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
166 exit;
167 }
168
169 do_action( 'tutor_before_rating_placed' );
170
171 $is_edit = 0 === $review_id ? false : true;
172
173 if ( ! tutor_is_rest() ) {
174 $previous_rating_id = $wpdb->get_var(
175 $wpdb->prepare(
176 "SELECT comment_ID
177 from {$wpdb->comments}
178 WHERE comment_post_ID = %d AND
179 user_id = %d AND
180 comment_type = 'tutor_course_rating'
181 LIMIT 1;",
182 $course_id,
183 $user_id
184 )
185 );
186
187 if ( ! empty( $previous_rating_id ) ) {
188 $review_id = $previous_rating_id;
189 $is_edit = true;
190 }
191 }
192
193 if ( $is_edit ) {
194 $wpdb->update(
195 $wpdb->comments,
196 array(
197 'comment_content' => $review,
198 'comment_approved' => $moderation ? 'hold' : 'approved',
199 'comment_date' => $date,
200 'comment_date_gmt' => get_gmt_from_date( $date ),
201 ),
202 array( 'comment_ID' => $review_id )
203 );
204
205 $rating_info = $wpdb->get_row(
206 $wpdb->prepare(
207 "SELECT * FROM {$wpdb->commentmeta}
208 WHERE comment_id = %d
209 AND meta_key = 'tutor_rating'; ",
210 $review_id
211 )
212 );
213
214 if ( $rating_info ) {
215 $wpdb->update(
216 $wpdb->commentmeta,
217 array( 'meta_value' => $rating ),
218 array(
219 'comment_id' => $review_id,
220 'meta_key' => 'tutor_rating',
221 )
222 );
223 } else {
224 $wpdb->insert(
225 $wpdb->commentmeta,
226 array(
227 'comment_id' => $review_id,
228 'meta_key' => 'tutor_rating',
229 'meta_value' => $rating,
230 )
231 );
232 }
233 } else {
234 $data = array(
235 'comment_post_ID' => esc_sql( $course_id ),
236 'comment_approved' => $moderation ? 'hold' : 'approved',
237 'comment_type' => 'tutor_course_rating',
238 'comment_date' => $date,
239 'comment_date_gmt' => get_gmt_from_date( $date ),
240 'user_id' => $user_id,
241 'comment_author' => $user->user_login,
242 'comment_agent' => 'TutorLMSPlugin',
243 );
244 if ( $review ) {
245 $data['comment_content'] = $review;
246 }
247
248 $wpdb->insert( $wpdb->comments, $data );
249 $comment_id = (int) $wpdb->insert_id;
250 $review_id = $comment_id;
251
252 if ( $comment_id ) {
253 $wpdb->insert(
254 $wpdb->commentmeta,
255 array(
256 'comment_id' => $comment_id,
257 'meta_key' => 'tutor_rating',
258 'meta_value' => $rating,
259 )
260 );
261
262 do_action( 'tutor_after_rating_placed', $comment_id );
263 }
264 }
265
266 if ( ! tutor_is_rest() ) {
267 wp_send_json_success(
268 array(
269 'message' => __( 'Rating placed successfully!', 'tutor' ),
270 'review_id' => $review_id,
271 )
272 );
273 } else {
274 return $is_edit ? 'updated' : 'created';
275 }
276 }
277
278 /**
279 * Delete a review
280 *
281 * @since 1.0.0
282 * @since 2.6.2 added params user_id.
283 * @param int $user_id the user id.
284 * @return void|bool
285 */
286 public function delete_tutor_review( $user_id = 0 ) {
287 if ( ! tutor_is_rest() ) {
288 tutor_utils()->checking_nonce();
289 }
290
291 $review_id = Input::post( 'review_id' );
292
293 if ( ! tutor_utils()->can_user_manage( 'review', $review_id, tutils()->get_user_id( $user_id ) ) ) {
294 wp_send_json_error( array( 'message' => __( 'Permissioned Denied!', 'tutor' ) ) );
295 exit;
296 }
297
298 global $wpdb;
299 $wpdb->delete( $wpdb->commentmeta, array( 'comment_id' => $review_id ) );
300 $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $review_id ) );
301
302 if ( tutor_is_rest() ) {
303 return true;
304 }
305
306 wp_send_json_success();
307 }
308
309 /**
310 * Add course in wishlist
311 *
312 * @since 1.0.0
313 * @return void|string
314 */
315 public function tutor_course_add_to_wishlist() {
316 tutor_utils()->checking_nonce();
317
318 // Redirect login since only logged in user can add courses to wishlist.
319 if ( ! is_user_logged_in() ) {
320 wp_send_json_error(
321 array(
322 'redirect_to' => wp_login_url( wp_get_referer() ),
323 )
324 );
325 }
326
327 $user_id = get_current_user_id();
328 $course_id = Input::post( 'course_id', 0, Input::TYPE_INT );
329
330 $result = $this->add_or_delete_wishlist( $user_id, $course_id );
331
332 if ( tutor_is_rest() ) {
333 return $result;
334 } elseif ( 'added' === $result ) {
335 wp_send_json_success(
336 array(
337 'status' => 'added',
338 'message' => __( 'Course added to wish list', 'tutor' ),
339 )
340 );
341 } else {
342 wp_send_json_success(
343 array(
344 'status' => 'removed',
345 'message' => __( 'Course removed from wish list', 'tutor' ),
346 )
347 );
348 }
349 }
350
351 /**
352 * Add or Delete wishlist by user_id and course_id
353 *
354 * @since 2.6.2
355 *
356 * @param int $user_id the user id.
357 * @param int $course_id the course_id to add to the wishlist.
358 *
359 * @return string
360 */
361 public function add_or_delete_wishlist( $user_id, $course_id ) {
362 global $wpdb;
363
364 $if_added_to_list = tutor_utils()->is_wishlisted( $course_id, $user_id );
365
366 $result = '';
367
368 if ( $if_added_to_list ) {
369 $wpdb->delete(
370 $wpdb->usermeta,
371 array(
372 'user_id' => $user_id,
373 'meta_key' => '_tutor_course_wishlist',
374 'meta_value' => $course_id,
375 )
376 );
377
378 $result = 'removed';
379 } else {
380 add_user_meta( $user_id, '_tutor_course_wishlist', $course_id );
381
382 $result = 'added';
383 }
384
385 return $result;
386 }
387
388 /**
389 * Process tutor login
390 *
391 * @since 1.6.3
392 *
393 * @since 2.1.3 Ajax removed, validation errors
394 * stores in session.
395 *
396 * @return void
397 */
398 public function process_tutor_login() {
399 $validation_error = new \WP_Error();
400
401 /**
402 * Separate nonce verification added to show nonce verification
403 * failed message in a proper way.
404 *
405 * @since 2.1.4
406 */
407 if ( ! wp_verify_nonce( $_POST[ tutor()->nonce ], tutor()->nonce_action ) ) { //phpcs:ignore
408 $validation_error->add( 401, __( 'Nonce verification failed', 'tutor' ) );
409 \set_transient( self::LOGIN_ERRORS_TRANSIENT_KEY, $validation_error->get_error_messages() );
410 return;
411 }
412 //phpcs:disable WordPress.Security.NonceVerification.Missing
413
414 /**
415 * No sanitization/wp_unslash needed for log & pwd since WordPress
416 * does itself
417 *
418 * @since 2.1.3
419 *
420 * @see https://developer.wordpress.org/reference/functions/wp_signon/
421 */
422 $username = tutor_utils()->array_get( 'log', $_POST ); //phpcs:ignore
423 $password = tutor_utils()->array_get( 'pwd', $_POST ); //phpcs:ignore
424 $redirect_to = isset( $_POST['redirect_to'] ) ? esc_url_raw( wp_unslash( $_POST['redirect_to'] ) ) : '';
425 $remember = isset( $_POST['rememberme'] );
426
427 try {
428 $creds = array(
429 'user_login' => trim( $username ),
430 'user_password' => $password,
431 'remember' => $remember,
432 );
433
434 $validation_error = apply_filters( 'tutor_process_login_errors', $validation_error, $creds['user_login'], $creds['user_password'] );
435
436 if ( $validation_error->get_error_code() ) {
437 $validation_error->add(
438 $validation_error->get_error_code(),
439 $validation_error->get_error_message()
440 );
441 }
442
443 if ( empty( $creds['user_login'] ) ) {
444 $validation_error->add(
445 400,
446 __( 'Username is required.', 'tutor' )
447 );
448 }
449
450 // On multi-site, ensure user exists on current site, if not add them before allowing login.
451 if ( is_multisite() ) {
452 $user_data = get_user_by( is_email( $creds['user_login'] ) ? 'email' : 'login', $creds['user_login'] );
453
454 if ( $user_data && ! is_user_member_of_blog( $user_data->ID, get_current_blog_id() ) ) {
455 add_user_to_blog( get_current_blog_id(), $user_data->ID, 'customer' );
456 }
457 }
458
459 // Perform the login.
460 $user = wp_signon( apply_filters( 'tutor_login_credentials', $creds ), is_ssl() );
461
462 if ( is_wp_error( $user ) ) {
463 // If no error exist then add WP login error, to prevent error duplication.
464 if ( ! $validation_error->has_errors() ) {
465 $validation_error->add( 400, $user->get_error_message() );
466 }
467 } else {
468 do_action( 'tutor_after_login_success', $user->ID );
469 // Since 1.9.8 do enroll if guest attempt to enroll.
470 $course_enroll_attempt = Input::post( 'tutor_course_enroll_attempt' );
471 if ( ! empty( $course_enroll_attempt ) && is_a( $user, 'WP_User' ) ) {
472 do_action( 'tutor_do_enroll_after_login_if_attempt', $course_enroll_attempt, $user->ID );
473 }
474 wp_safe_redirect( $redirect_to );
475 exit();
476 }
477 } catch ( \Exception $e ) {
478 do_action( 'tutor_login_failed' );
479 $validation_error->add( 400, $e->getMessage() );
480 } finally {
481 // Store errors in transient data.
482 \set_transient( self::LOGIN_ERRORS_TRANSIENT_KEY, $validation_error->get_error_messages() );
483 }
484 }
485
486 /**
487 * Create/Update announcement
488 *
489 * @since 1.7.9
490 * @return void
491 */
492 public function create_or_update_annoucement() {
493 tutor_utils()->checking_nonce();
494
495 $error = array();
496 $course_id = Input::post( 'tutor_announcement_course' );
497 $announcement_title = Input::post( 'tutor_announcement_title' );
498 $announcement_summary = Input::post( 'tutor_announcement_summary', '', Input::TYPE_TEXTAREA );
499
500 // Check if user can manage this announcment.
501 if ( ! tutor_utils()->can_user_manage( 'course', $course_id ) ) {
502 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
503 }
504
505 // Set data and sanitize it.
506 $form_data = array(
507 'post_type' => 'tutor_announcements',
508 'post_title' => $announcement_title,
509 'post_content' => $announcement_summary,
510 'post_parent' => $course_id,
511 'post_status' => 'publish',
512 );
513
514 if ( Input::has( 'announcement_id' ) ) {
515 $form_data['ID'] = Input::post( 'announcement_id' );
516 }
517
518 if ( ! empty( $form_data['ID'] ) ) {
519 if ( ! tutor_utils()->can_user_manage( 'announcement', $form_data['ID'] ) ) {
520 wp_send_json_error( array( 'message' => tutor_utils()->error_message() ) );
521 }
522 }
523
524 // Validation message set.
525 if ( empty( $form_data['post_parent'] ) ) {
526 $error['post_parent'] = __( 'Course name required', 'tutor' );
527
528 }
529
530 if ( empty( $form_data['post_title'] ) ) {
531 $error['post_title'] = __( 'Announcement title required', 'tutor' );
532 }
533
534 if ( empty( $form_data['post_content'] ) ) {
535 $error['post_content'] = __( 'Announcement summary required', 'tutor' );
536
537 }
538
539 if ( empty( $form_data['post_content'] ) ) {
540 $error['post_content'] = __( 'Announcement summary required', 'tutor' );
541
542 }
543
544 // If validation fails.
545 if ( count( $error ) > 0 ) {
546 wp_send_json_error(
547 array(
548 'message' => __( 'All fields required!', 'tutor' ),
549 'fields' => $error,
550 )
551 );
552 }
553
554 // Insert or update post.
555 $post_id = wp_insert_post( $form_data );
556 if ( $post_id > 0 ) {
557 $announcement = get_post( $post_id );
558 $action_type = Input::post( 'action_type' );
559
560 do_action( 'tutor_announcements/after/save', $post_id, $announcement, $action_type );
561
562 $resp_message = 'create' === $action_type ? __( 'Announcement created successfully', 'tutor' ) : __( 'Announcement updated successfully', 'tutor' );
563 wp_send_json_success( array( 'message' => $resp_message ) );
564 }
565
566 wp_send_json_error( array( 'message' => __( 'Something Went Wrong!', 'tutor' ) ) );
567 }
568
569 /**
570 * Delete announcement
571 *
572 * @since 1.7.9
573 * @return void
574 */
575 public function delete_annoucement() {
576 tutor_utils()->checking_nonce();
577
578 $announcement_id = Input::post( 'announcement_id' );
579
580 if ( ! tutor_utils()->can_user_manage( 'announcement', $announcement_id ) ) {
581 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
582 }
583
584 $delete = wp_delete_post( $announcement_id );
585 if ( $delete ) {
586 wp_send_json_success( array( 'message' => __( 'Announcement deleted successfully', 'tutor' ) ) );
587 }
588
589 wp_send_json_error( array( 'message' => __( 'Announcement delete failed', 'tutor' ) ) );
590 }
591
592 /**
593 * Get youtube video duration.
594 *
595 * @since 3.0.0
596 *
597 * @return void
598 */
599 public function ajax_youtube_video_duration() {
600 tutor_utils()->check_nonce();
601
602 $video_id = Input::post( 'video_id' );
603 if ( empty( $video_id ) ) {
604 $this->json_response( __( 'Video ID is required', 'tutor' ), null, HttpHelper::STATUS_BAD_REQUEST );
605 }
606
607 tutor_utils()->check_current_user_capability( 'edit_tutor_course' );
608
609 $api_key = tutor_utils()->get_option( 'lesson_video_duration_youtube_api_key', '' );
610 $url = "https://www.googleapis.com/youtube/v3/videos?id=$video_id&part=contentDetails&key=$api_key";
611
612 $request = HttpHelper::get( $url );
613 if ( HttpHelper::STATUS_OK === $request->get_status_code() ) {
614 $response = $request->get_json();
615 if ( isset( $response->items[0]->contentDetails->duration ) ) {
616 $duration = $response->items[0]->contentDetails->duration;
617 $this->json_response(
618 __( 'Fetched duration successfully', 'tutor' ),
619 array(
620 'duration' => $duration,
621 )
622 );
623 }
624 }
625
626 $this->json_response(
627 __( 'Failed to fetch duration', 'tutor' ),
628 null,
629 HttpHelper::STATUS_BAD_REQUEST
630 );
631 }
632 }
633