/**
  * Find a matching zone for a given package.
  * @since  2.6.0
  * @uses   wc_make_numeric_postcode()
  * @param  object $package
  * @return WC_Shipping_Zone
  */
 public static function get_zone_matching_package($package)
 {
     global $wpdb;
     $country = strtoupper(wc_clean($package['destination']['country']));
     $state = strtoupper(wc_clean($package['destination']['state']));
     $continent = strtoupper(wc_clean(WC()->countries->get_continent_code_for_country($country)));
     $postcode = wc_normalize_postcode(wc_clean($package['destination']['postcode']));
     $cache_key = WC_Cache_Helper::get_cache_prefix('shipping_zones') . 'wc_shipping_zone_' . md5(sprintf('%s+%s+%s', $country, $state, $postcode));
     $matching_zone_id = wp_cache_get($cache_key, 'shipping_zones');
     if (false === $matching_zone_id) {
         // Work out criteria for our zone search
         $criteria = array();
         $criteria[] = $wpdb->prepare("( ( location_type = 'country' AND location_code = %s )", $country);
         $criteria[] = $wpdb->prepare("OR ( location_type = 'state' AND location_code = %s )", $country . ':' . $state);
         $criteria[] = $wpdb->prepare("OR ( location_type = 'continent' AND location_code = %s ) )", $continent);
         // Postcode range and wildcard matching
         $postcode_locations = $wpdb->get_results("SELECT zone_id, location_code FROM {$wpdb->prefix}woocommerce_shipping_zone_locations WHERE location_type = 'postcode';");
         if ($postcode_locations) {
             $zone_ids_with_postcode_rules = array_map('absint', wp_list_pluck($postcode_locations, 'zone_id'));
             $matches = wc_postcode_location_matcher($postcode, $postcode_locations, 'zone_id', 'location_code');
             $do_not_match = array_unique(array_diff($zone_ids_with_postcode_rules, array_keys($matches)));
             if (!empty($do_not_match)) {
                 $criteria[] = "AND zones.zone_id NOT IN (" . implode(',', $do_not_match) . ")";
             }
         }
         // Get matching zones
         $matching_zone_id = $wpdb->get_var("\n\t\t\t\tSELECT zones.zone_id FROM {$wpdb->prefix}woocommerce_shipping_zones as zones\n\t\t\t\tLEFT OUTER JOIN {$wpdb->prefix}woocommerce_shipping_zone_locations as locations ON zones.zone_id = locations.zone_id\n\t\t\t\tWHERE " . implode(' ', $criteria) . "\n\t\t\t\tORDER BY zone_order ASC LIMIT 1\n\t\t\t");
         wp_cache_set($cache_key, $matching_zone_id, 'shipping_zones');
     }
     return new WC_Shipping_Zone($matching_zone_id ? $matching_zone_id : 0);
 }
/**
 * Format the postcode according to the country and length of the postcode.
 *
 * @param string $postcode
 * @param string $country
 * @return string Formatted postcode.
 */
function wc_format_postcode($postcode, $country)
{
    $postcode = wc_normalize_postcode($postcode);
    switch ($country) {
        case 'CA':
        case 'GB':
            $postcode = trim(substr_replace($postcode, ' ', -3, 0));
            break;
        case 'BR':
            $postcode = trim(substr_replace($postcode, '-', -3, 0));
            break;
    }
    return apply_filters('woocommerce_format_postcode', $postcode, $country);
}
Example #3
0
 /**
  * Searches for all matching country/state/postcode tax rates.
  *
  * @param array $args
  * @return array
  */
 public static function find_rates($args = array())
 {
     $args = wp_parse_args($args, array('country' => '', 'state' => '', 'city' => '', 'postcode' => '', 'tax_class' => ''));
     extract($args, EXTR_SKIP);
     if (!$country) {
         return array();
     }
     $postcode = wc_normalize_postcode(wc_clean($postcode));
     $cache_key = WC_Cache_Helper::get_cache_prefix('taxes') . 'wc_tax_rates_' . md5(sprintf('%s+%s+%s+%s+%s', $country, $state, $city, $postcode, $tax_class));
     $matched_tax_rates = wp_cache_get($cache_key, 'taxes');
     if (false === $matched_tax_rates) {
         $matched_tax_rates = self::get_matched_tax_rates($country, $state, $postcode, $city, $tax_class);
         wp_cache_set($cache_key, $matched_tax_rates, 'taxes');
     }
     return apply_filters('woocommerce_find_rates', $matched_tax_rates, $args);
 }
