Completed
Push — master ( 9fe8a1...557bd9 )
by Mike
22:24
created

WC_Countries::get_shipping_countries()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 5
eloc 11
c 2
b 0
f 1
nc 4
nop 0
dl 0
loc 21
rs 8.7624
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 18 and the first side effect is on line 4.

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
if ( ! defined( 'ABSPATH' ) ) {
4
	exit; // Exit if accessed directly
5
}
6
7
/**
8
 * WooCommerce countries
9
 *
10
 * The WooCommerce countries class stores country/state data.
11
 *
12
 * @class       WC_Countries
13
 * @version     2.3.0
14
 * @package     WooCommerce/Classes
15
 * @category    Class
16
 * @author      WooThemes
17
 */
18
class WC_Countries {
19
20
	/** @var array Array of locales */
21
	public $locale;
22
23
	/** @var array Array of address formats for locales */
24
	public $address_formats;
25
26
	/**
27
	 * Auto-load in-accessible properties on demand.
28
	 * @param  mixed $key
29
	 * @return mixed
30
	 */
31
	public function __get( $key ) {
32
		if ( 'countries' == $key ) {
33
			return $this->get_countries();
34
		} elseif ( 'states' == $key ) {
35
			return $this->get_states();
36
		}
37
	}
38
39
	/**
40
	 * Get all countries.
41
	 * @return array
42
	 */
43
	public function get_countries() {
44
		if ( empty( $this->countries ) ) {
45
			$this->countries = apply_filters( 'woocommerce_countries', include( WC()->plugin_path() . '/i18n/countries.php' ) );
46
			if ( apply_filters( 'woocommerce_sort_countries', true ) ) {
47
				asort( $this->countries );
48
			}
49
		}
50
		return $this->countries;
51
	}
52
53
	/**
54
	 * Get all continents.
55
	 * @return array
56
	 */
57
	public function get_continents() {
58
		if ( empty( $this->continents ) ) {
59
			$this->continents = apply_filters( 'woocommerce_continents', include( WC()->plugin_path() . '/i18n/continents.php' ) );
60
		}
61
		return $this->continents;
62
	}
63
64
	/**
65
	 * Get continent code for a country code.
66
	 * @since 2.6.0
67
	 * @param $cc string
68
	 * @return string
69
	 */
70
	public function get_continent_code_for_country( $cc ) {
71
		$cc                 = trim( strtoupper( $cc ) );
72
		$continents         = $this->get_continents();
73
		$continents_and_ccs = wp_list_pluck( $continents, 'countries' );
74
		foreach ( $continents_and_ccs as $continent_code => $countries ) {
75
			if ( false !== array_search( $cc, $countries ) ) {
76
				return $continent_code;
77
			}
78
		}
79
		return '';
80
	}
81
82
	/**
83
	 * Load the states.
84
	 */
85
	public function load_country_states() {
86
		global $states;
87
88
		// States set to array() are blank i.e. the country has no use for the state field.
89
		$states = array(
90
			'AF' => array(),
91
			'AT' => array(),
92
			'AX' => array(),
93
			'BE' => array(),
94
			'BI' => array(),
95
			'CZ' => array(),
96
			'DE' => array(),
97
			'DK' => array(),
98
			'EE' => array(),
99
			'FI' => array(),
100
			'FR' => array(),
101
			'IS' => array(),
102
			'IL' => array(),
103
			'KR' => array(),
104
			'NL' => array(),
105
			'NO' => array(),
106
			'PL' => array(),
107
			'PT' => array(),
108
			'SG' => array(),
109
			'SK' => array(),
110
			'SI' => array(),
111
			'LK' => array(),
112
			'SE' => array(),
113
			'VN' => array(),
114
		);
115
116
		// Load only the state files the shop owner wants/needs.
117
		$allowed = array_merge( $this->get_allowed_countries(), $this->get_shipping_countries() );
118
119
		if ( $allowed ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $allowed 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...
120
			foreach ( $allowed as $code => $country ) {
121
				if ( ! isset( $states[ $code ] ) && file_exists( WC()->plugin_path() . '/i18n/states/' . $code . '.php' ) ) {
122
					include( WC()->plugin_path() . '/i18n/states/' . $code . '.php' );
123
				}
124
			}
125
		}
126
127
		$this->states = apply_filters( 'woocommerce_states', $states );
128
	}
129
130
	/**
131
	 * Get the states for a country.
132
	 * @param  string $cc country code
133
	 * @return array of states
134
	 */
135
	public function get_states( $cc = null ) {
136
		if ( empty( $this->states ) ) {
137
			$this->load_country_states();
138
		}
139
140
		if ( ! is_null( $cc ) ) {
141
			return isset( $this->states[ $cc ] ) ? $this->states[ $cc ] : false;
142
		} else {
143
			return $this->states;
144
		}
145
	}
146
147
	/**
148
	 * Get the base country for the store.
149
	 * @return string
150
	 */
151
	public function get_base_country() {
152
		$default = wc_get_base_location();
153
		return apply_filters( 'woocommerce_countries_base_country', $default['country'] );
154
	}
155
156
	/**
157
	 * Get the base state for the store.
158
	 * @return string
159
	 */
160
	public function get_base_state() {
161
		$default = wc_get_base_location();
162
		return apply_filters( 'woocommerce_countries_base_state', $default['state'] );
163
	}
164
165
	/**
166
	 * Get the base city for the store.
167
	 * @return string
168
	 */
169
	public function get_base_city() {
170
		return apply_filters( 'woocommerce_countries_base_city', '' );
171
	}
172
173
	/**
174
	 * Get the base postcode for the store.
175
	 * @return string
176
	 */
177
	public function get_base_postcode() {
178
		return apply_filters( 'woocommerce_countries_base_postcode', '' );
179
	}
180
181
	/**
182
	 * Get the allowed countries for the store.
183
	 * @return array
184
	 */
185
	public function get_allowed_countries() {
186
		if ( 'all' === get_option( 'woocommerce_allowed_countries' ) ) {
187
			return $this->countries;
188
		}
189
190
		if( 'all_except' === get_option( 'woocommerce_allowed_countries' ) ) {
191
			$except_countries = get_option( 'woocommerce_all_except_countries', array() );
192
193
			if ( ! $except_countries ) {
194
				return $this->countries;
195
			} else {
196
				$all_except_countries = $this->countries;
197
				foreach( $except_countries as $country ) {
198
					unset( $all_except_countries[ $country ] );
199
				}
200
				return apply_filters( 'woocommerce_countries_allowed_countries', $all_except_countries );
201
			}
202
		}
203
204
		$countries = array();
205
206
		$raw_countries = get_option( 'woocommerce_specific_allowed_countries', array() );
207
208
		if ( $raw_countries ) {
209
			foreach ( $raw_countries as $country ) {
210
				$countries[ $country ] = $this->countries[ $country ];
211
			}
212
		}
213
214
		return apply_filters( 'woocommerce_countries_allowed_countries', $countries );
215
	}
216
217
	/**
218
	 * Get the countries you ship to.
219
	 * @return array
220
	 */
221
	public function get_shipping_countries() {
222
		if ( '' === get_option( 'woocommerce_ship_to_countries' ) ) {
223
			return $this->get_allowed_countries();
224
		}
225
226
		if ( 'all' === get_option( 'woocommerce_ship_to_countries' ) ) {
227
			return $this->countries;
228
		}
229
230
		$countries = array();
231
232
		$raw_countries = get_option( 'woocommerce_specific_ship_to_countries' );
233
234
		if ( $raw_countries ) {
235
			foreach ( $raw_countries as $country ) {
236
				$countries[ $country ] = $this->countries[ $country ];
237
			}
238
		}
239
240
		return apply_filters( 'woocommerce_countries_shipping_countries', $countries );
241
	}
242
243
	/**
244
	 * Get allowed country states.
245
	 * @return array
246
	 */
247
	public function get_allowed_country_states() {
248
		if ( get_option( 'woocommerce_allowed_countries' ) !== 'specific' ) {
249
			return $this->states;
250
		}
251
252
		$states = array();
253
254
		$raw_countries = get_option( 'woocommerce_specific_allowed_countries' );
255
256
		if ( $raw_countries ) {
257
			foreach ( $raw_countries as $country ) {
258
				if ( isset( $this->states[ $country ] ) ) {
259
					$states[ $country ] = $this->states[ $country ];
260
				}
261
			}
262
		}
263
264
		return apply_filters( 'woocommerce_countries_allowed_country_states', $states );
265
	}
266
267
	/**
268
	 * Get shipping country states.
269
	 * @return array
270
	 */
271
	public function get_shipping_country_states() {
272
		if ( get_option( 'woocommerce_ship_to_countries' ) == '' ) {
273
			return $this->get_allowed_country_states();
274
		}
275
276
		if ( get_option( 'woocommerce_ship_to_countries' ) !== 'specific' ) {
277
			return $this->states;
278
		}
279
280
		$states = array();
281
282
		$raw_countries = get_option( 'woocommerce_specific_ship_to_countries' );
283
284
		if ( $raw_countries ) {
285
			foreach ( $raw_countries as $country ) {
286
				if ( ! empty( $this->states[ $country ] ) ) {
287
					$states[ $country ] = $this->states[ $country ];
288
				}
289
			}
290
		}
291
292
		return apply_filters( 'woocommerce_countries_shipping_country_states', $states );
293
	}
294
295
	/**
296
	 * Gets an array of countries in the EU.
297
	 *
298
	 * MC (monaco) and IM (isle of man, part of UK) also use VAT.
299
	 *
300
	 * @param  $type Type of countries to retrieve. Blank for EU member countries. eu_vat for EU VAT countries.
301
	 * @return string[]
302
	 */
303
	public function get_european_union_countries( $type = '' ) {
304
		$countries = array( 'AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HU', 'HR', 'IE', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK' );
305
306
		if ( 'eu_vat' === $type ) {
307
			$countries[] = 'MC';
308
			$countries[] = 'IM';
309
		}
310
311
		return $countries;
312
	}
313
314
	/**
315
	 * Gets the correct string for shipping - either 'to the' or 'to'
316
	 * @return string
317
	 */
318
	public function shipping_to_prefix( $country_code = '' ) {
319
		$country_code = $country_code ? $country_code : WC()->customer->get_shipping_country();
320
		$countries    = array( 'GB', 'US', 'AE', 'CZ', 'DO', 'NL', 'PH', 'USAF' );
321
		$return       = in_array( $country_code, $countries ) ? __( 'to the', 'woocommerce' ) : __( 'to', 'woocommerce' );
322
323
		return apply_filters( 'woocommerce_countries_shipping_to_prefix', $return, $country_code );
324
	}
325
326
	/**
327
	 * Prefix certain countries with 'the'
328
	 * @return string
329
	 */
330
	public function estimated_for_prefix( $country_code = '' ) {
331
		$country_code = $country_code ? $country_code : $this->get_base_country();
332
		$countries    = array( 'GB', 'US', 'AE', 'CZ', 'DO', 'NL', 'PH', 'USAF' );
333
		$return       = in_array( $country_code, $countries ) ? __( 'the', 'woocommerce' ) . ' ' : '';
334
335
		return apply_filters( 'woocommerce_countries_estimated_for_prefix', $return, $country_code );
336
	}
337
338
	/**
339
	 * Correctly name tax in some countries VAT on the frontend.
340
	 * @return string
341
	 */
342
	public function tax_or_vat() {
343
		$return = in_array( $this->get_base_country(), $this->get_european_union_countries( 'eu_vat' ) ) ? __( 'VAT', 'woocommerce' ) : __( 'Tax', 'woocommerce' );
344
345
		return apply_filters( 'woocommerce_countries_tax_or_vat', $return );
346
	}
347
348
	/**
349
	 * Include the Inc Tax label.
350
	 * @return string
351
	 */
352
	public function inc_tax_or_vat() {
353
		$return = in_array( $this->get_base_country(), $this->get_european_union_countries( 'eu_vat' ) ) ? __( '(incl. VAT)', 'woocommerce' ) : __( '(incl. tax)', 'woocommerce' );
354
355
		return apply_filters( 'woocommerce_countries_inc_tax_or_vat', $return );
356
	}
357
358
	/**
359
	 * Include the Ex Tax label.
360
	 * @return string
361
	 */
362
	public function ex_tax_or_vat() {
363
		$return = in_array( $this->get_base_country(), $this->get_european_union_countries( 'eu_vat' ) ) ? __( '(ex. VAT)', 'woocommerce' ) : __( '(ex. tax)', 'woocommerce' );
364
365
		return apply_filters( 'woocommerce_countries_ex_tax_or_vat', $return );
366
	}
367
368
	/**
369
	 * Outputs the list of countries and states for use in dropdown boxes.
370
	 * @param string $selected_country (default: '')
371
	 * @param string $selected_state (default: '')
372
	 * @param bool $escape (default: false)
373
	 * @param bool   $escape (default: false)
374
	 */
375
	public function country_dropdown_options( $selected_country = '', $selected_state = '', $escape = false ) {
376
		if ( $this->countries ) foreach ( $this->countries as $key => $value ) :
377
			if ( $states = $this->get_states( $key ) ) :
378
				echo '<optgroup label="' . esc_attr( $value ) . '">';
379
					foreach ( $states as $state_key => $state_value ) :
380
						echo '<option value="' . esc_attr( $key ) . ':' . $state_key . '"';
381
382
						if ( $selected_country == $key && $selected_state == $state_key ) {
383
							echo ' selected="selected"';
384
						}
385
386
						echo '>' . $value . ' &mdash; ' . ( $escape ? esc_js( $state_value ) : $state_value ) . '</option>';
387
					endforeach;
388
				echo '</optgroup>';
389
			else :
390
				echo '<option';
391
				if ( $selected_country == $key && $selected_state == '*' ) {
392
					echo ' selected="selected"';
393
				}
394
				echo ' value="' . esc_attr( $key ) . '">' . ( $escape ? esc_js( $value ) : $value ) . '</option>';
395
			endif;
396
		endforeach;
397
	}
398
399
	/**
400
	 * Get country address formats.
401
	 * @return array
402
	 */
403
	public function get_address_formats() {
404
		if ( ! $this->address_formats ) :
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->address_formats 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...
405
406
			// Common formats
407
			$postcode_before_city = "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}";
408
409
			// Define address formats
410
			$this->address_formats = apply_filters( 'woocommerce_localisation_address_formats', array(
411
				'default' => "{name}\n{company}\n{address_1}\n{address_2}\n{city}\n{state}\n{postcode}\n{country}",
412
				'AU' => "{name}\n{company}\n{address_1}\n{address_2}\n{city} {state} {postcode}\n{country}",
413
				'AT' => $postcode_before_city,
414
				'BE' => $postcode_before_city,
415
				'CA' => "{company}\n{name}\n{address_1}\n{address_2}\n{city} {state} {postcode}\n{country}",
416
				'CH' => $postcode_before_city,
417
				'CL' => "{company}\n{name}\n{address_1}\n{address_2}\n{state}\n{postcode} {city}\n{country}",
418
				'CN' => "{country} {postcode}\n{state}, {city}, {address_2}, {address_1}\n{company}\n{name}",
419
				'CZ' => $postcode_before_city,
420
				'DE' => $postcode_before_city,
421
				'EE' => $postcode_before_city,
422
				'FI' => $postcode_before_city,
423
				'DK' => $postcode_before_city,
424
				'FR' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city_upper}\n{country}",
425
				'HK' => "{company}\n{first_name} {last_name_upper}\n{address_1}\n{address_2}\n{city_upper}\n{state_upper}\n{country}",
426
				'HU' => "{name}\n{company}\n{city}\n{address_1}\n{address_2}\n{postcode}\n{country}",
427
				'IN' => "{company}\n{name}\n{address_1}\n{address_2}\n{city} - {postcode}\n{state}, {country}",
428
				'IS' => $postcode_before_city,
429
				'IT' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode}\n{city}\n{state_upper}\n{country}",
430
				'JP' => "{postcode}\n{state}{city}{address_1}\n{address_2}\n{company}\n{last_name} {first_name}\n{country}",
431
				'TW' => "{company}\n{last_name} {first_name}\n{address_1}\n{address_2}\n{state}, {city} {postcode}\n{country}",
432
				'LI' => $postcode_before_city,
433
				'NL' => $postcode_before_city,
434
				'NZ' => "{name}\n{company}\n{address_1}\n{address_2}\n{city} {postcode}\n{country}",
435
				'NO' => $postcode_before_city,
436
				'PL' => $postcode_before_city,
437
				'SK' => $postcode_before_city,
438
				'SI' => $postcode_before_city,
439
				'ES' => "{name}\n{company}\n{address_1}\n{address_2}\n{postcode} {city}\n{state}\n{country}",
440
				'SE' => $postcode_before_city,
441
				'TR' => "{name}\n{company}\n{address_1}\n{address_2}\n{postcode} {city} {state}\n{country}",
442
				'US' => "{name}\n{company}\n{address_1}\n{address_2}\n{city}, {state_code} {postcode}\n{country}",
443
				'VN' => "{name}\n{company}\n{address_1}\n{city}\n{country}",
444
			));
445
		endif;
446
447
		return $this->address_formats;
448
	}
