/** * 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); }
/** * 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); }