So I was trying to create a woocommerce shipping method that takes the cart subtotal and charges a user-defined percentage of the cart subtotal as a shipping fee. As a first step towards this goal, ehat I did was basically like this
class Subtotal_Percentage_Method extends WC_Shipping_Method {
// to store percentage
private $percentage_rate
// constructor that handles settings
// here is where i start calculation
public function calculate_shipping($packages = array()) {
$cost = $this->percentage_rate * 1000;
add_rate(array(
'id' => $this->id,
'label' => $this->title,
'cost' => $cost
));
}
}
This one works. However, it doesn't work when I change the calculate_shipping method to use the cart subtotal in the calculation like this
public function calculate_shipping($packages = array()) {
$subtotal = WC()->cart->subtotal;
$cost = $subtotal * $this->percentage_rate / 100;
add_rate(array(
'id' => $this->id,
'label' => $this->title,
'cost' => $cost
));
}
Can anyone show me what I'm doing wrong?
As this is related to shipping packages (as cart items can be splitted (divided) into multiple shipping packages), you need to use instead the variable $packages
argument included in calculate_shipping()
method.
So your code will be lightly different without using WC_Cart
Object methods:
public function calculate_shipping( $packages = array() ) {
$total = $total_tax = 0; // Initializing
// Loop through shipping packages
foreach( $packages as $key => $package ){
// Loop through cart items for this package
foreach( $package['contents'] as $item ){
$total += $item['total']; // Item subtotal discounted
$total_tax += $item['total_tax']; // Item subtotal tax discounted
}
}
add_rate( array(
'id' => $this->id,
'label' => $this->title,
'cost' => $total * $this->percentage_rate / 100,
// 'calc_tax' => 'per_item'
) );
}
Code goes in functions.php file of your active child theme (active theme). Tested and works.
Note: Here the calculation is made on cart items subtotal after discount (without taxes). You can add easily add make it on cart items subtotal after discount with taxes, replacing:
'cost' => $total * $this->percentage_rate / 100,
by:
'cost' => ($total + $total_tax) * $this->percentage_rate / 100,
You can see how are made the shipping packages looking to:
WC_Cart
get_shipping_packages()
method source code
If you want to handle also shipping classes and more, check:
WC_Shipping_Flat_Rate
calculate_shipping()
method source code.