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