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

class-lp-user-factory.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.3.9.1, at inc/user/class-lp-user-factory.php

587 lines 18.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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@email.com>
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();
587