PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
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.4.8, at inc/user/class-lp-user-factory.php

588 lines 18.0 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 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@email.com>
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();
588