Reputation: 41
Is it possible to get a list of available shipping-methods based on
only a total amount and/or country code?
I quess it is possible by building my own SQL query, but I was wondering if it is also possible with the standard Woo-commerce functions.
I've tried it with the function:
$shipping_methods = WC()->shipping->get_shipping_methods(),
but that gives me all shipping methods without filtering on country or cost. for example: local_pickup looks like
[local_pickup] => WC_Shipping_Local_Pickup Object
(
[supports] => Array
(
[0] => shipping-zones
[1] => instance-settings
[2] => instance-settings-modal
)
[id] => local_pickup
[method_title] => Afhalen
[method_description] => Sta klanten toe bestellingen zelf op te halen. Standaard worden winkelgebaseerde belastingen toegepast wanneer gekozen is voor lokaal ophalen, onafhankelijk van het adres van de klant.
[enabled] => yes
[title] =>
[rates] => Array
(
)
[tax_status] =>
[fee] =>
[minimum_fee] =>
[instance_id] => 0
[instance_form_fields] => Array
(
[title] => Array
(
[title] => Titel
[type] => text
[description] => Dit bepaalt de titel die de gebruiker ziet tijdens het afrekenen.
[default] => Afhalen
[desc_tip] => 1
)
[tax_status] => Array
(
[title] => Belastingstatus
[type] => select
[class] => wc-enhanced-select
[default] => taxable
[options] => Array
(
[taxable] => Belastbaar
[none] => Geen
)
)
[cost] => Array
(
[title] => Kosten
[type] => text
[placeholder] => 0
[description] => Optionele kosten voor afhalen.
[default] =>
[desc_tip] => 1
)
)
[instance_settings] => Array
(
)
[availability] =>
[countries] => Array
(
)
[plugin_id] => woocommerce_
[errors] => Array
(
)
[settings] => Array
(
[title] =>
[tax_status] =>
[cost] =>
)
[form_fields] => Array
(
)
[data:protected] => Array
(
)
[cost] =>
)
Next I tried the following code, but I get no results at all.
print_r ( WC()->shipping->calculate_shipping( get_shipping_packages()));
die('ready');
function get_shipping_packages(){
global $wpdb, $woocommerce;
// Clear the Cart
$woocommerce->cart->empty_cart();
// Add an existing product to the cart, so $packages[0]['contents'] will not be empty...
$product_id = 26;
WC()->cart->add_to_cart($product_id);
$packages = array();
$packages[0]['contents'] = WC()->cart->cart_contents;
$packages[0]['contents_cost'] = 25;
$packages[0]['destination']['country'] = 'NL';
$packages[0]['destination']['state'] = null;
$packages[0]['destination']['postcode'] = null;
$packages[0]['destination']['city'] = null;
$packages[0]['destination']['address'] = null;
return ($packages);
}
Upvotes: 1
Views: 21661
Reputation: 51
I improved Victor's answer a bit. print_r($class)
inside foreach
shows the rest of the options. I wanted to use a custom title instead of the method's title and needed to get free shipping also.
$zones = WC_Shipping_Zones::get_zones();
$methods = array_column( $zones, 'shipping_methods' );
foreach ( $methods[0] as $key => $class ) {
// Method's ID and custom name
$item = [
"id" => $class->method_title,
"name" => $class->title
];
// Price with and without taxes
if(isset($class->instance_settings["cost"]) && $class->instance_settings["cost"] > 0){
$item["price_excl"] = number_format($class->instance_settings["cost"], 2, '.', '');
$item["price_incl"] = number_format($class->instance_settings["cost"] / 100 * 24 + $class->instance_settings["cost"], 2, '.', '');
}
// If minimum amount is required
if(isset($class->min_amount) && $class->min_amount > 0) $item["minimum"] = (float)$class->min_amount;
$data[] = $item;
}
print_r($data);
die();
Upvotes: 2
Reputation: 1155
I was able to get a list of all the available shipping methods and create a new normalized array using the shipping method ID and name:
function prefix_get_available_shipping_methods(){
if ( ! class_exists( 'WC_Shipping_Zones' ) ) {
return array();
}
$zones = WC_Shipping_Zones::get_zones();
if ( ! is_array( $zones ) ) {
return array();
}
$shipping_methods = array_column( $zones, 'shipping_methods' );
$flatten = array_merge( ...$shipping_methods );
$normalized_shipping_methods = array();
foreach ( $flatten as $key => $class ) {
$normalized_shipping_methods[ $class->id ] = $class->method_title;
}
return $normalized_shipping_methods;
}
Upvotes: 0
Reputation: 4192
I was able to get this done through the WC_Shipping_Zones
class.
$zones = WC_Shipping_Zones::get_zones();
$methods = array_map(function($zone) {
return $zone['shipping_methods'];
}, $zones);
Upvotes: 2
Reputation: 41
Finally I found a way to get the shipping methods.
Here is my solution, feedback is welcome..
function shipping() {
global $woocommerce;
$active_methods = array();
$values = array ('country' => 'NL',
'amount' => 100);
// Fake product number to get a filled card....
$woocommerce->cart->add_to_cart('1');
WC()->shipping->calculate_shipping(get_shipping_packages($values));
$shipping_methods = WC()->shipping->packages;
foreach ($shipping_methods[0]['rates'] as $id => $shipping_method) {
$active_methods[] = array( 'id' => $shipping_method->method_id,
'type' => $shipping_method->method_id,
'provider' => $shipping_method->method_id,
'name' => $shipping_method->label,
'price' => number_format($shipping_method->cost, 2, '.', ''));
}
return $active_methods;
}
function get_shipping_packages($value) {
// Packages array for storing 'carts'
$packages = array();
$packages[0]['contents'] = WC()->cart->cart_contents;
$packages[0]['contents_cost'] = $value['amount'];
$packages[0]['applied_coupons'] = WC()->session->applied_coupon;
$packages[0]['destination']['country'] = $value['countries'];
$packages[0]['destination']['state'] = '';
$packages[0]['destination']['postcode'] = '';
$packages[0]['destination']['city'] = '';
$packages[0]['destination']['address'] = '';
$packages[0]['destination']['address_2']= '';
return apply_filters('woocommerce_cart_shipping_packages', $packages);
}
Upvotes: 3