449
450
	/**
451
	 * Get country address format.
452
	 * @param  array  $args (default: array())
453
	 * @return string address
454
	 */
455
	public function get_formatted_address( $args = array() ) {
456
		$default_args = array(
457
			'first_name' => '',
458
			'last_name'  => '',
459
			'company'    => '',
460
			'address_1'  => '',
461
			'address_2'  => '',
462
			'city'       => '',
463
			'state'      => '',
464
			'postcode'   => '',
465
			'country'    => ''
466
		);
467
468
		$args = array_map( 'trim', wp_parse_args( $args, $default_args ) );
469
470
		extract( $args );
471
472
		// Get all formats
473
		$formats = $this->get_address_formats();
474
475
		// Get format for the address' country
476
		$format = ( $country && isset( $formats[ $country ] ) ) ? $formats[ $country ] : $formats['default'];
477
478
		// Handle full country name
479
		$full_country = ( isset( $this->countries[ $country ] ) ) ? $this->countries[ $country ] : $country;
480
481
		// Country is not needed if the same as base
482
		if ( $country == $this->get_base_country() && ! apply_filters( 'woocommerce_formatted_address_force_country_display', false ) ) {
483
			$format = str_replace( '{country}', '', $format );
484
		}
485
486
		// Handle full state name
487
		$full_state = ( $country && $state && isset( $this->states[ $country ][ $state ] ) ) ? $this->states[ $country ][ $state ] : $state;
488
489
		// Substitute address parts into the string
490
		$replace = array_map( 'esc_html', apply_filters( 'woocommerce_formatted_address_replacements', array(
491
			'{first_name}'       => $first_name,
492
			'{last_name}'        => $last_name,
493
			'{name}'             => $first_name . ' ' . $last_name,
494
			'{company}'          => $company,
495
			'{address_1}'        => $address_1,
496
			'{address_2}'        => $address_2,
497
			'{city}'             => $city,
498
			'{state}'            => $full_state,
499
			'{postcode}'         => $postcode,
500
			'{country}'          => $full_country,
501
			'{first_name_upper}' => strtoupper( $first_name ),
502
			'{last_name_upper}'  => strtoupper( $last_name ),
503
			'{name_upper}'       => strtoupper( $first_name . ' ' . $last_name ),
504
			'{company_upper}'    => strtoupper( $company ),
505
			'{address_1_upper}'  => strtoupper( $address_1 ),
506
			'{address_2_upper}'  => strtoupper( $address_2 ),
507
			'{city_upper}'       => strtoupper( $city ),
508
			'{state_upper}'      => strtoupper( $full_state ),
509
			'{state_code}'       => strtoupper( $state ),
510
			'{postcode_upper}'   => strtoupper( $postcode ),
511
			'{country_upper}'    => strtoupper( $full_country ),
512
		), $args ) );
513
514
		$formatted_address = str_replace( array_keys( $replace ), $replace, $format );
515
516
		// Clean up white space
517
		$formatted_address = preg_replace( '/  +/', ' ', trim( $formatted_address ) );
518
		$formatted_address = preg_replace( '/\n\n+/', "\n", $formatted_address );
519
520
		// Break newlines apart and remove empty lines/trim commas and white space
521
		$formatted_address = array_filter( array_map( array( $this, 'trim_formatted_address_line' ), explode( "\n", $formatted_address ) ) );
522
523
		// Add html breaks
524
		$formatted_address = implode( '<br/>', $formatted_address );
525
526
		// We're done!
527
		return $formatted_address;
528
	}
