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.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 4.1.7.3.1 4.1.7.3.2 All 140 releases
← All changes | inc/rest-api/v1/frontend/class-lp-rest-courses-controller.php +482 -296 4.1.7.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,13 +87,21 @@
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 - 'description' => __( 'Unique identifier for the resource.', 'learnpress' ),
103 + 'description' => __( 'A unique identifier for the resource.', 'learnpress' ),
59 104 'type' => 'string',
60 105 ),
61 106 ),
62 107 array(
@@ -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,92 +449,107 @@
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 - if ( empty( absint( $request['id'] ) ) ) {
286 - throw new Exception( esc_html__( 'Error: No course available!.', 'learnpress' ) );
287 - }
288 -
289 - $course_id = absint( $request['id'] );
290 - $course = learn_press_get_course( $course_id );
291 - $user = learn_press_get_current_user();
292 -
498 + $course_id = absint( $request['id'] ?? 0 );
499 + $course = CourseModel::find( $course_id, true );
293 500 if ( ! $course ) {
294 501 throw new Exception( esc_html__( 'Invalid course!', 'learnpress' ) );
295 502 }
296 503
297 - $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 + }
298 510
299 - if ( ! $can_enroll->check ) {
300 - throw new Exception( $can_enroll->message ?? esc_html__( 'Error: Cannot enroll course.', 'learnpress' ) );
301 - }
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();
302 518
303 - $filter = new LP_User_Items_Filter();
304 - $filter->user_id = get_current_user_id();
305 - $filter->item_id = $course_id;
306 - $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() );
307 520
308 - // Case: if user bought course - or create order manual with order "completed".
309 - if ( $course_item && 'purchased' == $course_item->status ) {
310 - $user_item_data = [
311 - 'user_item_id' => $course_item->user_item_id,
312 - 'graduation' => LP_COURSE_GRADUATION_IN_PROGRESS,
313 - 'status' => LP_COURSE_ENROLLED,
314 - 'start_time' => current_time( 'mysql', true ),
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(),
315 529 ];
316 -
317 - $user_item_new_or_update = new LP_User_Item_Course( $user_item_data );
318 - $result = $user_item_new_or_update->update();
319 -
320 - if ( ! $result ) {
321 - throw new Exception( esc_html__( 'Error: Can\'t Enroll course.', 'learnpress' ) );
322 - }
323 -
324 - 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 + );
325 536 } else { // Case enroll course free
326 - LearnPress::instance()->session->set( 'order_awaiting_payment', '' );
327 -
328 537 $cart = LearnPress::instance()->cart;
329 538 $checkout = LP_Checkout::instance();
330 539
331 540 if ( ! learn_press_enable_cart() ) {
332 - $order_awaiting_payment = LearnPress::instance()->session->order_awaiting_payment;
333 541 $cart->empty_cart();
334 - LearnPress::instance()->session->order_awaiting_payment = $order_awaiting_payment;
335 542 }
336 543
337 - $cart_id = $cart->add_to_cart( $course_id, 1, array() );
338 -
544 + $cart_id = $cart->add_to_cart( $course_id );
339 545 if ( ! $cart_id ) {
340 - throw new Exception( esc_html__( 'Error: Can\'t add Course to cart.', 'learnpress' ) );
546 + throw new Exception( esc_html__( 'Error: The course cannot be added to the cart.', 'learnpress' ) );
341 547 }
342 548
343 549 if ( is_user_logged_in() ) {
344 550 $order_id = $checkout->create_order();
345 -
346 - if ( is_wp_error( $order_id ) ) {
347 - throw new Exception( $order_id->get_error_message() );
348 - }
349 -
350 - $order = new LP_Order( $order_id );
351 -
551 + $order = new LP_Order( $order_id );
352 552 $order->payment_complete();
353 553
354 554 $cart->empty_cart();
355 555 }
@@ -355,41 +555,38 @@
355 555 }
356 556 }
357 557
358 558 if ( is_user_logged_in() ) {
359 - $response->status = 'success';
360 - // Course has no items
361 559 $response->message = esc_html__(
362 - 'Congrats! You enroll course successfully. Redirecting...',
560 + 'Congrats! You have enrolled in the course successfully. Redirecting...',
363 561 'learnpress'
364 562 );
365 563
366 - $response->data->redirect = $course->get_redirect_url_after_enroll();
367 -
368 - if ( empty( $course->count_items() ) ) {
369 - $response->data->redirect = get_permalink( $course->get_id() );
370 - }
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() );
371 566 } else {
567 + $redirect_url = LP_Page_Controller::get_link_page( 'checkout', [], true );
372 568 $redirect_url = apply_filters(
373 569 'learnpress/rest-api/courses/enroll/redirect',
374 - learn_press_get_page_link( 'checkout' ),
570 + $redirect_url,
375 571 $course_id
376 572 );
377 573
378 574 if ( empty( $redirect_url ) ) {
379 - throw new Exception( __( 'Error: Please setup page for checkout.', 'learnpress' ) );
380 - } elseif ( ! is_user_logged_in() ) { // Fix case: cache page with user anonymous
381 - $redirect_url = LP_Helper::get_link_no_cache( $redirect_url );
575 + throw new Exception( __( 'Error: Please set up a page for checkout.', 'learnpress' ) );
382 576 }
383 577
578 + $redirect_url = LP_Helper::get_link_no_cache( $redirect_url );
384 579 $response->message = esc_html__( 'Redirecting...', 'learnpress' );
385 - $response->data->redirect = $redirect_url;
580 + $response->data->redirect = esc_url_raw( $redirect_url );
386 581 }
582 +
583 + $response->status = 'success';
387 584 } catch ( Exception $e ) {
388 585 $response->message = $e->getMessage();
389 586 }
390 587
391 - wp_send_json( $response );
588 + return $response;
392 589 }
393 590
394 591 /**
395 592 * Rest API for Purchase course in single course.
@@ -400,12 +597,11 @@
400 597 * @throws Exception .
401 598 * @author Nhamdv
402 599 */
403 600 public function purchase_course( WP_REST_Request $request ) {
404 - $response = new LP_REST_Response();
405 - $response->data = new stdClass();
406 - $params = $request->get_params();
407 - $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();
408 604
409 605 try {
410 606 $course_id = $params['id'];
411 607 $allow_repurchase_type = $params['repurchaseType'] ?? false;
@@ -413,105 +609,94 @@
413 609 if ( ! $course_id ) {
414 610 throw new Exception( __( 'Error: Invalid Course ID.', 'learnpress' ) );
415 611 }
416 612
417 - $course = learn_press_get_course( $course_id );
418 -
613 + $course = CourseModel::find( $course_id, true );
419 614 if ( ! $course ) {
420 615 throw new Exception( __( 'Error: No Course available.', 'learnpress' ) );
421 616 }
422 617
423 - $user = learn_press_get_current_user();
424 -
425 - if ( ! $user->can_purchase_course( $course_id ) ) {
426 - throw new Exception( esc_html__( 'Error: Cannot purchase 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() );
427 623 }
428 624
429 - $latest_user_item_id = 0;
430 -
431 - $filter = new LP_User_Items_Filter();
432 - $filter->user_id = get_current_user_id();
433 - $filter->item_id = $course_id;
434 - $course_item = $lp_user_items_db->get_last_user_course( $filter );
435 -
436 - if ( $course_item && isset( $course_item->user_item_id ) ) {
437 - $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 + );
438 640 }
439 641
440 - if ( $course->allow_repurchase() && ! empty( $latest_user_item_id ) && empty( $allow_repurchase_type ) ) {
441 - if ( $course->allow_repurchase_course_option() === 'popup' ) {
442 - ob_start();
443 - ?>
444 - <div class="lp_allow_repuchase_select">
445 - <ul>
446 - <li>
447 - <label>
448 - <input name="_lp_allow_repurchase_type" value="reset" type="radio" checked="checked" />
449 - <?php esc_html_e( 'Reset Course progress', 'learnpress' ); ?>
450 - </label>
451 - </li>
452 - <li>
453 - <label>
454 - <input name="_lp_allow_repurchase_type" value="keep" type="radio" />
455 - <?php esc_html_e( 'Continue Course progress', 'learnpress' ); ?>
456 - </label>
457 - </li>
458 - </ul>
459 - </div>
460 - <?php
461 - $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 );
462 655 $response->data->type = 'allow_repurchase';
463 656 $response->data->titlePopup = esc_html__( 'Repurchase Options', 'learnpress' );
464 657 $response->status = 'success';
465 658
466 659 return rest_ensure_response( $response );
467 - } else {
468 - learn_press_update_user_item_meta( $latest_user_item_id, '_lp_allow_repurchase_type', $course->allow_repurchase_course_option() );
469 660 }
470 661 }
471 662
472 - LearnPress::instance()->session->set( 'order_awaiting_payment', '' );
473 -
474 - $cart = LearnPress::instance()->cart;
475 - $checkout = LP_Checkout::instance();
476 -
663 + $cart = LearnPress::instance()->cart;
477 664 if ( ! learn_press_enable_cart() ) {
478 - $order_awaiting_payment = LearnPress::instance()->session->order_awaiting_payment;
479 665 $cart->empty_cart();
480 - LearnPress::instance()->session->order_awaiting_payment = $order_awaiting_payment;
481 666 }
482 667
483 - 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' );
484 670
485 - $cart_id = $cart->add_to_cart( $course_id, 1, array() );
486 -
487 - if ( ! $cart_id ) {
488 - throw new Exception( __( 'Error: Can\'t add Course to cart.', 'learnpress' ) );
671 + $cart_id = $cart->add_to_cart( $course_id, 1, $params );
672 + if ( empty( $cart_id ) ) {
673 + throw new Exception( __( 'Error: The course cannot be added to the cart.', 'learnpress' ) );
489 674 }
490 675
491 - if ( ! empty( $allow_repurchase_type ) ) {
492 - 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 );
493 678 }
494 679
680 + $redirect_url = LP_Page_Controller::get_link_page( 'checkout', [], true );
495 681 $redirect_url = apply_filters(
496 682 'learnpress/rest-api/courses/purchase/redirect',
497 - learn_press_get_page_link( 'checkout' ),
683 + $redirect_url,
498 684 $course_id,
499 685 $cart_id
500 686 );
501 687
502 688 if ( empty( $redirect_url ) ) {
503 - throw new Exception( __( 'Error: Please setup page for checkout.', 'learnpress' ) );
504 - } elseif ( ! is_user_logged_in() ) { // Fix case: cache page with user anonymous
505 - $redirect_url = LP_Helper::get_link_no_cache( $redirect_url );
689 + throw new Exception( __( 'Error: Please set up a page for checkout.', 'learnpress' ) );
506 690 }
507 691
692 + $redirect_url = LP_Helper::get_link_no_cache( $redirect_url );
508 693 $response->status = 'success';
509 694 $response->message = sprintf(
510 - esc_html__( '"%s" has been added to your cart.', 'learnpress' ),
695 + esc_html__( '"%s" has been added to your cart. Redirecting...', 'learnpress' ),
511 696 $course->get_title()
512 697 );
513 - $response->data->redirect = $redirect_url;
698 + $response->data->redirect = esc_url_raw( $redirect_url );
514 699 } catch ( Exception $e ) {
515 700 $response->message = $e->getMessage();
516 701 }
517 702
@@ -534,56 +719,39 @@
534 719 if ( ! $course_id ) {
535 720 throw new Exception( __( 'Invalid params', 'learnpress' ) );
536 721 }
537 722
538 - $course = learn_press_get_course( $course_id );
539 -
540 - if ( ! $course ) {
723 + $courseModel = CourseModel::find( $course_id, true );
724 + if ( ! $courseModel ) {
541 725 throw new Exception( __( 'Invalid course', 'learnpress' ) );
542 726 }
543 727
544 - $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 + }
545 732
546 - // if ( ! is_user_logged_in() ) {
547 - // throw new Exception( esc_html__( 'Please login!', 'learnpress' ) );
548 - // }
733 + $userCourseModel = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true );
734 + if ( ! $userCourseModel ) {
735 + throw new Exception( __( 'Invalid user course', 'learnpress' ) );
736 + }
549 737
550 - $can_retry = $user->can_retry_course( $course_id );
551 -
552 - if ( ! $can_retry ) {
553 - throw new Exception( __( 'You can\'t retry course', '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 - $user_course_data = $user->get_course_data( $course_id );
557 -
558 - // Up retaken.
559 - $user_course_data->increase_retake_count();
560 -
561 - // Set status, start_time, end_time of course to enrolled.
562 - $user_course_data->set_status( LP_COURSE_ENROLLED )
563 - ->set_start_time( current_time( 'mysql', true ) )
564 - ->set_end_time( '' )
565 - ->set_graduation( 'in-progress' )
566 - ->update();
567 -
568 - // Remove items' course user learned.
569 - $filter_remove = new LP_User_Items_Filter();
570 - $filter_remove->parent_id = $user_course_data->get_user_item_id();
571 - $filter_remove->user_id = $user_course_data->get_user_id();
572 - $filter_remove->limit = - 1;
573 - LP_User_Items_DB::getInstance()->remove_items_of_user_course( $filter_remove );
574 -
575 - // Create new result in table learnpress_user_item_results.
576 - LP_User_Items_Result_DB::instance()->insert( $user_course_data->get_user_item_id() );
577 -
578 746 $response->status = 'success';
579 - $response->message = esc_html__( 'Now you can learn this course', 'learnpress' );
580 - $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;
581 749 } catch ( Exception $e ) {
582 750 $response->message = $e->getMessage();
583 751 }
584 752
585 - wp_send_json( $response );
753 + return $response;
586 754 }
587 755
588 756 /**
589 757 * @param WP_REST_Request $request
@@ -644,17 +812,17 @@
644 812 return rest_ensure_response( $response );
645 813 }
646 814
647 815 /**
648 - * Rest API for Continue in single course.
816 + * Rest API for get item continue in single course.
649 817 *
650 818 * @param WP_REST_Request $request
651 - * @author minhpd
652 - * @editor tungnx
819 + *
820 + * @return LP_REST_Response
653 821 * @since 4.1.4
654 - * @version 1.0.2
822 + * @version 1.0.5
655 823 */
656 - public function continue_course( WP_REST_Request $request ) {
824 + public function continue_course( WP_REST_Request $request ): LP_REST_Response {
657 825 $params = $request->get_params();
658 826 $response = new LP_REST_Response();
659 827 $response->data = '';
660 828
@@ -661,20 +829,28 @@
661 829 try {
662 830 $flag_found = false;
663 831 $item_link = '';
664 832 $course_id = absint( $params['courseId'] ?? 0 );
665 - $user_id = absint( $params['userId'] ?? 0 );
833 + $user_id = get_current_user_id();
666 834
667 - $user = learn_press_get_user( $user_id );
668 - $course = learn_press_get_course( $course_id );
669 -
835 + $user = UserModel::find( $user_id, true );
836 + $course = CourseModel::find( $course_id, true );
670 837 if ( ! $course ) {
671 838 throw new Exception( __( 'Invalid course', 'learnpress' ) );
672 839 }
673 840
674 - $sections_items = $course->get_full_sections_and_items_course();
675 - $total_items = $course->count_items();
841 + if ( ! $user ) {
842 + return $response;
843 + }
676 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 +
677 853 if ( ! empty( $total_items ) ) {
678 854 foreach ( $sections_items as $section_items ) {
679 855 if ( $flag_found ) {
680 856 break;
@@ -680,9 +856,20 @@
680 856 break;
681 857 }
682 858
683 859 foreach ( $section_items->items as $item ) {
684 - 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 ) {
685 872 $item_link = $course->get_item_link( $item->id );
686 873 $flag_found = true;
687 874 break;
688 875 }
@@ -700,8 +887,7 @@
700 887 } catch ( Exception $e ) {
701 888 $response->message = $e->getMessage();
702 889 }
703 890
704 - wp_send_json( $response );
891 + return $response;
705 892 }
706 -
707 893 }