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.1 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 All 141 releases
← All changes | inc/cart/class-lp-cart.php +109 -271 4.1.7.2 → 4.4.9 View file →
@@ -5,11 +5,13 @@
5 5 * Simple Cart object for now. Maybe need to expand later
6 6 *
7 7 * @author ThimPress
8 8 * @package LearnPress/Classes
9 - * @version 1.0
9 + * @version 1.0.1
10 10 */
11 11
12 +use LearnPress\Models\CourseModel;
13 +
12 14 defined( 'ABSPATH' ) || exit();
13 15
14 16 class LP_Cart {
15 17
@@ -17,9 +19,9 @@
17 19 * Unique instance of LP_Cart
18 20 *
19 21 * @var LP_Cart object
20 22 */
21 - private static $instances = array();
23 + private static $instance = null;
22 24
23 25 /**
24 26 * Hold the content of the cart
25 27 *
@@ -24,9 +26,9 @@
24 26 * Hold the content of the cart
25 27 *
26 28 * @var array
27 29 */
28 - protected $_cart_content = array();
30 + protected $_cart_content = [];
29 31
30 32 /**
31 33 * Key of cart content stored in session
32 34 *
@@ -60,115 +62,42 @@
60 62
61 63 LP_Request::register( 'add-course-to-cart', array( $this, 'add_to_cart' ), 20 );
62 64 LP_Request::register( 'remove-cart-item', array( $this, 'remove_item' ), 20 );
63 65
64 - add_action( 'learn-press/add-to-cart', array( $this, 'calculate_totals' ), 10 );
66 + //add_action( 'learn-press/add-to-cart', array( $this, 'calculate_totals' ), 10 );
65 67 //add_action( 'wp', array( $this, 'maybe_set_cart_cookies' ), 99 );
66 68 //add_action( 'shutdown', array( $this, 'maybe_set_cart_cookies' ), 0 );
67 - add_action( 'wp_loaded', array( $this, 'init' ) );
69 + //add_action( 'wp_loaded', array( $this, 'init' ) );
68 70 }
69 71
70 72 /**
71 - * Init cart.
72 - * Get data from session and put to cart content.
73 - */
74 - function init() {
75 - // Only load on checkout page
76 - $page_checkout_option = untrailingslashit( get_the_permalink( learn_press_get_page_id( 'checkout' ) ) );
77 - $page_checkout_option = str_replace( '/', '\/', $page_checkout_option );
78 - $pattern = '/' . $page_checkout_option . '/';
79 - if ( ! preg_match( $pattern, LP_Helper::getUrlCurrent() ) ) {
80 - return;
81 - }
82 -
83 - $this->get_cart_from_session();
84 - }
85 -
86 - /**
87 - * @depecated 4.1.7.2
88 - */
89 - public function maybe_set_cart_cookies() {
90 -
91 - if ( ! headers_sent()/* && did_action( 'wp_loaded' )*/ ) {
92 - // $this->set_cart_cookies( ! $this->is_empty() );
93 - }
94 - }
95 -
96 - private function set_cart_cookies( $set = true ) {
97 - if ( $set ) {
98 - learn_press_setcookie( 'wordpress_lp_cart', 1 );
99 - } elseif ( isset( $_COOKIE['wordpress_lp_cart'] ) ) {
100 - learn_press_setcookie( 'wordpress_lp_cart', 0, time() - HOUR_IN_SECONDS );
101 - }
102 -
103 - do_action( 'learn_press_set_cart_cookies', $set );
104 - }
105 -
106 - /**
107 - * Get data from session
108 - *
109 - * @return array
110 - */
111 - public function get_cart_for_session() {
112 - $cart_session = array();
113 -
114 - if ( $this->get_cart() ) {
115 - foreach ( $this->get_cart() as $key => $values ) {
116 - $cart_session[ $key ] = $values;
117 - unset( $cart_session[ $key ]['data'] );
118 - }
119 - }
120 -
121 - return $cart_session;
122 - }
123 -
124 - /**
125 - * Get cart content.
126 - *
127 - * @return array
128 - */
129 - public function get_cart() {
130 - if ( ! did_action( 'wp_loaded' ) ) {
131 - _doing_it_wrong( __FUNCTION__, __( 'Get cart should not be called before the wp_loaded action.', 'learnpress' ), '2.3' );
132 - }
133 -
134 - if ( ! did_action( 'learn_press_cart_loaded_from_session' ) ) {
135 - $this->get_cart_from_session();
136 - }
137 -
138 - return array_filter( (array) $this->_cart_content );
139 - }
140 -
141 - /**
142 73 * Add course to cart.
143 74 *
144 - * @param int $item_id
145 - * @param int $quantity
75 + * @param int $item_id
76 + * @param int $quantity
146 77 * @param array $item_data
147 78 *
148 - * @return mixed
79 + * @return string|false
149 80 */
150 81 public function add_to_cart( int $item_id = 0, int $quantity = 1, array $item_data = array() ) {
151 82 try {
83 + /**
84 + * Todo: check it to change, not use get_post_type
85 + * Ex: addon membership has plan need payment, but not use custom post type
86 + * Or addon certificate, currently use custom post type, but feature after upgrade, not save on posts table
87 + */
152 88 $item_type = get_post_type( $item_id );
153 89
154 90 if ( ! in_array( $item_type, learn_press_get_item_types_can_purchase() ) ) {
155 - throw new Exception( 'Item type is invalid!', 'learnpress' );
91 + throw new Exception( __( 'Item type is invalid!', 'learnpress' ) );
156 92 }
157 93
158 94 switch ( $item_type ) {
159 95 case LP_COURSE_CPT:
160 - $course = learn_press_get_course( $item_id );
161 -
162 - if ( ! $course->is_purchasable() ) {
163 - throw new Exception( __( 'Sorry! This course is not purchasable.', 'learnpress' ) );
96 + $course = CourseModel::find( $item_id, true );
97 + if ( ! $course ) {
98 + throw new Exception( __( 'Course is not exists!', 'learnpress' ) );
164 99 }
165 -
166 - if ( ! $course->is_in_stock() ) {
167 - throw new Exception( __( 'Sorry! The number of enrolled students has reached limit', 'learnpress' ) );
168 - }
169 -
170 - $item_data['data'] = $course;
171 100 break;
172 101 default:
173 102 $item_data = apply_filters( 'learnpress/cart/add-item/item_type_' . $item_type, $item_data, $item_id, $quantity );
174 103 break;
@@ -173,12 +102,10 @@
173 102 $item_data = apply_filters( 'learnpress/cart/add-item/item_type_' . $item_type, $item_data, $item_id, $quantity );
174 103 break;
175 104 }
176 105
177 - // $item_data = apply_filters( 'learnpress/cart/item-data', $item_data, $item_id );
178 -
179 - $cart_id = $this->generate_cart_id( $item_id, $item_data );
180 -
106 + $cart_id = $this->generate_cart_id( $item_id, $item_data );
107 + $this->_cart_content = $this->get_cart_from_session();
181 108 $this->_cart_content[ $cart_id ] = apply_filters(
182 109 'learn_press_add_cart_item',
183 110 array_merge(
184 111 array(
@@ -183,25 +110,28 @@
183 110 array_merge(
184 111 array(
185 112 'item_id' => $item_id,
186 113 'quantity' => $quantity,
187 - 'data' => array(),
114 + //'data' => array(),
188 115 ),
189 116 $item_data
190 117 )
191 118 );
192 119
193 - $this->set_cart_cookies( true );
120 + // Fixed security, quantity must be > 0
121 + if ( (int) $this->_cart_content[ $cart_id ]['quantity'] <= 0 ) {
122 + $this->_cart_content[ $cart_id ]['quantity'] = 1;
123 + }
194 124
195 - /**
196 - * @see LP_Cart::calculate_totals()
197 - */
125 + // Update cart to session DB.
126 + $this->update_session( $this->_cart_content );
127 +
198 128 do_action( 'learn-press/add-to-cart', $item_id, $quantity, $item_data, $cart_id );
199 129
200 130 return $cart_id;
201 131 } catch ( Exception $e ) {
202 132 if ( $e->getMessage() ) {
203 - learn_press_add_message( $e->getMessage(), 'error' );
133 +
204 134 }
205 135
206 136 return false;
207 137 }
@@ -222,9 +152,9 @@
222 152 unset( $this->_cart_content['items'][ $item_id ] );
223 153
224 154 do_action( 'learn_press_cart_item_removed', $item_id, $this );
225 155
226 - $this->calculate_totals();
156 + $this->update_session( $this->_cart_content );
227 157
228 158 return true;
229 159 }
230 160
@@ -232,19 +162,25 @@
232 162 }
233 163
234 164 /**
235 165 * Re-calculate cart totals and update data to session
166 + *
167 + * @since 3.0.0
168 + * @version 4.0.2
236 169 */
237 170 public function calculate_totals() {
238 - $total = $subtotal = 0;
239 - $this->total = $this->subtotal = 0;
240 - $items = $this->get_cart();
171 + $data = new stdClass();
172 + $total = 0;
173 + $data->subtotal = $total;
174 + $data->total = $total;
175 + $subtotal = $total;
176 + $this->total = $total;
177 + $this->subtotal = $total;
178 + $items = $this->get_items();
241 179
242 180 if ( $items ) {
243 181 foreach ( $items as $cart_id => $item ) {
244 -
245 182 $item_type = get_post_type( $item['item_id'] );
246 -
247 183 if ( ! in_array( $item_type, learn_press_get_item_types_can_purchase() ) ) {
248 184 continue;
249 185 }
250 186
@@ -259,33 +195,49 @@
259 195 }
260 196
261 197 $total = $subtotal;
262 198
263 - $this->_cart_content[ $cart_id ]['subtotal'] = $subtotal;
264 - $this->_cart_content[ $cart_id ]['total'] = $total;
199 + $data->subtotal += $subtotal;
200 + $data->total += $total;
265 201
266 - $this->subtotal += $subtotal;
267 - $this->total += $total;
202 + // For template old use.
203 + LearnPress::instance()->cart->subtotal += $subtotal;
204 + LearnPress::instance()->cart->total += $total;
268 205 }
269 206 }
270 207
271 - $this->update_session();
208 + return apply_filters( 'lp/cart/calculate_total', $data, $items );
209 +
210 + //$this->update_session();
272 211 }
273 212
274 213 /**
275 214 * Update cart content to session
215 + *
216 + * @since 3.0.0
217 + * @version 1.0.1
276 218 */
277 - public function update_session() {
278 - learn_press_session_set( $this->_cart_session_key, $this->get_cart_for_session() );
279 - }
219 + public function update_session( array $cart_content = [] ) {
220 + //learn_press_session_set( $this->_cart_session_key, $this->get_cart_for_session() );
221 + //$cart = $this->get_cart();
280 222
281 - /**
282 - * Get cart id
283 - *
284 - * @return mixed
285 - */
286 - public function get_cart_id() {
287 - return ! empty( $_SESSION['learn_press_cart']['cart_id'] ) ? $_SESSION['learn_press_cart']['cart_id'] : 0;
223 + // Only save data item_id and quantity.
224 + /**
225 + * Current certificate is not compatible with type $data_cart_save,
226 + * because certificate override hook 'learn-press/review-order/cart-item-product' to set course.
227 + * Need rewrite certificate to compatible with new cart.
228 + */
229 + /*$data_cart_save = array_map(
230 + function ( $item ) {
231 + return array(
232 + 'item_id' => $item['item_id'],
233 + 'quantity' => $item['quantity'],
234 + );
235 + },
236 + $cart
237 + );*/
238 +
239 + LearnPress::instance()->session->set( $this->_cart_session_key, $cart_content, true );
288 240 }
289 241
290 242 /**
291 243 * Get all items from cart.
@@ -291,12 +243,10 @@
291 243 * Get all items from cart.
292 244 *
293 245 * @return array
294 246 */
295 - public function get_items() {
296 - $items = $this->get_cart();
297 -
298 - return $items;
247 + public function get_items(): array {
248 + return $this->get_cart_from_session();
299 249 }
300 250
301 251 /**
302 252 * Load cart content data from session
@@ -301,51 +251,21 @@
301 251 /**
302 252 * Load cart content data from session
303 253 *
304 254 * @since 3.0.0
305 - * @version 3.0.1
255 + * @version 3.0.2
256 + * @modify 4.2.0 - tungnx
306 257 */
307 258 public function get_cart_from_session() {
308 - if ( did_action( 'learn_press_get_cart_from_session' ) ) {
309 - return;
259 + $session_data = LearnPress::instance()->session->get_session_data();
260 + $cart = maybe_unserialize( $session_data['cart'] ?? '' );
261 + if ( ! is_array( $cart ) ) {
262 + $cart = [];
310 263 }
311 264
312 - $cart = learn_press_session_get( $this->_cart_session_key );
313 - $data = array();
314 - if ( $cart ) {
315 - foreach ( $cart as $cart_id => $values ) {
316 - if ( ! empty( $values['item_id'] ) ) {
317 - $item_type = get_post_type( $values['item_id'] );
318 - if ( ! in_array( $item_type, learn_press_get_item_types_can_purchase() ) ) {
319 - continue;
320 - }
265 + $this->_cart_content = $cart;
321 266
322 - switch ( $item_type ) {
323 - case LP_COURSE_CPT:
324 - $course = learn_press_get_course( $values['item_id'] );
325 - if ( $course && $course->exists() && $values['quantity'] > 0 ) {
326 - if ( ! $course->is_purchasable() ) {
327 - learn_press_add_message( sprintf( __( '%s has been removed from your cart because it can no longer be purchased.', 'learnpress' ), $course->get_title() ), 'error' );
328 - do_action( 'learn-press/remove-cart-item-from-session', $cart, $values );
329 - } else {
330 - $data = array_merge( $values, array( 'data' => $course ) );
331 - $this->_cart_content[ $cart_id ] = $data;
332 - }
333 - }
334 - break;
335 - default:
336 - $this->_cart_content[ $cart_id ] = apply_filters( 'learn-press/get-cart-item-from-session/item_type_' . $item_type, $data, $values, $cart_id );
337 - break;
338 - }
339 - }
340 - }
341 - }
342 -
343 - do_action( 'learn_press_cart_loaded_from_session' );
344 - LearnPress::instance()->session->set( $this->_cart_session_key, $this->get_cart_for_session() );
345 - do_action( 'learn_press_get_cart_from_session' );
346 -
347 - $this->calculate_totals();
267 + return $this->_cart_content;
348 268 }
349 269
350 270 /**
351 271 * Get cart sub-total
@@ -352,11 +272,11 @@
352 272 *
353 273 * @return mixed
354 274 */
355 275 public function get_subtotal() {
356 - $subtotal = apply_filters( 'learn_press_get_cart_subtotal', learn_press_format_price( $this->subtotal, true ) );
276 + $subtotal = learn_press_format_price( $this->subtotal, true );
357 277
358 - return apply_filters( 'learn-press/cart-subtotal', $subtotal );
278 + return apply_filters( 'learn-press/cart-subtotal', $subtotal, $this );
359 279 }
360 280
361 281 /**
362 282 * Get cart total
@@ -363,17 +283,17 @@
363 283 *
364 284 * @return mixed
365 285 */
366 286 public function get_total() {
367 - $total = apply_filters( 'learn_press_get_cart_total', learn_press_format_price( $this->total, true ) );
287 + $total = learn_press_format_price( $this->total, true );
368 288
369 - return apply_filters( 'learn-press/cart-total', $total );
289 + return apply_filters( 'learn-press/cart-total', $total, $this );
370 290 }
371 291
372 292 /**
373 293 * Generate unique cart id from course id and data.
374 294 *
375 - * @param int $course_id
295 + * @param int $course_id
376 296 * @param mixed $data
377 297 *
378 298 * @return string
379 299 */
@@ -395,21 +315,21 @@
395 315 return apply_filters( 'learn-press/cart-id', md5( join( '_', $cart_id ) ), $cart_id, $data );
396 316 }
397 317
398 318 /**
399 - * Return sub-total of cart content
319 + * Return subtotal of cart content
400 320 *
401 - * @param LP_Course $course
402 - * @param int $quantity
321 + * @param LP_Course|LP_Certificate|CourseModel $item
322 + * @param int $quantity
403 323 *
404 324 * @return mixed
405 325 */
406 - public function get_item_subtotal( $course, $quantity = 1 ) {
407 - $price = $course->get_price();
326 + public function get_item_subtotal( $item, int $quantity = 1 ) {
327 + $price = $item->get_price();
408 328 $row_price = $price * $quantity;
409 329 $course_subtotal = learn_press_format_price( $row_price, true );
410 330
411 - return apply_filters( 'learn-press/cart/item-subtotal', $course_subtotal, $course, $quantity, $this );
331 + return apply_filters( 'learn-press/cart/item-subtotal', $course_subtotal, $item, $quantity, $this );
412 332 }
413 333
414 334 /**
415 335 * Clean all items from cart
@@ -415,17 +335,19 @@
415 335 * Clean all items from cart
416 336 *
417 337 * @return $this
418 338 */
419 - public function empty_cart() {
339 + public function empty_cart(): LP_Cart {
420 340
421 341 do_action( 'learn-press/cart/before-empty' );
422 342
423 343 $this->_cart_content = array();
344 + $lp_session = LearnPress::instance()->session;
345 + $lp_session->remove( 'order_awaiting_payment', true );
346 + $lp_session->remove( 'cart', true );
347 + //unset( LearnPress::instance()->session->order_awaiting_payment );
348 + //unset( LearnPress::instance()->session->cart );
424 349
425 - unset( LearnPress::instance()->session->order_awaiting_payment );
426 - unset( LearnPress::instance()->session->cart );
427 -
428 350 do_action( 'learn-press/cart/emptied' );
429 351
430 352 return $this;
431 353 }
@@ -434,22 +356,12 @@
434 356 * Check if cart is empty or not
435 357 *
436 358 * @return bool
437 359 */
438 - public function is_empty() {
439 - return sizeof( $this->get_cart() ) === 0;
440 - }
360 + public function is_empty(): bool {
361 + $cart_content = $this->get_cart_from_session();
441 362
442 - /**
443 - * Get checkout url for checkout page
444 - * Return default url of checkout page
445 - *
446 - * @return mixed
447 - */
448 - public function get_checkout_url() {
449 - $checkout_url = learn_press_get_page_link( 'checkout' );
450 -
451 - return apply_filters( 'learn_press_get_checkout_url', $checkout_url );
363 + return sizeof( $cart_content ) === 0;
452 364 }
453 365
454 366 /**
455 367 * Checks if need to payment
@@ -457,97 +369,23 @@
457 369 *
458 370 * @return mixed
459 371 */
460 372 public function needs_payment() {
461 - return apply_filters( 'learn_press_cart_needs_payment', $this->total > 0, $this );
462 - }
373 + $cart_data = $this->calculate_totals();
463 374
464 - /**
465 - * Process action for purchase course button
466 - *
467 - * @param $course_id
468 - * @depecated 4.1.6.8
469 - */
470 - public function purchase_course_handler( $course_id ) {
471 - _deprecated_function( __FUNCTION__, '4.1.6.8' );
472 - do_action( 'learn_press_before_purchase_course_handler', $course_id, $this );
473 -
474 - if ( apply_filters( 'learn_press_purchase_single_course', true ) ) {
475 - $this->empty_cart();
476 - }
477 -
478 - $this->add_to_cart( $course_id, 1, $_POST );
479 - $redirect = learn_press_get_checkout_url();
480 - $has_checkout = $redirect ? true : false;
481 - $need_checkout = $this->needs_payment();
482 -
483 - // In case the course is FREE and "No checkout free course" is turn off
484 - if ( ! $need_checkout ) {
485 - $user = learn_press_get_current_user();
486 - if ( ! $user->has_purchased_course( $course_id )/* || $user->has_finished_course( $course_id ) */ ) {
487 - require_once LP_PLUGIN_PATH . '/inc/gateways/class-lp-gateway-none.php';
488 - $checkout = learn_press_get_checkout( array( 'payment_method' => new LP_Gateway_None() ) );
489 -
490 - /**
491 - * + Auto enroll
492 - */
493 - // add_filter( 'learn_press_checkout_success_result', '_learn_press_checkout_success_result', 10, 2 );
494 - $checkout->process_checkout();
495 - // remove_filter( 'learn_press_checkout_success_result', '_learn_press_checkout_success_result', 10 );
496 - }/*
497 - else {
498 - if ( $user->has_finished_course( $course_id ) ) {
499 - learn_press_add_message( __( 'You have already finished course', 'learnpress' ) );
500 - } else {
501 - learn_press_add_message( __( 'You have already enrolled course', 'learnpress' ) );
502 - }
503 - }*/
504 - } else {
505 -
506 - // Checkout page is not setting up
507 - if ( ! $has_checkout ) {
508 - learn_press_add_message( __( 'Checkout page hasn\'t been setup', 'learnpress' ), 'error' );
509 - } else {
510 - wp_redirect( apply_filters( 'learn_press_checkout_redirect', $redirect ) );
511 - exit();
512 - }
513 - }
514 -
515 - return;
375 + return apply_filters( 'learn_press_cart_needs_payment', $cart_data->total > 0, $this );
516 376 }
517 377
518 - /**
519 - * Destroy cart instance
520 - */
521 - public function destroy() {
522 378
523 - }
524 -
525 -
526 379 /**
527 380 * Get unique instance of LP_Cart object
528 381 *
529 - * @return LP_Cart|mixed
382 + * @return LP_Cart
530 383 */
531 384 public static function instance() {
532 - $class = __CLASS__;
533 - if ( function_exists( 'get_called_class' ) ) {
534 - $class = get_called_class();
385 + if ( is_null( self::$instance ) ) {
386 + self::$instance = new self();
535 387 }
536 388
537 - $backtrace = debug_backtrace();
538 -
539 - if ( isset( $backtrace[2]['function'] ) ) {
540 - if ( 'call_user_func' === $backtrace[2]['function'] ) {
541 - $class = $backtrace[2]['args'][0][0];
542 - }
543 - } elseif ( isset( $backtrace[2]['class'] ) ) {
544 - $class = $backtrace[2]['class'];
545 - }
546 -
547 - if ( empty( self::$instances[ $class ] ) ) {
548 - self::$instances[ $class ] = new $class();
549 - }
550 -
551 - return self::$instances[ $class ];
389 + return self::$instance;
552 390 }
553 391 }