529
530
	/**
531
	 * Trim white space and commas off a line.
532
	 * @param  string $line
533
	 * @return string
534
	 */
535
	private function trim_formatted_address_line( $line ) {
536
		return trim( $line, ", " );
537
	}
538
539
	/**
540
	 * Returns the fields we show by default. This can be filtered later on.
541
	 * @return array
542
	 */
543
	public function get_default_address_fields() {
544
		$fields = array(
545
			'first_name' => array(
546
				'label'        => __( 'First Name', 'woocommerce' ),
547
				'required'     => true,
548
				'class'        => array( 'form-row-first' ),
549
				'autocomplete' => 'given-name',
550
			),
551
			'last_name' => array(
552
				'label'        => __( 'Last Name', 'woocommerce' ),
553
				'required'     => true,
554
				'class'        => array( 'form-row-last' ),
555
				'clear'        => true,
556
				'autocomplete' => 'family-name',
557
			),
558
			'company' => array(
559
				'label'        => __( 'Company Name', 'woocommerce' ),
560
				'class'        => array( 'form-row-wide' ),
561
				'autocomplete' => 'organization',
562
			),
563
			'country' => array(
564
				'type'         => 'country',
565
				'label'        => __( 'Country', 'woocommerce' ),
566
				'required'     => true,
567
				'class'        => array( 'form-row-wide', 'address-field', 'update_totals_on_change' ),
568
				'autocomplete' => 'country',
569
			),
570
			'address_1' => array(
571
				'label'        => __( 'Address', 'woocommerce' ),
572
				'placeholder'  => _x( 'Street address', 'placeholder', 'woocommerce' ),
573
				'required'     => true,
574
				'class'        => array( 'form-row-wide', 'address-field' ),
575
				'autocomplete' => 'address-line1',
576
			),
577
			'address_2' => array(
578
				'placeholder'  => _x( 'Apartment, suite, unit etc. (optional)', 'placeholder', 'woocommerce' ),
579
				'class'        => array( 'form-row-wide', 'address-field' ),
580
				'required'     => false,
581
				'autocomplete' => 'address-line2',
582
			),
583
			'city' => array(
584
				'label'        => __( 'Town / City', 'woocommerce' ),
585
				'required'     => true,
586
				'class'        => array( 'form-row-wide', 'address-field' ),
587
				'autocomplete' => 'address-level2',
588
			),
589
			'state' => array(
590
				'type'         => 'state',
591
				'label'        => __( 'State / County', 'woocommerce' ),
592
				'required'     => true,
593
				'class'        => array( 'form-row-first', 'address-field' ),
594
				'validate'     => array( 'state' ),
595
				'autocomplete' => 'address-level1',
596
			),
597
			'postcode' => array(
598
				'label'        => __( 'Postcode / ZIP', 'woocommerce' ),
599
				'required'     => true,
600
				'class'        => array( 'form-row-last', 'address-field' ),
601
				'clear'        => true,
602
				'validate'     => array( 'postcode' ),
603
				'autocomplete' => 'postal-code',
604
			),
605
		);
606
607
		return apply_filters( 'woocommerce_default_address_fields', $fields );
608
	}
