PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.1.7.3.2
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.1.7.3.2
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / inc / rest-api / v1 / frontend / class-lp-rest-courses-controller.php

class-lp-rest-courses-controller.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.1.7.3.2, at inc/rest-api/v1/frontend/class-lp-rest-courses-controller.php

706 lines 21.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class LP_REST_Courses_Controller
5 */
6 class LP_REST_Courses_Controller extends LP_Abstract_REST_Controller {
7 /**
8 * LP_REST_Courses_Controller constructor.
9 */
10 public function __construct() {
11 $this->namespace = 'lp/v1';
12 $this->rest_base = 'courses';
13 parent::__construct();
14 }
15
16 /**
17 * Register routes API
18 */
19 public function register_routes() {
20 $this->routes = array(
21 'purchase-course' => array(
22 array(
23 'methods' => WP_REST_Server::CREATABLE,
24 'callback' => array( $this, 'purchase_course' ),
25 'permission_callback' => '__return_true',
26 ),
27 ),
28 'enroll-course' => array(
29 array(
30 'methods' => WP_REST_Server::CREATABLE,
31 'callback' => array( $this, 'enroll_courses' ),
32 'permission_callback' => '__return_true',
33 ),
34 ),
35 'retake-course' => array(
36 array(
37 'methods' => WP_REST_Server::CREATABLE,
38 'callback' => array( $this, 'retake_course' ),
39 'permission_callback' => function () {
40 return is_user_logged_in();
41 },
42 'schema' => array(
43 'type' => 'int',
44 ),
45 ),
46 ),
47 'archive-course' => array(
48 array(
49 'methods' => WP_REST_Server::ALLMETHODS,
50 'callback' => array( $this, 'list_courses' ),
51 'permission_callback' => '__return_true',
52 'args' => [],
53 ),
54 ),
55 '(?P<key>[\w]+)' => array(
56 'args' => array(
57 'id' => array(
58 'description' => __( 'A unique identifier for the resource.', 'learnpress' ),
59 'type' => 'string',
60 ),
61 ),
62 array(
63 'methods' => WP_REST_Server::READABLE,
64 'callback' => array( $this, 'get_item' ),
65 'permission_callback' => array( $this, 'check_admin_permission' ),
66 ),
67 array(
68 'methods' => WP_REST_Server::EDITABLE,
69 'callback' => array( $this, 'update_item' ),
70 'permission_callback' => array( $this, 'check_admin_permission' ),
71 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
72 ),
73 array(
74 'methods' => WP_REST_Server::DELETABLE,
75 'callback' => array( $this, 'delete_item' ),
76 'permission_callback' => array( $this, 'check_admin_permission' ),
77 ),
78 'schema' => array( $this, 'get_public_item_schema' ),
79 ),
80 'continue-course' => array(
81 array(
82 'methods' => WP_REST_Server::CREATABLE,
83 'callback' => array( $this, 'continue_course' ),
84 'permission_callback' => function () {
85 return is_user_logged_in();
86 },
87 ),
88 ),
89 );
90
91 parent::register_routes();
92 }
93
94 /**
95 * Check user is Admin
96 *
97 * @return bool
98 */
99 public function check_admin_permission(): bool {
100 return LP_Abstract_API::check_admin_permission();
101 }
102
103 /**
104 * Get list courses
105 *
106 * @param WP_REST_Request $request
107 *
108 * @return LP_REST_Response
109 */
110 public function list_courses( WP_REST_Request $request ): LP_REST_Response {
111 $response = new LP_REST_Response();
112 $response->data = new stdClass();
113
114 try {
115 $filter = new LP_Course_Filter();
116 $filter->page = absint( $request['paged'] ?? 1 );
117 $filter->post_title = LP_Helper::sanitize_params_submitted( $request['c_search'] ?? '' );
118 $fields_str = LP_Helper::sanitize_params_submitted( urldecode( $request['c_fields'] ?? '' ) );
119 $fields_exclude_str = LP_Helper::sanitize_params_submitted( urldecode( $request['c_exclude_fields'] ?? '' ) );
120 if ( ! empty( $fields_str ) ) {
121 $fields = explode( ',', $fields_str );
122 $filter->fields = $fields;
123 }
124 if ( ! empty( $fields_exclude_str ) ) {
125 $fields_exclude = explode( ',', $fields_exclude_str );
126 $filter->exclude_fields = $fields_exclude;
127 }
128 $filter->post_author = LP_Helper::sanitize_params_submitted( $request['c_author'] ?? 0 );
129 $author_ids_str = LP_Helper::sanitize_params_submitted( $request['c_authors'] ?? 0 );
130 if ( ! empty( $author_ids_str ) ) {
131 $author_ids = explode( ',', $author_ids_str );
132 $filter->post_authors = $author_ids;
133 }
134 $term_ids_str = LP_Helper::sanitize_params_submitted( urldecode( $request['term_id'] ) ?? '' );
135 if ( ! empty( $term_ids_str ) ) {
136 $term_ids = explode( ',', $term_ids_str );
137 $filter->term_ids = $term_ids;
138 }
139
140 $on_sale = absint( $request['on_sale'] ?? '0' );
141 1 === $on_sale ? $filter->sort_by[] = 'on_sale' : '';
142 $on_feature = absint( $request['on_feature'] ?? '0' );
143 1 === $on_feature ? $filter->sort_by[] = 'on_feature' : '';
144
145 $filter->order_by = LP_Helper::sanitize_params_submitted( ! empty( $request['order_by'] ) ? $request['order_by'] : 'post_date' );
146 $filter->order = LP_Helper::sanitize_params_submitted( ! empty( $request['order'] ) ? $request['order'] : 'DESC' );
147 $filter->limit = $request['limit'] ?? LP_Settings::get_option( 'archive_course_limit', 10 );
148 $return_type = $request['return_type'] ?? 'html';
149 if ( 'json' !== $return_type ) {
150 $filter->only_fields = array( 'DISTINCT(ID) AS ID' );
151 }
152
153 $total_rows = 0;
154 $filter = apply_filters( 'lp/api/courses/filter', $filter, $request );
155 $courses = LP_Course::get_courses( $filter, $total_rows );
156 $total_pages = LP_Database::get_total_pages( $filter->limit, $total_rows );
157
158 if ( 'json' === $return_type ) {
159 $response->data->courses = $courses;
160 $response->data->total_pages = $total_pages;
161 } else {
162 // For return data has html
163 if ( $courses ) {
164 global $wp, $post;
165
166 // Pagination
167 $archive_link = get_post_type_archive_link( LP_COURSE_CPT );
168
169 if ( isset( $term_link ) && ! is_wp_error( $term_link ) ) {
170 $archive_link = $term_link;
171 }
172
173 $template_pagination_path = $request['template_pagination_path'] ?? '';
174 if ( ! isset( $request['no_pagination'] ) ) {
175 if ( ! empty( $template_pagination_path ) ) {
176 $response->data->pagination = include $template_pagination_path;
177 } else {
178 $response->data->pagination = learn_press_get_template_content(
179 'loop/course/pagination.php',
180 array(
181 'total' => $total_pages,
182 'paged' => $filter->page,
183 )
184 );
185 }
186 }
187 // End Pagination
188
189 // Content items
190 ob_start();
191 $template_path_item = urldecode( $request['template_path_item'] ?? '' );
192 $template_path = urldecode( $request['template_path'] ?? '' ); // For wrapper all items, no foreach
193 $args_custom = json_decode( wp_unslash( $request['args_custom'] ?? '' ), true );
194
195 // For custom template return all list courses no foreach
196 if ( ! empty( $template_path ) ) {
197 if ( is_array( $args_custom ) && ! empty( $args_custom ) ) {
198 extract( $args_custom );
199 }
200
201 if ( file_exists( $template_path ) ) {
202 include $template_path;
203 }
204 } else {
205 // For custom template return all list courses foreach
206 if ( ! empty( $template_path_item ) ) {
207 if ( isset( $request['args_custom'] ) ) {
208 $args_custom = json_decode( $request['args_custom'], true );
209 }
210
211 $template_path_item = urldecode( $template_path_item );
212 }
213
214 // Todo: tungnx - should rewrite call template
215 foreach ( $courses as $course ) {
216 $post = get_post( $course->ID );
217 setup_postdata( $post );
218
219 if ( ! empty( $template_path_item ) ) {
220 if ( $args_custom ) {
221 extract( $args_custom );
222 }
223
224 if ( file_exists( $template_path_item ) ) {
225 include $template_path_item;
226 }
227 } else {
228 learn_press_get_template_part( 'content', 'course' );
229 }
230 }
231
232 wp_reset_postdata();
233 }
234 // End content items
235 } else {
236 LearnPress::instance()->template( 'course' )->no_courses_found();
237 }
238
239 $response->data->content = ob_get_clean();
240 $response->data->totals = $total_rows;
241
242 $from = 1 + ( $filter->page - 1 ) * $filter->limit;
243 $to = ( $filter->page * $filter->limit > $total_rows ) ? $total_rows : $filter->page * $filter->limit;
244
245 if ( 0 === $total_rows ) {
246 $response->data->from_to = '';
247 } elseif ( 1 === $total_rows ) {
248 $response->data->from_to = esc_html__( 'Showing only one result', 'learnpress' );
249 } else {
250 if ( $from == $to ) {
251 $response->data->from_to = sprintf( esc_html__( 'Showing last course of %s results', 'learnpress' ), $total_rows );
252 } else {
253 $from_to = $from . '-' . $to;
254 $response->data->from_to = sprintf( esc_html__( 'Showing %1$s of %2$s results', 'learnpress' ), $from_to, $total_rows );
255 }
256 }
257 }
258
259 $response->status = 'success';
260 } catch ( Throwable $e ) {
261 $response->message = $e->getMessage();
262 }
263
264 return apply_filters( 'lp/rest-api/frontend/course/archive_course/response', $response );
265 }
266
267 /**
268 * Rest API for Enroll in single course.
269 *
270 * @param WP_REST_Request $request
271 *
272 * @throws Exception .
273 * @author Nhamdv
274 * @editor tungnx
275 * @version 1.0.1
276 * @since 4.0.0
277 * @modify 4.1.2
278 */
279 public function enroll_courses( WP_REST_Request $request ) {
280 $response = new LP_REST_Response();
281 $response->data = new stdClass();
282 $lp_user_items_db = LP_User_Items_DB::getInstance();
283
284 try {
285 $course_id = absint( $request['id'] ?? 0 );
286 $course = learn_press_get_course( $course_id );
287 if ( ! $course ) {
288 throw new Exception( esc_html__( 'Invalid course!', 'learnpress' ) );
289 }
290
291 $user = learn_press_get_current_user();
292 $can_enroll = $user->can_enroll_course( $course_id, false );
293
294 if ( ! $can_enroll->check ) {
295 throw new Exception( $can_enroll->message ?? esc_html__( 'Error: Cannot enroll in the course.', 'learnpress' ) );
296 }
297
298 $filter = new LP_User_Items_Filter();
299 $filter->user_id = get_current_user_id();
300 $filter->item_id = $course_id;
301 $course_item = $lp_user_items_db->get_last_user_course( $filter );
302
303 // Case: if user bought course - or create order manual with order "completed".
304 if ( $course_item && 'purchased' == $course_item->status ) {
305 $user_item_data = [
306 'user_item_id' => $course_item->user_item_id,
307 'graduation' => LP_COURSE_GRADUATION_IN_PROGRESS,
308 'status' => LP_COURSE_ENROLLED,
309 'start_time' => time(),
310 ];
311
312 $user_item_new_or_update = new LP_User_Item_Course( $user_item_data );
313 $result = $user_item_new_or_update->update();
314
315 if ( ! $result ) {
316 throw new Exception( esc_html__( 'Error: Cannot Enroll in the course.', 'learnpress' ) );
317 }
318
319 do_action( 'learnpress/user/course-enrolled', $course_item->ref_id, $course_id, $user->get_id() );
320 } else { // Case enroll course free
321 LearnPress::instance()->session->set( 'order_awaiting_payment', '' );
322
323 $cart = LearnPress::instance()->cart;
324 $checkout = LP_Checkout::instance();
325
326 if ( ! learn_press_enable_cart() ) {
327 $order_awaiting_payment = LearnPress::instance()->session->order_awaiting_payment;
328 $cart->empty_cart();
329 LearnPress::instance()->session->order_awaiting_payment = $order_awaiting_payment;
330 }
331
332 $cart_id = $cart->add_to_cart( $course_id, 1, array() );
333
334 if ( ! $cart_id ) {
335 throw new Exception( esc_html__( 'Error: The course cannot be added to the cart.', 'learnpress' ) );
336 }
337
338 if ( is_user_logged_in() ) {
339 $order_id = $checkout->create_order();
340
341 if ( is_wp_error( $order_id ) ) {
342 throw new Exception( $order_id->get_error_message() );
343 }
344
345 $order = new LP_Order( $order_id );
346
347 $order->payment_complete();
348
349 $cart->empty_cart();
350 }
351 }
352
353 if ( is_user_logged_in() ) {
354 $response->status = 'success';
355 // Course has no items
356 $response->message = esc_html__(
357 'Congrats! You have enrolled in the course successfully. Redirecting...',
358 'learnpress'
359 );
360
361 $response->data->redirect = $course->get_redirect_url_after_enroll();
362
363 if ( empty( $course->count_items() ) ) {
364 $response->data->redirect = get_permalink( $course->get_id() );
365 }
366 } else {
367 $redirect_url = apply_filters(
368 'learnpress/rest-api/courses/enroll/redirect',
369 learn_press_get_page_link( 'checkout' ),
370 $course_id
371 );
372
373 if ( empty( $redirect_url ) ) {
374 throw new Exception( __( 'Error: Please set up a page for checkout.', 'learnpress' ) );
375 } elseif ( ! is_user_logged_in() ) { // Fix case: cache page with user anonymous
376 $redirect_url = LP_Helper::get_link_no_cache( $redirect_url );
377 }
378
379 $response->message = esc_html__( 'Redirecting...', 'learnpress' );
380 $response->data->redirect = $redirect_url;
381 }
382 } catch ( Exception $e ) {
383 $response->message = $e->getMessage();
384 }
385
386 wp_send_json( $response );
387 }
388
389 /**
390 * Rest API for Purchase course in single course.
391 *
392 * @param WP_REST_Request $request .
393 *
394 * @return WP_REST_Response|WP_Error
395 * @throws Exception .
396 * @author Nhamdv
397 */
398 public function purchase_course( WP_REST_Request $request ) {
399 $response = new LP_REST_Response();
400 $response->data = new stdClass();
401 $params = $request->get_params();
402 $lp_user_items_db = LP_User_Items_DB::getInstance();
403
404 try {
405 $course_id = $params['id'];
406 $allow_repurchase_type = $params['repurchaseType'] ?? false;
407
408 if ( ! $course_id ) {
409 throw new Exception( __( 'Error: Invalid Course ID.', 'learnpress' ) );
410 }
411
412 $course = learn_press_get_course( $course_id );
413
414 if ( ! $course ) {
415 throw new Exception( __( 'Error: No Course available.', 'learnpress' ) );
416 }
417
418 $user = learn_press_get_current_user();
419
420 if ( ! $user->can_purchase_course( $course_id ) ) {
421 throw new Exception( esc_html__( 'Error: Cannot purchase the course!', 'learnpress' ) );
422 }
423
424 $latest_user_item_id = 0;
425
426 $filter = new LP_User_Items_Filter();
427 $filter->user_id = get_current_user_id();
428 $filter->item_id = $course_id;
429 $course_item = $lp_user_items_db->get_last_user_course( $filter );
430
431 if ( $course_item && isset( $course_item->user_item_id ) ) {
432 $latest_user_item_id = $course_item->user_item_id;
433 }
434
435 if ( $course->allow_repurchase() && ! empty( $latest_user_item_id ) && empty( $allow_repurchase_type ) ) {
436 if ( $course->allow_repurchase_course_option() === 'popup' ) {
437 ob_start();
438 ?>
439 <div class="lp_allow_repuchase_select">
440 <ul>
441 <li>
442 <label>
443 <input name="_lp_allow_repurchase_type" value="reset" type="radio" checked="checked" />
444 <?php esc_html_e( 'Reset Course progress', 'learnpress' ); ?>
445 </label>
446 </li>
447 <li>
448 <label>
449 <input name="_lp_allow_repurchase_type" value="keep" type="radio" />
450 <?php esc_html_e( 'Continue Course progress', 'learnpress' ); ?>
451 </label>
452 </li>
453 </ul>
454 </div>
455 <?php
456 $response->data->html = ob_get_clean();
457 $response->data->type = 'allow_repurchase';
458 $response->data->titlePopup = esc_html__( 'Repurchase Options', 'learnpress' );
459 $response->status = 'success';
460
461 return rest_ensure_response( $response );
462 } else {
463 learn_press_update_user_item_meta( $latest_user_item_id, '_lp_allow_repurchase_type', $course->allow_repurchase_course_option() );
464 }
465 }
466
467 LearnPress::instance()->session->set( 'order_awaiting_payment', '' );
468
469 $cart = LearnPress::instance()->cart;
470 $checkout = LP_Checkout::instance();
471
472 if ( ! learn_press_enable_cart() ) {
473 $order_awaiting_payment = LearnPress::instance()->session->order_awaiting_payment;
474 $cart->empty_cart();
475 LearnPress::instance()->session->order_awaiting_payment = $order_awaiting_payment;
476 }
477
478 do_action( 'learnpress/rest-api/courses/purchase/before-add-to-cart' );
479
480 $cart_id = $cart->add_to_cart( $course_id, 1, array() );
481
482 if ( ! $cart_id ) {
483 throw new Exception( __( 'Error: The course cannot be added to the cart.', 'learnpress' ) );
484 }
485
486 if ( ! empty( $allow_repurchase_type ) ) {
487 learn_press_update_user_item_meta( $latest_user_item_id, '_lp_allow_repurchase_type', $allow_repurchase_type );
488 }
489
490 $redirect_url = apply_filters(
491 'learnpress/rest-api/courses/purchase/redirect',
492 learn_press_get_page_link( 'checkout' ),
493 $course_id,
494 $cart_id
495 );
496
497 if ( empty( $redirect_url ) ) {
498 throw new Exception( __( 'Error: Please set up a page for checkout.', 'learnpress' ) );
499 } elseif ( ! is_user_logged_in() ) { // Fix case: cache page with user anonymous
500 $redirect_url = LP_Helper::get_link_no_cache( $redirect_url );
501 }
502
503 $response->status = 'success';
504 $response->message = sprintf(
505 esc_html__( '"%s" has been added to your cart.', 'learnpress' ),
506 $course->get_title()
507 );
508 $response->data->redirect = $redirect_url;
509 } catch ( Exception $e ) {
510 $response->message = $e->getMessage();
511 }
512
513 return rest_ensure_response( $response );
514 }
515
516 /**
517 * Rest API for retake course.
518 *
519 * @param WP_REST_Request $request .
520 *
521 * @throws Exception .
522 */
523 public function retake_course( WP_REST_Request $request ) {
524 $response = new LP_REST_Response();
525
526 try {
527 $course_id = $request->get_param( 'id' );
528
529 if ( ! $course_id ) {
530 throw new Exception( __( 'Invalid params', 'learnpress' ) );
531 }
532
533 $course = learn_press_get_course( $course_id );
534
535 if ( ! $course ) {
536 throw new Exception( __( 'Invalid course', 'learnpress' ) );
537 }
538
539 $user = learn_press_get_current_user();
540
541 // if ( ! is_user_logged_in() ) {
542 // throw new Exception( esc_html__( 'Please login!', 'learnpress' ) );
543 // }
544
545 $can_retry = $user->can_retry_course( $course_id );
546
547 if ( ! $can_retry ) {
548 throw new Exception( __( 'You can\'t retry the course', 'learnpress' ) );
549 }
550
551 $user_course_data = $user->get_course_data( $course_id );
552 if ( ! $user_course_data ) {
553 throw new Exception( __( 'Invalid course data of user', 'learnpress' ) );
554 }
555
556 // Up retaken.
557 $user_course_data->increase_retake_count();
558
559 // Set status, start_time, end_time of course to enrol.
560 $user_course_data->set_status( LP_COURSE_ENROLLED )
561 ->set_start_time( time() )
562 ->set_end_time()
563 ->set_graduation( LP_COURSE_GRADUATION_IN_PROGRESS )
564 ->update();
565
566 // Remove items' course user learned.
567 $filter_remove = new LP_User_Items_Filter();
568 $filter_remove->parent_id = $user_course_data->get_user_item_id();
569 $filter_remove->user_id = $user_course_data->get_user_id();
570 $filter_remove->limit = - 1;
571 LP_User_Items_DB::getInstance()->remove_items_of_user_course( $filter_remove );
572
573 // Create new result in table learnpress_user_item_results.
574 LP_User_Items_Result_DB::instance()->insert( $user_course_data->get_user_item_id() );
575
576 $response->status = 'success';
577 $response->message = esc_html__( 'Now you can learn this course', 'learnpress' );
578 $response->data->url_redirect = $course->get_redirect_url_after_enroll();
579 } catch ( Exception $e ) {
580 $response->message = $e->getMessage();
581 }
582
583 wp_send_json( $response );
584 }
585
586 /**
587 * @param WP_REST_Request $request
588 *
589 * @return WP_REST_Response
590 */
591 public function get_items( $request ) {
592 $settings = LP_Settings::instance();
593 $response = array(
594 'result' => $settings->get(),
595 );
596
597 return rest_ensure_response( $response );
598 }
599
600 /**
601 * @param WP_REST_Request $request
602 *
603 * @return WP_REST_Response
604 */
605 public function get_item( $request ) {
606 $settings = LP_Settings::instance();
607 $response = array(
608 'result' => $settings->get( $request['key'] ),
609 );
610
611 return rest_ensure_response( $response );
612 }
613
614 /**
615 * @param WP_REST_Request $request
616 *
617 * @return WP_REST_Response
618 */
619 public function update_item( $request ) {
620 $response = array();
621 $settings = LP_Settings::instance();
622 $option = $settings->get( $request['key'] );
623
624 $settings->update( $request['key'], $request['data'] );
625 $new_option = $settings->get( $request['key'] );
626 $success = maybe_serialize( $option ) !== maybe_serialize( $new_option );
627
628 $response['success'] = $success;
629 $response['result'] = $success ? $new_option : $option;
630
631 return rest_ensure_response( $response );
632 }
633
634 /**
635 * @param WP_REST_Request $request
636 *
637 * @return WP_REST_Response
638 */
639 public function delete_item( $request ) {
640 $response = array();
641
642 return rest_ensure_response( $response );
643 }
644
645 /**
646 * Rest API for Continue in single course.
647 *
648 * @param WP_REST_Request $request
649 * @author minhpd
650 * @editor tungnx
651 * @since 4.1.4
652 * @version 1.0.2
653 */
654 public function continue_course( WP_REST_Request $request ) {
655 $params = $request->get_params();
656 $response = new LP_REST_Response();
657 $response->data = '';
658
659 try {
660 $flag_found = false;
661 $item_link = '';
662 $course_id = absint( $params['courseId'] ?? 0 );
663 $user_id = absint( $params['userId'] ?? 0 );
664
665 $user = learn_press_get_user( $user_id );
666 $course = learn_press_get_course( $course_id );
667
668 if ( ! $course ) {
669 throw new Exception( __( 'Invalid course', 'learnpress' ) );
670 }
671
672 $sections_items = $course->get_full_sections_and_items_course();
673 $total_items = $course->count_items();
674
675 if ( ! empty( $total_items ) ) {
676 foreach ( $sections_items as $section_items ) {
677 if ( $flag_found ) {
678 break;
679 }
680
681 foreach ( $section_items->items as $item ) {
682 if ( ! $user->has_completed_item( $item->id, $course_id ) ) {
683 $item_link = $course->get_item_link( $item->id );
684 $flag_found = true;
685 break;
686 }
687 }
688 }
689
690 if ( ! $flag_found ) {
691 $item_link = $course->get_item_link( $course->get_first_item_id() );
692 }
693 }
694
695 $response->data = $item_link;
696 $response->status = 'success';
697 $response->message = '';
698 } catch ( Exception $e ) {
699 $response->message = $e->getMessage();
700 }
701
702 wp_send_json( $response );
703 }
704
705 }
706