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/user/class-lp-user-factory.php +587 -586 4.3.8 → 4.4.9 View file →
@@ -1,586 +1,587 @@
1 -<?php
2 -
3 -use LearnPress\Background\LPBackgroundAjax;
4 -use LearnPress\Models\CourseModel;
5 -use LearnPress\Models\UserItems\UserCourseModel;
6 -use LearnPress\Models\UserItems\UserItemModel;
7 -
8 -defined( 'ABSPATH' ) || exit;
9 -
10 -/**
11 - * Class LP_User_Factory
12 - */
13 -class LP_User_Factory {
14 - /**
15 - * Init hooks
16 - */
17 - public static function init() {
18 - add_action( 'learn-press/order/status-changed', array( __CLASS__, 'update_user_items' ), 10, 3 );
19 - }
20 -
21 - /**
22 - * Handle when order changed status
23 - *
24 - * @param $the_id
25 - * @param $old_status
26 - * @param $new_status
27 - *
28 - * @Todo tungnx - should write on class LP_Order
29 - */
30 - public static function update_user_items( $the_id, $old_status, $new_status ) {
31 - ini_set( 'max_execution_time', 0 );
32 - $order = learn_press_get_order( $the_id );
33 - if ( ! $order ) {
34 - return;
35 - }
36 -
37 - try {
38 - switch ( $new_status ) {
39 - case LP_ORDER_PENDING:
40 - case LP_ORDER_PROCESSING:
41 - case LP_ORDER_CANCELLED:
42 - case LP_ORDER_FAILED:
43 - self::_update_user_item_order_pending( $order, $old_status, $new_status );
44 - break;
45 - case LP_ORDER_COMPLETED:
46 - self::_update_user_item_order_completed( $order, $old_status, $new_status );
47 - break;
48 - }
49 - } catch ( Exception $ex ) {
50 - error_log( __METHOD__ . ': ' . $ex->getMessage() );
51 - }
52 - ini_set( 'max_execution_time', LearnPress::$time_limit_default_of_sever );
53 - }
54 -
55 - /**
56 - * Update lp_user_items has Order
57 - * Only handle when change status LP Order from Completed to another status
58 - *
59 - * @param LP_Order $order
60 - * @param string $old_status
61 - * @param string $new_status
62 - *
63 - * @throws Exception
64 - * @author Nhamdv <[email protected]>
65 - * @editor tungnx
66 - * @modify 4.1.4
67 - * @version 1.0.4
68 - */
69 - protected static function _update_user_item_order_pending( $order, $old_status, $new_status ) {
70 - $items = $order->get_all_items();
71 - if ( ! $items ) {
72 - return;
73 - }
74 -
75 - if ( $old_status !== LP_ORDER_COMPLETED ) {
76 - return;
77 - }
78 -
79 - foreach ( $order->get_users() as $user_id ) {
80 - $user = learn_press_get_user( $user_id );
81 -
82 - foreach ( $items as $item ) {
83 - if ( isset( $item['item_id'] ) && LP_COURSE_CPT === $item['item_type'] ) {
84 - $course_id = $item['item_id'];
85 -
86 - if ( $user_id ) {
87 - $userCourse = UserCourseModel::find( $user_id, $course_id, true );
88 - // Check course is learning is sample order_id with order which is changing status
89 - if ( ! $userCourse || $userCourse->ref_id != $order->get_id() ) {
90 - continue;
91 - }
92 -
93 - // Only change status of user_item to cancel, not delete user_item and user_item_results.
94 - $userCourse->status = UserItemModel::STATUS_CANCEL;
95 - $userCourse->save();
96 - } else {
97 - $userCourseGuest = self::get_user_course_guest( $course_id, $order->get_user_email() );
98 - // Check course is learning is sample order_id with order which is changing status
99 - if ( ! $userCourseGuest || $userCourseGuest->ref_id != $order->get_id() ) {
100 - continue;
101 - }
102 -
103 - $userCourseGuest->status = UserItemModel::STATUS_CANCEL;
104 - $userCourseGuest->save();
105 - }
106 - } else {
107 - // For buy other item type (not course)
108 - // For case item is Certificate, when update code of Certificate, should remove this code
109 - if ( $item['item_type'] === 'lp_cert' ) {
110 - $item['_lp_cert_id'] = $item['item_id'];
111 - }
112 - do_action( 'lp/order-pending/update/user-item', $item, $order, $user );
113 - }
114 - }
115 - }
116 - }
117 -
118 - /**
119 - * Enroll course if Order completed
120 - * 1. Check if order change is the latest order of user for course
121 - * 2. Check if user_course was canceled, only update status to Enrolled
122 - * 3. Handle repurchase course if allow repurchase
123 - * 4. Create new user_course if first purchase course
124 - * 5. Enroll course free or no enroll requirement
125 - * 6. Enroll course for guest if auto enroll enable
126 - * 7. Send email background when user enroll course
127 - *
128 - * @param LP_Order $order
129 - * @param string $old_status
130 - * @param string $new_status
131 - *
132 - * @throws Exception
133 - * @editor tungnx
134 - * @modify 4.1.2
135 - * @version 1.0.6
136 - */
137 - protected static function _update_user_item_order_completed( LP_Order $order, string $old_status, string $new_status ) {
138 - $lp_order_db = LP_Order_DB::getInstance();
139 - $items = $order->get_all_items();
140 - if ( ! $items ) {
141 - return;
142 - }
143 -
144 - $usersCourses = [];
145 - foreach ( $order->get_users() as $user_id ) {
146 - $user = learn_press_get_user( $user_id );
147 -
148 - foreach ( $items as $item ) {
149 - if ( isset( $item['item_id'] ) && LP_COURSE_CPT === $item['item_type'] ) {
150 - $course_id = $item['item_id'];
151 -
152 - // Check order_id of user_item current must < new order_id
153 - $userCourse = UserCourseModel::find( $user_id, $course_id, true );
154 - if ( $user_id && $userCourse && $userCourse->ref_id > $order->get_id() ) {
155 - continue;
156 - } elseif ( ! $user_id ) {
157 - $userCourseGuest = self::get_user_course_guest( $course_id, $order->get_user_email() );
158 - if ( $userCourseGuest && $userCourseGuest->ref_id > $order->get_id() ) {
159 - continue;
160 - }
161 - }
162 -
163 - // Check user course was canceled? If yes, only update status to Enrolled
164 - if ( $user_id && $userCourse && $userCourse->ref_id == $order->get_id() ) {
165 - if ( $userCourse->get_status() === UserItemModel::STATUS_CANCEL ) {
166 - if ( ! empty( $userCourse->get_end_time() ) ) {
167 - $userCourse->status = UserItemModel::STATUS_FINISHED;
168 - } else {
169 - $userCourse->status = UserItemModel::STATUS_ENROLLED;
170 - }
171 - $userCourse->save();
172 - }
173 -
174 - continue;
175 - }
176 -
177 - if ( $order->is_manual() ) {
178 - $usersCourses[] = self::handle_item_manual_order_completed( $order, $user, $item );
179 - } else {
180 - $usersCourses[] = self::handle_item_order_completed( $order, $user, $item );
181 - }
182 - } else {
183 - // For buy other item type (not course)
184 - // For case item is Certificate, when update code of Certificate, should remove this code
185 - if ( $item['item_type'] === 'lp_cert' ) {
186 - $item['_lp_cert_id'] = $item['item_id'];
187 - // Fixed for old Certificate <= v4.1.2
188 - $item['_lp_course_id_of_cert'] = learn_press_get_order_item_meta(
189 - $item['order_item_id'],
190 - '_lp_course_id_of_cert'
191 - );
192 - }
193 - do_action( 'lp/order-completed/update/user-item', $item, $order, $user );
194 - }
195 - }
196 - }
197 -
198 - // Run background send emails when users enroll courses (send for instructor, admin, student...)
199 - if ( ! empty( $usersCourses ) ) {
200 - $userCourseIds = [];
201 - foreach ( $usersCourses as $userCourse ) {
202 - if ( ! $userCourse instanceof UserCourseModel ) {
203 - continue;
204 - }
205 -
206 - if ( $userCourse->get_status() !== UserItemModel::STATUS_ENROLLED ) {
207 - continue;
208 - }
209 -
210 - $userCourseIds[] = [
211 - 'user_id' => $userCourse->user_id,
212 - 'course_id' => $userCourse->item_id,
213 - ];
214 - }
215 -
216 - if ( empty( $userCourseIds ) ) {
217 - return;
218 - }
219 -
220 - /**
221 - * @uses SendEmailAjax::send_mail_users_enrolled_courses
222 - */
223 - $data_send = [
224 - 'user_course_ids' => $userCourseIds,
225 - 'lp-load-ajax' => 'send_mail_users_enrolled_courses',
226 - ];
227 - LPBackgroundAjax::handle( $data_send );
228 - }
229 - }
230 -
231 - /**
232 - * Handle something when Order completed
233 - *
234 - * @author tungnx
235 - * @since 4.1.3
236 - * @version 1.1.1
237 - */
238 - protected static function handle_item_order_completed( LP_Order $order, $user, $item ) {
239 - $lp_user_items_db = LP_User_Items_DB::getInstance();
240 - $userCourseResponse = null;
241 -
242 - try {
243 - $course_id = intval( $item['course_id'] ?? $item['item_id'] ?? 0 );
244 - $courseModel = CourseModel::find( $course_id, true );
245 - if ( ! $courseModel ) {
246 - return null;
247 - }
248 -
249 - $auto_enroll = LP_Settings::is_auto_start_course();
250 - $keep_progress_items_course = false;
251 -
252 - $user_id = $user->get_id();
253 - if ( $user instanceof LP_User_Guest ) {
254 - $user_id = 0;
255 - }
256 -
257 - /** Get the newest user_item_id of course for allow_repurchase */
258 - $userCourse = UserCourseModel::find( $user_id, $course_id, true );
259 -
260 - $latest_user_item_id = 0;
261 - $allow_repurchase_option = $courseModel->get_type_repurchase();
262 - $allow_repurchase_type = '';
263 -
264 - // Data user_item for save database
265 - $user_item_data = [
266 - 'user_id' => $user_id,
267 - 'item_id' => $course_id,
268 - 'ref_id' => $order->get_id(),
269 - 'start_time' => gmdate( LP_Datetime::$format, time() ),
270 - 'graduation' => UserItemModel::GRADUATION_IN_PROGRESS,
271 - ];
272 -
273 - if ( $user_id && $userCourse ) {
274 - $latest_user_item_id = $userCourse->get_user_item_id();
275 -
276 - /** Get allow_repurchase_type for reset, update. Add in: rest-api/v1/frontend/class-lp-courses-controller.php: purchase_course */
277 - $allow_repurchase_type = learn_press_get_user_item_meta( $latest_user_item_id, '_lp_allow_repurchase_type' );
278 - }
279 -
280 - $is_no_required_enroll = $courseModel->has_no_enroll_requirement();
281 - $is_in_stock = $courseModel->is_in_stock();
282 -
283 - // If > 1 time purchase same course and allow repurchase
284 - if ( $courseModel->enable_allow_repurchase() && ! empty( $latest_user_item_id )
285 - && ! $courseModel->is_free() && ! $is_no_required_enroll ) {
286 - if ( $allow_repurchase_option !== 'popup' ) {
287 - $allow_repurchase_type = $allow_repurchase_option;
288 - } elseif ( empty( $allow_repurchase_type ) ) {
289 - // For case course set repurchase Popup but buy via Upsell, PMS, Woo can't set allow_repurchase_type
290 - $allow_repurchase_type = 'keep';
291 - }
292 -
293 - /**
294 - * If keep course progress will reset start_time, end_time, status, graduation
295 - * where user_item_id = $latest_user_item_id
296 - */
297 - if ( $allow_repurchase_type === 'keep' ) {
298 - $keep_progress_items_course = true;
299 - // Set data for update user item
300 - $user_item_data['user_item_id'] = $latest_user_item_id;
301 - $user_item_data['end_time'] = null;
302 - $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
303 -
304 - do_action( 'lp/allow_repurchase_options/continue/db/update', $user_item_data, $latest_user_item_id );
305 - } elseif ( $allow_repurchase_type === 'reset' ) {
306 - $user_item_data['end_time'] = null;
307 - $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
308 - }
309 -
310 - learn_press_delete_user_item_meta( $latest_user_item_id, '_lp_allow_repurchase_type' );
311 - } elseif ( ! $courseModel->is_free() && ! $is_no_required_enroll && $is_in_stock ) { // First purchase course
312 - // Set data for create user_item
313 - if ( $auto_enroll ) {
314 - $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
315 - } else {
316 - $user_item_data['status'] = UserItemModel::STATUS_PURCHASED;
317 - $user_item_data['graduation'] = '';
318 - }
319 - } elseif ( $user_id && ( $is_in_stock || $is_no_required_enroll ) ) { // Enroll course free or No enroll requirement.
320 - // Set data for create user_item
321 - $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
322 - } elseif ( LP_Checkout::instance()->is_enable_guest_checkout()
323 - && $auto_enroll && ( $is_in_stock || $is_no_required_enroll ) ) {
324 - $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
325 - } else {
326 - return null;
327 - }
328 -
329 - $user_item_data = apply_filters(
330 - 'learn-press/order/user-course-data',
331 - $user_item_data,
332 - $order,
333 - $item,
334 - $courseModel,
335 - $user_id
336 - );
337 -
338 - $another_case = apply_filters(
339 - 'learn-press/order/completed/update-user-item/another-case/bool',
340 - false,
341 - $user_item_data,
342 - $order,
343 - $item,
344 - $courseModel,
345 - $user_id
346 - );
347 -
348 - if ( $another_case ) { // Handle another case to handle user_item
349 - $userCourseResponse = apply_filters(
350 - 'learn-press/order/completed/update-user-item/another-case',
351 - null,
352 - $user_item_data,
353 - $order,
354 - $item,
355 - $courseModel,
356 - $user_id
357 - );
358 - } elseif ( $keep_progress_items_course ) { // Update user_item to keep course progress
359 - $userCourse->ref_id = $order->get_id();
360 - $userCourse->status = $user_item_data['status'];
361 - $userCourse->graduation = $user_item_data['graduation'];
362 - $userCourse->start_time = $user_item_data['start_time'];
363 - $userCourse->end_time = null;
364 - $userCourse->save();
365 - $userCourseResponse = $userCourse;
366 - } else { // Create new user_item
367 - // Delete items old
368 - if ( ! $user_id ) {
369 - $userGuestCourse = self::get_user_course_guest( $course_id, $order->get_user_email() );
370 - if ( $userGuestCourse ) {
371 - $userGuestCourse->delete();
372 - }
373 - } elseif ( $userCourse ) {
374 - //$lp_user_items_db->delete_user_items_old( $user_id, $course_id );
375 - $userCourse->delete();
376 - }
377 -
378 - $userCourseNew = new UserCourseModel( $user_item_data );
379 - $userCourseNew->save();
380 - $userCourseResponse = $userCourseNew;
381 - }
382 -
383 - if ( isset( $user_item_data['status'] ) && UserItemModel::STATUS_ENROLLED == $user_item_data['status'] ) {
384 - do_action( 'learnpress/user/course-enrolled', $order->get_id(), $user_item_data['item_id'], $user_item_data['user_id'] );
385 - }
386 - } catch ( Throwable $e ) {
387 - LP_Debug::error_log( $e );
388 - }
389 -
390 - return $userCourseResponse;
391 - }
392 -
393 - /**
394 - * Handle something when Manual Order completed
395 - *
396 - * @author tungnx
397 - * @since 4.1.3
398 - * @version 1.0.4
399 - */
400 - protected static function handle_item_manual_order_completed( LP_Order $order, $user, $item ) {
401 - $userCourseResponse = null;
402 -
403 - try {
404 - $courseModel = CourseModel::find( $item['course_id'] ?? $item['item_id'] ?? 0, true );
405 - if ( ! $courseModel ) {
406 - return $userCourseResponse;
407 - }
408 -
409 - if ( $user instanceof LP_User_Guest ) {
410 - return $userCourseResponse;
411 - }
412 -
413 - // Data user_item for save database
414 - $user_item_data = [
415 - 'user_id' => $user->get_id(),
416 - 'item_id' => $courseModel->get_id(),
417 - 'ref_id' => $order->get_id(),
418 - ];
419 -
420 - $auto_enroll = LP_Settings::is_auto_start_course();
421 - if ( $auto_enroll ) {
422 - $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
423 - $user_item_data['graduation'] = UserItemModel::GRADUATION_IN_PROGRESS;
424 - } else {
425 - $user_item_data['status'] = UserItemModel::STATUS_PURCHASED;
426 - }
427 -
428 - $user_item_data = apply_filters(
429 - 'learn-press/order/manual/user-course-data',
430 - $user_item_data,
431 - $order,
432 - $item,
433 - $courseModel
434 - );
435 -
436 - // Delete lp_user_items old
437 - LP_User_Items_DB::getInstance()->delete_user_items_old( $user->get_id(), $courseModel->get_id() );
438 - // End
439 -
440 - $userCourseModelNew = new UserCourseModel( $user_item_data );
441 - $userCourseModelNew->save();
442 - $userCourseResponse = $userCourseModelNew;
443 -
444 - if ( UserItemModel::STATUS_ENROLLED == $userCourseResponse->get_status() ) {
445 - do_action( 'learnpress/user/course-enrolled', $order->get_id(), $user_item_data['item_id'], $user_item_data['user_id'] );
446 - }
447 - } catch ( Throwable $e ) {
448 - error_log( __FUNCTION__ . ': ' . $e->getMessage() );
449 - }
450 -
451 - return $userCourseResponse;
452 - }
453 -
454 - /**
455 - * Get user_course of user Guest
456 - *
457 - * @param $course_id
458 - * @param $email_guest
459 - *
460 - * @return UserCourseModel|false
461 - * @throws Exception
462 - * @since 4.2.7.3
463 - * @version 1.0.0
464 - */
465 - public static function get_user_course_guest( $course_id, $email_guest ) {
466 - $lp_user_items_db = LP_User_Items_DB::getInstance();
467 - $filter = new LP_User_Items_Filter();
468 - $filter->user_id = 0;
469 - $filter->item_id = $course_id;
470 - $filter->join[] = "INNER JOIN {$lp_user_items_db->tb_postmeta} pm ON pm.post_id = ref_id";
471 - $filter->join[] = "INNER JOIN {$lp_user_items_db->tb_postmeta} pm2 ON pm2.post_id = ref_id";
472 - $filter->where[] = "AND pm.meta_key = '_checkout_email'";
473 - $filter->where[] = $lp_user_items_db->wpdb->prepare( 'AND pm2.meta_value = %s', $email_guest );
474 -
475 - return UserCourseModel::get_user_item_model_from_db( $filter );
476 - }
477 -
478 - /**
479 - * Hook into wp users list to exclude our temp users.
480 - *
481 - * @param array $args
482 - *
483 - * @return mixed
484 - * @deprecated 4.2.7.3
485 - */
486 - /*public static function exclude_temp_users( $args ) {
487 - if ( LP_Request::get_string( 'lp-action' ) == 'pending-request' ) {
488 - $args['include'] = self::get_pending_requests();
489 - }
490 -
491 - return $args;
492 - }*/
493 -
494 - /**
495 - * Get pending requests be come a Teacher.
496 - *
497 - * @return array
498 - * @deprecated 4.2.7.3
499 - */
500 - /*public static function get_pending_requests() {
501 - global $wpdb;
502 - $query = $wpdb->prepare(
503 - "
504 - SELECT ID
505 - FROM {$wpdb->users} u
506 - INNER JOIN {$wpdb->usermeta} um ON um.user_id = u.ID AND um.meta_key = %s
507 - WHERE um.meta_value = %s
508 - ",
509 - '_requested_become_teacher',
510 - 'yes'
511 - );
512 -
513 - return $wpdb->get_col( $query );
514 - }*/
515 -
516 - /**
517 - * @deprecated 4.2.7.3
518 - */
519 - /*public static function get_guest_id() {
520 - return 0;// empty( $_COOKIE['learn_press_user_guest_id'] ) ? false : $_COOKIE['learn_press_user_guest_id'];
521 - }*/
522 -
523 - /**
524 - * @param $the_user
525 - * @param bool $force
526 - *
527 - * @return LP_Abstract_User
528 - * @deprecated 4.2.7.3
529 - */
530 - /*public static function get_user( $the_user, $force = false ) {
531 - $the_id = 0;
532 - if ( is_numeric( $the_user ) ) {
533 - $the_id = $the_user;
534 - } elseif ( $the_user instanceof LP_Abstract_User ) {
535 - $the_id = $the_user->id;
536 - } elseif ( isset( $the_user->ID ) ) {
537 - $the_id = $the_user->ID;
538 - } elseif ( null === $the_user ) {
539 - $the_id = get_current_user_id();
540 - }
541 -
542 - $user_class = self::get_user_class( $the_id );
543 - if ( $user_class instanceof LP_User_Guest ) {
544 - $the_id = self::get_guest_id();
545 - }
546 - if ( empty( self::$_users[ $the_id ] ) || $force ) {
547 - self::$_users[ $the_id ] = new $user_class( $the_id );
548 - }
549 -
550 - return self::$_users[ $the_id ];
551 - }*/
552 -
553 - /**
554 - * Get class name for User Object
555 - *
556 - * @param int
557 - *
558 - * @return string
559 - * @deprecated 4.2.7.3
560 - */
561 - // public static function get_user_class( $the_id = 0 ) {
562 - // $deleted = in_array( $the_id, self::$_deleted_users );
563 - // $exists_user = ! $deleted ? get_userdata( $the_id ) : false;
564 - // if ( $exists_user ) {
565 - // $class = 'LP_User';
566 - // } else {
567 - // if ( ! $deleted ) {
568 - // self::$_deleted_users[] = $the_id;
569 - // /**
570 - // * Prevent loading user does not exists in database
571 - // */
572 - // $user = new LP_User_Guest( $the_id );
573 - // wp_cache_add( $the_id, $user, 'users' );
574 - // wp_cache_add( '', $the_id, 'userlogins' );
575 - // wp_cache_add( '', $the_id, 'useremail' );
576 - // wp_cache_add( '', $the_id, 'userslugs' );
577 - // }
578 - // $is_logged_in = function_exists( 'is_user_logged_in' ) && is_user_logged_in();
579 - // $class = $is_logged_in ? 'LP_User' : 'LP_User_Guest';
580 - // }
581 - //
582 - // return apply_filters( 'learn_press_user_class', $class );
583 - // }
584 -}
585 -
586 -LP_User_Factory::init();
1 +<?php
2 +
3 +use LearnPress\Background\LPBackgroundAjax;
4 +use LearnPress\Models\CourseModel;
5 +use LearnPress\Models\UserItems\UserCourseModel;
6 +use LearnPress\Models\UserItems\UserItemModel;
7 +
8 +defined( 'ABSPATH' ) || exit;
9 +
10 +/**
11 + * Class LP_User_Factory
12 + */
13 +class LP_User_Factory {
14 + /**
15 + * Init hooks
16 + */
17 + public static function init() {
18 + add_action( 'learn-press/order/status-changed', array( __CLASS__, 'update_user_items' ), 10, 3 );
19 + }
20 +
21 + /**
22 + * Handle when order changed status
23 + *
24 + * @param $the_id
25 + * @param $old_status
26 + * @param $new_status
27 + *
28 + * @Todo tungnx - should write on class LP_Order
29 + */
30 + public static function update_user_items( $the_id, $old_status, $new_status ) {
31 + ini_set( 'max_execution_time', 0 );
32 + $order = learn_press_get_order( $the_id );
33 + if ( ! $order ) {
34 + return;
35 + }
36 +
37 + try {
38 + switch ( $new_status ) {
39 + case LP_ORDER_PENDING:
40 + case LP_ORDER_PROCESSING:
41 + case LP_ORDER_CANCELLED:
42 + case LP_ORDER_FAILED:
43 + case LP_ORDER_REFUNDED:
44 + self::_update_user_item_order_pending( $order, $old_status, $new_status );
45 + break;
46 + case LP_ORDER_COMPLETED:
47 + self::_update_user_item_order_completed( $order, $old_status, $new_status );
48 + break;
49 + }
50 + } catch ( Exception $ex ) {
51 + error_log( __METHOD__ . ': ' . $ex->getMessage() );
52 + }
53 + ini_set( 'max_execution_time', LearnPress::$time_limit_default_of_sever );
54 + }
55 +
56 + /**
57 + * Update lp_user_items has Order
58 + * Only handle when change status LP Order from Completed to another status
59 + *
60 + * @param LP_Order $order
61 + * @param string $old_status
62 + * @param string $new_status
63 + *
64 + * @throws Exception
65 + * @author Nhamdv <[email protected]>
66 + * @editor tungnx
67 + * @modify 4.1.4
68 + * @version 1.0.4
69 + */
70 + protected static function _update_user_item_order_pending( $order, $old_status, $new_status ) {
71 + $items = $order->get_all_items();
72 + if ( ! $items ) {
73 + return;
74 + }
75 +
76 + if ( $old_status !== LP_ORDER_COMPLETED ) {
77 + return;
78 + }
79 +
80 + foreach ( $order->get_users() as $user_id ) {
81 + $user = learn_press_get_user( $user_id );
82 +
83 + foreach ( $items as $item ) {
84 + if ( isset( $item['item_id'] ) && LP_COURSE_CPT === $item['item_type'] ) {
85 + $course_id = $item['item_id'];
86 +
87 + if ( $user_id ) {
88 + $userCourse = UserCourseModel::find( $user_id, $course_id, true );
89 + // Check course is learning is sample order_id with order which is changing status
90 + if ( ! $userCourse || $userCourse->ref_id != $order->get_id() ) {
91 + continue;
92 + }
93 +
94 + // Only change status of user_item to cancel, not delete user_item and user_item_results.
95 + $userCourse->status = UserItemModel::STATUS_CANCEL;
96 + $userCourse->save();
97 + } else {
98 + $userCourseGuest = self::get_user_course_guest( $course_id, $order->get_user_email() );
99 + // Check course is learning is sample order_id with order which is changing status
100 + if ( ! $userCourseGuest || $userCourseGuest->ref_id != $order->get_id() ) {
101 + continue;
102 + }
103 +
104 + $userCourseGuest->status = UserItemModel::STATUS_CANCEL;
105 + $userCourseGuest->save();
106 + }
107 + } else {
108 + // For buy other item type (not course)
109 + // For case item is Certificate, when update code of Certificate, should remove this code
110 + if ( $item['item_type'] === 'lp_cert' ) {
111 + $item['_lp_cert_id'] = $item['item_id'];
112 + }
113 + do_action( 'lp/order-pending/update/user-item', $item, $order, $user );
114 + }
115 + }
116 + }
117 + }
118 +
119 + /**
120 + * Enroll course if Order completed
121 + * 1. Check if order change is the latest order of user for course
122 + * 2. Check if user_course was canceled, only update status to Enrolled
123 + * 3. Handle repurchase course if allow repurchase
124 + * 4. Create new user_course if first purchase course
125 + * 5. Enroll course free or no enroll requirement
126 + * 6. Enroll course for guest if auto enroll enable
127 + * 7. Send email background when user enroll course
128 + *
129 + * @param LP_Order $order
130 + * @param string $old_status
131 + * @param string $new_status
132 + *
133 + * @throws Exception
134 + * @editor tungnx
135 + * @modify 4.1.2
136 + * @version 1.0.6
137 + */
138 + protected static function _update_user_item_order_completed( LP_Order $order, string $old_status, string $new_status ) {
139 + $lp_order_db = LP_Order_DB::getInstance();
140 + $items = $order->get_all_items();
141 + if ( ! $items ) {
142 + return;
143 + }
144 +
145 + $usersCourses = [];
146 + foreach ( $order->get_users() as $user_id ) {
147 + $user = learn_press_get_user( $user_id );
148 +
149 + foreach ( $items as $item ) {
150 + if ( isset( $item['item_id'] ) && LP_COURSE_CPT === $item['item_type'] ) {
151 + $course_id = $item['item_id'];
152 +
153 + // Check order_id of user_item current must < new order_id
154 + $userCourse = UserCourseModel::find( $user_id, $course_id, true );
155 + if ( $user_id && $userCourse && $userCourse->ref_id > $order->get_id() ) {
156 + continue;
157 + } elseif ( ! $user_id ) {
158 + $userCourseGuest = self::get_user_course_guest( $course_id, $order->get_user_email() );
159 + if ( $userCourseGuest && $userCourseGuest->ref_id > $order->get_id() ) {
160 + continue;
161 + }
162 + }
163 +
164 + // Check user course was canceled? If yes, only update status to Enrolled
165 + if ( $user_id && $userCourse && $userCourse->ref_id == $order->get_id() ) {
166 + if ( $userCourse->get_status() === UserItemModel::STATUS_CANCEL ) {
167 + if ( ! empty( $userCourse->get_end_time() ) ) {
168 + $userCourse->status = UserItemModel::STATUS_FINISHED;
169 + } else {
170 + $userCourse->status = UserItemModel::STATUS_ENROLLED;
171 + }
172 + $userCourse->save();
173 + }
174 +
175 + continue;
176 + }
177 +
178 + if ( $order->is_manual() ) {
179 + $usersCourses[] = self::handle_item_manual_order_completed( $order, $user, $item );
180 + } else {
181 + $usersCourses[] = self::handle_item_order_completed( $order, $user, $item );
182 + }
183 + } else {
184 + // For buy other item type (not course)
185 + // For case item is Certificate, when update code of Certificate, should remove this code
186 + if ( $item['item_type'] === 'lp_cert' ) {
187 + $item['_lp_cert_id'] = $item['item_id'];
188 + // Fixed for old Certificate <= v4.1.2
189 + $item['_lp_course_id_of_cert'] = learn_press_get_order_item_meta(
190 + $item['order_item_id'],
191 + '_lp_course_id_of_cert'
192 + );
193 + }
194 + do_action( 'lp/order-completed/update/user-item', $item, $order, $user );
195 + }
196 + }
197 + }
198 +
199 + // Run background send emails when users enroll courses (send for instructor, admin, student...)
200 + if ( ! empty( $usersCourses ) ) {
201 + $userCourseIds = [];
202 + foreach ( $usersCourses as $userCourse ) {
203 + if ( ! $userCourse instanceof UserCourseModel ) {
204 + continue;
205 + }
206 +
207 + if ( $userCourse->get_status() !== UserItemModel::STATUS_ENROLLED ) {
208 + continue;
209 + }
210 +
211 + $userCourseIds[] = [
212 + 'user_id' => $userCourse->user_id,
213 + 'course_id' => $userCourse->item_id,
214 + ];
215 + }
216 +
217 + if ( empty( $userCourseIds ) ) {
218 + return;
219 + }
220 +
221 + /**
222 + * @uses SendEmailAjax::send_mail_users_enrolled_courses
223 + */
224 + $data_send = [
225 + 'user_course_ids' => $userCourseIds,
226 + 'lp-load-ajax' => 'send_mail_users_enrolled_courses',
227 + ];
228 + LPBackgroundAjax::handle( $data_send );
229 + }
230 + }
231 +
232 + /**
233 + * Handle something when Order completed
234 + *
235 + * @author tungnx
236 + * @since 4.1.3
237 + * @version 1.1.1
238 + */
239 + protected static function handle_item_order_completed( LP_Order $order, $user, $item ) {
240 + $lp_user_items_db = LP_User_Items_DB::getInstance();
241 + $userCourseResponse = null;
242 +
243 + try {
244 + $course_id = intval( $item['course_id'] ?? $item['item_id'] ?? 0 );
245 + $courseModel = CourseModel::find( $course_id, true );
246 + if ( ! $courseModel ) {
247 + return null;
248 + }
249 +
250 + $auto_enroll = LP_Settings::is_auto_start_course();
251 + $keep_progress_items_course = false;
252 +
253 + $user_id = $user->get_id();
254 + if ( $user instanceof LP_User_Guest ) {
255 + $user_id = 0;
256 + }
257 +
258 + /** Get the newest user_item_id of course for allow_repurchase */
259 + $userCourse = UserCourseModel::find( $user_id, $course_id, true );
260 +
261 + $latest_user_item_id = 0;
262 + $allow_repurchase_option = $courseModel->get_type_repurchase();
263 + $allow_repurchase_type = '';
264 +
265 + // Data user_item for save database
266 + $user_item_data = [
267 + 'user_id' => $user_id,
268 + 'item_id' => $course_id,
269 + 'ref_id' => $order->get_id(),
270 + 'start_time' => gmdate( LP_Datetime::$format, time() ),
271 + 'graduation' => UserItemModel::GRADUATION_IN_PROGRESS,
272 + ];
273 +
274 + if ( $user_id && $userCourse ) {
275 + $latest_user_item_id = $userCourse->get_user_item_id();
276 +
277 + /** Get allow_repurchase_type for reset, update. Add in: rest-api/v1/frontend/class-lp-courses-controller.php: purchase_course */
278 + $allow_repurchase_type = learn_press_get_user_item_meta( $latest_user_item_id, '_lp_allow_repurchase_type' );
279 + }
280 +
281 + $is_no_required_enroll = $courseModel->has_no_enroll_requirement();
282 + $is_in_stock = $courseModel->is_in_stock();
283 +
284 + // If > 1 time purchase same course and allow repurchase
285 + if ( $courseModel->enable_allow_repurchase() && ! empty( $latest_user_item_id )
286 + && ! $courseModel->is_free() && ! $is_no_required_enroll ) {
287 + if ( $allow_repurchase_option !== 'popup' ) {
288 + $allow_repurchase_type = $allow_repurchase_option;
289 + } elseif ( empty( $allow_repurchase_type ) ) {
290 + // For case course set repurchase Popup but buy via Upsell, PMS, Woo can't set allow_repurchase_type
291 + $allow_repurchase_type = 'keep';
292 + }
293 +
294 + /**
295 + * If keep course progress will reset start_time, end_time, status, graduation
296 + * where user_item_id = $latest_user_item_id
297 + */
298 + if ( $allow_repurchase_type === 'keep' ) {
299 + $keep_progress_items_course = true;
300 + // Set data for update user item
301 + $user_item_data['user_item_id'] = $latest_user_item_id;
302 + $user_item_data['end_time'] = null;
303 + $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
304 +
305 + do_action( 'lp/allow_repurchase_options/continue/db/update', $user_item_data, $latest_user_item_id );
306 + } elseif ( $allow_repurchase_type === 'reset' ) {
307 + $user_item_data['end_time'] = null;
308 + $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
309 + }
310 +
311 + learn_press_delete_user_item_meta( $latest_user_item_id, '_lp_allow_repurchase_type' );
312 + } elseif ( ! $courseModel->is_free() && ! $is_no_required_enroll && $is_in_stock ) { // First purchase course
313 + // Set data for create user_item
314 + if ( $auto_enroll ) {
315 + $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
316 + } else {
317 + $user_item_data['status'] = UserItemModel::STATUS_PURCHASED;
318 + $user_item_data['graduation'] = '';
319 + }
320 + } elseif ( $user_id && ( $is_in_stock || $is_no_required_enroll ) ) { // Enroll course free or No enroll requirement.
321 + // Set data for create user_item
322 + $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
323 + } elseif ( LP_Checkout::instance()->is_enable_guest_checkout()
324 + && $auto_enroll && ( $is_in_stock || $is_no_required_enroll ) ) {
325 + $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
326 + } else {
327 + return null;
328 + }
329 +
330 + $user_item_data = apply_filters(
331 + 'learn-press/order/user-course-data',
332 + $user_item_data,
333 + $order,
334 + $item,
335 + $courseModel,
336 + $user_id
337 + );
338 +
339 + $another_case = apply_filters(
340 + 'learn-press/order/completed/update-user-item/another-case/bool',
341 + false,
342 + $user_item_data,
343 + $order,
344 + $item,
345 + $courseModel,
346 + $user_id
347 + );
348 +
349 + if ( $another_case ) { // Handle another case to handle user_item
350 + $userCourseResponse = apply_filters(
351 + 'learn-press/order/completed/update-user-item/another-case',
352 + null,
353 + $user_item_data,
354 + $order,
355 + $item,
356 + $courseModel,
357 + $user_id
358 + );
359 + } elseif ( $keep_progress_items_course ) { // Update user_item to keep course progress
360 + $userCourse->ref_id = $order->get_id();
361 + $userCourse->status = $user_item_data['status'];
362 + $userCourse->graduation = $user_item_data['graduation'];
363 + $userCourse->start_time = $user_item_data['start_time'];
364 + $userCourse->end_time = null;
365 + $userCourse->save();
366 + $userCourseResponse = $userCourse;
367 + } else { // Create new user_item
368 + // Delete items old
369 + if ( ! $user_id ) {
370 + $userGuestCourse = self::get_user_course_guest( $course_id, $order->get_user_email() );
371 + if ( $userGuestCourse ) {
372 + $userGuestCourse->delete();
373 + }
374 + } elseif ( $userCourse ) {
375 + //$lp_user_items_db->delete_user_items_old( $user_id, $course_id );
376 + $userCourse->delete();
377 + }
378 +
379 + $userCourseNew = new UserCourseModel( $user_item_data );
380 + $userCourseNew->save();
381 + $userCourseResponse = $userCourseNew;
382 + }
383 +
384 + if ( isset( $user_item_data['status'] ) && UserItemModel::STATUS_ENROLLED == $user_item_data['status'] ) {
385 + do_action( 'learnpress/user/course-enrolled', $order->get_id(), $user_item_data['item_id'], $user_item_data['user_id'] );
386 + }
387 + } catch ( Throwable $e ) {
388 + LP_Debug::error_log( $e );
389 + }
390 +
391 + return $userCourseResponse;
392 + }
393 +
394 + /**
395 + * Handle something when Manual Order completed
396 + *
397 + * @author tungnx
398 + * @since 4.1.3
399 + * @version 1.0.4
400 + */
401 + protected static function handle_item_manual_order_completed( LP_Order $order, $user, $item ) {
402 + $userCourseResponse = null;
403 +
404 + try {
405 + $courseModel = CourseModel::find( $item['course_id'] ?? $item['item_id'] ?? 0, true );
406 + if ( ! $courseModel ) {
407 + return $userCourseResponse;
408 + }
409 +
410 + if ( $user instanceof LP_User_Guest ) {
411 + return $userCourseResponse;
412 + }
413 +
414 + // Data user_item for save database
415 + $user_item_data = [
416 + 'user_id' => $user->get_id(),
417 + 'item_id' => $courseModel->get_id(),
418 + 'ref_id' => $order->get_id(),
419 + ];
420 +
421 + $auto_enroll = LP_Settings::is_auto_start_course();
422 + if ( $auto_enroll ) {
423 + $user_item_data['status'] = UserItemModel::STATUS_ENROLLED;
424 + $user_item_data['graduation'] = UserItemModel::GRADUATION_IN_PROGRESS;
425 + } else {
426 + $user_item_data['status'] = UserItemModel::STATUS_PURCHASED;
427 + }
428 +
429 + $user_item_data = apply_filters(
430 + 'learn-press/order/manual/user-course-data',
431 + $user_item_data,
432 + $order,
433 + $item,
434 + $courseModel
435 + );
436 +
437 + // Delete lp_user_items old
438 + LP_User_Items_DB::getInstance()->delete_user_items_old( $user->get_id(), $courseModel->get_id() );
439 + // End
440 +
441 + $userCourseModelNew = new UserCourseModel( $user_item_data );
442 + $userCourseModelNew->save();
443 + $userCourseResponse = $userCourseModelNew;
444 +
445 + if ( UserItemModel::STATUS_ENROLLED == $userCourseResponse->get_status() ) {
446 + do_action( 'learnpress/user/course-enrolled', $order->get_id(), $user_item_data['item_id'], $user_item_data['user_id'] );
447 + }
448 + } catch ( Throwable $e ) {
449 + error_log( __FUNCTION__ . ': ' . $e->getMessage() );
450 + }
451 +
452 + return $userCourseResponse;
453 + }
454 +
455 + /**
456 + * Get user_course of user Guest
457 + *
458 + * @param $course_id
459 + * @param $email_guest
460 + *
461 + * @return UserCourseModel|false
462 + * @throws Exception
463 + * @since 4.2.7.3
464 + * @version 1.0.0
465 + */
466 + public static function get_user_course_guest( $course_id, $email_guest ) {
467 + $lp_user_items_db = LP_User_Items_DB::getInstance();
468 + $filter = new LP_User_Items_Filter();
469 + $filter->user_id = 0;
470 + $filter->item_id = $course_id;
471 + $filter->join[] = "INNER JOIN {$lp_user_items_db->tb_postmeta} pm ON pm.post_id = ref_id";
472 + $filter->join[] = "INNER JOIN {$lp_user_items_db->tb_postmeta} pm2 ON pm2.post_id = ref_id";
473 + $filter->where[] = "AND pm.meta_key = '_checkout_email'";
474 + $filter->where[] = $lp_user_items_db->wpdb->prepare( 'AND pm2.meta_value = %s', $email_guest );
475 +
476 + return UserCourseModel::get_user_item_model_from_db( $filter );
477 + }
478 +
479 + /**
480 + * Hook into wp users list to exclude our temp users.
481 + *
482 + * @param array $args
483 + *
484 + * @return mixed
485 + * @deprecated 4.2.7.3
486 + */
487 + /*public static function exclude_temp_users( $args ) {
488 + if ( LP_Request::get_string( 'lp-action' ) == 'pending-request' ) {
489 + $args['include'] = self::get_pending_requests();
490 + }
491 +
492 + return $args;
493 + }*/
494 +
495 + /**
496 + * Get pending requests be come a Teacher.
497 + *
498 + * @return array
499 + * @deprecated 4.2.7.3
500 + */
501 + /*public static function get_pending_requests() {
502 + global $wpdb;
503 + $query = $wpdb->prepare(
504 + "
505 + SELECT ID
506 + FROM {$wpdb->users} u
507 + INNER JOIN {$wpdb->usermeta} um ON um.user_id = u.ID AND um.meta_key = %s
508 + WHERE um.meta_value = %s
509 + ",
510 + '_requested_become_teacher',
511 + 'yes'
512 + );
513 +
514 + return $wpdb->get_col( $query );
515 + }*/
516 +
517 + /**
518 + * @deprecated 4.2.7.3
519 + */
520 + /*public static function get_guest_id() {
521 + return 0;// empty( $_COOKIE['learn_press_user_guest_id'] ) ? false : $_COOKIE['learn_press_user_guest_id'];
522 + }*/
523 +
524 + /**
525 + * @param $the_user
526 + * @param bool $force
527 + *
528 + * @return LP_Abstract_User
529 + * @deprecated 4.2.7.3
530 + */
531 + /*public static function get_user( $the_user, $force = false ) {
532 + $the_id = 0;
533 + if ( is_numeric( $the_user ) ) {
534 + $the_id = $the_user;
535 + } elseif ( $the_user instanceof LP_Abstract_User ) {
536 + $the_id = $the_user->id;
537 + } elseif ( isset( $the_user->ID ) ) {
538 + $the_id = $the_user->ID;
539 + } elseif ( null === $the_user ) {
540 + $the_id = get_current_user_id();
541 + }
542 +
543 + $user_class = self::get_user_class( $the_id );
544 + if ( $user_class instanceof LP_User_Guest ) {
545 + $the_id = self::get_guest_id();
546 + }
547 + if ( empty( self::$_users[ $the_id ] ) || $force ) {
548 + self::$_users[ $the_id ] = new $user_class( $the_id );
549 + }
550 +
551 + return self::$_users[ $the_id ];
552 + }*/
553 +
554 + /**
555 + * Get class name for User Object
556 + *
557 + * @param int
558 + *
559 + * @return string
560 + * @deprecated 4.2.7.3
561 + */
562 + // public static function get_user_class( $the_id = 0 ) {
563 + // $deleted = in_array( $the_id, self::$_deleted_users );
564 + // $exists_user = ! $deleted ? get_userdata( $the_id ) : false;
565 + // if ( $exists_user ) {
566 + // $class = 'LP_User';
567 + // } else {
568 + // if ( ! $deleted ) {
569 + // self::$_deleted_users[] = $the_id;
570 + // /**
571 + // * Prevent loading user does not exists in database
572 + // */
573 + // $user = new LP_User_Guest( $the_id );
574 + // wp_cache_add( $the_id, $user, 'users' );
575 + // wp_cache_add( '', $the_id, 'userlogins' );
576 + // wp_cache_add( '', $the_id, 'useremail' );
577 + // wp_cache_add( '', $the_id, 'userslugs' );
578 + // }
579 + // $is_logged_in = function_exists( 'is_user_logged_in' ) && is_user_logged_in();
580 + // $class = $is_logged_in ? 'LP_User' : 'LP_User_Guest';
581 + // }
582 + //
583 + // return apply_filters( 'learn_press_user_class', $class );
584 + // }
585 +}
586 +
587 +LP_User_Factory::init();