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 / class-lp-checkout.php

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

609 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class LP_Checkout
4 *
5 * @author ThimPress <Nhamdv>
6 * @package LearnPress/Classes
7 * @version 4.0.0
8 */
9
10 use LearnPress\Helpers\Singleton;
11 use LearnPress\Models\CourseModel;
12 use LearnPress\Models\UserModel;
13
14 defined( 'ABSPATH' ) || exit;
15
16 class LP_Checkout {
17 use Singleton;
18
19 /**
20 * Payment method
21 *
22 * @var LP_Gateway_Abstract
23 */
24 public $payment_method = null;
25 /**
26 * Payment method string when user choice
27 *
28 * @var string $payment_method_str
29 */
30 public $payment_method_str = '';
31 /**
32 * @var null
33 */
34 public $user_login = null;
35 /**
36 * @var null
37 */
38 public $user_pass = null;
39 /**
40 * @var null
41 */
42 public $order_comment = null;
43 /**
44 * Handle the errors when checking out.
45 *
46 * @var array
47 */
48 public $errors = array();
49 /**
50 * @var string
51 */
52 protected $_checkout_email = '';
53 /**
54 * @var string
55 * @since 4.0.0
56 */
57 protected $guest_email = '';
58 /**
59 * @var string
60 * @since 4.0.0
61 */
62 protected $checkout_action = '';
63
64 public function init(): void {
65 if ( ! is_null( LearnPress::instance()->session ) ) {
66 $this->_checkout_email = LearnPress::instance()->session->get( 'checkout-email' );
67 }
68
69 add_action( 'set_logged_in_cookie', [ $this, 'set_logged_in_cookie' ] );
70 }
71
72 /**
73 * Create account when checking out with user guest and tick create account.
74 *
75 * @return int|WP_Error
76 */
77 protected function create_account(): int {
78 $user_id = 0;
79
80 try {
81 $email = $this->get_checkout_email();
82 $password = wp_generate_password();
83 $user_id = wp_create_user( $email, $password, $email );
84 } catch ( Throwable $e ) {
85 error_log( $e->getMessage() );
86 }
87
88 return $user_id;
89 }
90
91 /**
92 * Check valid fields login/register/guest checkout.
93 * Store session guest before login success.
94 * When user login success, will update session data of guest for user.
95 *
96 * @throws Exception
97 */
98 public function check_validate_fields() {
99 $session = LearnPress::instance()->session;
100 $data_session_before_user_login = $session->get_session_data();
101 $this->checkout_action = null;
102
103 if ( isset( $_POST['reg_email'] ) ) {
104 $this->checkout_action = 'register';
105 } elseif ( isset( $_POST['username'] ) ) {
106 $this->checkout_action = 'login';
107 } elseif ( isset( $_POST['guest_email'] ) ) {
108 $this->checkout_action = 'guest';
109 }
110
111 switch ( $this->checkout_action ) {
112 case 'login':
113 $user = wp_signon(
114 array(
115 'user_login' => LP_Request::get_param( 'username' ),
116 'user_password' => LP_Request::get_param( 'password' ),
117 'remember' => LP_Request::get_param( 'remember', false ),
118 ),
119 is_ssl()
120 );
121
122 if ( is_wp_error( $user ) ) {
123 throw new Exception( $user->get_error_message() );
124 } else {
125 wp_set_current_user( $user->ID );
126 }
127 break;
128 case 'register':
129 $default_fields = array(
130 'reg_email' => LP_Request::get_param( 'reg_email' ),
131 'reg_username' => LP_Request::get_param( 'reg_username' ),
132 'reg_password' => LP_Request::get_param( 'reg_password' ),
133 'reg_password2' => LP_Request::get_param( 'reg_password2' ),
134 );
135
136 if ( isset( $_POST['reg_first_name'] ) ) {
137 $default_fields['first_name'] = LP_Request::get_param( 'reg_first_name' );
138 }
139
140 if ( isset( $_POST['reg_last_name'] ) ) {
141 $default_fields['last_name'] = LP_Request::get_param( 'reg_last_name' );
142 }
143
144 if ( isset( $_POST['reg_display_name'] ) ) {
145 $default_fields['display_name'] = LP_Request::get_param( 'reg_display_name' );
146 }
147
148 $update_meta = isset( $_POST['_lp_custom_register_form'] ) ? LP_Helper::sanitize_params_submitted( $_POST['_lp_custom_register_form'] ) : array();
149
150 $user_id = LP_Forms_Handler::learnpress_create_new_customer(
151 $default_fields['reg_email'],
152 $default_fields['reg_username'],
153 $default_fields['reg_password'],
154 $default_fields['reg_password2'],
155 $default_fields,
156 $update_meta
157 );
158
159 if ( is_wp_error( $user_id ) ) {
160 throw new Exception( $user_id->get_error_message() );
161 } else {
162 // Directly authenticate the newly created user to bypass captcha plugins
163 // that hook into 'authenticate'. We already verified the password during registration.
164 $user = get_user_by( 'id', $user_id );
165
166 if ( ! $user instanceof WP_User ) {
167 throw new Exception( __( 'User registration succeeded but the user cannot be loaded.', 'learnpress' ) );
168 }
169
170 /*if ( ! wp_check_password( $default_fields['reg_password'], $user->user_pass, $user->ID ) ) {
171 throw new Exception( __( 'Incorrect password.', 'learnpress' ) );
172 }*/
173
174 wp_set_current_user( $user->ID );
175 wp_set_auth_cookie( $user->ID, true, is_ssl() );
176 do_action( 'wp_login', $user->user_login, $user );
177 }
178 break;
179 case 'guest':
180 $email_guest = LP_Request::get_param( 'guest_email' );
181 if ( ! is_email( $email_guest ) ) {
182 throw new Exception( __( 'Your email is not valid!', 'learnpress' ) );
183 }
184
185 $this->guest_email = $email_guest;
186 $this->_checkout_email = $email_guest;
187 break;
188 }
189
190 // Set session, cart for user have just login/register success.
191 if ( in_array( $this->checkout_action, [ 'login', 'register' ] ) ) {
192 foreach ( $data_session_before_user_login as $key => $item ) {
193 $session->set( $key, maybe_unserialize( $item ) );
194 }
195 $session->save_data();
196 }
197 }
198
199 /**
200 * Get email of user is being checkout.
201 *
202 * @return string
203 */
204 public function get_checkout_email() {
205 if ( $this->_checkout_email ) {
206 return $this->_checkout_email;
207 } elseif ( is_user_logged_in() ) {
208 $userModel = UserModel::find( get_current_user_id(), true );
209 if ( $userModel instanceof UserModel ) {
210 return $userModel->get_email();
211 }
212 }
213
214 return false;
215 }
216
217 /**
218 * @return bool|int
219 */
220 public function checkout_email_exists() {
221 $email = $this->get_checkout_email();
222
223 if ( ! $email ) {
224 return false;
225 }
226
227 $user = get_user_by( 'email', $email );
228 if ( ! $user ) {
229 return false;
230 }
231
232 return $user->ID;
233 }
234
235 /**
236 * Create LP Order.
237 *
238 * @return mixed|string
239 * @throws Exception
240 * @since 3.0.0
241 * @version 4.0.3
242 */
243 public function create_order() {
244 $cart = LearnPress::instance()->cart;
245 $cart_total = $cart->calculate_totals();
246 $order = new LP_Order();
247 $user_id = 0;
248 $user_can_register = get_option( 'users_can_register' );
249
250 if ( is_user_logged_in() ) {
251 $user_id = get_current_user_id();
252 } elseif ( $user_can_register ) {
253 $checkout_option = LP_Request::get_param( 'checkout-email-option' );
254 // Set user id for Order if buy with Guest and email exists on the user
255 $user_id = $this->checkout_email_exists();
256
257 // Create new user if buy with Guest and tick "Create new Account"
258 if ( $checkout_option === 'new-account' ) {
259 if ( $user_id ) {
260 throw new Exception( __( 'New account email is existed', 'learnpress' ), 0 );
261 }
262
263 //$order->set_meta( '_create_account', 'yes' );
264
265 $user_id = $this->create_account();
266 if ( $user_id ) {
267 // Notify mail create user success
268 wp_new_user_notification(
269 $user_id,
270 null,
271 apply_filters( 'learn-press/email-create-new-user-when-checkout', 'user' )
272 );
273 } else {
274 throw new Exception( __( 'Create account failed', 'learnpress' ), 0 );
275 }
276 }
277
278 // Get user_id Guest
279 if ( ! $user_id ) {
280 /**
281 * @var LP_User_Guest $user_guest
282 */
283 $user_guest = learn_press_get_user();
284 $user_id = $user_guest->get_id();
285 }
286 }
287
288 if ( $this->is_enable_guest_checkout() && $this->get_checkout_email() ) {
289 $order->set_checkout_email( $this->get_checkout_email() );
290 // Check email exists on the user will get user_id to set
291 if ( ! $user_id ) {
292 $user_id = $this->checkout_email_exists();
293 }
294 }
295
296 $order->set_customer_note( $this->order_comment );
297 $order->set_status( LP_ORDER_PENDING );
298 $order->set_total( $cart_total->total );
299 $order->set_subtotal( $cart_total->subtotal );
300 $order->set_user_ip_address( learn_press_get_ip() );
301 $order->set_user_agent( learn_press_get_user_agent() );
302 $order->set_created_via( 'checkout' );
303 $order->set_user_id( apply_filters( 'learn-press/checkout/default-user', $user_id ) );
304 if ( $this->payment_method instanceof LP_Gateway_Abstract ) {
305 $order->set_data( 'payment_method', $this->payment_method->get_id() );
306 $order->set_data( 'payment_method_title', $this->payment_method->get_title() );
307 }
308
309 $order_id = $order->save();
310
311 // Store the line items to the order
312 foreach ( $cart->get_items() as $item ) {
313 $item_type = get_post_type( $item['item_id'] );
314 if ( ! in_array( $item_type, learn_press_get_item_types_can_purchase() ) ) {
315 continue;
316 }
317
318 $item_id = $order->add_item( $item );
319 if ( ! $item_id ) {
320 throw new Exception( sprintf( __( 'Error %d: Unable to add item to order. Please try again.', 'learnpress' ), 402 ) );
321 }
322
323 do_action( 'learn-press/checkout/add-order-item-meta', $item_id, $item );
324 }
325
326 if ( ! empty( $this->user_id ) ) {
327 do_action( 'learn-press/checkout/update-user-meta', $this->user_id );
328 }
329
330 do_action( 'learn-press/checkout/update-order-meta', $order_id );
331
332 return $order_id;
333 }
334
335 /**
336 * Guest checkout is enable?
337 *
338 * @return bool
339 * @since 3.0.0
340 */
341 public function is_enable_guest_checkout(): bool {
342 return apply_filters(
343 'learn-press/checkout/enable-guest',
344 LP_Settings::get_option( 'guest_checkout', 'no' ) === 'yes'
345 );
346 }
347
348 /**
349 * Enable user can log in checkout page?
350 *
351 * @return bool
352 * @since 3.0.0
353 */
354 public function is_enable_login(): bool {
355 return apply_filters(
356 'learn-press/checkout/enable-login',
357 'yes' === LP_Settings::get_option( 'enable_login_checkout', 'yes' )
358 );
359 }
360
361 /**
362 * Enable user can register in checkout page?
363 *
364 * @return bool
365 * @since 3.0.0
366 */
367 public function is_enable_register(): bool {
368 return apply_filters(
369 'learn-press/checkout/enable-register',
370 'yes' === LP_Settings::get_option( 'enable_registration_checkout', 'yes' )
371 && get_option( 'users_can_register' )
372 );
373 }
374
375 /**
376 * Process checkout from request.
377 *
378 * @return void
379 * @throws Exception
380 */
381 public function process_checkout_handler() {
382 if ( strtolower( $_SERVER['REQUEST_METHOD'] ) != 'post' ) {
383 return;
384 }
385
386 /**
387 * Set default fields from request.
388 */
389 $this->payment_method_str = LP_Request::get_param( 'payment_method' );
390 $this->order_comment = LP_Request::get_param( 'order_comments' );
391 $this->_checkout_email = LP_Request::get_param( 'checkout-email' );
392 if ( $this->_checkout_email ) {
393 LearnPress::instance()->session->set( 'checkout-email', $this->_checkout_email );
394 }
395
396 $this->process_checkout();
397 }
398
399 /**
400 * Validate fields.
401 *
402 * Addon Upsell 4.0.1 use argument $errors
403 * Must update to 4.0.2 to use throw Error instead.
404 *
405 * @throws Exception
406 */
407 public function validate_checkout_fields() {
408 $this->errors = array();
409
410 // Check nonce
411 $nonce = LP_Request::get_param( 'learn-press-checkout-nonce' );
412 if ( ! wp_verify_nonce( $nonce, 'learn-press-checkout' ) ) {
413 throw new Exception( __( 'Your session has expired.', 'learnpress' ) );
414 }
415
416 $this->check_validate_fields();
417
418 do_action( 'learn-press/validate-checkout-fields', $this );
419 }
420
421 /**
422 * Validate checkout payment.
423 *
424 * @throws Exception
425 */
426 public function validate_payment() {
427 $cart = LearnPress::instance()->cart;
428 //$validate = true;
429
430 if ( $cart->needs_payment() ) {
431 if ( ! $this->payment_method instanceof LP_Gateway_Abstract ) {
432 $available_gateways = LP_Gateways::instance()->get_available_payment_gateways();
433
434 if ( ! isset( $available_gateways[ $this->payment_method_str ] ) ) {
435 throw new Exception( __( 'No payment method is selected', 'learnpress' ), LP_ERROR_NO_PAYMENT_METHOD_SELECTED );
436 } else {
437 $this->payment_method = $available_gateways[ $this->payment_method_str ];
438 }
439
440 $this->payment_method->validate_fields();
441 }
442 }
443 }
444
445 /**
446 * Process checkout.
447 *
448 * @throws Exception
449 */
450 public function process_checkout() {
451 ini_set( 'max_execution_time', HOUR_IN_SECONDS );
452 $result = array(
453 'result' => 'fail',
454 'message' => '',
455 );
456
457 try {
458 $lp_session = LearnPress::instance()->session;
459
460 do_action( 'learn-press/before-checkout' );
461
462 $cart = LearnPress::instance()->cart;
463 if ( $cart->is_empty() ) {
464 throw new Exception( __( 'Your cart is currently empty.', 'learnpress' ) );
465 }
466
467 foreach ( $cart->get_items() as $item ) {
468 $item_type = get_post_type( $item['item_id'] );
469
470 if ( ! in_array( $item_type, learn_press_get_item_types_can_purchase() ) ) {
471 throw new Exception( __( 'Type item buy invalid!', 'learnpress' ) );
472 }
473 }
474
475 // Validate fields
476 $this->validate_checkout_fields();
477 // Validate payment method
478 $this->validate_payment();
479
480 $user_id = $this->checkout_email_exists();
481 if ( ! $user_id ) {
482 $user_id = 0;
483 }
484
485 // Check user can purchase, enrolled course
486 foreach ( $cart->get_items() as $item ) {
487 $item_type = get_post_type( $item['item_id'] );
488 if ( LP_COURSE_CPT === $item_type ) {
489 $courseModel = CourseModel::find( $item['item_id'], true );
490 if ( ! $courseModel ) {
491 throw new Exception( __( 'Course is invalid!', 'learnpress' ) );
492 }
493
494 $userModel = UserModel::find( $user_id, true );
495
496 // Check user can purchase course
497 if ( ! $courseModel->is_free() ) {
498 $can_purchase = $courseModel->can_purchase( $userModel );
499 if ( is_wp_error( $can_purchase ) ) {
500 //throw new Exception( $can_purchase->get_error_message() );
501 learn_press_set_message(
502 [
503 'status' => 'error',
504 'content' => $can_purchase->get_error_message(),
505 ]
506 );
507 $result['redirect'] = LP_Page_Controller::get_link_page( 'checkout', [], true );
508 $result['message'] = $can_purchase->get_error_message();
509 learn_press_send_json( $result );
510 }
511 } else {
512 // Check user can enroll course
513 $can_enroll = $courseModel->can_enroll( $userModel );
514 if ( is_wp_error( $can_enroll ) ) {
515 learn_press_set_message(
516 [
517 'status' => 'error',
518 'content' => $can_enroll->get_error_message(),
519 ]
520 );
521 $result['redirect'] = LP_Page_Controller::get_link_page( 'checkout', [], true );
522 $result['message'] = $can_enroll->get_error_message();
523 learn_press_send_json( $result );
524 }
525 }
526 }
527 }
528
529 // Create order if not handle done.
530 $order_id = $lp_session->get( 'order_awaiting_payment', 0 );
531 if ( ! $order_id ) {
532 $order_id = $this->create_order();
533 if ( is_wp_error( $order_id ) ) {
534 throw new Exception( $order_id->get_error_message() );
535 }
536
537 $lp_session->set( 'order_awaiting_payment', $order_id, true );
538 }
539
540 // allow Third-party hook: send email and more...
541 do_action( 'learn-press/checkout-order-processed', $order_id, $this );
542
543 if ( $this->payment_method instanceof LP_Gateway_Abstract ) {
544 // Process Payment
545 $result = $this->payment_method->process_payment( $order_id );
546 if ( isset( $result['result'] ) ) {
547 if ( 'success' === $result['result'] ) {
548 // Clear cart.
549 LearnPress::instance()->get_cart()->empty_cart();
550 $result = apply_filters( 'learn-press/payment-successful-result', $result, $order_id );
551 }
552
553 if ( ! learn_press_is_ajax() ) {
554 ini_set( 'max_execution_time', LearnPress::$time_limit_default_of_sever );
555 wp_redirect( $result['redirect'] );
556 exit;
557 }
558 }
559 } else {
560 // For case enroll a course free.
561 $order = new LP_Order( $order_id );
562 if ( $order->payment_complete() ) {
563 $redirect = $order->get_checkout_order_received_url();
564
565 // Clear cart.
566 LearnPress::instance()->get_cart()->empty_cart();
567
568 $result = array(
569 'result' => 'success',
570 'redirect' => $redirect,
571 );
572
573 if ( ! learn_press_is_ajax() ) {
574 ini_set( 'max_execution_time', LearnPress::$time_limit_default_of_sever );
575 wp_redirect( $result['redirect'] );
576 exit;
577 }
578 }
579 }
580 } catch ( Throwable $e ) {
581 $result['message'] = $e->getMessage();
582 }
583
584 ini_set( 'max_execution_time', LearnPress::$time_limit_default_of_sever );
585 learn_press_send_json( $result );
586 }
587
588 /**
589 * Sync $_COOKIE[LOGGED_IN_COOKIE] within the current checkout request.
590 *
591 * Checkout runs over AJAX. When login/register succeeds, wp_signon() only
592 * sends a Set-Cookie header to the browser (effective on the next request)
593 * and does not update $_COOKIE for the current request. Hooking into
594 * 'set_logged_in_cookie' lets us grab the newly generated cookie value and
595 * assign it to $_COOKIE manually, so subsequent code in the same request
596 * (e.g. creating the order) correctly recognizes the logged-in user.
597 * LPBackgroundAjax use $_COOKIE to send mails.
598 *
599 * @param string $logged_in_cookie The newly generated logged_in cookie value.
600 */
601 public function set_logged_in_cookie( $logged_in_cookie ) {
602 if ( ! isset( $_POST['learn-press-checkout-nonce'] ) ) {
603 return;
604 }
605
606 $_COOKIE[ LOGGED_IN_COOKIE ] = $logged_in_cookie;
607 }
608 }
609