Search code examples
phpwordpresswoocommercecalculationshipping-method

How to get cart subtotal inside WC_Shipping_Method calculate_shipping() method


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?


Solution

  • 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.