1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* WooCommerce Cart Functions |
4
|
|
|
* |
5
|
|
|
* Functions for cart specific things. |
6
|
|
|
* |
7
|
|
|
* @author WooThemes |
8
|
|
|
* @category Core |
9
|
|
|
* @package WooCommerce/Functions |
10
|
|
|
* @version 2.5.0 |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
14
|
|
|
exit; // Exit if accessed directly |
15
|
|
|
} |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Prevent password protected products being added to the cart. |
19
|
|
|
* |
20
|
|
|
* @param bool $passed |
21
|
|
|
* @param int $product_id |
22
|
|
|
* @return bool |
23
|
|
|
*/ |
24
|
|
|
function wc_protected_product_add_to_cart( $passed, $product_id ) { |
25
|
|
|
if ( post_password_required( $product_id ) ) { |
26
|
|
|
$passed = false; |
27
|
|
|
wc_add_notice( __( 'This product is protected and cannot be purchased.', 'woocommerce' ), 'error' ); |
28
|
|
|
} |
29
|
|
|
return $passed; |
30
|
|
|
} |
31
|
|
|
add_filter( 'woocommerce_add_to_cart_validation', 'wc_protected_product_add_to_cart', 10, 2 ); |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Add a product to the cart. |
35
|
|
|
* |
36
|
|
|
* Validates the product can be added, then adds it if valid. |
37
|
|
|
* |
38
|
|
|
* @since 2.7.0 |
39
|
|
|
* @param int $product_or_variation_id contains the id of the product to add to the cart. |
40
|
|
|
* @param int $quantity contains the quantity of the item to add |
41
|
|
|
* @param array $data extra cart item data we want to pass into the item, including any data about the variation if applicable. |
42
|
|
|
* @return string|bool $cart_item_key that was added or false if validation failed. |
43
|
|
|
*/ |
44
|
|
|
function wc_add_to_cart( $product_or_variation_id = 0, $quantity = 1, $data = array() ) { |
45
|
|
|
try { |
46
|
|
|
$product = wc_get_product( $product_or_variation_id ); |
47
|
|
|
|
48
|
|
|
if ( empty( $product ) || ! $product->is_purchasable() ) { |
49
|
|
|
throw new Exception( __( 'Sorry, this product cannot be purchased.', 'woocommerce' ) ); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
$quantity = max( 0, apply_filters( 'woocommerce_add_to_cart_quantity', $quantity, $product, $data ) ); |
53
|
|
|
$data = (array) apply_filters( 'woocommerce_add_to_cart_data', $data, $product ); |
54
|
|
|
|
55
|
|
|
wc_add_to_cart_validate_stock( $product, $quantity ); |
56
|
|
|
|
57
|
|
|
$cart_item_key = WC()->cart->add_item( array( |
58
|
|
|
'product' => $product, |
59
|
|
|
'quantity' => $quantity, |
60
|
|
|
'data' => $data, |
61
|
|
|
) ); |
62
|
|
|
|
63
|
|
|
do_action( |
64
|
|
|
'woocommerce_add_to_cart', |
65
|
|
|
$cart_item_key, |
66
|
|
|
$product->get_id(), |
67
|
|
|
$quantity, |
68
|
|
|
is_callable( array( $product, 'get_variation_id' ) ) ? $product->get_variation_id() : 0, |
69
|
|
|
! empty( $data['variation'] ) ? $data['variation'] : array(), |
70
|
|
|
$data |
71
|
|
|
); |
72
|
|
|
|
73
|
|
|
return $cart_item_key; |
74
|
|
|
} catch ( Exception $e ) { |
75
|
|
|
wc_add_notice( $e->getMessage(), 'error' ); |
76
|
|
|
return false; |
77
|
|
|
} |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Check product has enough stock to be added to cart. |
82
|
|
|
* @since 2.7.0 |
83
|
|
|
* @param WC_Product $product |
84
|
|
|
* @param int $adding_quantity |
85
|
|
|
* @throws Exception |
86
|
|
|
*/ |
87
|
|
|
function wc_add_to_cart_validate_stock( $product, $adding_quantity = 0 ) { |
88
|
|
|
$products_qty_in_cart = wc_cart_item_quantities(); |
89
|
|
|
$managing_stock = $product->managing_stock(); |
90
|
|
|
$check_variation_stock = $product->is_type( 'variation' ) && true === $managing_stock; |
91
|
|
|
$check_id = $check_variation_stock ? $product->variation_id : $product->id; |
92
|
|
|
$in_cart_qty = isset( $products_qty_in_cart[ $check_id ] ) ? $products_qty_in_cart[ $check_id ] : 0; |
93
|
|
|
|
94
|
|
|
if ( ! $product->is_in_stock() ) { |
95
|
|
|
throw new Exception( sprintf( __( 'You cannot add "%s" to the cart because the product is out of stock.', 'woocommerce' ), $product->get_title() ) ); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
if ( $product->is_sold_individually() && $in_cart_qty && $adding_quantity ) { |
99
|
|
|
throw new Exception( sprintf( '<a href="%s" class="button wc-forward">%s</a> %s', wc_get_cart_url(), __( 'View Cart', 'woocommerce' ), sprintf( __( 'You cannot add another "%s" to your cart.', 'woocommerce' ), $product->get_title() ) ) ); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
if ( ! $product->has_enough_stock( $adding_quantity ) ) { |
103
|
|
|
throw new Exception( sprintf(__( 'You cannot add that amount of "%s" to the cart because there is not enough stock (%s remaining).', 'woocommerce' ), $product->get_title(), $product->get_stock_quantity() ) ); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Check stock based on all items in the cart. |
108
|
|
|
*/ |
109
|
|
|
if ( ! $product->has_enough_stock( $in_cart_qty + $adding_quantity ) ) { |
110
|
|
|
throw new Exception( '<a href="' . esc_url( wc_get_cart_url() ) . '" class="button wc-forward">' . __( 'View Cart', 'woocommerce' ) . '</a> ' . sprintf( __( 'You cannot add that amount to the cart — we have %s in stock and you already have %s in your cart.', 'woocommerce' ), $product->get_stock_quantity(), $check_qty ) ); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Finally consider any held stock, from pending orders. |
115
|
|
|
*/ |
116
|
|
|
if ( ! $product->has_enough_stock( $in_cart_qty + $adding_quantity + wc_get_held_stock_count( $product ) ) ) { |
117
|
|
|
throw new Exception( '<a href="' . esc_url( wc_get_cart_url() ) . '" class="button wc-forward">' . __( 'View Cart', 'woocommerce' ) . '</a> ' . sprintf(__( 'Sorry, we do not have enough "%s" in stock to fulfill your order right now. Please try again in %d minutes or edit your cart and try again. We apologise for any inconvenience caused.', 'woocommerce' ), $product->get_title(), get_option( 'woocommerce_hold_stock_minutes' ) ) ); |
118
|
|
|
} |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Get cart items quantities - merged so we can do accurate stock checks on items across multiple lines. |
123
|
|
|
* @since 2.7.0 |
124
|
|
|
* @return array |
125
|
|
|
*/ |
126
|
|
|
function wc_cart_item_quantities() { |
127
|
|
|
$quantities = array(); |
128
|
|
|
|
129
|
|
|
foreach ( WC()->cart->get_cart() as $cart_item_key => $item ) { |
130
|
|
|
$id = $item->get_product_id(); |
131
|
|
|
$quantities[ $id ] = isset( $quantities[ $id ] ) ? $quantities[ $id ] + $item->get_quantity() : $item->get_quantity(); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
return $quantities; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Clears the cart session when called. |
139
|
|
|
*/ |
140
|
|
|
function wc_empty_cart() { |
141
|
|
|
if ( ! isset( WC()->cart ) || '' === WC()->cart ) { |
142
|
|
|
WC()->cart = new WC_Cart(); |
143
|
|
|
} |
144
|
|
|
WC()->cart->empty_cart(); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Retrieves unvalidated referer from '_wp_http_referer' or HTTP referer. |
149
|
|
|
* |
150
|
|
|
* Do not use for redirects, use {@see wp_get_referer()} instead. |
151
|
|
|
* |
152
|
|
|
* @since 2.6.1 |
153
|
|
|
* @return string|false Referer URL on success, false on failure. |
154
|
|
|
*/ |
155
|
|
|
function wc_get_raw_referer() { |
156
|
|
|
if ( function_exists( 'wp_get_raw_referer' ) ) { |
157
|
|
|
return wp_get_raw_referer(); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) { |
161
|
|
|
return wp_unslash( $_REQUEST['_wp_http_referer'] ); |
162
|
|
|
} elseif ( ! empty( $_SERVER['HTTP_REFERER'] ) ) { |
163
|
|
|
return wp_unslash( $_SERVER['HTTP_REFERER'] ); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
return false; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Add to cart messages. |
171
|
|
|
* |
172
|
|
|
* @access public |
173
|
|
|
* @param int|array $products |
174
|
|
|
* @param bool $show_qty Should qty's be shown? Added in 2.6.0 |
175
|
|
|
* @param bool $return Return message rather than add it. |
176
|
|
|
*/ |
177
|
|
|
function wc_add_to_cart_message( $products, $show_qty = false, $return = false ) { |
178
|
|
|
$titles = array(); |
179
|
|
|
$count = 0; |
180
|
|
|
|
181
|
|
|
if ( ! is_array( $products ) ) { |
182
|
|
|
$products = array( $products => 1 ); |
183
|
|
|
$show_qty = false; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
if ( ! $show_qty ) { |
187
|
|
|
$products = array_fill_keys( array_keys( $products ), 1 ); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
foreach ( $products as $product_id => $qty ) { |
191
|
|
|
$titles[] = ( $qty > 1 ? absint( $qty ) . ' × ' : '' ) . sprintf( _x( '“%s”', 'Item name in quotes', 'woocommerce' ), strip_tags( get_the_title( $product_id ) ) ); |
192
|
|
|
$count += $qty; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
$titles = array_filter( $titles ); |
196
|
|
|
$added_text = sprintf( _n( '%s has been added to your cart.', '%s have been added to your cart.', $count, 'woocommerce' ), wc_format_list_of_items( $titles ) ); |
197
|
|
|
|
198
|
|
|
// Output success messages |
199
|
|
|
if ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) { |
200
|
|
|
$return_to = apply_filters( 'woocommerce_continue_shopping_redirect', wc_get_raw_referer() ? wp_validate_redirect( wc_get_raw_referer(), false ) : wc_get_page_permalink( 'shop' ) ); |
201
|
|
|
$message = sprintf( '<a href="%s" class="button wc-forward">%s</a> %s', esc_url( $return_to ), esc_html__( 'Continue Shopping', 'woocommerce' ), esc_html( $added_text ) ); |
202
|
|
|
} else { |
203
|
|
|
$message = sprintf( '<a href="%s" class="button wc-forward">%s</a> %s', esc_url( wc_get_page_permalink( 'cart' ) ), esc_html__( 'View Cart', 'woocommerce' ), esc_html( $added_text ) ); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
$message = apply_filters( 'wc_add_to_cart_message', $message, $product_id ); |
207
|
|
|
|
208
|
|
|
if ( $return ) { |
209
|
|
|
return $message; |
210
|
|
|
} else { |
211
|
|
|
wc_add_notice( $message ); |
212
|
|
|
} |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Comma separate a list of item names, and replace final comma with 'and' |
217
|
|
|
* @param array $items |
218
|
|
|
* @return string |
219
|
|
|
*/ |
220
|
|
|
function wc_format_list_of_items( $items ) { |
221
|
|
|
$item_string = ''; |
222
|
|
|
|
223
|
|
|
foreach ( $items as $key => $item ) { |
224
|
|
|
$item_string .= $item; |
225
|
|
|
|
226
|
|
|
if ( sizeof( $items ) === $key + 2 ) { |
227
|
|
|
$item_string .= ' ' . __( 'and', 'woocommerce' ) . ' '; |
228
|
|
|
} elseif ( sizeof( $items ) !== $key + 1 ) { |
229
|
|
|
$item_string .= ', '; |
230
|
|
|
} |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
return $item_string; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* Clear cart after payment. |
238
|
|
|
* |
239
|
|
|
* @access public |
240
|
|
|
*/ |
241
|
|
|
function wc_clear_cart_after_payment() { |
242
|
|
|
global $wp; |
243
|
|
|
|
244
|
|
|
if ( ! empty( $wp->query_vars['order-received'] ) ) { |
245
|
|
|
|
246
|
|
|
$order_id = absint( $wp->query_vars['order-received'] ); |
247
|
|
|
$order_key = isset( $_GET['key'] ) ? wc_clean( $_GET['key'] ) : ''; |
248
|
|
|
|
249
|
|
View Code Duplication |
if ( $order_id > 0 ) { |
|
|
|
|
250
|
|
|
$order = wc_get_order( $order_id ); |
251
|
|
|
|
252
|
|
|
if ( $order->get_order_key() === $order_key ) { |
253
|
|
|
WC()->cart->empty_cart(); |
254
|
|
|
} |
255
|
|
|
} |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
if ( WC()->session->order_awaiting_payment > 0 ) { |
259
|
|
|
$order = wc_get_order( WC()->session->order_awaiting_payment ); |
260
|
|
|
|
261
|
|
|
if ( $order && $order->get_id() > 0 ) { |
262
|
|
|
// If the order has not failed, or is not pending, the order must have gone through |
263
|
|
|
if ( ! $order->has_status( array( 'failed', 'pending', 'cancelled' ) ) ) { |
264
|
|
|
WC()->cart->empty_cart(); |
265
|
|
|
} |
266
|
|
|
} |
267
|
|
|
} |
268
|
|
|
} |
269
|
|
|
add_action( 'get_header', 'wc_clear_cart_after_payment' ); |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Get shipping methods. |
273
|
|
|
* |
274
|
|
|
* @access public |
275
|
|
|
*/ |
276
|
|
|
function wc_cart_totals_shipping_html() { |
277
|
|
|
$packages = WC()->shipping->get_packages(); |
278
|
|
|
|
279
|
|
|
foreach ( $packages as $key => $package ) { |
280
|
|
|
$chosen_method = wc_get_chosen_shipping_method_for_package( $key, $package ); |
281
|
|
|
$product_names = array(); |
282
|
|
|
// @codingStandardsIgnoreStart |
283
|
|
|
$package_name = apply_filters( 'woocommerce_shipping_package_name', sprintf( _n( 'Shipping', 'Shipping %d', ( $key + 1 ), 'woocommerce' ), ( $key + 1 ) ), $key, $package ); |
284
|
|
|
// @codingStandardsIgnoreEnd |
285
|
|
|
// |
286
|
|
|
if ( sizeof( $packages ) > 1 ) { |
287
|
|
|
foreach ( $package['contents'] as $item_id => $values ) { |
288
|
|
|
$product_names[] = $values['data']->get_title() . ' ×' . $values['quantity']; |
289
|
|
|
} |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
if ( 'yes' === get_option( 'woocommerce_shipping_debug_mode', 'no' ) && WC()->shipping->get_shipping_zone() ) { |
293
|
|
|
$package_name .= ' - ' . WC()->shipping->get_shipping_zone()->get_zone_name(); |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
wc_get_template( 'cart/cart-shipping.php', array( |
297
|
|
|
'package' => $package, |
298
|
|
|
'available_methods' => $package['rates'], |
299
|
|
|
'show_package_details' => sizeof( $packages ) > 1, |
300
|
|
|
'package_details' => implode( ', ', $product_names ), |
301
|
|
|
'package_name' => $package_name, |
302
|
|
|
'index' => $key, |
303
|
|
|
'chosen_method' => $chosen_method, |
304
|
|
|
) ); |
305
|
|
|
} |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* Get taxes total. Used when not showing itemized taxes. |
310
|
|
|
*/ |
311
|
|
|
function wc_cart_totals_taxes_total_html() { |
312
|
|
|
echo apply_filters( 'woocommerce_cart_totals_taxes_total_html', wc_price( WC()->cart->get_taxes_total() ) ); |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
/** |
316
|
|
|
* Get a coupon label. |
317
|
|
|
* |
318
|
|
|
* @access public |
319
|
|
|
* @param string $coupon |
320
|
|
|
* @param bool $echo or return |
321
|
|
|
*/ |
322
|
|
|
function wc_cart_totals_coupon_label( $coupon, $echo = true ) { |
323
|
|
|
if ( is_string( $coupon ) ) { |
324
|
|
|
$coupon = new WC_Coupon( $coupon ); |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
$label = apply_filters( 'woocommerce_cart_totals_coupon_label', esc_html( __( 'Coupon:', 'woocommerce' ) . ' ' . $coupon->get_code() ), $coupon ); |
328
|
|
|
|
329
|
|
|
if ( $echo ) { |
330
|
|
|
echo $label; |
331
|
|
|
} else { |
332
|
|
|
return $label; |
333
|
|
|
} |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
/** |
337
|
|
|
* Get a coupon value. |
338
|
|
|
* |
339
|
|
|
* @access public |
340
|
|
|
* @param string $coupon |
341
|
|
|
*/ |
342
|
|
|
function wc_cart_totals_coupon_html( $coupon ) { |
343
|
|
|
if ( is_string( $coupon ) ) { |
344
|
|
|
$coupon = new WC_Coupon( $coupon ); |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
$value = array(); |
348
|
|
|
|
349
|
|
|
if ( $amount = WC()->cart->get_coupon_discount_amount( $coupon->get_code(), ! wc_cart_prices_include_tax() ) ) { |
350
|
|
|
$discount_html = '-' . wc_price( $amount ); |
351
|
|
|
} else { |
352
|
|
|
$discount_html = ''; |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
$value[] = apply_filters( 'woocommerce_coupon_discount_amount_html', $discount_html, $coupon ); |
356
|
|
|
|
357
|
|
|
if ( $coupon->get_free_shipping() ) { |
358
|
|
|
$value[] = __( 'Free shipping coupon', 'woocommerce' ); |
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
// get rid of empty array elements |
362
|
|
|
$value = array_filter( $value ); |
363
|
|
|
$value = implode( ', ', $value ) . ' <a href="' . esc_url( add_query_arg( 'remove_coupon', urlencode( $coupon->get_code() ), defined( 'WOOCOMMERCE_CHECKOUT' ) ? wc_get_checkout_url() : wc_get_cart_url() ) ) . '" class="woocommerce-remove-coupon" data-coupon="' . esc_attr( $coupon->get_code() ) . '">' . __( '[Remove]', 'woocommerce' ) . '</a>'; |
364
|
|
|
|
365
|
|
|
echo apply_filters( 'woocommerce_cart_totals_coupon_html', $value, $coupon ); |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
/** |
369
|
|
|
* Get order total html including inc tax if needed. |
370
|
|
|
*/ |
371
|
|
|
function wc_cart_totals_order_total_html() { |
372
|
|
|
$value = '<strong>' . wc_price( WC()->cart->get_total() ) . '</strong> '; |
373
|
|
|
|
374
|
|
|
// If prices are tax inclusive, show taxes here |
375
|
|
|
if ( wc_tax_enabled() && wc_cart_prices_include_tax() ) { |
376
|
|
|
$tax_string_array = array(); |
377
|
|
|
|
378
|
|
|
if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) { |
379
|
|
|
foreach ( WC()->cart->get_tax_totals() as $code => $tax ) |
380
|
|
|
$tax_string_array[] = sprintf( '%s %s', $tax->formatted_amount, $tax->label ); |
381
|
|
|
} else { |
382
|
|
|
$tax_string_array[] = sprintf( '%s %s', wc_price( WC()->cart->get_taxes_total( true, true ) ), WC()->countries->tax_or_vat() ); |
383
|
|
|
} |
384
|
|
|
|
385
|
|
|
if ( ! empty( $tax_string_array ) ) { |
386
|
|
|
$taxable_address = WC()->customer->get_taxable_address(); |
387
|
|
|
$estimated_text = WC()->customer->is_customer_outside_base() && ! WC()->customer->has_calculated_shipping() |
388
|
|
|
? sprintf( ' ' . __( 'estimated for %s', 'woocommerce' ), WC()->countries->estimated_for_prefix( $taxable_address[0] ) . WC()->countries->countries[ $taxable_address[0] ] ) |
389
|
|
|
: ''; |
390
|
|
|
$value .= '<small class="includes_tax">' . sprintf( __( '(includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) . $estimated_text ) . '</small>'; |
391
|
|
|
} |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
echo apply_filters( 'woocommerce_cart_totals_order_total_html', $value ); |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
/** |
398
|
|
|
* Get the fee value. |
399
|
|
|
* |
400
|
|
|
* @param object $fee |
401
|
|
|
*/ |
402
|
|
|
function wc_cart_totals_fee_html( $fee ) { |
403
|
|
|
$cart_totals_fee_html = ! wc_cart_prices_include_tax() ? wc_price( $fee->amount ) : wc_price( $fee->amount + $fee->tax ); |
404
|
|
|
|
405
|
|
|
echo apply_filters( 'woocommerce_cart_totals_fee_html', $cart_totals_fee_html, $fee ); |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
/** |
409
|
|
|
* Get a shipping methods full label including price. |
410
|
|
|
* @param WC_Shipping_Rate $method |
411
|
|
|
* @return string |
412
|
|
|
*/ |
413
|
|
|
function wc_cart_totals_shipping_method_label( $method ) { |
414
|
|
|
$label = $method->get_label(); |
415
|
|
|
|
416
|
|
|
if ( $method->cost > 0 ) { |
417
|
|
|
if ( ! wc_cart_prices_include_tax() ) { |
418
|
|
|
$label .= ': ' . wc_price( $method->cost ); |
419
|
|
|
if ( $method->get_shipping_tax() > 0 && wc_prices_include_tax() ) { |
420
|
|
|
$label .= ' <small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>'; |
421
|
|
|
} |
422
|
|
|
} else { |
423
|
|
|
$label .= ': ' . wc_price( $method->cost + $method->get_shipping_tax() ); |
424
|
|
View Code Duplication |
if ( $method->get_shipping_tax() > 0 && ! wc_prices_include_tax() ) { |
|
|
|
|
425
|
|
|
$label .= ' <small class="tax_label">' . WC()->countries->inc_tax_or_vat() . '</small>'; |
426
|
|
|
} |
427
|
|
|
} |
428
|
|
|
} |
429
|
|
|
|
430
|
|
|
return apply_filters( 'woocommerce_cart_shipping_method_full_label', $label, $method ); |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
/** |
434
|
|
|
* Round discount. |
435
|
|
|
* |
436
|
|
|
* @param float $value |
437
|
|
|
* @param int $precision |
438
|
|
|
* @return float |
439
|
|
|
*/ |
440
|
|
|
function wc_cart_round_discount( $value, $precision = false ) { |
441
|
|
|
if ( ! $precision ) { |
|
|
|
|
442
|
|
|
$precision = wc_get_price_decimals(); |
443
|
|
|
} |
444
|
|
|
if ( version_compare( PHP_VERSION, '5.3.0', '>=' ) ) { |
445
|
|
|
return round( $value, $precision, WC_DISCOUNT_ROUNDING_MODE ); |
446
|
|
|
} else { |
447
|
|
|
return round( $value, $precision ); |
448
|
|
|
} |
449
|
|
|
} |
450
|
|
|
|
451
|
|
|
/** |
452
|
|
|
* Gets chosen shipping method IDs from chosen_shipping_methods session, without instance IDs. |
453
|
|
|
* @since 2.6.2 |
454
|
|
|
* @return string[] |
455
|
|
|
*/ |
456
|
|
|
function wc_get_chosen_shipping_method_ids() { |
457
|
|
|
$method_ids = array(); |
458
|
|
|
$chosen_methods = WC()->session->get( 'chosen_shipping_methods', array() ); |
459
|
|
|
foreach ( $chosen_methods as $chosen_method ) { |
|
|
|
|
460
|
|
|
$chosen_method = explode( ':', $chosen_method ); |
461
|
|
|
$method_ids[] = current( $chosen_method ); |
462
|
|
|
} |
463
|
|
|
return $method_ids; |
464
|
|
|
} |
465
|
|
|
|
466
|
|
|
/** |
467
|
|
|
* Get cart cross sells. |
468
|
|
|
* @since 2.7.0 |
469
|
|
|
* @return array |
470
|
|
|
*/ |
471
|
|
|
function wc_get_cart_cross_sells() { |
472
|
|
|
$cross_sells = array(); |
473
|
|
|
$in_cart = array(); |
474
|
|
|
if ( ! WC()->cart->is_empty() ) { |
475
|
|
|
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) { |
476
|
|
|
if ( $values['quantity'] > 0 ) { |
477
|
|
|
$cross_sells = array_merge( $values['data']->get_cross_sells(), $cross_sells ); |
478
|
|
|
$in_cart[] = $values['product_id']; |
479
|
|
|
} |
480
|
|
|
} |
481
|
|
|
} |
482
|
|
|
$cross_sells = array_diff( $cross_sells, $in_cart ); |
483
|
|
|
return $cross_sells; |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
/** |
487
|
|
|
* See if we're displaying tax in the cart in a certain way. |
488
|
|
|
* @since 2.7.0 |
489
|
|
|
* @return boolean |
490
|
|
|
*/ |
491
|
|
|
function wc_cart_prices_include_tax() { |
492
|
|
|
return 'incl' === get_option( 'woocommerce_tax_display_cart', 'excl' ); |
493
|
|
|
} |
494
|
|
|
|
495
|
|
|
/** |
496
|
|
|
* Determines the value that the customer spent and the subtotal |
497
|
|
|
* displayed, used for things like coupon validation. |
498
|
|
|
* |
499
|
|
|
* Since the coupon lines are displayed based on the TAX DISPLAY value |
500
|
|
|
* of cart, this is used to determine the spend. |
501
|
|
|
* |
502
|
|
|
* If cart totals are shown including tax, use the subtotal. |
503
|
|
|
* If cart totals are shown excluding tax, use the subtotal ex tax |
504
|
|
|
* (tax is shown after coupons). |
505
|
|
|
* |
506
|
|
|
* @since 2.7.0 |
507
|
|
|
* @return string |
508
|
|
|
*/ |
509
|
|
|
function wc_cart_subtotal_to_display() { |
510
|
|
|
return wc_format_decimal( WC()->cart->get_subtotal( wc_cart_prices_include_tax() ) ); |
511
|
|
|
} |
512
|
|
|
|
513
|
|
|
/** |
514
|
|
|
* Gets the sub total (after calculation). |
515
|
|
|
* |
516
|
|
|
* @param bool $compound whether to include compound taxes |
517
|
|
|
* @return string formatted price |
518
|
|
|
*/ |
519
|
|
|
function wc_cart_subtotal_html( $compound = false, $echo = true ) { |
520
|
|
|
// If the cart has compound tax, we want to show the subtotal as |
521
|
|
|
// cart + shipping + non-compound taxes (after discount) |
522
|
|
|
if ( $compound ) { |
523
|
|
|
$cart_subtotal = WC()->cart->cart_contents_total + WC()->cart->shipping_total + WC()->cart->get_taxes_total( false, false ); |
524
|
|
|
$suffix = ''; |
525
|
|
|
|
526
|
|
|
// Otherwise we show cart items totals only (before discount) |
527
|
|
|
} else { |
528
|
|
|
$cart_subtotal = wc_cart_subtotal_to_display(); |
529
|
|
|
|
530
|
|
|
if ( wc_cart_prices_include_tax() ) { |
531
|
|
|
$suffix = wc_cart_prices_include_tax() ? '' : '<small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>'; |
532
|
|
|
} else { |
533
|
|
|
$suffix = wc_cart_prices_include_tax() ? '<small class="tax_label">' . WC()->countries->inc_tax_or_vat() . '</small>' : ''; |
534
|
|
|
} |
535
|
|
|
} |
536
|
|
|
|
537
|
|
|
$html = apply_filters( 'woocommerce_cart_subtotal', wc_price( $cart_subtotal ) . ' ' . $suffix, $compound, WC()->cart ); |
538
|
|
|
|
539
|
|
|
if ( $echo ) { |
540
|
|
|
echo $html; |
541
|
|
|
} else { |
542
|
|
|
return $html; |
543
|
|
|
} |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
/** |
547
|
|
|
* Get the product row price per item. |
548
|
|
|
* @since 2.7.0 |
549
|
|
|
* @param WC_Product $product |
550
|
|
|
* @param int $quantity to show |
551
|
|
|
* @return string formatted price |
552
|
|
|
*/ |
553
|
|
|
function wc_cart_product_price_html( $product, $quantity = 1 ) { |
554
|
|
|
if ( wc_cart_prices_include_tax() ) { |
555
|
|
|
$price = $product->get_price_including_tax( $quantity ); |
556
|
|
|
$suffix = wc_cart_prices_include_tax() ? '' : '<small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>'; |
557
|
|
|
} else { |
558
|
|
|
$price = $product->get_price_excluding_tax( $quantity ); |
559
|
|
|
$suffix = wc_cart_prices_include_tax() ? '<small class="tax_label">' . WC()->countries->inc_tax_or_vat() . '</small>' : ''; |
560
|
|
|
} |
561
|
|
|
return apply_filters( 'woocommerce_cart_product_price_html', wc_price( $product->is_taxable() ? $price . ' ' . $suffix : $price ), $product, $quantity ); |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
/** |
565
|
|
|
* Should we show shipping in the cart? |
566
|
|
|
* @since 2.7.0 |
567
|
|
|
* @return bool |
568
|
|
|
*/ |
569
|
|
|
function wc_cart_show_shipping() { |
570
|
|
|
if ( ! wc_shipping_enabled() || WC()->cart->is_empty() ) { |
571
|
|
|
return false; |
572
|
|
|
} |
573
|
|
|
|
574
|
|
|
if ( 'yes' === get_option( 'woocommerce_shipping_cost_requires_address' ) && ! WC()->customer->has_calculated_shipping() && ! WC()->customer->has_shipping_address() ) { |
575
|
|
|
return false; |
576
|
|
|
} |
577
|
|
|
|
578
|
|
|
return apply_filters( 'woocommerce_cart_ready_to_calc_shipping', true ); |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
/** |
582
|
|
|
* Load the persistent cart. |
583
|
|
|
*/ |
584
|
|
|
function wc_load_persistent_cart() { |
585
|
|
|
if ( ! is_user_logged_in() ) { |
586
|
|
|
return; |
587
|
|
|
} |
588
|
|
|
$cart = WC()->session->get( 'cart', null ); |
589
|
|
|
|
590
|
|
|
if ( is_null( $cart ) && ( $saved_cart = get_user_meta( get_current_user_id(), '_woocommerce_persistent_cart', true ) ) ) { |
591
|
|
|
$cart = array(); |
592
|
|
|
$cart['items'] = $saved_cart; |
593
|
|
|
WC()->session->set( 'cart', $cart ); |
594
|
|
|
} |
595
|
|
|
} |
596
|
|
|
add_action( 'wp_loaded', 'wc_load_persistent_cart', 5 ); |
597
|
|
|
|
598
|
|
|
/** |
599
|
|
|
* Update the persistent cart. |
600
|
|
|
*/ |
601
|
|
|
function wc_update_persistent_cart() { |
602
|
|
|
update_user_meta( get_current_user_id(), '_woocommerce_persistent_cart', WC()->cart->get_cart_for_session() ); |
603
|
|
|
} |
604
|
|
|
add_action( 'woocommerce_cart_updated', 'wc_update_persistent_cart' ); |
605
|
|
|
|
606
|
|
|
/** |
607
|
|
|
* Delete the persistent cart. |
608
|
|
|
*/ |
609
|
|
|
function wc_delete_persistent_cart() { |
610
|
|
|
delete_user_meta( get_current_user_id(), '_woocommerce_persistent_cart' ); |
611
|
|
|
} |
612
|
|
|
add_action( 'woocommerce_cart_emptied', 'wc_delete_persistent_cart' ); |
613
|
|
|
|
614
|
|
|
/** |
615
|
|
|
* Get chosen method for package from session. |
616
|
|
|
* @param int $key |
617
|
|
|
* @param array $package |
618
|
|
|
* @return string|bool |
619
|
|
|
*/ |
620
|
|
|
function wc_get_chosen_shipping_method_for_package( $key, $package ) { |
621
|
|
|
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' ); |
622
|
|
|
$chosen_method = isset( $chosen_methods[ $key ] ) ? $chosen_methods[ $key ] : false; |
623
|
|
|
$changed = wc_shipping_methods_have_changed( $key, $package ); |
624
|
|
|
|
625
|
|
|
// If not set, not available, or available methods have changed, set to the DEFAULT option |
626
|
|
|
if ( ! $chosen_method || $changed || ! isset( $package['rates'][ $chosen_method ] ) ) { |
627
|
|
|
$chosen_method = wc_get_default_shipping_method_for_package( $key, $package, $chosen_method ); |
628
|
|
|
$chosen_methods[ $key ] = $chosen_method; |
629
|
|
|
WC()->session->set( 'chosen_shipping_methods', $chosen_methods ); |
630
|
|
|
do_action( 'woocommerce_shipping_method_chosen', $chosen_method ); |
631
|
|
|
} |
632
|
|
|
|
633
|
|
|
return $chosen_method; |
634
|
|
|
} |
635
|
|
|
|
636
|
|
|
/** |
637
|
|
|
* Choose the default method for a package. |
638
|
|
|
* @param string $key |
639
|
|
|
* @param array $package |
640
|
|
|
* @return string |
641
|
|
|
*/ |
642
|
|
|
function wc_get_default_shipping_method_for_package( $key, $package, $chosen_method ) { |
|
|
|
|
643
|
|
|
$rate_keys = array_keys( $package['rates'] ); |
644
|
|
|
$default = current( $rate_keys ); |
645
|
|
|
$coupons = WC()->cart->get_coupons(); |
646
|
|
|
|
647
|
|
|
foreach ( $coupons as $coupon ) { |
648
|
|
|
if ( $coupon->get_free_shipping() ) { |
649
|
|
|
foreach ( $rate_keys as $rate_key ) { |
650
|
|
|
if ( 0 === stripos( $rate_key, 'free_shipping' ) ) { |
651
|
|
|
$default = $rate_key; |
652
|
|
|
break; |
653
|
|
|
} |
654
|
|
|
} |
655
|
|
|
break; |
656
|
|
|
} |
657
|
|
|
} |
658
|
|
|
|
659
|
|
|
return apply_filters( 'woocommerce_shipping_chosen_method', $default, $package['rates'], $chosen_method ); |
660
|
|
|
} |
661
|
|
|
|
662
|
|
|
/** |
663
|
|
|
* See if the methods have changed since the last request. |
664
|
|
|
* @param int $key |
665
|
|
|
* @param array $package |
666
|
|
|
* @return bool |
667
|
|
|
*/ |
668
|
|
|
function wc_shipping_methods_have_changed( $key, $package ) { |
669
|
|
|
// Lookup previous methods from session. |
670
|
|
|
$previous_shipping_methods = WC()->session->get( 'previous_shipping_methods' ); |
671
|
|
|
|
672
|
|
|
// Get new and old rates. |
673
|
|
|
$new_rates = array_keys( $package['rates'] ); |
674
|
|
|
$prev_rates = isset( $previous_shipping_methods[ $key ] ) ? $previous_shipping_methods[ $key ] : false; |
675
|
|
|
|
676
|
|
|
// Update session. |
677
|
|
|
$previous_shipping_methods[ $key ] = $new_rates; |
678
|
|
|
WC()->session->set( 'previous_shipping_methods', $previous_shipping_methods ); |
679
|
|
|
|
680
|
|
|
return $new_rates != $prev_rates; |
681
|
|
|
} |
682
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.