Completed
Push — master ( e4380d...bbc130 )
by Mike
07:56
created

wc-core-functions.php ➔ wc_set_time_limit()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 3
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 5
rs 9.2
1
<?php
1 ignored issue
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 60 and the first side effect is on line 14.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * WooCommerce Core Functions
4
 *
5
 * General core functions available on both the front-end and admin.
6
 *
7
 * @author 		WooThemes
8
 * @category 	Core
9
 * @package 	WooCommerce/Functions
10
 * @version     2.1.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
// Include core functions (available in both admin and frontend).
18
include( 'wc-conditional-functions.php' );
19
include( 'wc-coupon-functions.php' );
20
include( 'wc-user-functions.php' );
21
include( 'wc-deprecated-functions.php' );
22
include( 'wc-formatting-functions.php' );
23
include( 'wc-order-functions.php' );
24
include( 'wc-page-functions.php' );
25
include( 'wc-product-functions.php' );
26
include( 'wc-account-functions.php' );
27
include( 'wc-term-functions.php' );
28
include( 'wc-attribute-functions.php' );
29
include( 'wc-rest-functions.php' );
30
31
/**
32
 * Filters on data used in admin and frontend.
33
 */
34
add_filter( 'woocommerce_coupon_code', 'html_entity_decode' );
35
add_filter( 'woocommerce_coupon_code', 'sanitize_text_field' );
36
add_filter( 'woocommerce_coupon_code', 'strtolower' ); // Coupons case-insensitive by default
37
add_filter( 'woocommerce_stock_amount', 'intval' ); // Stock amounts are integers by default
38
add_filter( 'woocommerce_shipping_rate_label', 'sanitize_text_field' ); // Shipping rate label
39
40
/**
41
 * Short Description (excerpt).
42
 */
43
add_filter( 'woocommerce_short_description', 'wptexturize' );
44
add_filter( 'woocommerce_short_description', 'convert_smilies' );
45
add_filter( 'woocommerce_short_description', 'convert_chars' );
46
add_filter( 'woocommerce_short_description', 'wpautop' );
47
add_filter( 'woocommerce_short_description', 'shortcode_unautop' );
48
add_filter( 'woocommerce_short_description', 'prepend_attachment' );
49
add_filter( 'woocommerce_short_description', 'do_shortcode', 11 ); // AFTER wpautop()
50
51
/**
52
 * Create a new order programmatically.
53
 *
54
 * Returns a new order object on success which can then be used to add additional data.
55
 *
56
 * @param  array $args
57
 *
58
 * @return WC_Order on success, WP_Error on failure.
59
 */
