woocommerce/includes/class-wc-countries.php

1284 lines
36 KiB
PHP
Raw Normal View History

2011-08-09 15:16:18 +00:00
<?php
2017-12-21 20:10:55 +00:00
/**
* WooCommerce countries
*
* @package WooCommerce\l10n
* @version 3.3.0
2017-12-21 20:10:55 +00:00
*/
2015-11-06 09:22:19 +00:00
defined( 'ABSPATH' ) || exit;
2015-11-06 09:22:19 +00:00
2011-08-09 15:16:18 +00:00
/**
2011-08-10 17:11:11 +00:00
* The WooCommerce countries class stores country/state data.
2011-08-09 15:16:18 +00:00
*/
2012-01-27 16:38:39 +00:00
class WC_Countries {
2012-08-06 22:43:39 +00:00
2017-12-21 20:10:55 +00:00
/**
* Locales list.
*
* @var array
*/
public $locale = array();
2012-08-14 19:42:38 +00:00
2017-12-21 20:10:55 +00:00
/**
* List of address formats for locales.
*
* @var array
*/
public $address_formats = array();
2012-08-06 22:43:39 +00:00
/**
* Auto-load in-accessible properties on demand.
2017-12-21 20:10:55 +00:00
*
* @param mixed $key Key.
* @return mixed
*/
public function __get( $key ) {
2017-12-21 20:10:55 +00:00
if ( 'countries' === $key ) {
return $this->get_countries();
2017-12-21 20:10:55 +00:00
} elseif ( 'states' === $key ) {
return $this->get_states();
}
}
/**
2015-01-18 18:59:17 +00:00
* Get all countries.
2017-12-21 20:10:55 +00:00
*
* @return array
*/
public function get_countries() {
if ( empty( $this->countries ) ) {
$this->countries = apply_filters( 'woocommerce_countries', include WC()->plugin_path() . '/i18n/countries.php' );
2015-01-18 18:59:17 +00:00
if ( apply_filters( 'woocommerce_sort_countries', true ) ) {
asort( $this->countries );
}
}
2017-12-21 20:10:55 +00:00
return $this->countries;
}
2012-08-06 22:43:39 +00:00
2015-12-08 11:15:02 +00:00
/**
* Get all continents.
2017-12-21 20:10:55 +00:00
*
2015-12-08 11:15:02 +00:00
* @return array
*/
public function get_continents() {
if ( empty( $this->continents ) ) {
$this->continents = apply_filters( 'woocommerce_continents', include WC()->plugin_path() . '/i18n/continents.php' );
2015-12-08 11:15:02 +00:00
}
2017-12-21 20:10:55 +00:00
2015-12-08 11:15:02 +00:00
return $this->continents;
}
2015-12-15 12:39:52 +00:00
/**
* Get continent code for a country code.
2017-12-21 20:10:55 +00:00
*
2015-12-15 12:39:52 +00:00
* @since 2.6.0
2017-12-21 20:10:55 +00:00
* @param string $cc Continent code.
2015-12-15 12:39:52 +00:00
* @return string
*/
public function get_continent_code_for_country( $cc ) {
2015-12-15 15:00:45 +00:00
$cc = trim( strtoupper( $cc ) );
2015-12-15 12:39:52 +00:00
$continents = $this->get_continents();
$continents_and_ccs = wp_list_pluck( $continents, 'countries' );
2015-12-15 15:00:45 +00:00
foreach ( $continents_and_ccs as $continent_code => $countries ) {
if ( false !== array_search( $cc, $countries, true ) ) {
2015-12-15 15:00:45 +00:00
return $continent_code;
}
}
2017-12-21 20:10:55 +00:00
2015-12-15 15:00:45 +00:00
return '';
2015-12-15 12:39:52 +00:00
}
/**
2015-01-18 18:59:17 +00:00
* Load the states.
*/
public function load_country_states() {
global $states;
2012-08-06 22:43:39 +00:00
// States set to array() are blank i.e. the country has no use for the state field.
$states = array(
2012-07-26 16:29:49 +00:00
'AF' => array(),
'AT' => array(),
2015-07-17 19:29:21 +00:00
'AX' => array(),
2012-02-28 10:12:13 +00:00
'BE' => array(),
'BH' => array(),
2012-07-26 16:29:49 +00:00
'BI' => array(),
'CZ' => array(),
'DE' => array(),
'DK' => array(),
2013-09-10 12:41:40 +00:00
'EE' => array(),
'FI' => array(),
'FR' => array(),
'GP' => array(),
'GF' => array(),
'IS' => array(),
'IL' => array(),
2018-02-12 10:34:40 +00:00
'IM' => array(),
2013-01-20 12:50:39 +00:00
'KR' => array(),
'KW' => array(),
'LB' => array(),
'LU' => array(),
'MQ' => array(),
2018-06-11 15:23:27 +00:00
'MT' => array(),
'NL' => array(),
'NO' => array(),
'PL' => array(),
'PT' => array(),
'RE' => array(),
'SG' => array(),
'SK' => array(),
'SI' => array(),
'LK' => array(),
'SE' => array(),
'VN' => array(),
'YT' => array(),
);
2015-01-18 18:59:17 +00:00
// Load only the state files the shop owner wants/needs.
$allowed = array_merge( $this->get_allowed_countries(), $this->get_shipping_countries() );
2016-06-06 18:39:23 +00:00
if ( ! empty( $allowed ) ) {
foreach ( $allowed as $code => $country ) {
if ( ! isset( $states[ $code ] ) && file_exists( WC()->plugin_path() . '/i18n/states/' . $code . '.php' ) ) {
include WC()->plugin_path() . '/i18n/states/' . $code . '.php';
}
}
}
$this->states = apply_filters( 'woocommerce_states', $states );
}
/**
* Get the states for a country.
2017-12-21 20:10:55 +00:00
*
* @param string $cc Country code.
* @return false|array of states
*/
2014-05-30 12:33:09 +00:00
public function get_states( $cc = null ) {
if ( empty( $this->states ) ) {
$this->load_country_states();
}
2015-01-18 18:59:17 +00:00
2014-05-30 12:33:09 +00:00
if ( ! is_null( $cc ) ) {
return isset( $this->states[ $cc ] ) ? $this->states[ $cc ] : false;
} else {
return $this->states;
}
}
/**
* Get the base address (first line) for the store.
2017-12-21 20:10:55 +00:00
*
* @since 3.1.1
* @return string
*/
public function get_base_address() {
$base_address = get_option( 'woocommerce_store_address', '' );
return apply_filters( 'woocommerce_countries_base_address', $base_address );
}
/**
* Get the base address (second line) for the store.
2017-12-21 20:10:55 +00:00
*
* @since 3.1.1
* @return string
*/
public function get_base_address_2() {
$base_address_2 = get_option( 'woocommerce_store_address_2', '' );
return apply_filters( 'woocommerce_countries_base_address_2', $base_address_2 );
}
2012-08-14 19:42:38 +00:00
/**
* Get the base country for the store.
2017-12-21 20:10:55 +00:00
*
2012-08-14 19:42:38 +00:00
* @return string
*/
public function get_base_country() {
2014-12-23 17:34:05 +00:00
$default = wc_get_base_location();
return apply_filters( 'woocommerce_countries_base_country', $default['country'] );
}
2012-08-14 19:42:38 +00:00
/**
* Get the base state for the store.
2017-12-21 20:10:55 +00:00
*
2012-08-14 19:42:38 +00:00
* @return string
*/
public function get_base_state() {
2014-12-23 17:34:05 +00:00
$default = wc_get_base_location();
return apply_filters( 'woocommerce_countries_base_state', $default['state'] );
}
/**
* Get the base city for the store.
2017-12-21 20:10:55 +00:00
*
* @version 3.1.1
* @return string
*/
public function get_base_city() {
$base_city = get_option( 'woocommerce_store_city', '' );
return apply_filters( 'woocommerce_countries_base_city', $base_city );
}
/**
* Get the base postcode for the store.
2017-12-21 20:10:55 +00:00
*
* @since 3.1.1
* @return string
*/
public function get_base_postcode() {
$base_postcode = get_option( 'woocommerce_store_postcode', '' );
return apply_filters( 'woocommerce_countries_base_postcode', $base_postcode );
2011-08-09 15:16:18 +00:00
}
2012-08-14 19:42:38 +00:00
/**
* Get the allowed countries for the store.
2017-12-21 20:10:55 +00:00
*
2012-08-14 19:42:38 +00:00
* @return array
*/
public function get_allowed_countries() {
2016-04-28 16:37:30 +00:00
if ( 'all' === get_option( 'woocommerce_allowed_countries' ) ) {
2017-09-06 09:40:40 +00:00
return apply_filters( 'woocommerce_countries_allowed_countries', $this->countries );
2016-04-28 16:37:30 +00:00
}
if ( 'all_except' === get_option( 'woocommerce_allowed_countries' ) ) {
$except_countries = get_option( 'woocommerce_all_except_countries', array() );
if ( ! $except_countries ) {
return $this->countries;
} else {
$all_except_countries = $this->countries;
foreach ( $except_countries as $country ) {
unset( $all_except_countries[ $country ] );
}
return apply_filters( 'woocommerce_countries_allowed_countries', $all_except_countries );
}
}
2011-08-09 15:16:18 +00:00
$countries = array();
2012-08-06 22:43:39 +00:00
$raw_countries = get_option( 'woocommerce_specific_allowed_countries', array() );
2012-08-06 22:43:39 +00:00
if ( $raw_countries ) {
foreach ( $raw_countries as $country ) {
$countries[ $country ] = $this->countries[ $country ];
}
2015-01-18 18:59:17 +00:00
}
2012-08-06 22:43:39 +00:00
return apply_filters( 'woocommerce_countries_allowed_countries', $countries );
2011-08-09 15:16:18 +00:00
}
2012-11-27 16:22:47 +00:00
/**
* Get the countries you ship to.
2017-12-21 20:10:55 +00:00
*
* @return array
*/
public function get_shipping_countries() {
if ( '' === get_option( 'woocommerce_ship_to_countries' ) ) {
2016-04-28 16:37:30 +00:00
return $this->get_allowed_countries();
2015-01-18 18:59:17 +00:00
}
2016-04-28 16:37:30 +00:00
if ( 'all' === get_option( 'woocommerce_ship_to_countries' ) ) {
return $this->countries;
2015-01-18 18:59:17 +00:00
}
$countries = array();
$raw_countries = get_option( 'woocommerce_specific_ship_to_countries' );
if ( $raw_countries ) {
foreach ( $raw_countries as $country ) {
$countries[ $country ] = $this->countries[ $country ];
}
2015-01-18 18:59:17 +00:00
}
return apply_filters( 'woocommerce_countries_shipping_countries', $countries );
}
2012-11-27 16:22:47 +00:00
/**
* Get allowed country states.
2017-12-21 20:10:55 +00:00
*
* @return array
*/
public function get_allowed_country_states() {
2015-01-18 18:59:17 +00:00
if ( get_option( 'woocommerce_allowed_countries' ) !== 'specific' ) {
return $this->states;
2015-01-18 18:59:17 +00:00
}
$states = array();
$raw_countries = get_option( 'woocommerce_specific_allowed_countries' );
if ( $raw_countries ) {
foreach ( $raw_countries as $country ) {
if ( isset( $this->states[ $country ] ) ) {
$states[ $country ] = $this->states[ $country ];
}
2015-01-18 18:59:17 +00:00
}
}
return apply_filters( 'woocommerce_countries_allowed_country_states', $states );
}
2012-08-06 22:43:39 +00:00
/**
* Get shipping country states.
2017-12-21 20:10:55 +00:00
*
* @return array
*/
public function get_shipping_country_states() {
2017-12-21 20:10:55 +00:00
if ( get_option( 'woocommerce_ship_to_countries' ) === '' ) {
return $this->get_allowed_country_states();
2015-01-18 18:59:17 +00:00
}
2015-01-18 18:59:17 +00:00
if ( get_option( 'woocommerce_ship_to_countries' ) !== 'specific' ) {
return $this->states;
2015-01-18 18:59:17 +00:00
}
$states = array();
$raw_countries = get_option( 'woocommerce_specific_ship_to_countries' );
if ( $raw_countries ) {
foreach ( $raw_countries as $country ) {
if ( ! empty( $this->states[ $country ] ) ) {
$states[ $country ] = $this->states[ $country ];
}
2015-01-18 18:59:17 +00:00
}
}
return apply_filters( 'woocommerce_countries_shipping_country_states', $states );
}
2012-08-14 19:42:38 +00:00
/**
* Gets an array of countries in the EU.
*
* MC (monaco) and IM (isle of man, part of UK) also use VAT.
*
* @param string $type Type of countries to retrieve. Blank for EU member countries. eu_vat for EU VAT countries.
2014-09-07 23:37:55 +00:00
* @return string[]
2012-08-14 19:42:38 +00:00
*/
public function get_european_union_countries( $type = '' ) {
$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' );
if ( 'eu_vat' === $type ) {
$countries[] = 'MC';
$countries[] = 'IM';
}
return $countries;
2011-10-31 10:54:49 +00:00
}
2012-08-06 22:43:39 +00:00
2012-08-14 19:42:38 +00:00
/**
2017-12-21 20:10:55 +00:00
* Gets the correct string for shipping - either 'to the' or 'to'.
*
2017-12-21 20:10:55 +00:00
* @param string $country_code Country code.
2012-08-14 19:42:38 +00:00
* @return string
*/
public function shipping_to_prefix( $country_code = '' ) {
$country_code = $country_code ? $country_code : WC()->customer->get_shipping_country();
$countries = array( 'GB', 'US', 'AE', 'CZ', 'DO', 'NL', 'PH', 'USAF' );
$return = in_array( $country_code, $countries, true ) ? __( 'to the', 'woocommerce' ) : __( 'to', 'woocommerce' );
2014-11-20 00:43:09 +00:00
return apply_filters( 'woocommerce_countries_shipping_to_prefix', $return, $country_code );
2011-08-09 15:16:18 +00:00
}
2012-08-06 22:43:39 +00:00
2012-08-14 19:42:38 +00:00
/**
2017-12-21 20:10:55 +00:00
* Prefix certain countries with 'the'.
*
2017-12-21 20:10:55 +00:00
* @param string $country_code Country code.
2012-08-14 19:42:38 +00:00
* @return string
*/
public function estimated_for_prefix( $country_code = '' ) {
$country_code = $country_code ? $country_code : $this->get_base_country();
$countries = array( 'GB', 'US', 'AE', 'CZ', 'DO', 'NL', 'PH', 'USAF' );
$return = in_array( $country_code, $countries, true ) ? __( 'the', 'woocommerce' ) . ' ' : '';
2012-08-06 22:43:39 +00:00
return apply_filters( 'woocommerce_countries_estimated_for_prefix', $return, $country_code );
2015-01-18 18:59:17 +00:00
}
2012-08-14 19:42:38 +00:00
/**
2015-01-18 18:59:17 +00:00
* Correctly name tax in some countries VAT on the frontend.
2017-12-21 20:10:55 +00:00
*
2012-08-14 19:42:38 +00:00
* @return string
*/
public function tax_or_vat() {
$return = in_array( $this->get_base_country(), array_merge( $this->get_european_union_countries( 'eu_vat' ), array( 'NO' ) ), true ) ? __( 'VAT', 'woocommerce' ) : __( 'Tax', 'woocommerce' );
2012-08-06 22:43:39 +00:00
2012-08-14 19:42:38 +00:00
return apply_filters( 'woocommerce_countries_tax_or_vat', $return );
2011-10-31 10:54:49 +00:00
}
2012-08-06 22:43:39 +00:00
2012-08-14 19:42:38 +00:00
/**
* Include the Inc Tax label.
2017-12-21 20:10:55 +00:00
*
2012-08-14 19:42:38 +00:00
* @return string
*/
public function inc_tax_or_vat() {
$return = in_array( $this->get_base_country(), array_merge( $this->get_european_union_countries( 'eu_vat' ), array( 'NO' ) ), true ) ? __( '(incl. VAT)', 'woocommerce' ) : __( '(incl. tax)', 'woocommerce' );
2012-08-06 22:43:39 +00:00
2012-08-14 19:42:38 +00:00
return apply_filters( 'woocommerce_countries_inc_tax_or_vat', $return );
2011-10-31 10:54:49 +00:00
}
2012-08-06 22:43:39 +00:00
2012-08-14 19:42:38 +00:00
/**
* Include the Ex Tax label.
2017-12-21 20:10:55 +00:00
*
2012-08-14 19:42:38 +00:00
* @return string
*/
public function ex_tax_or_vat() {
$return = in_array( $this->get_base_country(), array_merge( $this->get_european_union_countries( 'eu_vat' ), array( 'NO' ) ), true ) ? __( '(ex. VAT)', 'woocommerce' ) : __( '(ex. tax)', 'woocommerce' );
2012-08-06 22:43:39 +00:00
2012-08-14 19:42:38 +00:00
return apply_filters( 'woocommerce_countries_ex_tax_or_vat', $return );
2011-08-09 15:16:18 +00:00
}
2012-08-06 22:43:39 +00:00
2012-08-14 19:42:38 +00:00
/**
* Outputs the list of countries and states for use in dropdown boxes.
2017-12-21 20:10:55 +00:00
*
* @param string $selected_country Selected country.
* @param string $selected_state Selected state.
* @param bool $escape If should escape HTML.
2012-08-14 19:42:38 +00:00
*/
public function country_dropdown_options( $selected_country = '', $selected_state = '', $escape = false ) {
2017-12-21 20:10:55 +00:00
if ( $this->countries ) {
foreach ( $this->countries as $key => $value ) {
$states = $this->get_states( $key );
if ( $states ) {
echo '<optgroup label="' . esc_attr( $value ) . '">';
2017-12-21 20:10:55 +00:00
foreach ( $states as $state_key => $state_value ) {
echo '<option value="' . esc_attr( $key ) . ':' . esc_attr( $state_key ) . '"';
2017-08-08 16:32:21 +00:00
if ( $selected_country === $key && $selected_state === $state_key ) {
echo ' selected="selected"';
2017-08-08 16:32:21 +00:00
}
2017-12-21 20:10:55 +00:00
echo '>' . esc_html( $value ) . ' &mdash; ' . ( $escape ? esc_js( $state_value ) : $state_value ) . '</option>'; // WPCS: XSS ok.
}
echo '</optgroup>';
2017-12-21 20:10:55 +00:00
} else {
echo '<option';
2017-08-08 16:32:21 +00:00
if ( $selected_country === $key && '*' === $selected_state ) {
echo ' selected="selected"';
}
2017-12-21 20:10:55 +00:00
echo ' value="' . esc_attr( $key ) . '">' . ( $escape ? esc_js( $value ) : $value ) . '</option>'; // WPCS: XSS ok.
}
}
}
2011-08-09 15:16:18 +00:00
}
2012-08-06 22:43:39 +00:00
2012-08-14 19:42:38 +00:00
/**
2015-11-03 13:31:20 +00:00
* Get country address formats.
*
* These define how addresses are formatted for display in various countries.
*
2012-08-14 19:42:38 +00:00
* @return array
*/
public function get_address_formats() {
2016-06-06 18:39:23 +00:00
if ( empty( $this->address_formats ) ) {
$this->address_formats = apply_filters(
'woocommerce_localisation_address_formats', array(
'default' => "{name}\n{company}\n{address_1}\n{address_2}\n{city}\n{state}\n{postcode}\n{country}",
'AU' => "{name}\n{company}\n{address_1}\n{address_2}\n{city} {state} {postcode}\n{country}",
'AT' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'BE' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'CA' => "{company}\n{name}\n{address_1}\n{address_2}\n{city} {state} {postcode}\n{country}",
'CH' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'CL' => "{company}\n{name}\n{address_1}\n{address_2}\n{state}\n{postcode} {city}\n{country}",
'CN' => "{country} {postcode}\n{state}, {city}, {address_2}, {address_1}\n{company}\n{name}",
'CZ' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'DE' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'EE' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'FI' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'DK' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'FR' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city_upper}\n{country}",
'HK' => "{company}\n{first_name} {last_name_upper}\n{address_1}\n{address_2}\n{city_upper}\n{state_upper}\n{country}",
'HU' => "{name}\n{company}\n{city}\n{address_1}\n{address_2}\n{postcode}\n{country}",
'IN' => "{company}\n{name}\n{address_1}\n{address_2}\n{city} - {postcode}\n{state}, {country}",
'IS' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'IT' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode}\n{city}\n{state_upper}\n{country}",
'JP' => "{postcode}\n{state} {city} {address_1}\n{address_2}\n{company}\n{last_name} {first_name}\n{country}",
'TW' => "{company}\n{last_name} {first_name}\n{address_1}\n{address_2}\n{state}, {city} {postcode}\n{country}",
'LI' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'NL' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'NZ' => "{name}\n{company}\n{address_1}\n{address_2}\n{city} {postcode}\n{country}",
'NO' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'PL' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'PT' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'SK' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'SI' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'ES' => "{name}\n{company}\n{address_1}\n{address_2}\n{postcode} {city}\n{state}\n{country}",
'SE' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'TR' => "{name}\n{company}\n{address_1}\n{address_2}\n{postcode} {city} {state}\n{country}",
'US' => "{name}\n{company}\n{address_1}\n{address_2}\n{city}, {state_code} {postcode}\n{country}",
'VN' => "{name}\n{company}\n{address_1}\n{city}\n{country}",
)
);
2016-06-06 18:39:23 +00:00
}
return $this->address_formats;
}
2012-08-06 22:43:39 +00:00
2012-08-14 19:42:38 +00:00
/**
2015-01-18 18:59:17 +00:00
* Get country address format.
2017-12-21 20:10:55 +00:00
*
* @param array $args Arguments.
* @param string $separator How to separate address lines. @since 3.5.0.
2017-12-21 20:10:55 +00:00
* @return string
2012-08-14 19:42:38 +00:00
*/
public function get_formatted_address( $args = array(), $separator = '<br/>' ) {
$default_args = array(
'first_name' => '',
2015-03-05 09:20:24 +00:00
'last_name' => '',
'company' => '',
'address_1' => '',
'address_2' => '',
'city' => '',
'state' => '',
'postcode' => '',
'country' => '',
);
2015-03-05 09:20:24 +00:00
2017-12-21 20:10:55 +00:00
$args = array_map( 'trim', wp_parse_args( $args, $default_args ) );
$state = $args['state'];
$country = $args['country'];
2012-08-06 22:43:39 +00:00
2017-12-21 20:10:55 +00:00
// Get all formats.
$formats = $this->get_address_formats();
2012-08-06 22:43:39 +00:00
2017-12-21 20:10:55 +00:00
// Get format for the address' country.
$format = ( $country && isset( $formats[ $country ] ) ) ? $formats[ $country ] : $formats['default'];
2012-08-06 22:43:39 +00:00
2017-12-21 20:10:55 +00:00
// Handle full country name.
$full_country = ( isset( $this->countries[ $country ] ) ) ? $this->countries[ $country ] : $country;
2012-08-06 22:43:39 +00:00
2017-12-21 20:10:55 +00:00
// Country is not needed if the same as base.
if ( $country === $this->get_base_country() && ! apply_filters( 'woocommerce_formatted_address_force_country_display', true ) ) {
2012-10-16 15:22:07 +00:00
$format = str_replace( '{country}', '', $format );
2015-03-05 09:20:24 +00:00
}
2012-08-06 22:43:39 +00:00
2017-12-21 20:10:55 +00:00
// Handle full state name.
2015-03-05 09:20:24 +00:00
$full_state = ( $country && $state && isset( $this->states[ $country ][ $state ] ) ) ? $this->states[ $country ][ $state ] : $state;
2012-08-06 22:43:39 +00:00
2017-12-21 20:10:55 +00:00
// Substitute address parts into the string.
$replace = array_map(
'esc_html', apply_filters(
'woocommerce_formatted_address_replacements', array(
'{first_name}' => $args['first_name'],
'{last_name}' => $args['last_name'],
'{name}' => $args['first_name'] . ' ' . $args['last_name'],
'{company}' => $args['company'],
'{address_1}' => $args['address_1'],
'{address_2}' => $args['address_2'],
'{city}' => $args['city'],
'{state}' => $full_state,
'{postcode}' => $args['postcode'],
'{country}' => $full_country,
'{first_name_upper}' => strtoupper( $args['first_name'] ),
'{last_name_upper}' => strtoupper( $args['last_name'] ),
'{name_upper}' => strtoupper( $args['first_name'] . ' ' . $args['last_name'] ),
'{company_upper}' => strtoupper( $args['company'] ),
'{address_1_upper}' => strtoupper( $args['address_1'] ),
'{address_2_upper}' => strtoupper( $args['address_2'] ),
'{city_upper}' => strtoupper( $args['city'] ),
'{state_upper}' => strtoupper( $full_state ),
'{state_code}' => strtoupper( $state ),
'{postcode_upper}' => strtoupper( $args['postcode'] ),
'{country_upper}' => strtoupper( $full_country ),
), $args
)
);
2012-10-16 15:22:07 +00:00
$formatted_address = str_replace( array_keys( $replace ), $replace, $format );
2012-08-06 22:43:39 +00:00
2017-12-21 20:10:55 +00:00
// Clean up white space.
2012-10-16 15:22:07 +00:00
$formatted_address = preg_replace( '/ +/', ' ', trim( $formatted_address ) );
$formatted_address = preg_replace( '/\n\n+/', "\n", $formatted_address );
2012-08-06 22:43:39 +00:00
2017-12-21 20:10:55 +00:00
// Break newlines apart and remove empty lines/trim commas and white space.
$formatted_address = array_filter( array_map( array( $this, 'trim_formatted_address_line' ), explode( "\n", $formatted_address ) ) );
2017-12-21 20:10:55 +00:00
// Add html breaks.
$formatted_address = implode( $separator, $formatted_address );
2012-08-06 22:43:39 +00:00
// We're done!
return $formatted_address;
}
2012-08-06 22:43:39 +00:00
/**
2015-01-18 18:59:17 +00:00
* Trim white space and commas off a line.
2017-12-21 20:10:55 +00:00
*
* @param string $line Line.
* @return string
*/
private function trim_formatted_address_line( $line ) {
2017-12-21 20:10:55 +00:00
return trim( $line, ', ' );
}
/**
* Returns the fields we show by default. This can be filtered later on.
2017-12-21 20:10:55 +00:00
*
* @return array
*/
public function get_default_address_fields() {
2018-06-26 13:48:29 +00:00
$address_2_placeholder = __( 'Apartment, suite, unit etc.', 'woocommerce' );
if ( 'optional' === get_option( 'woocommerce_checkout_address_2_field', 'optional' ) ) {
$address_2_placeholder .= ' (' . __( 'optional', 'woocommerce' ) . ')';
}
$fields = array(
2015-01-18 18:59:17 +00:00
'first_name' => array(
'label' => __( 'First name', 'woocommerce' ),
'required' => true,
'class' => array( 'form-row-first' ),
'autocomplete' => 'given-name',
2016-12-13 18:48:39 +00:00
'priority' => 10,
),
'last_name' => array(
'label' => __( 'Last name', 'woocommerce' ),
'required' => true,
'class' => array( 'form-row-last' ),
'autocomplete' => 'family-name',
2016-12-13 18:48:39 +00:00
'priority' => 20,
),
'company' => array(
'label' => __( 'Company name', 'woocommerce' ),
'class' => array( 'form-row-wide' ),
'autocomplete' => 'organization',
2016-12-13 18:48:39 +00:00
'priority' => 30,
'required' => 'required' === get_option( 'woocommerce_checkout_company_field', 'optional' ),
),
'country' => array(
'type' => 'country',
'label' => __( 'Country', 'woocommerce' ),
'required' => true,
'class' => array( 'form-row-wide', 'address-field', 'update_totals_on_change' ),
'autocomplete' => 'country',
2016-12-13 18:48:39 +00:00
'priority' => 40,
),
'address_1' => array(
Change field label and placeholder to minimize user error, add translators notice Status Quo: Working with several high-volume WooCommerce shops (in the range of several thousand orders per day combined), we've seen that the current placeholder text (and its translations in particular) lead to quite a few users filling in their address data incorrectly. You'd be surprised by the number of people who fail to properly write down their own address (house number missing, house number in wrong place). Problem: This leads to incomplete shipping labels, unsuccessful deliveries, and costly returns (especially for international shipping: 10-40 Euros lost per parcel). Solution: While some of these may stem from misdirected or incomplete browser auto-fills, we've seen (by customizing the language files for German, French, Spanish and Italian) that a more descriptive placeholder text helps reduce user errors on address entry. The goal is basically to make this as fool-proof as possible. Why this matters: At 1000 orders shipped per day, getting the error rate from 5% down to 4% means 10 less parcels coming back every day, which can save hundreds of Euros per day. Choice of wording: - "Address" is not just one field, but rather the sum of all address fields that will end up on a shipping label. - "Street Address" is what the user needs to input here, hence the new label for the two address fields - "House number and street name" is the most descriptive placeholder text I can come up with for this field (assuming the U.S. as default), hence the new placeholder text. - Translator notice added since many countries will have the house number after the street name. References: - https://en.wikipedia.org/wiki/Address_(geography)
2017-04-20 01:46:14 +00:00
'label' => __( 'Street address', 'woocommerce' ),
/* translators: use local order of street name and house number. */
'placeholder' => esc_attr__( 'House number and street name', 'woocommerce' ),
'required' => true,
'class' => array( 'form-row-wide', 'address-field' ),
'autocomplete' => 'address-line1',
2016-12-13 18:48:39 +00:00
'priority' => 50,
),
'address_2' => array(
2018-06-26 13:48:29 +00:00
'placeholder' => esc_attr( $address_2_placeholder ),
'class' => array( 'form-row-wide', 'address-field' ),
'autocomplete' => 'address-line2',
2016-12-13 18:48:39 +00:00
'priority' => 60,
'required' => 'required' === get_option( 'woocommerce_checkout_address_2_field', 'optional' ),
),
'city' => array(
'label' => __( 'Town / City', 'woocommerce' ),
'required' => true,
'class' => array( 'form-row-wide', 'address-field' ),
'autocomplete' => 'address-level2',
2016-12-13 18:48:39 +00:00
'priority' => 70,
),
'state' => array(
'type' => 'state',
'label' => __( 'State / County', 'woocommerce' ),
'required' => true,
'class' => array( 'form-row-wide', 'address-field' ),
'validate' => array( 'state' ),
'autocomplete' => 'address-level1',
2016-12-13 18:48:39 +00:00
'priority' => 80,
),
'postcode' => array(
'label' => __( 'Postcode / ZIP', 'woocommerce' ),
'required' => true,
'class' => array( 'form-row-wide', 'address-field' ),
'validate' => array( 'postcode' ),
'autocomplete' => 'postal-code',
2016-12-13 18:48:39 +00:00
'priority' => 90,
),
);
if ( 'hidden' === get_option( 'woocommerce_checkout_company_field', 'optional' ) ) {
unset( $fields['company'] );
}
if ( 'hidden' === get_option( 'woocommerce_checkout_address_2_field', 'optional' ) ) {
unset( $fields['address_2'] );
}
return apply_filters( 'woocommerce_default_address_fields', $fields );
}
/**
2013-12-03 12:14:12 +00:00
* Get JS selectors for fields which are shown/hidden depending on the locale.
2017-12-21 20:10:55 +00:00
*
* @return array
*/
2013-12-03 12:14:12 +00:00
public function get_country_locale_field_selectors() {
$locale_fields = array(
2015-01-18 18:59:17 +00:00
'address_1' => '#billing_address_1_field, #shipping_address_1_field',
'address_2' => '#billing_address_2_field, #shipping_address_2_field',
'state' => '#billing_state_field, #shipping_state_field, #calc_shipping_state_field',
'postcode' => '#billing_postcode_field, #shipping_postcode_field, #calc_shipping_postcode_field',
'city' => '#billing_city_field, #shipping_city_field, #calc_shipping_city_field',
);
2013-12-03 12:14:12 +00:00
return apply_filters( 'woocommerce_country_locale_field_selectors', $locale_fields );
}
2012-08-14 19:42:38 +00:00
/**
2015-01-18 18:59:17 +00:00
* Get country locale settings.
*
* These locales override the default country selections after a country is chosen.
*
2012-08-14 19:42:38 +00:00
* @return array
*/
public function get_country_locale() {
2016-06-06 18:39:23 +00:00
if ( empty( $this->locale ) ) {
$this->locale = apply_filters(
'woocommerce_get_country_locale', array(
'AE' => array(
'postcode' => array(
'required' => false,
'hidden' => true,
),
'state' => array(
'required' => false,
),
),
'AF' => array(
'state' => array(
'required' => false,
),
),
'AT' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'AU' => array(
'city' => array(
'label' => __( 'Suburb', 'woocommerce' ),
),
'postcode' => array(
'label' => __( 'Postcode', 'woocommerce' ),
),
'state' => array(
'label' => __( 'State', 'woocommerce' ),
),
),
'AX' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'BD' => array(
'postcode' => array(
'required' => false,
),
'state' => array(
'label' => __( 'District', 'woocommerce' ),
),
),
'BE' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
'label' => __( 'Province', 'woocommerce' ),
),
),
'BH' => array(
'postcode' => array(
'required' => false,
),
'state' => array(
'required' => false,
),
),
'BI' => array(
'state' => array(
'required' => false,
),
),
'BO' => array(
'postcode' => array(
'required' => false,
'hidden' => true,
),
),
'BS' => array(
'postcode' => array(
'required' => false,
'hidden' => true,
),
),
'CA' => array(
'state' => array(
'label' => __( 'Province', 'woocommerce' ),
),
),
'CH' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'label' => __( 'Canton', 'woocommerce' ),
'required' => false,
),
),
'CL' => array(
'city' => array(
'required' => true,
),
'postcode' => array(
'required' => false,
),
'state' => array(
'label' => __( 'Region', 'woocommerce' ),
),
),
'CN' => array(
'state' => array(
'label' => __( 'Province', 'woocommerce' ),
),
),
'CO' => array(
'postcode' => array(
'required' => false,
),
),
'CZ' => array(
'state' => array(
'required' => false,
),
),
'DE' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'DK' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'EE' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'FI' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'FR' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'GP' => array(
'state' => array(
'required' => false,
),
),
'GF' => array(
'state' => array(
'required' => false,
),
),
'HK' => array(
'postcode' => array(
'required' => false,
),
'city' => array(
'label' => __( 'Town / District', 'woocommerce' ),
),
'state' => array(
'label' => __( 'Region', 'woocommerce' ),
),
),
'HU' => array(
'state' => array(
'label' => __( 'County', 'woocommerce' ),
),
),
'ID' => array(
'state' => array(
'label' => __( 'Province', 'woocommerce' ),
),
),
'IE' => array(
'postcode' => array(
'required' => false,
'label' => __( 'Eircode', 'woocommerce' ),
),
'state' => array(
'label' => __( 'County', 'woocommerce' ),
),
),
'IS' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'IL' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
2018-02-12 10:34:40 +00:00
'IM' => array(
'state' => array(
2018-02-12 10:34:40 +00:00
'required' => false,
),
),
'IT' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => true,
'label' => __( 'Province', 'woocommerce' ),
),
),
'JP' => array(
'state' => array(
'label' => __( 'Prefecture', 'woocommerce' ),
'priority' => 66,
),
'postcode' => array(
'priority' => 65,
),
),
'KR' => array(
'state' => array(
'required' => false,
),
),
'KW' => array(
'state' => array(
'required' => false,
),
),
'LB' => array(
'state' => array(
'required' => false,
),
),
'MQ' => array(
'state' => array(
2018-06-11 15:23:27 +00:00
'required' => false,
),
),
'MT' => array(
'state' => array(
'required' => false,
),
),
'NL' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
'label' => __( 'Province', 'woocommerce' ),
),
),
'NG' => array(
'postcode' => array(
'label' => __( 'Postcode', 'woocommerce' ),
'required' => false,
'hidden' => true,
),
'state' => array(
'label' => __( 'State', 'woocommerce' ),
),
),
'NZ' => array(
'postcode' => array(
'label' => __( 'Postcode', 'woocommerce' ),
),
'state' => array(
'required' => false,
'label' => __( 'Region', 'woocommerce' ),
),
),
'NO' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'NP' => array(
'state' => array(
'label' => __( 'State / Zone', 'woocommerce' ),
),
'postcode' => array(
'required' => false,
),
),
'PL' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'PT' => array(
'state' => array(
'required' => false,
),
),
'RE' => array(
'state' => array(
'required' => false,
),
),
'RO' => array(
'state' => array(
2017-12-30 12:34:12 +00:00
'label' => __( 'County', 'woocommerce' ),
'required' => false,
),
),
'SG' => array(
'state' => array(
'required' => false,
),
'city' => array(
'required' => false,
'hidden' => true,
),
),
'SK' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'SI' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'SR' => array(
'postcode' => array(
'required' => false,
'hidden' => true,
),
),
'ES' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'label' => __( 'Province', 'woocommerce' ),
),
),
'LI' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'label' => __( 'Municipality', 'woocommerce' ),
'required' => false,
),
),
'LK' => array(
'state' => array(
'required' => false,
),
),
'LU' => array(
'state' => array(
'required' => false,
),
),
'MD' => array(
'state' => array(
2017-12-30 12:34:12 +00:00
'label' => __( 'Municipality / District', 'woocommerce' ),
),
),
'SE' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'required' => false,
),
),
'TR' => array(
'postcode' => array(
'priority' => 65,
),
'state' => array(
'label' => __( 'Province', 'woocommerce' ),
),
),
'US' => array(
'postcode' => array(
'label' => __( 'ZIP', 'woocommerce' ),
),
'state' => array(
'label' => __( 'State', 'woocommerce' ),
),
),
'GB' => array(
'postcode' => array(
'label' => __( 'Postcode', 'woocommerce' ),
),
'state' => array(
'label' => __( 'County', 'woocommerce' ),
'required' => false,
),
),
'VN' => array(
'state' => array(
'required' => false,
),
'postcode' => array(
'priority' => 65,
'required' => false,
'hidden' => false,
),
'address_2' => array(
'required' => false,
'hidden' => true,
),
),
'WS' => array(
'postcode' => array(
'required' => false,
'hidden' => true,
),
),
'YT' => array(
'state' => array(
'required' => false,
),
),
'ZA' => array(
'state' => array(
'label' => __( 'Province', 'woocommerce' ),
),
),
'ZW' => array(
'postcode' => array(
'required' => false,
'hidden' => true,
),
),
)
);
2012-08-06 22:43:39 +00:00
$this->locale = array_intersect_key( $this->locale, array_merge( $this->get_allowed_countries(), $this->get_shipping_countries() ) );
2012-08-06 22:43:39 +00:00
// Default Locale Can be filtered to override fields in get_address_fields(). Countries with no specific locale will use default.
$this->locale['default'] = apply_filters( 'woocommerce_get_country_locale_default', $this->get_default_address_fields() );
2012-08-06 22:43:39 +00:00
2017-12-21 20:10:55 +00:00
// Filter default AND shop base locales to allow overides via a single function. These will be used when changing countries on the checkout.
2015-01-18 18:59:17 +00:00
if ( ! isset( $this->locale[ $this->get_base_country() ] ) ) {
$this->locale[ $this->get_base_country() ] = $this->locale['default'];
2015-01-18 18:59:17 +00:00
}
2012-08-06 22:43:39 +00:00
2015-01-18 18:59:17 +00:00
$this->locale['default'] = apply_filters( 'woocommerce_get_country_locale_base', $this->locale['default'] );
$this->locale[ $this->get_base_country() ] = apply_filters( 'woocommerce_get_country_locale_base', $this->locale[ $this->get_base_country() ] );
}
2012-08-06 22:43:39 +00:00
return $this->locale;
}
2012-08-06 22:43:39 +00:00
/**
2015-11-03 13:31:20 +00:00
* Apply locale and get address fields.
2017-12-21 20:10:55 +00:00
*
* @param mixed $country Country.
* @param string $type Address type, defaults to 'billing_'.
* @return array
*/
public function get_address_fields( $country = '', $type = 'billing_' ) {
if ( ! $country ) {
2015-01-18 18:59:17 +00:00
$country = $this->get_base_country();
}
2013-07-19 14:08:40 +00:00
2015-01-18 18:59:17 +00:00
$fields = $this->get_default_address_fields();
$locale = $this->get_country_locale();
2012-08-06 22:43:39 +00:00
if ( isset( $locale[ $country ] ) ) {
$fields = wc_array_overlay( $fields, $locale[ $country ] );
2012-07-10 12:36:13 +00:00
}
2012-08-06 22:43:39 +00:00
2017-12-21 20:10:55 +00:00
// Prepend field keys.
$address_fields = array();
2012-08-06 22:43:39 +00:00
2012-07-10 12:36:13 +00:00
foreach ( $fields as $key => $value ) {
if ( 'state' === $key ) {
$value['country_field'] = $type . 'country';
}
2015-01-18 18:59:17 +00:00
$address_fields[ $type . $key ] = $value;
}
2012-08-06 22:43:39 +00:00
// Add email and phone fields.
if ( 'billing_' === $type ) {
if ( 'hidden' !== get_option( 'woocommerce_checkout_phone_field', 'required' ) ) {
$address_fields['billing_phone'] = array(
'label' => __( 'Phone', 'woocommerce' ),
'required' => 'required' === get_option( 'woocommerce_checkout_phone_field', 'required' ),
'type' => 'tel',
'class' => array( 'form-row-wide' ),
'validate' => array( 'phone' ),
'autocomplete' => 'tel',
'priority' => 100,
);
}
$address_fields['billing_email'] = array(
2016-12-19 12:19:44 +00:00
'label' => __( 'Email address', 'woocommerce' ),
'required' => true,
'type' => 'email',
'class' => array( 'form-row-wide' ),
2016-12-19 12:19:44 +00:00
'validate' => array( 'email' ),
'autocomplete' => 'no' === get_option( 'woocommerce_registration_generate_username' ) ? 'email' : 'email username',
'priority' => 110,
);
2012-07-10 12:36:13 +00:00
}
2012-08-06 22:43:39 +00:00
2016-11-25 12:24:23 +00:00
/**
* Important note on this filter: Changes to address fields can and will be overridden by
* the woocommerce_default_address_fields. The locales/default locales apply on top based
* on country selection. If you want to change things like the required status of an
* address field, filter woocommerce_default_address_fields instead.
*/
return apply_filters( 'woocommerce_' . $type . 'fields', $address_fields, $country );
}
}