609
610
	/**
611
	 * Get JS selectors for fields which are shown/hidden depending on the locale.
612
	 * @return array
613
	 */
614
	public function get_country_locale_field_selectors() {
615
		$locale_fields = array (
616
			'address_1' => '#billing_address_1_field, #shipping_address_1_field',
617
			'address_2' => '#billing_address_2_field, #shipping_address_2_field',
618
			'state'     => '#billing_state_field, #shipping_state_field, #calc_shipping_state_field',
619
			'postcode'  => '#billing_postcode_field, #shipping_postcode_field, #calc_shipping_postcode_field',
620
			'city'      => '#billing_city_field, #shipping_city_field, #calc_shipping_city_field',
621
		);
622
		return apply_filters( 'woocommerce_country_locale_field_selectors', $locale_fields );
623
	}
624
625
	/**
626
	 * Get country locale settings.
627
	 * @return array
628
	 * @todo  [2.4] Check select2 4.0.0 compatibility with `placeholder` attribute and uncomment relevant lines. https://github.com/woothemes/woocommerce/issues/7729
629
	 */
630
	public function get_country_locale() {
631
		if ( ! $this->locale ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->locale 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...
632
633
			// Locale information used by the checkout
634
			$this->locale = apply_filters( 'woocommerce_get_country_locale', array(
635
				'AE' => array(
636
					'postcode' => array(
637
						'required' => false,
638
						'hidden'   => true
639
					),
640
				),
641
				'AF' => array(
642
					'state' => array(
643
						'required' => false,
644
					),
645
				),
646
				'AT' => array(
647
					'postcode_before_city' => true,
648
					'state' => array(
649
						'required' => false
650
					)
651
				),
652
				'AU' => array(
653
					'city'      => array(
654
						'label'       => __( 'Suburb', 'woocommerce' ),
655
					),
656
					'postcode'  => array(
657
						'label'       => __( 'Postcode', 'woocommerce' ),
658
					),
659
					'state'     => array(
660
						'label'       => __( 'State', 'woocommerce' ),
661
					)
662
				),
663
				'AX' => array(
664
					'postcode_before_city' => true,
665
					'state' => array(
666
						'required' => false,
667
					),
668
				),
669
				'BD' => array(
670
					'postcode' => array(
671
						'required' => false
672
					),
673
					'state' => array(
674
						'label'       => __( 'District', 'woocommerce' ),
675
					)
676
				),
677
				'BE' => array(
678
					'postcode_before_city' => true,
679
					'state' => array(
680
						'required'    => false,
681
						'label'       => __( 'Province', 'woocommerce' ),
682
					),
683
				),
684
				'BI' => array(
685
					'state' => array(
686
						'required' => false,
687
					),
688
				),
689
				'BO' => array(
690
					'postcode' => array(
691
						'required' => false,
692
						'hidden'   => true
693
					),
694
				),
695
				'BS' => array(
696
					'postcode' => array(
697
						'required' => false,
698
						'hidden'   => true
699
					),
700
				),
701
				'CA' => array(
702
					'state' => array(
703
						'label'       => __( 'Province', 'woocommerce' ),
704
					)
705
				),
706
				'CH' => array(
707
					'postcode_before_city' => true,
708
					'state' => array(
709
						'label'       => __( 'Canton', 'woocommerce' ),
710
						'required'    => false
711
					)
712
				),
713
				'CL' => array(
714
					'city'      => array(
715
						'required' 	=> true,
716
					),
717
					'postcode'  => array(
718
						'required' => false
719
					),
720
					'state'     => array(
721
						'label'       => __( 'Region', 'woocommerce' ),
722
					)
723
				),
724
				'CN' => array(
725
					'state' => array(
726
						'label'       => __( 'Province', 'woocommerce' ),
727
					)
728
				),
729
				'CO' => array(
730
					'postcode' => array(
731
						'required' => false
732
					)
733
				),
734
				'CZ' => array(
735
					'state' => array(
736
						'required' => false
737
					)
738
				),
739
				'DE' => array(
740
					'postcode_before_city' => true,
741
					'state' => array(
742
						'required' => false
743
					)
744
				),
745
				'DK' => array(
746
					'postcode_before_city' => true,
747
					'state' => array(
748
						'required' => false
749
					)
750
				),
751
				'EE' => array(
752
					'postcode_before_city' => true,
753
					'state' => array(
754
						'required' => false
755
					)
756
				),
757
				'FI' => array(
758
					'postcode_before_city' => true,
759
					'state' => array(
760
						'required' => false
761
					)
762
				),
763
				'FR' => array(
764
					'postcode_before_city' => true,
765
					'state' => array(
766
						'required' => false
767
					)
768
				),
769
				'HK' => array(
770
					'postcode' => array(
771
						'required' => false
772
					),
773
					'city'  => array(
774
						'label'       => __( 'Town / District', 'woocommerce' ),
775
					),
776
					'state' => array(
777
						'label'       => __( 'Region', 'woocommerce' ),
778
					)
779
				),
780
				'HU' => array(
781
					'state' => array(
782
						'label'       => __( 'County', 'woocommerce' ),
783
					)
784
				),
785
				'ID' => array(
786
					'state' => array(
787
						'label'       => __( 'Province', 'woocommerce' ),
788
					)
789
				),
790
				'IE' => array(
791
					'postcode' => array(
792
						'required' => false,
793
						'label'    => __( 'Postcode', 'woocommerce' ),
794
					),
795
				),
796
				'IS' => array(
797
					'postcode_before_city' => true,
798
					'state' => array(
799
						'required' => false
800
					)
801
				),
802
				'IL' => array(
803
					'postcode_before_city' => true,
804
					'state' => array(
805
						'required' => false
806
					)
807
				),
808
				'IT' => array(
809
					'postcode_before_city' => true,
810
					'state' => array(
811
						'required'    => true,
812
						'label'       => __( 'Province', 'woocommerce' ),
813
					)
814
				),
815
				'JP' => array(
816
					'state' => array(
817
						'label' => __( 'Prefecture', 'woocommerce' )
818
					)
819
				),
820
				'KR' => array(
821
					'state' => array(
822
						'required' => false
823
					)
824
				),
825
				'NL' => array(
826
					'postcode_before_city' => true,
827
					'state' => array(
828
						'required'    => false,
829
						'label'       => __( 'Province', 'woocommerce' ),
830
					)
831
				),
832
				'NZ' => array(
833
					'postcode' => array(
834
						'label' => __( 'Postcode', 'woocommerce' )
835
					),
836
					'state' => array(
837
						'required' => false,
838
						'label'    => __( 'Region', 'woocommerce' )
839
					)
840
				),
841
				'NO' => array(
842
					'postcode_before_city' => true,
843
					'state' => array(
844
						'required' => false
845
					)
846
				),
847
				'NP' => array(
848
					'state' => array(
849
						'label'       => __( 'State / Zone', 'woocommerce' ),
850
					),
851
					'postcode' => array(
852
						'required' => false
853
					)
854
				),
855
				'PL' => array(
856
					'postcode_before_city' => true,
857
					'state' => array(
858
						'required' => false
859
					)
860
				),
861
				'PT' => array(
862
					'state' => array(
863
						'required' => false
864
					)
865
				),
866
				'RO' => array(
867
					'state' => array(
868
						'required' => false
869
					)
870
				),
871
				'SG' => array(
872
					'state' => array(
873
						'required' => false
874
					)
875
				),
876
				'SK' => array(
877
					'postcode_before_city' => true,
878
					'state' => array(
879
						'required' => false
880
					)
881
				),
882
				'SI' => array(
883
					'postcode_before_city' => true,
884
					'state' => array(
885
						'required' => false
886
					)
887
				),
888
				'ES' => array(
889
					'postcode_before_city' => true,
890
					'state' => array(
891
						'label'       => __( 'Province', 'woocommerce' ),
892
					)
893
				),
894
				'LI' => array(
895
					'postcode_before_city' => true,
896
					'state' => array(
897
						'label'       => __( 'Municipality', 'woocommerce' ),
898
						'required'    => false
899
					)
900
				),
901
				'LK' => array(
902
					'state' => array(
903
						'required' => false
904
					)
905
				),
906
				'SE' => array(
907
					'postcode_before_city' => true,
908
					'state' => array(
909
						'required' => false
910
					)
911
				),
912
				'TR' => array(
913
					'postcode_before_city' => true,
914
					'state' => array(
915
						'label'       => __( 'Province', 'woocommerce' ),
916
					)
917
				),
918
				'US' => array(
919
					'postcode'  => array(
920
						'label'       => __( 'ZIP', 'woocommerce' ),
921
					),
922
					'state'     => array(
923
						'label'       => __( 'State', 'woocommerce' ),
924
					)
925
				),
926
				'GB' => array(
927
					'postcode'  => array(
928
						'label'       => __( 'Postcode', 'woocommerce' ),
929
					),
930
					'state'     => array(
931
						'label'       => __( 'County', 'woocommerce' ),
932
						'required'    => false
933
					)
934
				),
935
				'VN' => array(
936
					'postcode_before_city' => true,
937
					'state' => array(
938
						'required' => false
939
					),
940
					'postcode' => array(
941
						'required' => false,
942
						'hidden'   => false
943
					),
944
					'address_2' => array(
945
						'required' => false,
946
						'hidden'   => true
947
					)
948
				),
949
				'WS' => array(
950
					'postcode' => array(
951
						'required' => false,
952
						'hidden'   => true
953
					),
954
				),
955
				'ZA' => array(
956
					'state' => array(
957
						'label'       => __( 'Province', 'woocommerce' ),
958
					)
959
				),
960
				'ZW' => array(
961
					'postcode' => array(
962
						'required' => false,
963
						'hidden'   => true
964
					),
965
				),
966
			));
967
968
			$this->locale = array_intersect_key( $this->locale, array_merge( $this->get_allowed_countries(), $this->get_shipping_countries() ) );
969
970
			// Default Locale Can be filtered to override fields in get_address_fields().
971
			// Countries with no specific locale will use default.
972
			$this->locale['default'] = apply_filters('woocommerce_get_country_locale_default', $this->get_default_address_fields() );
973
974
			// Filter default AND shop base locales to allow overides via a single function. These will be used when changing countries on the checkout
975
			if ( ! isset( $this->locale[ $this->get_base_country() ] ) ) {
976
				$this->locale[ $this->get_base_country() ] = $this->locale['default'];
977
			}
978
979
			$this->locale['default']                   = apply_filters( 'woocommerce_get_country_locale_base', $this->locale['default'] );
980
			$this->locale[ $this->get_base_country() ] = apply_filters( 'woocommerce_get_country_locale_base', $this->locale[ $this->get_base_country() ] );
981
		}
982
983
		return $this->locale;
984
	}
