PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.5
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.5
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.5, at inc/class-lp-checkout.php

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