2016-11-15 21:53:11 +00:00
< ? php
2018-03-08 18:33:27 +00:00
/**
* Class WC_Shipping_Zone_Data_Store file .
*
* @ package WooCommerce\DataStores
*/
2016-11-15 21:53:11 +00:00
if ( ! defined ( 'ABSPATH' ) ) {
exit ;
}
/**
2016-11-16 11:18:47 +00:00
* WC Shipping Zone Data Store .
2016-11-15 21:53:11 +00:00
*
2017-03-15 16:36:53 +00:00
* @ version 3.0 . 0
2016-11-15 21:53:11 +00:00
*/
2016-11-22 13:54:51 +00:00
class WC_Shipping_Zone_Data_Store extends WC_Data_Store_WP implements WC_Shipping_Zone_Data_Store_Interface , WC_Object_Data_Store_Interface {
2016-11-15 21:53:11 +00:00
/**
* Method to create a new shipping zone .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:33:27 +00:00
* @ param WC_Shipping_Zone $zone Shipping zone object .
2016-11-15 21:53:11 +00:00
*/
public function create ( & $zone ) {
global $wpdb ;
2018-03-07 19:16:01 +00:00
$wpdb -> insert (
2018-11-23 14:57:51 +00:00
$wpdb -> prefix . 'woocommerce_shipping_zones' ,
array (
2018-03-07 19:16:01 +00:00
'zone_name' => $zone -> get_zone_name (),
'zone_order' => $zone -> get_zone_order (),
)
);
2016-11-15 21:53:11 +00:00
$zone -> set_id ( $wpdb -> insert_id );
$zone -> save_meta_data ();
$this -> save_locations ( $zone );
$zone -> apply_changes ();
2019-11-28 13:03:57 +00:00
WC_Cache_Helper :: invalidate_cache_group ( 'shipping_zones' );
2016-11-15 21:53:11 +00:00
WC_Cache_Helper :: get_transient_version ( 'shipping' , true );
}
/**
2016-11-15 23:02:21 +00:00
* Update zone in the database .
2016-11-15 21:53:11 +00:00
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:33:27 +00:00
* @ param WC_Shipping_Zone $zone Shipping zone object .
2016-11-15 21:53:11 +00:00
*/
public function update ( & $zone ) {
global $wpdb ;
if ( $zone -> get_id () ) {
2018-03-07 19:16:01 +00:00
$wpdb -> update (
2018-11-23 14:57:51 +00:00
$wpdb -> prefix . 'woocommerce_shipping_zones' ,
array (
2018-03-07 19:16:01 +00:00
'zone_name' => $zone -> get_zone_name (),
'zone_order' => $zone -> get_zone_order (),
2018-11-23 14:57:51 +00:00
),
array ( 'zone_id' => $zone -> get_id () )
2018-03-07 19:16:01 +00:00
);
2016-11-15 21:53:11 +00:00
}
$zone -> save_meta_data ();
$this -> save_locations ( $zone );
$zone -> apply_changes ();
2019-11-28 13:03:57 +00:00
WC_Cache_Helper :: invalidate_cache_group ( 'shipping_zones' );
2016-11-15 21:53:11 +00:00
WC_Cache_Helper :: get_transient_version ( 'shipping' , true );
}
/**
* Method to read a shipping zone from the database .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:33:27 +00:00
* @ param WC_Shipping_Zone $zone Shipping zone object .
* @ throws Exception If invalid data store .
2016-11-15 21:53:11 +00:00
*/
public function read ( & $zone ) {
global $wpdb ;
2018-03-08 18:33:27 +00:00
2021-01-12 17:53:22 +00:00
// Zone 0 is used as a default if no other zones fit.
2018-03-07 19:16:01 +00:00
if ( 0 === $zone -> get_id () || '0' === $zone -> get_id () ) {
2016-11-15 21:53:11 +00:00
$this -> read_zone_locations ( $zone );
2017-07-11 07:19:42 +00:00
$zone -> set_zone_name ( __ ( 'Locations not covered by your other zones' , 'woocommerce' ) );
2016-11-15 21:53:11 +00:00
$zone -> read_meta_data ();
$zone -> set_object_read ( true );
2021-01-12 17:53:22 +00:00
/**
* Indicate that the WooCommerce shipping zone has been loaded .
*
* @ param WC_Shipping_Zone $zone The shipping zone that has been loaded .
*/
2016-11-15 21:53:11 +00:00
do_action ( 'woocommerce_shipping_zone_loaded' , $zone );
2021-01-12 17:53:22 +00:00
return ;
}
$zone_data = $wpdb -> get_row (
$wpdb -> prepare (
" SELECT zone_name, zone_order FROM { $wpdb -> prefix } woocommerce_shipping_zones WHERE zone_id = %d LIMIT 1 " ,
$zone -> get_id ()
)
);
if ( ! $zone_data ) {
2016-11-15 23:16:04 +00:00
throw new Exception ( __ ( 'Invalid data store.' , 'woocommerce' ) );
2016-11-15 21:53:11 +00:00
}
2021-01-12 17:53:22 +00:00
$zone -> set_zone_name ( $zone_data -> zone_name );
$zone -> set_zone_order ( $zone_data -> zone_order );
$this -> read_zone_locations ( $zone );
$zone -> read_meta_data ();
$zone -> set_object_read ( true );
/** This action is documented in includes/datastores/class-wc-shipping-zone-data-store.php. */
do_action ( 'woocommerce_shipping_zone_loaded' , $zone );
2016-11-15 21:53:11 +00:00
}
/**
* Deletes a shipping zone from the database .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:33:27 +00:00
* @ param WC_Shipping_Zone $zone Shipping zone object .
2018-03-07 19:16:01 +00:00
* @ param array $args Array of args to pass to the delete method .
2018-03-08 18:33:27 +00:00
* @ return void
2016-11-15 21:53:11 +00:00
*/
public function delete ( & $zone , $args = array () ) {
2019-02-26 16:53:52 +00:00
$zone_id = $zone -> get_id ();
if ( $zone_id ) {
2016-11-15 21:53:11 +00:00
global $wpdb ;
2019-02-26 16:53:52 +00:00
// Delete methods and their settings.
$methods = $this -> get_methods ( $zone_id , false );
if ( $methods ) {
foreach ( $methods as $method ) {
$this -> delete_method ( $method -> instance_id );
}
}
// Delete zone.
$wpdb -> delete ( $wpdb -> prefix . 'woocommerce_shipping_zone_locations' , array ( 'zone_id' => $zone_id ) );
$wpdb -> delete ( $wpdb -> prefix . 'woocommerce_shipping_zones' , array ( 'zone_id' => $zone_id ) );
2016-11-15 21:53:11 +00:00
$zone -> set_id ( null );
2019-02-26 16:53:52 +00:00
2019-11-28 13:03:57 +00:00
WC_Cache_Helper :: invalidate_cache_group ( 'shipping_zones' );
2017-02-09 12:59:13 +00:00
WC_Cache_Helper :: get_transient_version ( 'shipping' , true );
2019-02-26 16:53:52 +00:00
do_action ( 'woocommerce_delete_shipping_zone' , $zone_id );
2016-11-15 21:53:11 +00:00
}
}
2016-11-15 22:55:14 +00:00
/**
2016-11-15 23:02:21 +00:00
* Get a list of shipping methods for a specific zone .
2016-11-15 22:55:14 +00:00
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:33:27 +00:00
* @ param int $zone_id Zone ID .
2018-03-07 19:16:01 +00:00
* @ param bool $enabled_only True to request enabled methods only .
2016-11-15 22:55:14 +00:00
* @ return array Array of objects containing method_id , method_order , instance_id , is_enabled
*/
public function get_methods ( $zone_id , $enabled_only ) {
global $wpdb ;
2018-03-08 18:33:27 +00:00
if ( $enabled_only ) {
$raw_methods_sql = " SELECT method_id, method_order, instance_id, is_enabled FROM { $wpdb -> prefix } woocommerce_shipping_zone_methods WHERE zone_id = %d AND is_enabled = 1 " ;
} else {
$raw_methods_sql = " SELECT method_id, method_order, instance_id, is_enabled FROM { $wpdb -> prefix } woocommerce_shipping_zone_methods WHERE zone_id = %d " ;
}
2018-11-23 17:10:52 +00:00
return $wpdb -> get_results ( $wpdb -> prepare ( $raw_methods_sql , $zone_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2016-11-15 22:55:14 +00:00
}
/**
* Get count of methods for a zone .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:33:27 +00:00
* @ param int $zone_id Zone ID .
2016-11-15 22:55:14 +00:00
* @ return int Method Count
*/
public function get_method_count ( $zone_id ) {
global $wpdb ;
return $wpdb -> get_var ( $wpdb -> prepare ( " SELECT COUNT(*) FROM { $wpdb -> prefix } woocommerce_shipping_zone_methods WHERE zone_id = %d " , $zone_id ) );
}
/**
* Add a shipping method to a zone .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:33:27 +00:00
* @ param int $zone_id Zone ID .
* @ param string $type Method Type / ID .
* @ param int $order Method Order .
2016-11-15 22:55:14 +00:00
* @ return int Instance ID
*/
public function add_method ( $zone_id , $type , $order ) {
global $wpdb ;
$wpdb -> insert (
$wpdb -> prefix . 'woocommerce_shipping_zone_methods' ,
array (
'method_id' => $type ,
'zone_id' => $zone_id ,
'method_order' => $order ,
),
array (
'%s' ,
'%d' ,
'%d' ,
)
);
return $wpdb -> insert_id ;
}
/**
* Delete a method instance .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:33:27 +00:00
* @ param int $instance_id Instance ID .
2016-11-15 22:55:14 +00:00
*/
public function delete_method ( $instance_id ) {
global $wpdb ;
2019-02-26 16:53:52 +00:00
$method = $this -> get_method ( $instance_id );
if ( ! $method ) {
return ;
}
delete_option ( 'woocommerce_' . $method -> method_id . '_' . $instance_id . '_settings' );
2016-11-15 22:55:14 +00:00
$wpdb -> delete ( $wpdb -> prefix . 'woocommerce_shipping_zone_methods' , array ( 'instance_id' => $instance_id ) );
2019-02-26 16:53:52 +00:00
2017-01-07 05:46:31 +00:00
do_action ( 'woocommerce_delete_shipping_zone_method' , $instance_id );
2016-11-15 22:55:14 +00:00
}
/**
* Get a shipping zone method instance .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:33:27 +00:00
* @ param int $instance_id Instance ID .
2016-11-15 22:55:14 +00:00
* @ return object
*/
public function get_method ( $instance_id ) {
global $wpdb ;
2017-02-13 12:58:42 +00:00
return $wpdb -> get_row ( $wpdb -> prepare ( " SELECT zone_id, method_id, instance_id, method_order, is_enabled FROM { $wpdb -> prefix } woocommerce_shipping_zone_methods WHERE instance_id = %d LIMIT 1; " , $instance_id ) );
2016-11-15 22:55:14 +00:00
}
/**
* Find a matching zone ID for a given package .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:33:27 +00:00
* @ param object $package Package information .
2016-11-15 22:55:14 +00:00
* @ return int
*/
public function get_zone_id_from_package ( $package ) {
global $wpdb ;
2018-03-07 19:16:01 +00:00
$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' ] ) );
2016-11-15 22:55:14 +00:00
2018-03-08 18:33:27 +00:00
// Work out criteria for our zone search.
2016-11-15 23:02:21 +00:00
$criteria = array ();
2016-11-15 22:55:14 +00:00
$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 );
2018-03-07 19:16:01 +00:00
$criteria [] = 'OR ( location_type IS NULL ) )' ;
2016-11-15 22:55:14 +00:00
2018-03-08 18:33:27 +00:00
// Postcode range and wildcard matching.
2016-11-15 22:55:14 +00:00
$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' , $country );
$do_not_match = array_unique ( array_diff ( $zone_ids_with_postcode_rules , array_keys ( $matches ) ) );
if ( ! empty ( $do_not_match ) ) {
2018-03-07 19:16:01 +00:00
$criteria [] = 'AND zones.zone_id NOT IN (' . implode ( ',' , $do_not_match ) . ')' ;
2016-11-15 22:55:14 +00:00
}
}
2019-08-07 06:56:28 +00:00
2019-08-07 04:04:14 +00:00
/**
* Get shipping zone criteria
*
* @ since 3.6 . 6
* @ param array $criteria Get zone criteria .
2019-08-07 06:56:28 +00:00
* @ param array $package Package information .
* @ param array $postcode_locations Postcode range and wildcard matching .
2019-08-07 04:04:14 +00:00
*/
$criteria = apply_filters ( 'woocommerce_get_zone_criteria' , $criteria , $package , $postcode_locations );
2016-11-15 22:55:14 +00:00
2018-03-08 18:33:27 +00:00
// Get matching zones.
2018-03-07 19:16:01 +00:00
return $wpdb -> get_var (
" SELECT zones.zone_id FROM { $wpdb -> prefix } woocommerce_shipping_zones as zones
2016-11-15 22:55:14 +00:00
LEFT OUTER JOIN { $wpdb -> prefix } woocommerce_shipping_zone_locations as locations ON zones . zone_id = locations . zone_id AND location_type != 'postcode'
2018-11-23 17:10:52 +00:00
WHERE " . implode( ' ', $criteria ) // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2020-04-27 16:31:52 +00:00
. ' ORDER BY zone_order ASC, zones.zone_id ASC LIMIT 1'
2018-03-07 19:16:01 +00:00
);
2016-11-15 22:55:14 +00:00
}
/**
* Return an ordered list of zones .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-11-15 22:55:14 +00:00
* @ return array An array of objects containing a zone_id , zone_name , and zone_order .
*/
public function get_zones () {
global $wpdb ;
2017-07-19 09:16:50 +00:00
return $wpdb -> get_results ( " SELECT zone_id, zone_name, zone_order FROM { $wpdb -> prefix } woocommerce_shipping_zones order by zone_order ASC, zone_id ASC; " );
2016-11-15 22:55:14 +00:00
}
/**
* Return a zone ID from an instance ID .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2018-03-08 18:33:27 +00:00
* @ param int $id Instnace ID .
2016-11-15 22:55:14 +00:00
* @ return int
*/
public function get_zone_id_by_instance_id ( $id ) {
global $wpdb ;
return $wpdb -> get_var ( $wpdb -> prepare ( " SELECT zone_id FROM { $wpdb -> prefix } woocommerce_shipping_zone_methods as methods WHERE methods.instance_id = %d LIMIT 1; " , $id ) );
}
2016-11-15 21:53:11 +00:00
/**
* Read location data from the database .
*
2018-03-08 18:33:27 +00:00
* @ param WC_Shipping_Zone $zone Shipping zone object .
2016-11-15 21:53:11 +00:00
*/
private function read_zone_locations ( & $zone ) {
global $wpdb ;
2018-03-08 18:33:27 +00:00
$locations = $wpdb -> get_results (
$wpdb -> prepare (
" SELECT location_code, location_type FROM { $wpdb -> prefix } woocommerce_shipping_zone_locations WHERE zone_id = %d " ,
$zone -> get_id ()
)
);
if ( $locations ) {
2016-11-15 21:53:11 +00:00
foreach ( $locations as $location ) {
$zone -> add_location ( $location -> location_code , $location -> location_type );
}
}
}
/**
* Save locations to the DB .
* This function clears old locations , then re - inserts new if any changes are found .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2017-05-12 08:48:46 +00:00
*
2018-03-08 18:33:27 +00:00
* @ param WC_Shipping_Zone $zone Shipping zone object .
2017-05-12 08:48:46 +00:00
*
* @ return bool | void
2016-11-15 21:53:11 +00:00
*/
private function save_locations ( & $zone ) {
$changed_props = array_keys ( $zone -> get_changes () );
2018-03-08 18:33:27 +00:00
if ( ! in_array ( 'zone_locations' , $changed_props , true ) ) {
2016-11-15 21:53:11 +00:00
return false ;
}
global $wpdb ;
$wpdb -> delete ( $wpdb -> prefix . 'woocommerce_shipping_zone_locations' , array ( 'zone_id' => $zone -> get_id () ) );
foreach ( $zone -> get_zone_locations ( 'edit' ) as $location ) {
2018-03-07 19:16:01 +00:00
$wpdb -> insert (
2018-11-23 14:57:51 +00:00
$wpdb -> prefix . 'woocommerce_shipping_zone_locations' ,
array (
2018-03-07 19:16:01 +00:00
'zone_id' => $zone -> get_id (),
'location_code' => $location -> code ,
'location_type' => $location -> type ,
)
);
2016-11-15 21:53:11 +00:00
}
}
}