2

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?

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
waifu-master
  • 23
  • 1
  • 4

1 Answers1

2

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.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399