Here is the function I'm using to define and set the shipping rate based on the cart total:
function adjust_shipping_rate( $rates, $package ) {
if (is_admin() && !defined('DOING_AJAX')) {
return;
}
$cart_total = WC()->cart->get_subtotal();
// Define shipping rates based on cart total
$shipping_rates = [
['min' => 0, 'max' => 50, 'rate' => 20],
['min' => 50.1, 'max' => 100, 'rate' => 15],
['min' => 100.1, 'max' => 200, 'rate' => 10],
['min' => 200.1, 'max' => PHP_INT_MAX, 'rate' => 5]
];
// Find the appropriate shipping rate
foreach ($shipping_rates as $range) {
if ($cart_total >= $range['min'] && $cart_total <= $range['max']) {
foreach ($rates as $rate_key => $rate) {
if (strpos($rate_key, 'flat_rate') === 0) {
$rates[$rate_key]->cost = $range['rate'];
}
}
break;
}
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'adjust_shipping_rate', 10, 2 );
I confirmed that without this function, the shipping rate currency is being properly converted, however with this function, the cost is staying the same but the formatting is converting. for instance, instead of $5 shipping converting to 4,61€, it's converting to 5,00€.
We're using WooPayments and their multi-currency rates.
How can I get the current currency conversion rate, so that I can do the conversion myself in my function? I know get_woocommerce_currency() grabs the currency code, so I was hoping that there's something I can hook into to grab the currency rates set in WooPayments, but I'm not able to find any similar situations.
Am I just going about this incorrectly? I don't want to have to install a plugin for the shipping rates if I don't have to.
It seems that the plugin WooPayments plugin is already using woocommerce_package_rates
hook, so maybe lowering the hook priority will take the hand before, allowing WooPayments plugin conversion to make its job on your customized shipping rates.
Also, your code can be simplified/optimized. To finish, tax rate handling is missing from your current code.
Try the following:
add_filter( 'woocommerce_package_rates', 'custom_flat_rate_shipping_cost', 1, 2 );
function custom_flat_rate_shipping_cost( $rates, $package ) {
// Define shipping rates costs based on cart subtotal thresholds
$threshold_shipping_rate_cost = [
['threshold' => 200, 'rate' => 5],
['threshold' => 100, 'rate' => 10],
['threshold' => 50, 'rate' => 15],
['threshold' => 0, 'rate' => 20],
];
// Get Cart Subtotal excl. taxes for the current shipping package
$subtotal = $package['contents_cost'];
// Find the appropriate shipping rate
foreach ($rates as $rate_key => $rate) {
if ( 'flat_rate' !== $rate->method_id ) continue;
foreach ($threshold_shipping_rate_cost as $data) {
if ( $subtotal >= $data['threshold']) {
$base_cost = $rate->cost; // Original rate cost
$has_taxes = false; // Initializing
$taxes = array(); // Initializing
$rates[$rate_key]->cost = $data['rate']; // Set the new cost
// Loop through taxes array (change taxes rate cost if enabled)
foreach ($rate->taxes as $key => $tax){
if( $tax > 0 ){
$conv_rate = $tax / $base_cost; // Get the conversion tax rate
$taxes[$key] = $data['rate'] * $conv_rate; // Set the new tax cost in the array
$has_taxes = true; // Enabling tax changes
}
}
// Set the array of shipping tax cost (if any)
if( $has_taxes ) {
$rates[$rate_key]->taxes = $taxes;
}
break;
}
}
}
return $rates;
}
Code goes in functions.php file of your child theme (or in a plugin). It could work.
Important: You will have to empty your cart to refresh shipping methods cache.
Note that $package['contents_cost']
(or WC()->cart->get_subtotal()
) is the cart subtotal excluding taxes. For cart subtotal including taxes, use $package['cart_subtotal']
(or WC()->cart->subtotal
).