/**
 * Used by shipping zones and taxes to compare a given $postcode to stored
 * postcodes to find matches for numerical ranges, and wildcards.
 * @since 2.6.0
 * @param string $postcode Postcode you want to match against stored postcodes
 * @param array  $objects Array of postcode objects from Database
 * @param string $object_id_key DB column name for the ID.
 * @param string $object_compare_key DB column name for the value.
 * @param string $country Country from which this postcode belongs. Allows for formatting.
 * @return array Array of matching object ID and matching values.
 */
function wc_postcode_location_matcher($postcode, $objects, $object_id_key, $object_compare_key, $country = '')
{
    $postcode = wc_normalize_postcode($postcode);
    $wildcard_postcodes = array_map('wc_clean', wc_get_wildcard_postcodes($postcode, $country));
    $matches = array();
    foreach ($objects as $object) {
        $object_id = $object->{$object_id_key};
        $compare_against = $object->{$object_compare_key};
        // Handle postcodes containing ranges.
        if (strstr($compare_against, '...')) {
            $range = array_map('trim', explode('...', $compare_against));
            if (2 !== sizeof($range)) {
                continue;
            }
            list($min, $max) = $range;
            // If the postcode is non-numeric, make it numeric.
            if (!is_numeric($min) || !is_numeric($max)) {
                $compare = wc_make_numeric_postcode($postcode);
                $min = str_pad(wc_make_numeric_postcode($min), strlen($compare), '0');
                $max = str_pad(wc_make_numeric_postcode($max), strlen($compare), '0');
            } else {
                $compare = $postcode;
            }
            if ($compare >= $min && $compare <= $max) {
                $matches[$object_id] = isset($matches[$object_id]) ? $matches[$object_id] : array();
                $matches[$object_id][] = $compare_against;
            }
            // Wildcard and standard comparison.
        } elseif (in_array($compare_against, $wildcard_postcodes)) {
            $matches[$object_id] = isset($matches[$object_id]) ? $matches[$object_id] : array();
            $matches[$object_id][] = $compare_against;
        }
    }
    return $matches;
}
 /**
  * Add location (state or postcode) to a zone.
  * @param string $code
  * @param string $type state or postcode
  */
 public function add_location($code, $type)
 {
     if ($this->is_valid_location_type($type)) {
         if ('postcode' === $type) {
             $code = wc_normalize_postcode($code);
         }
         $location = array('code' => wc_clean($code), 'type' => wc_clean($type));
         $this->_data['zone_locations'][] = (object) $location;
         $this->_locations_changed = true;
     }
 }
 /**
  * Find a matching zone for a given package.
  * @since  2.6.0
  * @uses   wc_make_numeric_postcode()
  * @param  object $package
  * @return WC_Shipping_Zone
  */
 public static function get_zone_matching_package($package)
 {
     $country = strtoupper(wc_clean($package['destination']['country']));
     $state = strtoupper(wc_clean($package['destination']['state']));
     $continent = strtoupper(wc_clean(WC()->countries->get_continent_code_for_country($country)));
     $postcode = wc_normalize_postcode(wc_clean($package['destination']['postcode']));
     $cache_key = WC_Cache_Helper::get_cache_prefix('shipping_zones') . 'wc_shipping_zone_' . md5(sprintf('%s+%s+%s', $country, $state, $postcode));
     $matching_zone_id = wp_cache_get($cache_key, 'shipping_zones');
     if (false === $matching_zone_id) {
         $data_store = WC_Data_Store::load('shipping-zone');
         $matching_zone_id = $data_store->get_zone_id_from_package($package);
         wp_cache_set($cache_key, $matching_zone_id, 'shipping_zones');
     }
     return new WC_Shipping_Zone($matching_zone_id ? $matching_zone_id : 0);
 }