60
function wc_create_order( $args = array() ) {
61
	$default_args = array(
62
		'status'        => '',
63
		'customer_id'   => null,
64
		'customer_note' => null,
65
		'order_id'      => 0,
66
		'created_via'   => '',
67
		'cart_hash'     => '',
68
		'parent'        => 0,
69
	);
70
71
	$args       = wp_parse_args( $args, $default_args );
72
	$order_data = array();
73
74
	if ( $args['order_id'] > 0 ) {
75
		$updating         = true;
76
		$order_data['ID'] = $args['order_id'];
77
	} else {
78
		$updating                    = false;
79
		$order_data['post_type']     = 'shop_order';
80
		$order_data['post_status']   = 'wc-' . apply_filters( 'woocommerce_default_order_status', 'pending' );
81
		$order_data['ping_status']   = 'closed';
82
		$order_data['post_author']   = 1;
83
		$order_data['post_password'] = uniqid( 'order_' );
84
		$order_data['post_title']    = sprintf( __( 'Order &ndash; %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) );
85
		$order_data['post_parent']   = absint( $args['parent'] );
86
	}
87
88
	if ( $args['status'] ) {
89
		if ( ! in_array( 'wc-' . $args['status'], array_keys( wc_get_order_statuses() ) ) ) {
90
			return new WP_Error( 'woocommerce_invalid_order_status', __( 'Invalid order status', 'woocommerce' ) );
91
		}
92
		$order_data['post_status']  = 'wc-' . $args['status'];
93
	}
94
95
	if ( ! is_null( $args['customer_note'] ) ) {
96
		$order_data['post_excerpt'] = $args['customer_note'];
97
	}
98
99
	if ( $updating ) {
100
		$order_id = wp_update_post( $order_data );
101
	} else {
102
		$order_id = wp_insert_post( apply_filters( 'woocommerce_new_order_data', $order_data ), true );
103
	}
104
105
	if ( is_wp_error( $order_id ) ) {
106
		return $order_id;
107
	}
108
109
	if ( ! $updating ) {
110
		update_post_meta( $order_id, '_order_key', 'wc_' . apply_filters( 'woocommerce_generate_order_key', uniqid( 'order_' ) ) );
111
		update_post_meta( $order_id, '_order_currency', get_woocommerce_currency() );
112
		update_post_meta( $order_id, '_prices_include_tax', get_option( 'woocommerce_prices_include_tax' ) );
113
		update_post_meta( $order_id, '_customer_ip_address', WC_Geolocation::get_ip_address() );
114
		update_post_meta( $order_id, '_customer_user_agent', isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '' );
115
		update_post_meta( $order_id, '_customer_user', 0 );
116
		update_post_meta( $order_id, '_created_via', sanitize_text_field( $args['created_via'] ) );
117
		update_post_meta( $order_id, '_cart_hash', sanitize_text_field( $args['cart_hash'] ) );
118
	}
119
120
	if ( is_numeric( $args['customer_id'] ) ) {
121
		update_post_meta( $order_id, '_customer_user', $args['customer_id'] );
122
	}
123
124
	update_post_meta( $order_id, '_order_version', WC_VERSION );
125
126
	return wc_get_order( $order_id );
127
}
128
129
/**
130
 * Update an order. Uses wc_create_order.
131
 *
132
 * @param  array $args
133
 * @return string | WC_Order
134
 */
135
function wc_update_order( $args ) {
136
	if ( ! $args['order_id'] ) {
137
		return new WP_Error( __( 'Invalid order ID', 'woocommerce' ) );
138
	}
139
	return wc_create_order( $args );
140
}
141
142
/**
143
 * Get template part (for templates like the shop-loop).
144
 *
145
 * WC_TEMPLATE_DEBUG_MODE will prevent overrides in themes from taking priority.
146
 *
147
 * @access public
148
 * @param mixed $slug
149
 * @param string $name (default: '')
150
 */
151
function wc_get_template_part( $slug, $name = '' ) {
152
	$template = '';
153
154
	// Look in yourtheme/slug-name.php and yourtheme/woocommerce/slug-name.php
155 View Code Duplication
	if ( $name && ! WC_TEMPLATE_DEBUG_MODE ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
156
		$template = locate_template( array( "{$slug}-{$name}.php", WC()->template_path() . "{$slug}-{$name}.php" ) );
157
	}
158
159
	// Get default slug-name.php
160
	if ( ! $template && $name && file_exists( WC()->plugin_path() . "/templates/{$slug}-{$name}.php" ) ) {
161
		$template = WC()->plugin_path() . "/templates/{$slug}-{$name}.php";
162
	}
163
164
	// If template file doesn't exist, look in yourtheme/slug.php and yourtheme/woocommerce/slug.php
165 View Code Duplication
	if ( ! $template && ! WC_TEMPLATE_DEBUG_MODE ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
166
		$template = locate_template( array( "{$slug}.php", WC()->template_path() . "{$slug}.php" ) );
167
	}
168
169
	// Allow 3rd party plugins to filter template file from their plugin.
170
	$template = apply_filters( 'wc_get_template_part', $template, $slug, $name );
171
172
	if ( $template ) {
173
		load_template( $template, false );
174
	}
175
}
176
177
/**
178
 * Get other templates (e.g. product attributes) passing attributes and including the file.
179
 *
180
 * @access public
181
 * @param string $template_name
182
 * @param array $args (default: array())
183
 * @param string $template_path (default: '')
184
 * @param string $default_path (default: '')
185
 */
186
function wc_get_template( $template_name, $args = array(), $template_path = '', $default_path = '' ) {
187
	if ( $args && is_array( $args ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $args of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
188
		extract( $args );
189
	}
190
191
	$located = wc_locate_template( $template_name, $template_path, $default_path );
192
193
	if ( ! file_exists( $located ) ) {
194
		_doing_it_wrong( __FUNCTION__, sprintf( '<code>%s</code> does not exist.', $located ), '2.1' );
195
		return;
196
	}
197
198
	// Allow 3rd party plugin filter template file from their plugin.
199
	$located = apply_filters( 'wc_get_template', $located, $template_name, $args, $template_path, $default_path );
200
201
	do_action( 'woocommerce_before_template_part', $template_name, $template_path, $located, $args );
202
203
	include( $located );
204
205
	do_action( 'woocommerce_after_template_part', $template_name, $template_path, $located, $args );
206
}
207
208
/**
209
 * Like wc_get_template, but returns the HTML instead of outputting.
210
 * @see wc_get_template
211
 * @since 2.5.0
212
 */
213
function wc_get_template_html( $template_name, $args = array(), $template_path = '', $default_path = '' ) {
214
	ob_start();
215
	wc_get_template( $template_name, $args, $template_path, $default_path );
216
	return ob_get_clean();
217
}
218
219
/**
220
 * Locate a template and return the path for inclusion.
221
 *
222
 * This is the load order:
223
 *
224
 *		yourtheme		/	$template_path	/	$template_name
225
 *		yourtheme		/	$template_name
226
 *		$default_path	/	$template_name
227
 *
228
 * @access public
229
 * @param string $template_name
230
 * @param string $template_path (default: '')
231
 * @param string $default_path (default: '')
232
 * @return string
233
 */
234
function wc_locate_template( $template_name, $template_path = '', $default_path = '' ) {
235
	if ( ! $template_path ) {
236
		$template_path = WC()->template_path();
237
	}
238
239
	if ( ! $default_path ) {
240
		$default_path = WC()->plugin_path() . '/templates/';
241
	}
242
243
	// Look within passed path within the theme - this is priority.
244
	$template = locate_template(
245
		array(
246
			trailingslashit( $template_path ) . $template_name,
247
			$template_name
248
		)
249
	);
250
251
	// Get default template/
252
	if ( ! $template || WC_TEMPLATE_DEBUG_MODE ) {
253
		$template = $default_path . $template_name;
254
	}
255
256
	// Return what we found.
257
	return apply_filters( 'woocommerce_locate_template', $template, $template_name, $template_path );
258
}
259
260
/**
261
 * Get Base Currency Code.
262
 *
263
 * @return string
264
 */
265
function get_woocommerce_currency() {
266
	return apply_filters( 'woocommerce_currency', get_option('woocommerce_currency') );
267
}
268
269
/**
270
 * Get full list of currency codes.
271
 *
272
 * @return array
273
 */
274
function get_woocommerce_currencies() {
275
	return array_unique(
276
		apply_filters( 'woocommerce_currencies',
277
			array(
278
				'AED' => __( 'United Arab Emirates dirham', 'woocommerce' ),
279
				'AFN' => __( 'Afghan afghani', 'woocommerce' ),
280
				'ALL' => __( 'Albanian lek', 'woocommerce' ),
281
				'AMD' => __( 'Armenian dram', 'woocommerce' ),
282
				'ANG' => __( 'Netherlands Antillean guilder', 'woocommerce' ),
283
				'AOA' => __( 'Angolan kwanza', 'woocommerce' ),
284
				'ARS' => __( 'Argentine peso', 'woocommerce' ),
285
				'AUD' => __( 'Australian dollar', 'woocommerce' ),
286
				'AWG' => __( 'Aruban florin', 'woocommerce' ),
287
				'AZN' => __( 'Azerbaijani manat', 'woocommerce' ),
288
				'BAM' => __( 'Bosnia and Herzegovina convertible mark', 'woocommerce' ),
289
				'BBD' => __( 'Barbadian dollar', 'woocommerce' ),
290
				'BDT' => __( 'Bangladeshi taka', 'woocommerce' ),
291
				'BGN' => __( 'Bulgarian lev', 'woocommerce' ),
292
				'BHD' => __( 'Bahraini dinar', 'woocommerce' ),
293
				'BIF' => __( 'Burundian franc', 'woocommerce' ),
294
				'BMD' => __( 'Bermudian dollar', 'woocommerce' ),
295
				'BND' => __( 'Brunei dollar', 'woocommerce' ),
296
				'BOB' => __( 'Bolivian boliviano', 'woocommerce' ),
297
				'BRL' => __( 'Brazilian real', 'woocommerce' ),
298
				'BSD' => __( 'Bahamian dollar', 'woocommerce' ),
299
				'BTC' => __( 'Bitcoin', 'woocommerce' ),
300
				'BTN' => __( 'Bhutanese ngultrum', 'woocommerce' ),
301
				'BWP' => __( 'Botswana pula', 'woocommerce' ),
302
				'BYR' => __( 'Belarusian ruble', 'woocommerce' ),
303
				'BZD' => __( 'Belize dollar', 'woocommerce' ),
304
				'CAD' => __( 'Canadian dollar', 'woocommerce' ),
305
				'CDF' => __( 'Congolese franc', 'woocommerce' ),
306
				'CHF' => __( 'Swiss franc', 'woocommerce' ),
307
				'CLP' => __( 'Chilean peso', 'woocommerce' ),
308
				'CNY' => __( 'Chinese yuan', 'woocommerce' ),
309
				'COP' => __( 'Colombian peso', 'woocommerce' ),
310
				'CRC' => __( 'Costa Rican col&oacute;n', 'woocommerce' ),
311
				'CUC' => __( 'Cuban convertible peso', 'woocommerce' ),
312
				'CUP' => __( 'Cuban peso', 'woocommerce' ),
313
				'CVE' => __( 'Cape Verdean escudo', 'woocommerce' ),
314
				'CZK' => __( 'Czech koruna', 'woocommerce' ),
315
				'DJF' => __( 'Djiboutian franc', 'woocommerce' ),
316
				'DKK' => __( 'Danish krone', 'woocommerce' ),
317
				'DOP' => __( 'Dominican peso', 'woocommerce' ),
318
				'DZD' => __( 'Algerian dinar', 'woocommerce' ),
319
				'EGP' => __( 'Egyptian pound', 'woocommerce' ),
320
				'ERN' => __( 'Eritrean nakfa', 'woocommerce' ),
321
				'ETB' => __( 'Ethiopian birr', 'woocommerce' ),
322
				'EUR' => __( 'Euro', 'woocommerce' ),
323
				'FJD' => __( 'Fijian dollar', 'woocommerce' ),
324
				'FKP' => __( 'Falkland Islands pound', 'woocommerce' ),
325
				'GBP' => __( 'Pound sterling', 'woocommerce' ),
326
				'GEL' => __( 'Georgian lari', 'woocommerce' ),
327
				'GGP' => __( 'Guernsey pound', 'woocommerce' ),
328
				'GHS' => __( 'Ghana cedi', 'woocommerce' ),
329
				'GIP' => __( 'Gibraltar pound', 'woocommerce' ),
330
				'GMD' => __( 'Gambian dalasi', 'woocommerce' ),
331
				'GNF' => __( 'Guinean franc', 'woocommerce' ),
332
				'GTQ' => __( 'Guatemalan quetzal', 'woocommerce' ),
333
				'GYD' => __( 'Guyanese dollar', 'woocommerce' ),
334
				'HKD' => __( 'Hong Kong dollar', 'woocommerce' ),
335
				'HNL' => __( 'Honduran lempira', 'woocommerce' ),
336
				'HRK' => __( 'Croatian kuna', 'woocommerce' ),
337
				'HTG' => __( 'Haitian gourde', 'woocommerce' ),
338
				'HUF' => __( 'Hungarian forint', 'woocommerce' ),
339
				'IDR' => __( 'Indonesian rupiah', 'woocommerce' ),
340
				'ILS' => __( 'Israeli new shekel', 'woocommerce' ),
341
				'IMP' => __( 'Manx pound', 'woocommerce' ),
342
				'INR' => __( 'Indian rupee', 'woocommerce' ),
343
				'IQD' => __( 'Iraqi dinar', 'woocommerce' ),
344
				'IRR' => __( 'Iranian rial', 'woocommerce' ),
345
				'ISK' => __( 'Icelandic kr&oacute;na', 'woocommerce' ),
346
				'JEP' => __( 'Jersey pound', 'woocommerce' ),
347
				'JMD' => __( 'Jamaican dollar', 'woocommerce' ),
348
				'JOD' => __( 'Jordanian dinar', 'woocommerce' ),
349
				'JPY' => __( 'Japanese yen', 'woocommerce' ),
350
				'KES' => __( 'Kenyan shilling', 'woocommerce' ),
351
				'KGS' => __( 'Kyrgyzstani som', 'woocommerce' ),
352
				'KHR' => __( 'Cambodian riel', 'woocommerce' ),
353
				'KMF' => __( 'Comorian franc', 'woocommerce' ),
354
				'KPW' => __( 'North Korean won', 'woocommerce' ),
355
				'KRW' => __( 'South Korean won', 'woocommerce' ),
356
				'KWD' => __( 'Kuwaiti dinar', 'woocommerce' ),
357
				'KYD' => __( 'Cayman Islands dollar', 'woocommerce' ),
358
				'KZT' => __( 'Kazakhstani tenge', 'woocommerce' ),
359
				'LAK' => __( 'Lao kip', 'woocommerce' ),
360
				'LBP' => __( 'Lebanese pound', 'woocommerce' ),
361
				'LKR' => __( 'Sri Lankan rupee', 'woocommerce' ),
362
				'LRD' => __( 'Liberian dollar', 'woocommerce' ),
363
				'LSL' => __( 'Lesotho loti', 'woocommerce' ),
364
				'LYD' => __( 'Libyan dinar', 'woocommerce' ),
365
				'MAD' => __( 'Moroccan dirham', 'woocommerce' ),
366
				'MDL' => __( 'Moldovan leu', 'woocommerce' ),
367
				'MGA' => __( 'Malagasy ariary', 'woocommerce' ),
368
				'MKD' => __( 'Macedonian denar', 'woocommerce' ),
369
				'MMK' => __( 'Burmese kyat', 'woocommerce' ),
370
				'MNT' => __( 'Mongolian t&ouml;gr&ouml;g', 'woocommerce' ),
371
				'MOP' => __( 'Macanese pataca', 'woocommerce' ),
372
				'MRO' => __( 'Mauritanian ouguiya', 'woocommerce' ),
373
				'MUR' => __( 'Mauritian rupee', 'woocommerce' ),
374
				'MVR' => __( 'Maldivian rufiyaa', 'woocommerce' ),
375
				'MWK' => __( 'Malawian kwacha', 'woocommerce' ),
376
				'MXN' => __( 'Mexican peso', 'woocommerce' ),
377
				'MYR' => __( 'Malaysian ringgit', 'woocommerce' ),
378
				'MZN' => __( 'Mozambican metical', 'woocommerce' ),
379
				'NAD' => __( 'Namibian dollar', 'woocommerce' ),
380
				'NGN' => __( 'Nigerian naira', 'woocommerce' ),
381
				'NIO' => __( 'Nicaraguan c&oacute;rdoba', 'woocommerce' ),
382
				'NOK' => __( 'Norwegian krone', 'woocommerce' ),
383
				'NPR' => __( 'Nepalese rupee', 'woocommerce' ),
384
				'NZD' => __( 'New Zealand dollar', 'woocommerce' ),
385
				'OMR' => __( 'Omani rial', 'woocommerce' ),
386
				'PAB' => __( 'Panamanian balboa', 'woocommerce' ),
387
				'PEN' => __( 'Peruvian nuevo sol', 'woocommerce' ),
388
				'PGK' => __( 'Papua New Guinean kina', 'woocommerce' ),
389
				'PHP' => __( 'Philippine peso', 'woocommerce' ),
390
				'PKR' => __( 'Pakistani rupee', 'woocommerce' ),
391
				'PLN' => __( 'Polish z&#x142;oty', 'woocommerce' ),
392
				'PRB' => __( 'Transnistrian ruble', 'woocommerce' ),
393
				'PYG' => __( 'Paraguayan guaran&iacute;', 'woocommerce' ),
394
				'QAR' => __( 'Qatari riyal', 'woocommerce' ),
395
				'RON' => __( 'Romanian leu', 'woocommerce' ),
396
				'RSD' => __( 'Serbian dinar', 'woocommerce' ),
397
				'RUB' => __( 'Russian ruble', 'woocommerce' ),
398
				'RWF' => __( 'Rwandan franc', 'woocommerce' ),
399
				'SAR' => __( 'Saudi riyal', 'woocommerce' ),
400
				'SBD' => __( 'Solomon Islands dollar', 'woocommerce' ),
401
				'SCR' => __( 'Seychellois rupee', 'woocommerce' ),
402
				'SDG' => __( 'Sudanese pound', 'woocommerce' ),
403
				'SEK' => __( 'Swedish krona', 'woocommerce' ),
404
				'SGD' => __( 'Singapore dollar', 'woocommerce' ),
405
				'SHP' => __( 'Saint Helena pound', 'woocommerce' ),
406
				'SLL' => __( 'Sierra Leonean leone', 'woocommerce' ),
407
				'SOS' => __( 'Somali shilling', 'woocommerce' ),
408
				'SRD' => __( 'Surinamese dollar', 'woocommerce' ),
409
				'SSP' => __( 'South Sudanese pound', 'woocommerce' ),
410
				'STD' => __( 'S&atilde;o Tom&eacute; and Pr&iacute;ncipe dobra', 'woocommerce' ),
411
				'SYP' => __( 'Syrian pound', 'woocommerce' ),
412
				'SZL' => __( 'Swazi lilangeni', 'woocommerce' ),
413
				'THB' => __( 'Thai baht', 'woocommerce' ),
414
				'TJS' => __( 'Tajikistani somoni', 'woocommerce' ),
415
				'TMT' => __( 'Turkmenistan manat', 'woocommerce' ),
416
				'TND' => __( 'Tunisian dinar', 'woocommerce' ),
417
				'TOP' => __( 'Tongan pa&#x2bb;anga', 'woocommerce' ),
418
				'TRY' => __( 'Turkish lira', 'woocommerce' ),
419
				'TTD' => __( 'Trinidad and Tobago dollar', 'woocommerce' ),
420
				'TWD' => __( 'New Taiwan dollar', 'woocommerce' ),
421
				'TZS' => __( 'Tanzanian shilling', 'woocommerce' ),
422
				'UAH' => __( 'Ukrainian hryvnia', 'woocommerce' ),
423
				'UGX' => __( 'Ugandan shilling', 'woocommerce' ),
424
				'USD' => __( 'United States dollar', 'woocommerce' ),
425
				'UYU' => __( 'Uruguayan peso', 'woocommerce' ),
426
				'UZS' => __( 'Uzbekistani som', 'woocommerce' ),
427
				'VEF' => __( 'Venezuelan bol&iacute;var', 'woocommerce' ),
428
				'VND' => __( 'Vietnamese &#x111;&#x1ed3;ng', 'woocommerce' ),
429
				'VUV' => __( 'Vanuatu vatu', 'woocommerce' ),
430
				'WST' => __( 'Samoan t&#x101;l&#x101;', 'woocommerce' ),
431
				'XAF' => __( 'Central African CFA franc', 'woocommerce' ),
432
				'XCD' => __( 'East Caribbean dollar', 'woocommerce' ),
433
				'XOF' => __( 'West African CFA franc', 'woocommerce' ),
434
				'XPF' => __( 'CFP franc', 'woocommerce' ),
435
				'YER' => __( 'Yemeni rial', 'woocommerce' ),
436
				'ZAR' => __( 'South African rand', 'woocommerce' ),
437
				'ZMW' => __( 'Zambian kwacha', 'woocommerce' ),
438
			)
439
		)
440
	);
441
}
442
443
/**
444
 * Get Currency symbol.
445
 *
446
 * @param string $currency (default: '')
447
 * @return string
448
 */
449
function get_woocommerce_currency_symbol( $currency = '' ) {
450
	if ( ! $currency ) {
451
		$currency = get_woocommerce_currency();
452
	}
453
454
	$symbols = apply_filters( 'woocommerce_currency_symbols', array(
455
		'AED' => '&#x62f;.&#x625;',
456
		'AFN' => '&#x60b;',
457
		'ALL' => 'L',
458
		'AMD' => 'AMD',
459
		'ANG' => '&fnof;',
460
		'AOA' => 'Kz',
461
		'ARS' => '&#36;',
462
		'AUD' => '&#36;',
463
		'AWG' => '&fnof;',
464
		'AZN' => 'AZN',
465
		'BAM' => 'KM',
466
		'BBD' => '&#36;',
467
		'BDT' => '&#2547;&nbsp;',
468
		'BGN' => '&#1083;&#1074;.',
469
		'BHD' => '.&#x62f;.&#x628;',
470
		'BIF' => 'Fr',
471
		'BMD' => '&#36;',
472
		'BND' => '&#36;',
473
		'BOB' => 'Bs.',
474
		'BRL' => '&#82;&#36;',
475
		'BSD' => '&#36;',
476
		'BTC' => '&#3647;',
477
		'BTN' => 'Nu.',
478
		'BWP' => 'P',
479
		'BYR' => 'Br',
480
		'BZD' => '&#36;',
481
		'CAD' => '&#36;',
482
		'CDF' => 'Fr',
483
		'CHF' => '&#67;&#72;&#70;',
484
		'CLP' => '&#36;',
485
		'CNY' => '&yen;',
486
		'COP' => '&#36;',
487
		'CRC' => '&#x20a1;',
488
		'CUC' => '&#36;',
489
		'CUP' => '&#36;',
490
		'CVE' => '&#36;',
491
		'CZK' => '&#75;&#269;',
492
		'DJF' => 'Fr',
493
		'DKK' => 'DKK',
494
		'DOP' => 'RD&#36;',
495
		'DZD' => '&#x62f;.&#x62c;',
496
		'EGP' => 'EGP',
497
		'ERN' => 'Nfk',
498
		'ETB' => 'Br',
499
		'EUR' => '&euro;',
500
		'FJD' => '&#36;',
501
		'FKP' => '&pound;',
502
		'GBP' => '&pound;',
503
		'GEL' => '&#x10da;',
504
		'GGP' => '&pound;',
505
		'GHS' => '&#x20b5;',
506
		'GIP' => '&pound;',
507
		'GMD' => 'D',
508
		'GNF' => 'Fr',
509
		'GTQ' => 'Q',
510
		'GYD' => '&#36;',
511
		'HKD' => '&#36;',
512
		'HNL' => 'L',
513
		'HRK' => 'Kn',
514
		'HTG' => 'G',
515
		'HUF' => '&#70;&#116;',
516
		'IDR' => 'Rp',
517
		'ILS' => '&#8362;',
518
		'IMP' => '&pound;',
519
		'INR' => '&#8377;',
520
		'IQD' => '&#x639;.&#x62f;',
521
		'IRR' => '&#xfdfc;',
522
		'ISK' => 'Kr.',
523
		'JEP' => '&pound;',
524
		'JMD' => '&#36;',
525
		'JOD' => '&#x62f;.&#x627;',
526
		'JPY' => '&yen;',
527
		'KES' => 'KSh',
528
		'KGS' => '&#x43b;&#x432;',
529
		'KHR' => '&#x17db;',
530
		'KMF' => 'Fr',
531
		'KPW' => '&#x20a9;',
532
		'KRW' => '&#8361;',
533
		'KWD' => '&#x62f;.&#x643;',
534
		'KYD' => '&#36;',
535
		'KZT' => 'KZT',
536
		'LAK' => '&#8365;',
537
		'LBP' => '&#x644;.&#x644;',
538
		'LKR' => '&#xdbb;&#xdd4;',
539
		'LRD' => '&#36;',
540
		'LSL' => 'L',
541
		'LYD' => '&#x644;.&#x62f;',
542
		'MAD' => '&#x62f;. &#x645;.',
543
		'MAD' => '&#x62f;.&#x645;.',
544
		'MDL' => 'L',
545
		'MGA' => 'Ar',
546
		'MKD' => '&#x434;&#x435;&#x43d;',
547
		'MMK' => 'Ks',
548
		'MNT' => '&#x20ae;',
549
		'MOP' => 'P',
550
		'MRO' => 'UM',
551
		'MUR' => '&#x20a8;',
552
		'MVR' => '.&#x783;',
553
		'MWK' => 'MK',
554
		'MXN' => '&#36;',
555
		'MYR' => '&#82;&#77;',
556
		'MZN' => 'MT',
557
		'NAD' => '&#36;',
558
		'NGN' => '&#8358;',
559
		'NIO' => 'C&#36;',
560
		'NOK' => '&#107;&#114;',
561
		'NPR' => '&#8360;',
562
		'NZD' => '&#36;',
563
		'OMR' => '&#x631;.&#x639;.',
564
		'PAB' => 'B/.',
565
		'PEN' => 'S/.',
566
		'PGK' => 'K',
567
		'PHP' => '&#8369;',
568
		'PKR' => '&#8360;',
569
		'PLN' => '&#122;&#322;',
570
		'PRB' => '&#x440;.',
571
		'PYG' => '&#8370;',
572
		'QAR' => '&#x631;.&#x642;',
573
		'RMB' => '&yen;',
574
		'RON' => 'lei',
575
		'RSD' => '&#x434;&#x438;&#x43d;.',
576
		'RUB' => '&#8381;',
577
		'RWF' => 'Fr',
578
		'SAR' => '&#x631;.&#x633;',
579
		'SBD' => '&#36;',
580
		'SCR' => '&#x20a8;',
581
		'SDG' => '&#x62c;.&#x633;.',
582
		'SEK' => '&#107;&#114;',
583
		'SGD' => '&#36;',
584
		'SHP' => '&pound;',
585
		'SLL' => 'Le',
586
		'SOS' => 'Sh',
587
		'SRD' => '&#36;',
588
		'SSP' => '&pound;',
589
		'STD' => 'Db',
590
		'SYP' => '&#x644;.&#x633;',
591
		'SZL' => 'L',
592
		'THB' => '&#3647;',
593
		'TJS' => '&#x405;&#x41c;',
594
		'TMT' => 'm',
595
		'TND' => '&#x62f;.&#x62a;',
596
		'TOP' => 'T&#36;',
597
		'TRY' => '&#8378;',
598
		'TTD' => '&#36;',
599
		'TWD' => '&#78;&#84;&#36;',
600
		'TZS' => 'Sh',
601
		'UAH' => '&#8372;',
602
		'UGX' => 'UGX',
603
		'USD' => '&#36;',
604
		'UYU' => '&#36;',
605
		'UZS' => 'UZS',
606
		'VEF' => 'Bs F',
607
		'VND' => '&#8363;',
608
		'VUV' => 'Vt',
609
		'WST' => 'T',
610
		'XAF' => 'Fr',
611
		'XCD' => '&#36;',
612
		'XOF' => 'Fr',
613
		'XPF' => 'Fr',
614
		'YER' => '&#xfdfc;',
615
		'ZAR' => '&#82;',
616
		'ZMW' => 'ZK',
617
	) );
618
619
	$currency_symbol = isset( $symbols[ $currency ] ) ? $symbols[ $currency ] : '';
620
621
	return apply_filters( 'woocommerce_currency_symbol', $currency_symbol, $currency );
622
}
623
624
/**
625
 * Send HTML emails from WooCommerce.
626
 *
627
 * @param mixed $to
628
 * @param mixed $subject
629
 * @param mixed $message
630
 * @param string $headers (default: "Content-Type: text/html\r\n")
631
 * @param string $attachments (default: "")
632
 */
633
function wc_mail( $to, $subject, $message, $headers = "Content-Type: text/html\r\n", $attachments = "" ) {
634
	$mailer = WC()->mailer();
635
636
	$mailer->send( $to, $subject, $message, $headers, $attachments );
637
}
638
639
/**
640
 * Get an image size.
641
 *
642
 * Variable is filtered by woocommerce_get_image_size_{image_size}.
643
 *
644
 * @param mixed $image_size
645
 * @return array
646
 */
647
function wc_get_image_size( $image_size ) {
648
	if ( is_array( $image_size ) ) {
649
		$width  = isset( $image_size[0] ) ? $image_size[0] : '300';
650
		$height = isset( $image_size[1] ) ? $image_size[1] : '300';
651
		$crop   = isset( $image_size[2] ) ? $image_size[2] : 1;
652
653
		$size = array(
654
			'width'  => $width,
655
			'height' => $height,
656
			'crop'   => $crop
657
		);
658
659
		$image_size = $width . '_' . $height;
660
661
	} elseif ( in_array( $image_size, array( 'shop_thumbnail', 'shop_catalog', 'shop_single' ) ) ) {
662
		$size           = get_option( $image_size . '_image_size', array() );
663
		$size['width']  = isset( $size['width'] ) ? $size['width'] : '300';
664
		$size['height'] = isset( $size['height'] ) ? $size['height'] : '300';
665
		$size['crop']   = isset( $size['crop'] ) ? $size['crop'] : 0;
666
667
	} else {
668
		$size = array(
669
			'width'  => '300',
670
			'height' => '300',
671
			'crop'   => 1
672
		);
673
	}
674
675
	return apply_filters( 'woocommerce_get_image_size_' . $image_size, $size );
676
}
677
678
/**
679
 * Queue some JavaScript code to be output in the footer.
680
 *
681
 * @param string $code
682
 */
683
function wc_enqueue_js( $code ) {
684
	global $wc_queued_js;
685
686
	if ( empty( $wc_queued_js ) ) {
687
		$wc_queued_js = '';
688
	}
689
690
	$wc_queued_js .= "\n" . $code . "\n";
691
}
692
693
/**
694
 * Output any queued javascript code in the footer.
695
 */
696
function wc_print_js() {
697
	global $wc_queued_js;
698
699
	if ( ! empty( $wc_queued_js ) ) {
700
		// Sanitize.
701
		$wc_queued_js = wp_check_invalid_utf8( $wc_queued_js );
702
		$wc_queued_js = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", $wc_queued_js );
703
		$wc_queued_js = str_replace( "\r", '', $wc_queued_js );
704
705
		$js = "<!-- WooCommerce JavaScript -->\n<script type=\"text/javascript\">\njQuery(function($) { $wc_queued_js });\n</script>\n";
706
707
		/**
708
		 * woocommerce_queued_js filter.
709
		 *
710
		 * @since 2.6.0
711
		 * @param string $js JavaScript code.
712
		 */
713
		echo apply_filters( 'woocommerce_queued_js', $js );
714
715
		unset( $wc_queued_js );
716
	}
717
}
718
719
/**
720
 * Set a cookie - wrapper for setcookie using WP constants.
721
 *
722
 * @param  string  $name   Name of the cookie being set.
723
 * @param  string  $value  Value of the cookie.
724
 * @param  integer $expire Expiry of the cookie.
725
 * @param  string  $secure Whether the cookie should be served only over https.
726
 */
727
function wc_setcookie( $name, $value, $expire = 0, $secure = false ) {
728
	if ( ! headers_sent() ) {
729
		setcookie( $name, $value, $expire, COOKIEPATH ? COOKIEPATH : '/', COOKIE_DOMAIN, $secure );
730
	} elseif ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
731
		headers_sent( $file, $line );
732
		trigger_error( "{$name} cookie cannot be set - headers already sent by {$file} on line {$line}", E_USER_NOTICE );
733
	}
734
}
735
736
/**
737
 * Get the URL to the WooCommerce REST API.
738
 *
739
 * @since 2.1
740
 * @param string $path an endpoint to include in the URL.
741
 * @return string the URL.
742
 */
743
function get_woocommerce_api_url( $path ) {
744
745
	$_version = substr( WC_API::VERSION, 0, 1 );
0 ignored issues
show
Deprecated Code introduced by
The constant WC_API::VERSION has been deprecated with message: 2.6.0

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
746
	$version  = defined( 'WC_API_REQUEST_VERSION' ) ? WC_API_REQUEST_VERSION : $_version;
747
748
	$url = get_home_url( null, "wc-api/v{$version}/", is_ssl() ? 'https' : 'http' );
749
750
	if ( ! empty( $path ) && is_string( $path ) ) {
751
		$url .= ltrim( $path, '/' );
752
	}
753
754
	return $url;
755
}
756
757
/**
758
 * Get a log file path.
759
 *
760
 * @since 2.2
761
 * @param string $handle name.
762
 * @return string the log file path.
763
 */
764
function wc_get_log_file_path( $handle ) {
765
	return trailingslashit( WC_LOG_DIR ) . $handle . '-' . sanitize_file_name( wp_hash( $handle ) ) . '.log';
766
}
767
768
/**
769
 * Init for our rewrite rule fixes.
770
 */
771
function wc_fix_rewrite_rules_init() {
772
	$permalinks = get_option( 'woocommerce_permalinks' );
773
774
	if ( ! empty( $permalinks['use_verbose_page_rules'] ) ) {
775
		$GLOBALS['wp_rewrite']->use_verbose_page_rules = true;
776
	}
777
}
778
add_action( 'init', 'wc_fix_rewrite_rules_init' );
779
780
/**
781
 * Various rewrite rule fixes.
782
 *
783
 * @since 2.2
784
 * @param array $rules
785
 * @return array
786
 */
787
function wc_fix_rewrite_rules( $rules ) {
788
	global $wp_rewrite;
789
790
	$permalinks        = get_option( 'woocommerce_permalinks' );
791
	$product_permalink = empty( $permalinks['product_base'] ) ? _x( 'product', 'slug', 'woocommerce' ) : $permalinks['product_base'];
792
793
	// Fix the rewrite rules when the product permalink have %product_cat% flag.
794
	if ( preg_match( '`/(.+)(/%product_cat%)`' , $product_permalink, $matches ) ) {
795
		foreach ( $rules as $rule => $rewrite ) {
796
797
			if ( preg_match( '`^' . preg_quote( $matches[1], '`' ) . '/\(`', $rule ) && preg_match( '/^(index\.php\?product_cat)(?!(.*product))/', $rewrite ) ) {
798
				unset( $rules[ $rule ] );
799
			}
800
		}
801
	}
802
803
	// If the shop page is used as the base, we need to enable verbose rewrite rules or sub pages will 404.
804
	if ( ! empty( $permalinks['use_verbose_page_rules'] ) ) {
805
		$page_rewrite_rules = $wp_rewrite->page_rewrite_rules();
806
		$rules              = array_merge( $page_rewrite_rules, $rules );
807
	}
808
809
	return $rules;
810
}
811
add_filter( 'rewrite_rules_array', 'wc_fix_rewrite_rules' );
812
813
/**
814
 * Prevent product attachment links from breaking when using complex rewrite structures.
815
 *
816
 * @param  string $link
817
 * @param  id $post_id
818
 * @return string
819
 */
820
function wc_fix_product_attachment_link( $link, $post_id ) {
821
	global $wp_rewrite;
822
823
	$post = get_post( $post_id );
824
	if ( 'product' === get_post_type( $post->post_parent ) ) {
825
		$permalinks        = get_option( 'woocommerce_permalinks' );
826
		$product_permalink = empty( $permalinks['product_base'] ) ? _x( 'product', 'slug', 'woocommerce' ) : $permalinks['product_base'];
827
		if ( preg_match( '/\/(.+)(\/%product_cat%)$/' , $product_permalink, $matches ) ) {
828
			$link = home_url( '/?attachment_id=' . $post->ID );
829
		}
830
	}
831
	return $link;
832
}
833
add_filter( 'attachment_link', 'wc_fix_product_attachment_link', 10, 2 );
834
835
/**
836
 * Protect downloads from ms-files.php in multisite.
837
 *
838
 * @param mixed $rewrite
839
 * @return string
840
 */
841
function wc_ms_protect_download_rewite_rules( $rewrite ) {
842
	if ( ! is_multisite() || 'redirect' == get_option( 'woocommerce_file_download_method' ) ) {
843
		return $rewrite;
844
	}
845
846
	$rule  = "\n# WooCommerce Rules - Protect Files from ms-files.php\n\n";
847
	$rule .= "<IfModule mod_rewrite.c>\n";
848
	$rule .= "RewriteEngine On\n";
849
	$rule .= "RewriteCond %{QUERY_STRING} file=woocommerce_uploads/ [NC]\n";
850
	$rule .= "RewriteRule /ms-files.php$ - [F]\n";
851
	$rule .= "</IfModule>\n\n";
852
853
	return $rule . $rewrite;
854
}
855
add_filter( 'mod_rewrite_rules', 'wc_ms_protect_download_rewite_rules' );
856
857
/**
858
 * WooCommerce Core Supported Themes.
859
 *
860
 * @since 2.2
861
 * @return string[]
862
 */
863
function wc_get_core_supported_themes() {
864
	return array( 'twentysixteen', 'twentyfifteen', 'twentyfourteen', 'twentythirteen', 'twentyeleven', 'twentytwelve', 'twentyten' );
865
}
866
867
/**
868
 * Wrapper function to execute the `woocommerce_deliver_webhook_async` cron.
869
 * hook, see WC_Webhook::process().
870
 *
871
 * @since 2.2
872
 * @param int $webhook_id webhook ID to deliver.
873
 * @param mixed $arg hook argument.
874
 */
875
function wc_deliver_webhook_async( $webhook_id, $arg ) {
876
877
	$webhook = new WC_Webhook( $webhook_id );
878
879
	$webhook->deliver( $arg );
880
}
881
add_action( 'woocommerce_deliver_webhook_async', 'wc_deliver_webhook_async', 10, 2 );
882
883
/**
884
 * Enables template debug mode.
885
 */
886
function wc_template_debug_mode() {
887
	if ( ! defined( 'WC_TEMPLATE_DEBUG_MODE' ) ) {
888
		$status_options = get_option( 'woocommerce_status_options', array() );
889
		if ( ! empty( $status_options['template_debug_mode'] ) && current_user_can( 'manage_options' ) ) {
890
			define( 'WC_TEMPLATE_DEBUG_MODE', true );
891
		} else {
892
			define( 'WC_TEMPLATE_DEBUG_MODE', false );
893
		}
894
	}
895
}
896
add_action( 'after_setup_theme', 'wc_template_debug_mode', 20 );
897
898
/**
899
 * Formats a string in the format COUNTRY:STATE into an array.
900
 *
901
 * @since 2.3.0
902
 * @param  string $country_string
903
 * @return array
904
 */
905
function wc_format_country_state_string( $country_string ) {
906
	if ( strstr( $country_string, ':' ) ) {
907
		list( $country, $state ) = explode( ':', $country_string );
908
	} else {
909
		$country = $country_string;
910
		$state   = '';
911
	}
912
	return array(
913
		'country' => $country,
914
		'state'   => $state
915
	);
916
}
917
918
/**
919
 * Get the store's base location.
920
 *
921
 * @todo should the woocommerce_default_country option be renamed to contain 'base'?
922
 * @since 2.3.0
923
 * @return array
924
 */
925
function wc_get_base_location() {
926
	$default = apply_filters( 'woocommerce_get_base_location', get_option( 'woocommerce_default_country' ) );
927
928
	return wc_format_country_state_string( $default );
929
}
930
931
/**
932
 * Get the customer's default location.
933
 *
934
 * Filtered, and set to base location or left blank. If cache-busting,
935
 * this should only be used when 'location' is set in the querystring.
936
 *
937
 * @todo should the woocommerce_default_country option be renamed to contain 'base'?
938
 * @todo deprecate woocommerce_customer_default_location and support an array filter only to cover all cases.
939
 * @since 2.3.0
940
 * @return array
941
 */
942
function wc_get_customer_default_location() {
943
	$location = array();
944
945
	switch ( get_option( 'woocommerce_default_customer_address' ) ) {
946
		case 'geolocation_ajax' :
947
		case 'geolocation' :
948
			// Exclude common bots from geolocation by user agent.
949
			$ua = isset( $_SERVER['HTTP_USER_AGENT'] ) ? strtolower( $_SERVER['HTTP_USER_AGENT'] ) : '';
950
951
			if ( ! strstr( $ua, 'bot' ) && ! strstr( $ua, 'spider' ) && ! strstr( $ua, 'crawl' ) ) {
952
				$location = WC_Geolocation::geolocate_ip( '', true, false );
953
			}
954
955
			// Base fallback.
956
			if ( empty( $location['country'] ) ) {
957
				$location = wc_format_country_state_string( apply_filters( 'woocommerce_customer_default_location', get_option( 'woocommerce_default_country' ) ) );
958
			}
959
		break;
960
		case 'base' :
961
			$location = wc_format_country_state_string( apply_filters( 'woocommerce_customer_default_location', get_option( 'woocommerce_default_country' ) ) );
962
		break;
963
		default :
964
			$location = wc_format_country_state_string( apply_filters( 'woocommerce_customer_default_location', '' ) );
965
		break;
966
	}
967
968
	return apply_filters( 'woocommerce_customer_default_location_array', $location );
969
}
970
971
// This function can be removed when WP 3.9.2 or greater is required.
972
if ( ! function_exists( 'hash_equals' ) ) :
973
	/**
974
	 * Compare two strings in constant time.
975
	 *
976
	 * This function was added in PHP 5.6.
977
	 * It can leak the length of a string.
978
	 *
979
	 * @since 3.9.2
980
	 *
981
	 * @param string $a Expected string.
982
	 * @param string $b Actual string.
983
	 * @return bool Whether strings are equal.
984
	 */
985
	function hash_equals( $a, $b ) {
986
		$a_length = strlen( $a );
987
		if ( $a_length !== strlen( $b ) ) {
988
			return false;
989
		}
990
		$result = 0;
991
992
		// Do not attempt to "optimize" this.
993
		for ( $i = 0; $i < $a_length; $i++ ) {
994
			$result |= ord( $a[ $i ] ) ^ ord( $b[ $i ] );
995
		}
996
997
		return $result === 0;
998
	}
999
endif;
1000
1001
/**
1002
 * Generate a rand hash.
1003
 *
1004
 * @since  2.4.0
1005
 * @return string
1006
 */
1007
function wc_rand_hash() {
1008
	if ( function_exists( 'openssl_random_pseudo_bytes' ) ) {
1009
		return bin2hex( openssl_random_pseudo_bytes( 20 ) );
1010
	} else {
1011
		return sha1( wp_rand() );
1012
	}
1013
}
1014
1015
/**
1016
 * WC API - Hash.
1017
 *
1018
 * @since  2.4.0
1019
 * @param  string $data
1020
 * @return string
1021
 */
1022
function wc_api_hash( $data ) {
1023
	return hash_hmac( 'sha256', $data, 'wc-api' );
1024
}
1025
1026
/**
1027
 * Find all possible combinations of values from the input array and return in a logical order.
1028
 * @since 2.5.0
1029
 * @param array $input
1030
 * @return array
1031
 */
1032
function wc_array_cartesian( $input ) {
1033
	$input   = array_filter( $input );
1034
	$results = array();
1035
	$indexes = array();
1036
	$index   = 0;
1037
1038
	// Generate indexes from keys and values so we have a logical sort order
1039
	foreach ( $input as $key => $values ) {
1040
		foreach ( $values as $value ) {
1041
			$indexes[ $key ][ $value ] = $index++;
1042
		}
1043
	}
1044
1045
	// Loop over the 2D array of indexes and generate all combinations
1046
	foreach ( $indexes as $key => $values ) {
1047
		// When result is empty, fill with the values of the first looped array
1048
		if ( empty( $results ) ) {
1049
			foreach ( $values as $value ) {
1050
				$results[] = array( $key => $value );
1051
			}
1052
1053
		// Second and subsequent input sub-array merging.
1054
		} else {
1055
			foreach ( $results as $result_key => $result ) {
1056
				foreach ( $values as $value ) {
1057
					// If the key is not set, we can set it
1058
					if ( ! isset( $results[ $result_key ][ $key ] ) ) {
1059
						$results[ $result_key ][ $key ] = $value;
1060
					// If the key is set, we can add a new combination to the results array
1061
					} else {
1062
						$new_combination         = $results[ $result_key ];
1063
						$new_combination[ $key ] = $value;
1064
						$results[]               = $new_combination;
1065
					}
1066
				}
1067
			}
1068
		}
1069
	}
1070
1071
	// Sort the indexes
1072
	arsort( $results );
1073
1074
	// Convert indexes back to values
1075
	foreach ( $results as $result_key => $result ) {
1076
		$converted_values = array();
1077
1078
		// Sort the values
1079
		arsort( $results[ $result_key ] );
1080
1081
		// Convert the values
1082
		foreach ( $results[ $result_key ] as $key => $value ) {
1083
			$converted_values[ $key ] = array_search( $value, $indexes[ $key ] );
1084
		}
1085
1086
		$results[ $result_key ] = $converted_values;
1087
	}
1088
1089
	return $results;
1090
}
1091
1092
/**
1093
 * Run a MySQL transaction query, if supported.
1094
 * @param string $type start (default), commit, rollback
1095
 * @since 2.5.0
1096
 */
1097
function wc_transaction_query( $type = 'start' ) {
1098
	global $wpdb;
1099
1100
	$wpdb->hide_errors();
1101
1102
	if ( ! defined( 'WC_USE_TRANSACTIONS' ) ) {
1103
		define( 'WC_USE_TRANSACTIONS', true );
1104
	}
1105
1106
	if ( WC_USE_TRANSACTIONS ) {
1107
		switch ( $type ) {
1108
			case 'commit' :
1109
				$wpdb->query( 'COMMIT' );
1110
				break;
1111
			case 'rollback' :
1112
				$wpdb->query( 'ROLLBACK' );
1113
				break;
1114
			default :
1115
				$wpdb->query( 'START TRANSACTION' );
1116
			break;
1117
		}
1118
	}
1119
}
1120
1121
/**
1122
 * Gets the url to the cart page.
1123
 *
1124
 * @since  2.5.0
1125
 *
1126
 * @return string Url to cart page
1127
 */
1128
function wc_get_cart_url() {
1129
	return apply_filters( 'woocommerce_get_cart_url', wc_get_page_permalink( 'cart' ) );
1130
}
1131
1132
/**
1133
 * Gets the url to the checkout page.
1134
 *
1135
 * @since  2.5.0
1136
 *
1137
 * @return string Url to checkout page
1138
 */
1139
function wc_get_checkout_url() {
1140
	$checkout_url = wc_get_page_permalink( 'checkout' );
1141 View Code Duplication
	if ( $checkout_url ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1142
		// Force SSL if needed
1143
		if ( is_ssl() || 'yes' === get_option( 'woocommerce_force_ssl_checkout' ) ) {
1144
			$checkout_url = str_replace( 'http:', 'https:', $checkout_url );
1145
		}
1146
	}
1147
1148
	return apply_filters( 'woocommerce_get_checkout_url', $checkout_url );
1149
}
1150
1151
/**
1152
 * Register a shipping method.
1153
 *
1154
 * @since 1.5.7
1155
 * @param string|object $shipping_method class name (string) or a class object.
1156
 */
1157
function woocommerce_register_shipping_method( $shipping_method ) {
1158
	WC()->shipping->register_shipping_method( $shipping_method );
1159
}
1160
1161
if ( ! function_exists( 'wc_get_shipping_zone' ) ) {
1162
	/**
1163
	 * Get the shipping zone matching a given package from the cart.
1164
	 *
1165
	 * @since  2.6.0
1166
	 * @uses   WC_Shipping_Zones::get_zone_matching_package
1167
	 * @param  array $package
1168
	 * @return WC_Shipping_Zone
1169
	 */
1170
	function wc_get_shipping_zone( $package ) {
1171
		return WC_Shipping_Zones::get_zone_matching_package( $package );
0 ignored issues
show
Documentation introduced by
$package is of type array, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1172
	}
1173
}
1174
1175
/**
1176
 * Get a nice name for credit card providers.
1177
 *
1178
 * @since  2.6.0
1179
 * @param  string $type Provider Slug/Type
1180
 * @return string
1181
 */
1182
function wc_get_credit_card_type_label( $type ) {
1183
	// Normalize
1184
	$type = strtolower( $type );
1185
	$type = str_replace( '-', ' ', $type );
1186
	$type = str_replace( '_', ' ', $type );
1187
1188
	$labels = apply_filters( 'wocommerce_credit_card_type_labels', array(
1189
		'mastercard'       => __( 'MasterCard', 'woocommerce' ),
1190
		'visa'             => __( 'Visa', 'woocommerce' ),
1191
		'discover'         => __( 'Discover', 'woocommerce' ),
1192
		'american express' => __( 'American Express', 'woocommerce' ),
1193
		'diners'           => __( 'Diners', 'woocommerce' ),
1194
		'jcb'              => __( 'JCB', 'woocommerce' ),
1195
	) );
1196
1197
	return apply_filters( 'woocommerce_get_credit_card_type_label', ( array_key_exists( $type, $labels ) ? $labels[ $type ] : ucfirst( $type ) ) );
1198
}
1199
1200
/**
1201
 * Outputs a "back" link so admin screens can easily jump back a page.
1202
 *
1203
 * @param string $label Title of the page to return to.
1204
 * @param string $url   URL of the page to return to.
1205
 */
1206
function wc_back_link( $label, $url ) {
1207
	echo '<small class="wc-admin-breadcrumb"><a href="' . esc_url( $url ) . '" title="' . esc_attr( $label ) . '">&#x2934;</a></small>';
1208
}
1209
1210
/**
1211
 * Display a WooCommerce help tip.
1212
 *
1213
 * @since  2.5.0
1214
 *
1215
 * @param  string $tip        Help tip text
1216
 * @param  bool   $allow_html Allow sanitized HTML if true or escape
1217
 * @return string
1218
 */
1219
function wc_help_tip( $tip, $allow_html = false ) {
1220
	if ( $allow_html ) {
1221
		$tip = wc_sanitize_tooltip( $tip );
1222
	} else {
1223
		$tip = esc_attr( $tip );
1224
	}
1225
1226
	return '<span class="woocommerce-help-tip" data-tip="' . $tip . '"></span>';
1227
}
1228
1229
/**
1230
 * Return a list of potential postcodes for wildcard searching.
1231
 * @since 2.6.0
1232
 * @param  string $postcode
1233
 * @return array
1234
 */
1235
function wc_get_wildcard_postcodes( $postcode ) {
1236
	$postcodes         = array( '*', strtoupper( $postcode ), strtoupper( $postcode ) . '*' );
1237
	$postcode_length   = strlen( $postcode );
1238
	$wildcard_postcode = strtoupper( $postcode );
1239
1240
	for ( $i = 0; $i < $postcode_length; $i ++ ) {
1241
		$wildcard_postcode = substr( $wildcard_postcode, 0, -1 );
1242
		$postcodes[] = $wildcard_postcode . '*';
1243
	}
1244
	return $postcodes;
1245
}
1246
1247
/**
1248
 * Used by shipping zones and taxes to compare a given $postcode to stored
1249
 * postcodes to find matches for numerical ranges, and wildcards.
1250
 * @since 2.6.0
1251
 * @param string $postcode Postcode you want to match against stored postcodes
1252
 * @param array $objects Array of postcode objects from Database
1253
 * @param string $object_compare_key DB column name for the ID.
1254
 * @param string $object_compare_key DB column name for the value.
1255
 * @return array Array of matching object ID and values.
1256
 */
1257
function wc_postcode_location_matcher( $postcode, $objects, $object_id_key, $object_compare_key ) {
1258
	$postcode           = wc_normalize_postcode( $postcode );
1259
	$wildcard_postcodes = array_map( 'wc_clean', wc_get_wildcard_postcodes( $postcode ) );
1260
	$postcodes          = array_map( 'wc_normalize_postcode', wp_list_pluck( $objects, $object_compare_key, $object_id_key ) );
1261
	$matches            = array();
1262
1263
	foreach ( $postcodes as $object_id => $compare_against ) {
1264
		$compare = $postcode;
1265
1266
		// Handle postcodes containing ranges.
1267
		if ( strstr( $compare_against, '...' ) ) {
1268
			$range = array_map( 'trim', explode( '...', $compare_against ) );
1269
1270
			if ( 2 !== sizeof( $range ) ) {
1271
				continue;
1272
			}
1273
1274
			list( $min, $max ) = $range;
1275
1276
			// If the postcode is non-numeric, make it numeric.
1277
			if ( ! is_numeric( $min ) || ! is_numeric( $max ) ) {
1278
				$compare = wc_make_numeric_postcode( $compare );
1279
				$min     = str_pad( wc_make_numeric_postcode( $min ), strlen( $compare ), '0' );
1280
				$max     = str_pad( wc_make_numeric_postcode( $max ), strlen( $compare ), '0' );
1281
			}
1282
1283
			if ( $compare >= $min && $compare <= $max ) {
1284
				$matches[ $object_id ] = $compare_against;
1285
			}
1286
1287
		// Wildcard and standard comparison.
1288
		} elseif ( in_array( $compare_against, $wildcard_postcodes ) ) {
1289
			$matches[ $object_id ] = $compare_against;
1290
		}
1291
	}
1292
1293
	return $matches;
1294
}
1295
1296
/**
1297
 * Gets number of shipping methods currently enabled. Used to identify if
1298
 * shipping is configured.
1299
 *
1300
 * @since  2.6.0
1301
 * @param  bool $include_legacy Count legacy shipping methods too.
1302
 * @return int
1303
 */
1304
function wc_get_shipping_method_count( $include_legacy = false ) {
1305
	global $wpdb;
1306
1307
	$transient_name = 'wc_shipping_method_count_' . ( $include_legacy ? 1 : 0 ) . '_' . WC_Cache_Helper::get_transient_version( 'shipping' );
1308
	$method_count   = get_transient( $transient_name );
1309
1310
	if ( false === $method_count ) {
1311
		$method_count = absint( $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}woocommerce_shipping_zone_methods" ) );
1312
1313
		if ( $include_legacy ) {
1314
			// Count activated methods that don't support shipping zones.
1315
			$methods = WC()->shipping->get_shipping_methods();
1316
1317
			foreach ( $methods as $method ) {
1318
				if ( isset( $method->enabled ) && 'yes' === $method->enabled && ! $method->supports( 'shipping-zones' ) ) {
1319
					$method_count++;
1320
				}
1321
			}
1322
		}
1323
1324
		set_transient( $transient_name, $method_count, DAY_IN_SECONDS * 30 );
1325
	}
1326
1327
	return absint( $method_count );
1328
}
1329
1330
/**
1331
 * Wrapper for set_time_limit to see if it is enabled.
1332
 */
1333
function wc_set_time_limit( $limit = 0 ) {
1334
	if ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) {
1335
		@set_time_limit( $limit );
1336
	}
1337
}
1338