985
986
	/**
987
	 * Apply locale and get address fields.
988
	 * @param  mixed  $country (default: '')
989
	 * @param  string $type (default: 'billing_')
990
	 * @return array
991
	 */
992
	public function get_address_fields( $country = '', $type = 'billing_' ) {
993
		if ( ! $country ) {
994
			$country = $this->get_base_country();
995
		}
996
997
		$fields = $this->get_default_address_fields();
998
		$locale = $this->get_country_locale();
999
1000
		if ( isset( $locale[ $country ] ) ) {
1001
			$fields = wc_array_overlay( $fields, $locale[ $country ] );
1002
		}
1003
1004
		// Prepend field keys
1005
		$address_fields = array();
1006
1007
		foreach ( $fields as $key => $value ) {
1008
			$keys = array_keys( $fields );
1009
			$address_fields[ $type . $key ] = $value;
1010
1011
			// Add email and phone after company or last
1012
			if ( 'billing_' === $type && ( 'company' === $key || ( ! array_key_exists( 'company', $fields ) && $key === end( $keys ) ) ) ) {
1013
				$address_fields['billing_email'] = array(
1014
					'label'        => __( 'Email Address', 'woocommerce' ),
1015
					'required'     => true,
1016
					'type'         => 'email',
1017
					'class'        => array( 'form-row-first' ),
1018
					'validate'     => array( 'email' ),
1019
					'autocomplete' => 'email',
1020
				);
1021
				$address_fields['billing_phone'] = array(
1022
					'label'        => __( 'Phone', 'woocommerce' ),
1023
					'required'     => true,
1024
					'type'         => 'tel',
1025
					'class'        => array( 'form-row-last' ),
1026
					'clear'        => true,
1027
					'validate'     => array( 'phone' ),
1028
					'autocomplete' => 'tel',
1029
				);
1030
			}
1031
		}
1032
1033
		$address_fields = apply_filters( 'woocommerce_' . $type . 'fields', $address_fields, $country );
1034
1035
		return $address_fields;
1036
	}
1037
}
1038