PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.9
4.4.10 4.4.9.1 4.4.9 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 All 142 releases
← All changes | inc/rest-api/v1/frontend/class-lp-rest-courses-controller.php +474 -286 4.1.7.3.2 → 4.4.9 View file →
@@ -2,8 +2,23 @@
2 2
3 3 /**
4 4 * Class LP_REST_Courses_Controller
5 5 */
6 +
7 +use LearnPress\Background\LPBackgroundAjax;
8 +use LearnPress\ExternalPlugin\Elementor\Widgets\Course\ListCoursesByPageElementor;
9 +use LearnPress\Filters\Course\CourseJsonFilter;
10 +use LearnPress\Helpers\Response;
11 +use LearnPress\Helpers\Template;
12 +use LearnPress\Models\CourseModel;
13 +use LearnPress\Models\PostModel;
14 +use LearnPress\Models\UserItems\UserCourseModel;
15 +use LearnPress\Models\UserItems\UserItemModel;
16 +use LearnPress\Models\UserModel;
17 +use LearnPress\Services\CourseService;
18 +use LearnPress\TemplateHooks\Course\ListCoursesTemplate;
19 +use LearnPress\TemplateHooks\Course\SingleCourseTemplate;
20 +
6 21 class LP_REST_Courses_Controller extends LP_Abstract_REST_Controller {
7 22 /**
8 23 * LP_REST_Courses_Controller constructor.
9 24 */
@@ -17,16 +32,38 @@
17 32 * Register routes API
18 33 */
19 34 public function register_routes() {
20 35 $this->routes = array(
21 - 'purchase-course' => array(
36 + '' => array(
22 37 array(
38 + 'methods' => WP_REST_Server::ALLMETHODS,
39 + 'callback' => array( $this, 'get_courses' ),
40 + ),
41 + ),
42 + 'edit-archive-block' => array(
43 + array(
44 + 'methods' => WP_REST_Server::ALLMETHODS,
45 + 'callback' => array( $this, 'get_courses_archive_block' ),
46 + 'permission_callback' => '__return_true',
47 + 'args' => array(),
48 + ),
49 + ),
50 + 'courses-suggest' => array(
51 + array(
52 + 'methods' => WP_REST_Server::ALLMETHODS,
53 + 'callback' => array( $this, 'courses_suggest' ),
54 + 'permission_callback' => '__return_true',
55 + 'args' => [],
56 + ),
57 + ),
58 + 'purchase-course' => array(
59 + array(
23 60 'methods' => WP_REST_Server::CREATABLE,
24 61 'callback' => array( $this, 'purchase_course' ),
25 62 'permission_callback' => '__return_true',
26 63 ),
27 64 ),
28 - 'enroll-course' => array(
65 + 'enroll-course' => array(
29 66 array(
30 67 'methods' => WP_REST_Server::CREATABLE,
31 68 'callback' => array( $this, 'enroll_courses' ),
32 69 'permission_callback' => '__return_true',
@@ -31,9 +68,9 @@
31 68 'callback' => array( $this, 'enroll_courses' ),
32 69 'permission_callback' => '__return_true',
33 70 ),
34 71 ),
35 - 'retake-course' => array(
72 + 'retake-course' => array(
36 73 array(
37 74 'methods' => WP_REST_Server::CREATABLE,
38 75 'callback' => array( $this, 'retake_course' ),
39 76 'permission_callback' => function () {
@@ -43,9 +80,9 @@
43 80 'type' => 'int',
44 81 ),
45 82 ),
46 83 ),
47 - 'archive-course' => array(
84 + /*'archive-course' => array(
48 85 array(
49 86 'methods' => WP_REST_Server::ALLMETHODS,
50 87 'callback' => array( $this, 'list_courses' ),
51 88 'permission_callback' => '__return_true',
@@ -50,10 +87,18 @@
50 87 'callback' => array( $this, 'list_courses' ),
51 88 'permission_callback' => '__return_true',
52 89 'args' => [],
53 90 ),
91 + ),*/
92 + 'courses-widget-by-page' => array(
93 + array(
94 + 'methods' => WP_REST_Server::ALLMETHODS,
95 + 'callback' => array( $this, 'courses_widget_by_page' ),
96 + 'permission_callback' => '__return_true',
97 + 'args' => [],
98 + ),
54 99 ),
55 - '(?P<key>[\w]+)' => array(
100 + '(?P<key>[\w]+)' => array(
56 101 'args' => array(
57 102 'id' => array(
58 103 'description' => __( 'A unique identifier for the resource.', 'learnpress' ),
59 104 'type' => 'string',
@@ -76,15 +121,13 @@
76 121 'permission_callback' => array( $this, 'check_admin_permission' ),
77 122 ),
78 123 'schema' => array( $this, 'get_public_item_schema' ),
79 124 ),
80 - 'continue-course' => array(
125 + 'continue-course' => array(
81 126 array(
82 127 'methods' => WP_REST_Server::CREATABLE,
83 128 'callback' => array( $this, 'continue_course' ),
84 - 'permission_callback' => function () {
85 - return is_user_logged_in();
86 - },
129 + 'permission_callback' => '__return_true',
87 130 ),
88 131 ),
89 132 );
90 133
@@ -100,139 +143,268 @@
100 143 return LP_Abstract_API::check_admin_permission();
101 144 }
102 145
103 146 /**
104 - * Get list courses
147 + * Get list courses, return JSON data, not to handle HTML
105 148 *
106 149 * @param WP_REST_Request $request
107 150 *
108 - * @return LP_REST_Response
151 + * @return Response
152 + * @since 4.2.8.2
153 + * @version 1.0.1
109 154 */
110 - public function list_courses( WP_REST_Request $request ): LP_REST_Response {
111 - $response = new LP_REST_Response();
112 - $response->data = new stdClass();
155 + public function get_courses( WP_REST_Request $request ): Response {
156 + $response = new Response();
113 157
114 158 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;
159 + $filter = new CourseJsonFilter();
160 + $params = $request->get_params();
161 + $total_rows = 0;
162 +
163 + CourseService::handle_params_for_query_list_courses( $filter, $params );
164 + $filter->only_fields = [ CourseJsonFilter::COL_ID ];
165 +
166 + $coursesRs = CourseService::get_list_courses( $filter, $total_rows );
167 +
168 + $courses = [];
169 + foreach ( $coursesRs as $course ) {
170 + $courseModel = CourseModel::find( $course->ID, true );
171 + $allow_fields = apply_filters(
172 + 'lp/rest-api/courses/allow_fields',
173 + [
174 + CourseJsonFilter::COL_ID,
175 + CourseJsonFilter::COL_POST_TITLE,
176 + CourseJsonFilter::COL_POST_NAME,
177 + CourseJsonFilter::COL_POST_AUTHOR,
178 + CourseJsonFilter::COL_LANG,
179 + CourseJsonFilter::COL_IS_SALE,
180 + ],
181 + $courseModel,
182 + $params
183 + );
184 + if ( ! $courseModel ) {
185 + continue;
186 + }
187 +
188 + $course_info = new stdClass();
189 + foreach ( $allow_fields as $field ) {
190 + $course_info->$field = $courseModel->$field;
191 + }
192 +
193 + $courses[] = $course_info;
123 194 }
124 - if ( ! empty( $fields_exclude_str ) ) {
125 - $fields_exclude = explode( ',', $fields_exclude_str );
126 - $filter->exclude_fields = $fields_exclude;
195 +
196 + $response->status = Response::STATUS_SUCCESS;
197 + $response->data->courses = $courses;
198 + $response->data->total = $total_rows;
199 + $response->data->page = $filter->page;
200 + $response->data->total_pages = LP_Database::get_total_pages( $filter->limit, $total_rows );
201 + } catch ( Throwable $e ) {
202 + $response->message = $e->getMessage();
203 + }
204 +
205 + return apply_filters( 'lp/rest-api/frontend/course/archive_course/response', $response );
206 + }
207 +
208 + /**
209 + * Get list courses display layout when edit on archive block
210 + *
211 + * @param WP_REST_Request $request
212 + *
213 + * @return Response
214 + * @since 4.3.7
215 + * @version 1.0.0
216 + */
217 + public function get_courses_archive_block( WP_REST_Request $request ): Response {
218 + $response = new Response();
219 +
220 + try {
221 + $filter = new CourseJsonFilter();
222 + $params = $request->get_params();
223 + $total_rows = 0;
224 +
225 + CourseService::handle_params_for_query_list_courses( $filter, $params );
226 + // For permission, it only displays for Editor easy config layout, not for get data primary
227 + $filter->only_fields = [ CourseJsonFilter::COL_ID ];
228 + $filter->post_status = [ PostModel::STATUS_PUBLISH ];
229 + $coursesRs = CourseService::get_list_courses( $filter, $total_rows );
230 +
231 + $courses = [];
232 + $singleCourseTemplate = SingleCourseTemplate::instance();
233 + foreach ( $coursesRs as $course ) {
234 + $courseModel = CourseModel::find( $course->ID, true );
235 + if ( ! $courseModel ) {
236 + continue;
237 + }
238 +
239 + $courseItem = new stdClass();
240 + $courseItem->ID = $course->ID;
241 + $courseItem->description = $singleCourseTemplate->html_short_description( $courseModel );
242 + $courseItem->price = $singleCourseTemplate->html_price( $courseModel );
243 + $courseItem->title = $courseModel->get_title();
244 + $courseItem->student = $singleCourseTemplate->html_count_student( $courseModel );
245 + $courseItem->lesson = $singleCourseTemplate->html_count_item( $courseModel, LP_LESSON_CPT );
246 + $courseItem->duration = $singleCourseTemplate->html_duration( $courseModel );
247 + $courseItem->quiz = $singleCourseTemplate->html_count_item( $courseModel, LP_QUIZ_CPT );
248 + $courseItem->level = $singleCourseTemplate->html_level( $courseModel );
249 + $courseItem->image = $singleCourseTemplate->html_image( $courseModel );
250 + $courseItem->instructor = $singleCourseTemplate->html_instructor( $courseModel, false, [ 'is_link' => false ] );
251 + $courseItem->category = $singleCourseTemplate->html_categories( $courseModel );
252 + $courseItem->button = __( 'Read more', 'learnpress' );
253 +
254 + $courses[] = apply_filters( 'lp/rest-api/frontend/course/archive_course/courses', $courseItem, $courseModel );
127 255 }
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;
256 +
257 + $response->status = Response::STATUS_SUCCESS;
258 + $response->data->courses = $courses;
259 + $response->data->total = $total_rows;
260 + $response->data->page = $filter->page;
261 + $response->data->total_pages = LP_Database::get_total_pages( $filter->limit, $total_rows );
262 + } catch ( Throwable $e ) {
263 + $response->message = $e->getMessage();
264 + }
265 +
266 + return apply_filters( 'lp/rest-api/frontend/course/archive_course/response', $response );
267 + }
268 +
269 + /**
270 + * Get list courses for search suggest
271 + *
272 + * @param WP_REST_Request $request
273 + *
274 + * @return Response
275 + * @since 4.3.7
276 + * @version 1.0.0
277 + */
278 + public function courses_suggest( WP_REST_Request $request ): Response {
279 + $response = new Response();
280 +
281 + try {
282 + $filter = new CourseJsonFilter();
283 + $params = $request->get_params();
284 + $total_rows = 0;
285 +
286 + CourseService::handle_params_for_query_list_courses( $filter, $params );
287 + $filter->only_fields = [ CourseJsonFilter::COL_ID ];
288 + $filter->post_status = [ PostModel::STATUS_PUBLISH ];
289 +
290 + $coursesRs = CourseService::get_list_courses( $filter, $total_rows );
291 +
292 + $courses = [];
293 + foreach ( $coursesRs as $course ) {
294 + $courseModel = CourseModel::find( $course->ID, true );
295 + $courses[] = $courseModel;
133 296 }
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 297
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' : '';
298 + $data = array(
299 + 'courses' => $courses,
300 + 'keyword' => $request['c_search'],
301 + 'total_course' => $total_rows,
302 + );
303 + ob_start();
304 + do_action( 'learn-press/rest-api/courses/suggest/layout', $data );
305 + $response->data->content = ob_get_clean();
306 + $response->data->totals = $total_rows;
307 + $response->status = Response::STATUS_SUCCESS;
308 + } catch ( Throwable $e ) {
309 + $response->message = $e->getMessage();
310 + }
144 311
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 - }
312 + return apply_filters( 'lp/rest-api/courses-search-suggest/response', $response );
313 + }
152 314
315 + /**
316 + * Get list courses
317 + *
318 + * @param WP_REST_Request $request
319 + *
320 + * @depreacted 4.3.7
321 + * @return LP_REST_Response
322 + */
323 + public function list_courses( WP_REST_Request $request ): LP_REST_Response {
324 + $response = new LP_REST_Response();
325 + $response->data = new stdClass();
326 + $listCoursesTemplate = ListCoursesTemplate::instance();
327 + $pagination_type = LP_Settings::get_option( 'course_pagination_type' );
328 +
329 + try {
330 + throw new Exception( 'Deprecated function from 4.3.7' );
331 + $filter = new CourseJsonFilter();
332 + $params = $request->get_params();
333 + $params['c_status'] = 'publish';
334 + $params['c_fields'] = 'ID, post_title, post_content, post_status, post_author, meta_input';
335 + CourseService::handle_params_for_query_list_courses( $filter, $params );
336 +
337 + // Check is in category page.
338 + /*if ( ! empty( $request->get_param( 'page_term_id_current' ) ) &&
339 + empty( $request->get_param( 'term_id' ) ) ) {
340 + $filter->term_ids[] = $request->get_param( 'page_term_id_current' );
341 + } // Check is in tag page.
342 + elseif ( ! empty( $request->get_param( 'page_tag_id_current' ) ) &&
343 + empty( $request->get_param( 'tag_id' ) ) ) {
344 + $filter->tag_ids[] = $request->get_param( 'page_tag_id_current' );
345 + }*/
346 +
153 347 $total_rows = 0;
154 - $filter = apply_filters( 'lp/api/courses/filter', $filter, $request );
155 - $courses = LP_Course::get_courses( $filter, $total_rows );
348 + $courses = CourseService::get_list_courses( $filter, $total_rows );
156 349 $total_pages = LP_Database::get_total_pages( $filter->limit, $total_rows );
157 -
350 + $return_type = $request['return_type'] ?? 'html';
158 351 if ( 'json' === $return_type ) {
159 352 $response->data->courses = $courses;
160 353 $response->data->total_pages = $total_pages;
161 354 } else {
162 355 // For return data has html
356 + ob_start();
163 357 if ( $courses ) {
164 - global $wp, $post;
358 + if ( ! empty( $request['c_suggest'] ) ) {
359 + $data = array(
360 + 'courses' => $courses,
361 + 'keyword' => $request['c_search'],
362 + 'total_course' => $total_rows,
363 + );
364 + do_action( 'learn-press/rest-api/courses/suggest/layout', $data );
365 + } else {
366 + global $wp, $post;
165 367
166 - // Pagination
167 - $archive_link = get_post_type_archive_link( LP_COURSE_CPT );
368 + // Template Pagination.
369 + switch ( $pagination_type ) {
370 + case 'load-more':
371 + if ( $filter->page < $total_pages ) {
372 + $response->data->pagination = $listCoursesTemplate->html_pagination_load_more();
373 + }
374 + break;
375 + case 'infinite':
376 + if ( $filter->page < $total_pages ) {
377 + $response->data->pagination = $listCoursesTemplate->html_pagination_infinite();
378 + }
379 + break;
380 + default:
381 + $pagination_args = [
382 + 'total_pages' => $total_pages,
383 + 'paged' => $filter->page,
384 + 'base' => add_query_arg( 'paged', '%#%', learn_press_get_page_link( 'courses' ) ),
385 + ];
386 + $response->data->pagination = $listCoursesTemplate->html_pagination_number( $pagination_args );
387 + break;
388 + }
389 + $response->data->pagination_type = $pagination_type;
390 + // End Pagination
168 391
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;
392 + // For custom template
393 + $template_path = apply_filters( 'lp/api/courses/template', '', $request );
394 + if ( ! empty( $template_path ) ) {
395 + Template::instance()->get_template( $template_path, compact( 'courses', 'total_pages', 'request' ) );
177 396 } 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 );
397 + foreach ( $courses as $course ) {
398 + $post = get_post( $course->ID );
399 + setup_postdata( $post );
400 + Template::instance()->get_frontend_template( 'content-course.php' );
209 401 }
210 402
211 - $template_path_item = urldecode( $template_path_item );
403 + wp_reset_postdata();
212 404 }
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();
405 + // End content items
233 406 }
234 - // End content items
235 407 } else {
236 408 LearnPress::instance()->template( 'course' )->no_courses_found();
237 409 }
238 410
@@ -249,9 +421,21 @@
249 421 } else {
250 422 if ( $from == $to ) {
251 423 $response->data->from_to = sprintf( esc_html__( 'Showing last course of %s results', 'learnpress' ), $total_rows );
252 424 } else {
253 - $from_to = $from . '-' . $to;
425 + switch ( $pagination_type ) {
426 + case 'load-more':
427 + case 'infinite':
428 + $from_to = $filter->page * $filter->limit;
429 + if ( $from_to > $total_rows ) {
430 + $from_to = $total_rows;
431 + }
432 + break;
433 + default:
434 + $from_to = $from . '-' . $to;
435 + break;
436 + }
437 +
254 438 $response->data->from_to = sprintf( esc_html__( 'Showing %1$s of %2$s results', 'learnpress' ), $from_to, $total_rows );
255 439 }
256 440 }
257 441 }
@@ -257,9 +441,10 @@
257 441 }
258 442
259 443 $response->status = 'success';
260 444 } catch ( Throwable $e ) {
261 - $response->message = $e->getMessage();
445 + $response->data->content = $e->getMessage();
446 + $response->message = $e->getMessage();
262 447 }
263 448
264 449 return apply_filters( 'lp/rest-api/frontend/course/archive_course/response', $response );
265 450 }
@@ -264,74 +449,100 @@
264 449 return apply_filters( 'lp/rest-api/frontend/course/archive_course/response', $response );
265 450 }
266 451
267 452 /**
453 + * Get list courses - Widget Elementor
454 + *
455 + * @param WP_REST_Request $request
456 + *
457 + * @return LP_REST_Response
458 + */
459 + public function courses_widget_by_page( WP_REST_Request $request ): LP_REST_Response {
460 + $response = new LP_REST_Response();
461 + $response->data = new stdClass();
462 +
463 + try {
464 + $settings = array_merge(
465 + $request->get_params(),
466 + [
467 + 'courses_ul_classes' => [ 'list-courses-elm' ],
468 + ]
469 + );
470 + $response->data->content = ListCoursesByPageElementor::render_data_from_setting( $settings );
471 +
472 + $response->status = 'success';
473 + } catch ( Throwable $e ) {
474 + ob_end_clean();
475 + $response->data->content = $e->getMessage();
476 + $response->message = $e->getMessage();
477 + }
478 +
479 + return apply_filters( 'lp/rest-api/frontend/course/archive_course/response', $response );
480 + }
481 +
482 + /**
268 483 * Rest API for Enroll in single course.
269 484 *
270 485 * @param WP_REST_Request $request
271 486 *
272 - * @throws Exception .
487 + * @return LP_REST_Response
273 488 * @author Nhamdv
274 489 * @editor tungnx
275 - * @version 1.0.1
490 + * @version 1.0.3
276 491 * @since 4.0.0
277 - * @modify 4.1.2
278 492 */
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();
493 + public function enroll_courses( WP_REST_Request $request ): LP_REST_Response {
494 + $response = new LP_REST_Response();
495 + $response->data = new stdClass();
283 496
284 497 try {
285 498 $course_id = absint( $request['id'] ?? 0 );
286 - $course = learn_press_get_course( $course_id );
499 + $course = CourseModel::find( $course_id, true );
287 500 if ( ! $course ) {
288 501 throw new Exception( esc_html__( 'Invalid course!', 'learnpress' ) );
289 502 }
290 503
291 - $user = learn_press_get_current_user();
292 - $can_enroll = $user->can_enroll_course( $course_id, false );
504 + $user_id = get_current_user_id();
505 + $user = UserModel::find( $user_id, true );
506 + $can_enroll = $course->can_enroll( $user );
507 + if ( $can_enroll instanceof WP_Error ) {
508 + throw new Exception( $can_enroll->get_error_message() );
509 + }
293 510
294 - if ( ! $can_enroll->check ) {
295 - throw new Exception( $can_enroll->message ?? esc_html__( 'Error: Cannot enroll in the course.', 'learnpress' ) );
296 - }
511 + // Case: if user bought course
512 + $userCourse = UserCourseModel::find( $user_id, $course_id, true );
513 + if ( $userCourse && $userCourse->has_purchased() ) {
514 + $userCourse->graduation = LP_COURSE_GRADUATION_IN_PROGRESS;
515 + $userCourse->status = LP_COURSE_ENROLLED;
516 + $userCourse->start_time = gmdate( LP_Datetime::$format, time() );
517 + $userCourse->save();
297 518
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 );
519 + do_action( 'learnpress/user/course-enrolled', $userCourse->ref_id, $course_id, $user->get_id() );
302 520
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(),
521 + /**
522 + * Send mail user enrolled course
523 + * @uses SendEmailAjax::send_mail_user_enrolled_course()
524 + */
525 + $data_send = [
526 + $userCourse->ref_id,
527 + $course_id,
528 + $user->get_id(),
310 529 ];
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() );
530 + LPBackgroundAjax::handle(
531 + [
532 + 'params' => $data_send,
533 + 'lp-load-ajax' => 'send_mail_user_enrolled_course',
534 + ]
535 + );
320 536 } else { // Case enroll course free
321 - LearnPress::instance()->session->set( 'order_awaiting_payment', '' );
322 -
323 537 $cart = LearnPress::instance()->cart;
324 538 $checkout = LP_Checkout::instance();
325 539
326 540 if ( ! learn_press_enable_cart() ) {
327 - $order_awaiting_payment = LearnPress::instance()->session->order_awaiting_payment;
328 541 $cart->empty_cart();
329 - LearnPress::instance()->session->order_awaiting_payment = $order_awaiting_payment;
330 542 }
331 543
332 - $cart_id = $cart->add_to_cart( $course_id, 1, array() );
333 -
544 + $cart_id = $cart->add_to_cart( $course_id );
334 545 if ( ! $cart_id ) {
335 546 throw new Exception( esc_html__( 'Error: The course cannot be added to the cart.', 'learnpress' ) );
336 547 }
337 548
@@ -336,15 +547,9 @@
336 547 }
337 548
338 549 if ( is_user_logged_in() ) {
339 550 $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 -
551 + $order = new LP_Order( $order_id );
347 552 $order->payment_complete();
348 553
349 554 $cart->empty_cart();
350 555 }
@@ -350,41 +555,38 @@
350 555 }
351 556 }
352 557
353 558 if ( is_user_logged_in() ) {
354 - $response->status = 'success';
355 - // Course has no items
356 559 $response->message = esc_html__(
357 560 'Congrats! You have enrolled in the course successfully. Redirecting...',
358 561 'learnpress'
359 562 );
360 563
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 - }
564 + $first_item_id = $course->get_first_item_id();
565 + $response->data->redirect = $first_item_id ? $course->get_item_link( $first_item_id ) : get_the_permalink( $course->get_id() );
366 566 } else {
567 + $redirect_url = LP_Page_Controller::get_link_page( 'checkout', [], true );
367 568 $redirect_url = apply_filters(
368 569 'learnpress/rest-api/courses/enroll/redirect',
369 - learn_press_get_page_link( 'checkout' ),
570 + $redirect_url,
370 571 $course_id
371 572 );
372 573
373 574 if ( empty( $redirect_url ) ) {
374 575 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 576 }
378 577
578 + $redirect_url = LP_Helper::get_link_no_cache( $redirect_url );
379 579 $response->message = esc_html__( 'Redirecting...', 'learnpress' );
380 - $response->data->redirect = $redirect_url;
580 + $response->data->redirect = esc_url_raw( $redirect_url );
381 581 }
582 +
583 + $response->status = 'success';
382 584 } catch ( Exception $e ) {
383 585 $response->message = $e->getMessage();
384 586 }
385 587
386 - wp_send_json( $response );
588 + return $response;
387 589 }
388 590
389 591 /**
390 592 * Rest API for Purchase course in single course.
@@ -395,12 +597,11 @@
395 597 * @throws Exception .
396 598 * @author Nhamdv
397 599 */
398 600 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();
601 + $response = new LP_REST_Response();
602 + $response->data = new stdClass();
603 + $params = $request->get_params();
403 604
404 605 try {
405 606 $course_id = $params['id'];
406 607 $allow_repurchase_type = $params['repurchaseType'] ?? false;
@@ -408,89 +609,79 @@
408 609 if ( ! $course_id ) {
409 610 throw new Exception( __( 'Error: Invalid Course ID.', 'learnpress' ) );
410 611 }
411 612
412 - $course = learn_press_get_course( $course_id );
413 -
613 + $course = CourseModel::find( $course_id, true );
414 614 if ( ! $course ) {
415 615 throw new Exception( __( 'Error: No Course available.', 'learnpress' ) );
416 616 }
417 617
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' ) );
618 + $user_id = get_current_user_id();
619 + $user = UserModel::find( $user_id, true );
620 + $can_purchase = $course->can_purchase( $user );
621 + if ( $can_purchase instanceof WP_Error ) {
622 + throw new Exception( $can_purchase->get_error_message() );
422 623 }
423 624
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;
625 + $userCourse = UserCourseModel::find( $user_id, $course_id, true );
626 + $option_repurchase = [
627 + 'reset' => esc_html__( 'Reset course progress', 'learnpress' ),
628 + 'keep' => esc_html__( 'Keep course progress', 'learnpress' ),
629 + ];
630 + $html_li_repurchase = '';
631 + foreach ( $option_repurchase as $key => $value ) {
632 + $html_li_repurchase .= sprintf(
633 + '<li><label>%s</label></li>',
634 + sprintf(
635 + '<input name="_lp_allow_repurchase_type" value="%s" type="radio" checked="checked"/> %s',
636 + $key,
637 + $value
638 + )
639 + );
433 640 }
434 641
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();
642 + $repurchase_type = $course->get_type_repurchase();
643 + $section_popup_repurchase = [
644 + 'wrapper' => '<div class="lp_allow_repurchase_select">',
645 + 'ul' => '<ul>',
646 + 'list' => $html_li_repurchase,
647 + 'ul_end' => '</ul>',
648 + 'wrapper_end' => '</div>',
649 + ];
650 + if ( $course->enable_allow_repurchase()
651 + && $user_id && $userCourse
652 + && empty( $allow_repurchase_type ) ) {
653 + if ( $repurchase_type === 'popup' ) {
654 + $response->data->html = Template::combine_components( $section_popup_repurchase );
457 655 $response->data->type = 'allow_repurchase';
458 656 $response->data->titlePopup = esc_html__( 'Repurchase Options', 'learnpress' );
459 657 $response->status = 'success';
460 658
461 659 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 660 }
465 661 }
466 662
467 - LearnPress::instance()->session->set( 'order_awaiting_payment', '' );
468 -
469 - $cart = LearnPress::instance()->cart;
470 - $checkout = LP_Checkout::instance();
471 -
663 + $cart = LearnPress::instance()->cart;
472 664 if ( ! learn_press_enable_cart() ) {
473 - $order_awaiting_payment = LearnPress::instance()->session->order_awaiting_payment;
474 665 $cart->empty_cart();
475 - LearnPress::instance()->session->order_awaiting_payment = $order_awaiting_payment;
476 666 }
477 667
478 - do_action( 'learnpress/rest-api/courses/purchase/before-add-to-cart' );
668 + // @deprecated hook since v4.2.7.3
669 + //do_action( 'learnpress/rest-api/courses/purchase/before-add-to-cart' );
479 670
480 - $cart_id = $cart->add_to_cart( $course_id, 1, array() );
481 -
482 - if ( ! $cart_id ) {
671 + $cart_id = $cart->add_to_cart( $course_id, 1, $params );
672 + if ( empty( $cart_id ) ) {
483 673 throw new Exception( __( 'Error: The course cannot be added to the cart.', 'learnpress' ) );
484 674 }
485 675
486 - if ( ! empty( $allow_repurchase_type ) ) {
487 - learn_press_update_user_item_meta( $latest_user_item_id, '_lp_allow_repurchase_type', $allow_repurchase_type );
676 + if ( ! empty( $allow_repurchase_type ) && $userCourse ) {
677 + learn_press_update_user_item_meta( $userCourse->get_user_item_id(), '_lp_allow_repurchase_type', $allow_repurchase_type );
488 678 }
489 679
680 + $redirect_url = LP_Page_Controller::get_link_page( 'checkout', [], true );
490 681 $redirect_url = apply_filters(
491 682 'learnpress/rest-api/courses/purchase/redirect',
492 - learn_press_get_page_link( 'checkout' ),
683 + $redirect_url,
493 684 $course_id,
494 685 $cart_id
495 686 );
496 687
@@ -495,18 +686,17 @@
495 686 );
496 687
497 688 if ( empty( $redirect_url ) ) {
498 689 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 690 }
502 691
692 + $redirect_url = LP_Helper::get_link_no_cache( $redirect_url );
503 693 $response->status = 'success';
504 694 $response->message = sprintf(
505 - esc_html__( '"%s" has been added to your cart.', 'learnpress' ),
695 + esc_html__( '"%s" has been added to your cart. Redirecting...', 'learnpress' ),
506 696 $course->get_title()
507 697 );
508 - $response->data->redirect = $redirect_url;
698 + $response->data->redirect = esc_url_raw( $redirect_url );
509 699 } catch ( Exception $e ) {
510 700 $response->message = $e->getMessage();
511 701 }
512 702
@@ -529,59 +719,39 @@
529 719 if ( ! $course_id ) {
530 720 throw new Exception( __( 'Invalid params', 'learnpress' ) );
531 721 }
532 722
533 - $course = learn_press_get_course( $course_id );
534 -
535 - if ( ! $course ) {
723 + $courseModel = CourseModel::find( $course_id, true );
724 + if ( ! $courseModel ) {
536 725 throw new Exception( __( 'Invalid course', 'learnpress' ) );
537 726 }
538 727
539 - $user = learn_press_get_current_user();
728 + $userModel = UserModel::find( get_current_user_id(), true );
729 + if ( ! $userModel ) {
730 + throw new Exception( __( 'Invalid user', 'learnpress' ) );
731 + }
540 732
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' ) );
733 + $userCourseModel = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true );
734 + if ( ! $userCourseModel ) {
735 + throw new Exception( __( 'Invalid user course', 'learnpress' ) );
549 736 }
550 737
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' ) );
738 + $userCourseModel->handle_retake();
739 + $item_continue = $userCourseModel->get_item_continue();
740 + if ( $item_continue ) {
741 + $link_continue = $courseModel->get_item_link( $item_continue->ID );
742 + } else {
743 + $link_continue = $courseModel->get_permalink();
554 744 }
555 745
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 746 $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();
747 + $response->message = esc_html__( 'Now you can begin this course', 'learnpress' );
748 + $response->data->url_redirect = $link_continue;
579 749 } catch ( Exception $e ) {
580 750 $response->message = $e->getMessage();
581 751 }
582 752
583 - wp_send_json( $response );
753 + return $response;
584 754 }
585 755
586 756 /**
587 757 * @param WP_REST_Request $request
@@ -642,17 +812,17 @@
642 812 return rest_ensure_response( $response );
643 813 }
644 814
645 815 /**
646 - * Rest API for Continue in single course.
816 + * Rest API for get item continue in single course.
647 817 *
648 818 * @param WP_REST_Request $request
649 - * @author minhpd
650 - * @editor tungnx
819 + *
820 + * @return LP_REST_Response
651 821 * @since 4.1.4
652 - * @version 1.0.2
822 + * @version 1.0.5
653 823 */
654 - public function continue_course( WP_REST_Request $request ) {
824 + public function continue_course( WP_REST_Request $request ): LP_REST_Response {
655 825 $params = $request->get_params();
656 826 $response = new LP_REST_Response();
657 827 $response->data = '';
658 828
@@ -659,20 +829,28 @@
659 829 try {
660 830 $flag_found = false;
661 831 $item_link = '';
662 832 $course_id = absint( $params['courseId'] ?? 0 );
663 - $user_id = absint( $params['userId'] ?? 0 );
833 + $user_id = get_current_user_id();
664 834
665 - $user = learn_press_get_user( $user_id );
666 - $course = learn_press_get_course( $course_id );
667 -
835 + $user = UserModel::find( $user_id, true );
836 + $course = CourseModel::find( $course_id, true );
668 837 if ( ! $course ) {
669 838 throw new Exception( __( 'Invalid course', 'learnpress' ) );
670 839 }
671 840
672 - $sections_items = $course->get_full_sections_and_items_course();
673 - $total_items = $course->count_items();
841 + if ( ! $user ) {
842 + return $response;
843 + }
674 844
845 + $userCourseModel = UserCourseModel::find( $user_id, $course_id, true );
846 + if ( ! $userCourseModel ) {
847 + throw new Exception( __( 'Invalid user course', 'learnpress' ) );
848 + }
849 +
850 + $sections_items = $course->get_section_items();
851 + $total_items = $course->get_total_items();
852 +
675 853 if ( ! empty( $total_items ) ) {
676 854 foreach ( $sections_items as $section_items ) {
677 855 if ( $flag_found ) {
678 856 break;
@@ -678,9 +856,20 @@
678 856 break;
679 857 }
680 858
681 859 foreach ( $section_items->items as $item ) {
682 - if ( ! $user->has_completed_item( $item->id, $course_id ) ) {
860 + $item_id = $item->id ?? $item->item_id;
861 + $item_type = $item->type ?? $item->item_type;
862 +
863 + $userItemModel = UserItemModel::find_user_item(
864 + $user_id,
865 + $item_id,
866 + $item_type,
867 + $course_id,
868 + LP_COURSE_CPT,
869 + true
870 + );
871 + if ( ! $userItemModel || $userItemModel->get_status() !== LP_ITEM_COMPLETED ) {
683 872 $item_link = $course->get_item_link( $item->id );
684 873 $flag_found = true;
685 874 break;
686 875 }
@@ -698,8 +887,7 @@
698 887 } catch ( Exception $e ) {
699 888 $response->message = $e->getMessage();
700 889 }
701 890
702 - wp_send_json( $response );
891 + return $response;
703 892 }
704 -
705 893 }