PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.2
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.2
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 / cart / class-lp-cart.php

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

392 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class LP_Cart
4 *
5 * Simple Cart object for now. Maybe need to expand later
6 *
7 * @author ThimPress
8 * @package LearnPress/Classes
9 * @version 1.0.1
10 */
11
12 use LearnPress\Models\CourseModel;
13
14 defined( 'ABSPATH' ) || exit();
15
16 class LP_Cart {
17
18 /**
19 * Unique instance of LP_Cart
20 *
21 * @var LP_Cart object
22 */
23 private static $instance = null;
24
25 /**
26 * Hold the content of the cart
27 *
28 * @var array
29 */
30 protected $_cart_content = [];
31
32 /**
33 * Key of cart content stored in session
34 *
35 * @var string
36 */
37 protected $_cart_session_key = 'cart';
38
39 /**
40 * Cart total
41 *
42 * @var int
43 */
44 public $total = 0;
45
46 /**
47 * Cart subtotal
48 *
49 * @var int
50 */
51 public $subtotal = 0;
52
53 /**
54 * Constructor
55 *
56 * @param string $key . Added since 3.3.0
57 */
58 public function __construct( $key = '' ) {
59 if ( $key ) {
60 $this->_cart_session_key = $key;
61 }
62
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 );
65
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' ) );
70 }
71
72 /**
73 * Add course to cart.
74 *
75 * @param int $item_id
76 * @param int $quantity
77 * @param array $item_data
78 *
79 * @return string|false
80 */
81 public function add_to_cart( int $item_id = 0, int $quantity = 1, array $item_data = array() ) {
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 */
88 $item_type = get_post_type( $item_id );
89
90 if ( ! in_array( $item_type, learn_press_get_item_types_can_purchase() ) ) {
91 throw new Exception( 'Item type is invalid!', 'learnpress' );
92 }
93
94 switch ( $item_type ) {
95 case LP_COURSE_CPT:
96 $course = CourseModel::find( $item_id, true );
97 if ( ! $course ) {
98 throw new Exception( __( 'Course is not exists!', 'learnpress' ) );
99 }
100 break;
101 default:
102 $item_data = apply_filters( 'learnpress/cart/add-item/item_type_' . $item_type, $item_data, $item_id, $quantity );
103 break;
104 }
105
106 $cart_id = $this->generate_cart_id( $item_id, $item_data );
107 $this->_cart_content = $this->get_cart_from_session();
108 $this->_cart_content[ $cart_id ] = apply_filters(
109 'learn_press_add_cart_item',
110 array_merge(
111 array(
112 'item_id' => $item_id,
113 'quantity' => $quantity,
114 //'data' => array(),
115 ),
116 $item_data
117 )
118 );
119
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 }
124
125 // Update cart to session DB.
126 $this->update_session( $this->_cart_content );
127
128 do_action( 'learn-press/add-to-cart', $item_id, $quantity, $item_data, $cart_id );
129
130 return $cart_id;
131 } catch ( Exception $e ) {
132 if ( $e->getMessage() ) {
133
134 }
135
136 return false;
137 }
138 }
139
140 /**
141 * Remove an item from cart
142 *
143 * @param $item_id
144 *
145 * @return bool
146 */
147 public function remove_item( $item_id ) {
148 if ( isset( $this->_cart_content['items'][ $item_id ] ) ) {
149
150 do_action( 'learn_press_remove_cart_item', $item_id, $this );
151
152 unset( $this->_cart_content['items'][ $item_id ] );
153
154 do_action( 'learn_press_cart_item_removed', $item_id, $this );
155
156 $this->update_session( $this->_cart_content );
157
158 return true;
159 }
160
161 return false;
162 }
163
164 /**
165 * Re-calculate cart totals and update data to session
166 *
167 * @since 3.0.0
168 * @version 4.0.2
169 */
170 public function calculate_totals() {
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();
179
180 if ( $items ) {
181 foreach ( $items as $cart_id => $item ) {
182 $item_type = get_post_type( $item['item_id'] );
183 if ( ! in_array( $item_type, learn_press_get_item_types_can_purchase() ) ) {
184 continue;
185 }
186
187 switch ( $item_type ) {
188 case LP_COURSE_CPT:
189 $course = learn_press_get_course( $item['item_id'] );
190 $subtotal = $course->get_price() * absint( $item['quantity'] );
191 break;
192 default:
193 $subtotal = apply_filters( 'learnpress/cart/calculate_sub_total/item_type_' . $item_type, $subtotal, $item );
194 break;
195 }
196
197 $total = $subtotal;
198
199 $data->subtotal += $subtotal;
200 $data->total += $total;
201
202 // For template old use.
203 LearnPress::instance()->cart->subtotal += $subtotal;
204 LearnPress::instance()->cart->total += $total;
205 }
206 }
207
208 return apply_filters( 'lp/cart/calculate_total', $data, $items );
209
210 //$this->update_session();
211 }
212
213 /**
214 * Update cart content to session
215 *
216 * @since 3.0.0
217 * @version 1.0.1
218 */
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();
222
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 );
240 }
241
242 /**
243 * Get all items from cart.
244 *
245 * @return array
246 */
247 public function get_items(): array {
248 return $this->get_cart_from_session();
249 }
250
251 /**
252 * Load cart content data from session
253 *
254 * @since 3.0.0
255 * @version 3.0.2
256 * @modify 4.2.0 - tungnx
257 */
258 public function get_cart_from_session() {
259 $session_data = LearnPress::instance()->session->get_session_data();
260 $cart = maybe_unserialize( $session_data['cart'] ?? '' );
261 if ( ! is_array( $cart ) ) {
262 $cart = [];
263 }
264
265 $this->_cart_content = $cart;
266
267 return $this->_cart_content;
268 }
269
270 /**
271 * Get cart sub-total
272 *
273 * @return mixed
274 */
275 public function get_subtotal() {
276 $subtotal = learn_press_format_price( $this->subtotal, true );
277
278 return apply_filters( 'learn-press/cart-subtotal', $subtotal, $this );
279 }
280
281 /**
282 * Get cart total
283 *
284 * @return mixed
285 */
286 public function get_total() {
287 $total = learn_press_format_price( $this->total, true );
288
289 return apply_filters( 'learn-press/cart-total', $total, $this );
290 }
291
292 /**
293 * Generate unique cart id from course id and data.
294 *
295 * @param int $course_id
296 * @param mixed $data
297 *
298 * @return string
299 */
300 public function generate_cart_id( $course_id, $data = '' ) {
301 $cart_id = array( $course_id );
302
303 if ( is_array( $data ) ) {
304 foreach ( $data as $key => $value ) {
305 $cart_id[1] = '';
306
307 if ( is_array( $value ) || is_object( $value ) ) {
308 $value = http_build_query( $value );
309 }
310
311 $cart_id[1] .= trim( $key ) . trim( $value );
312 }
313 }
314
315 return apply_filters( 'learn-press/cart-id', md5( join( '_', $cart_id ) ), $cart_id, $data );
316 }
317
318 /**
319 * Return subtotal of cart content
320 *
321 * @param LP_Course|LP_Certificate|CourseModel $item
322 * @param int $quantity
323 *
324 * @return mixed
325 */
326 public function get_item_subtotal( $item, int $quantity = 1 ) {
327 $price = $item->get_price();
328 $row_price = $price * $quantity;
329 $course_subtotal = learn_press_format_price( $row_price, true );
330
331 return apply_filters( 'learn-press/cart/item-subtotal', $course_subtotal, $item, $quantity, $this );
332 }
333
334 /**
335 * Clean all items from cart
336 *
337 * @return $this
338 */
339 public function empty_cart(): LP_Cart {
340
341 do_action( 'learn-press/cart/before-empty' );
342
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 );
349
350 do_action( 'learn-press/cart/emptied' );
351
352 return $this;
353 }
354
355 /**
356 * Check if cart is empty or not
357 *
358 * @return bool
359 */
360 public function is_empty(): bool {
361 $cart_content = $this->get_cart_from_session();
362
363 return sizeof( $cart_content ) === 0;
364 }
365
366 /**
367 * Checks if need to payment
368 * Return true if cart total greater than 0
369 *
370 * @return mixed
371 */
372 public function needs_payment() {
373 $cart_data = $this->calculate_totals();
374
375 return apply_filters( 'learn_press_cart_needs_payment', $cart_data->total > 0, $this );
376 }
377
378
379 /**
380 * Get unique instance of LP_Cart object
381 *
382 * @return LP_Cart
383 */
384 public static function instance() {
385 if ( is_null( self::$instance ) ) {
386 self::$instance = new self();
387 }
388
389 return self::$instance;
390 }
391 }
392