I have a code snippet running on a Woocommerce site that calculates and adds a handling fee to the cart total.
There are two parts to the calculation:
The snippet does all of this fine, however it fails if the cart contains a mixture of products.
That is, if one product has the particular attribute, and another product doesn't have this attribute, then the set fee is not added.
I need the set fee to be added if at least one product in the cart has this attribute. Here is the code:
<?php
// Hook to add a handling fee
add_action( 'woocommerce_cart_calculate_fees','handling_fee' );
function handling_fee($cart_object) {
global $woocommerce;
$specialfeeattr = 71; // attribute id for the special fee
$spfee = 0.00; // initialize special fee
$percentage = 0.18; // percentage to add to shipping total
$orderFeeUSD = 3.20; //fee per transaction USD
$orderFeeCAD = 4.00; //fee per transaction CAD
$orderFeeEUR = 2.62; //fee per transaction EUR
$orderFeeGBP = 2.26; //fee per transaction GBP
$currentCurrency = get_woocommerce_currency();
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
foreach ( $cart_object->cart_contents as $key => $value ) {
$proid = $value['product_id']; //get the product id from cart
$product = wc_get_product( $proid );
$attr = $product->get_attributes();
//check if attributes array has fulfillment attribute included
if (array_key_exists ('pa_fulfillment', $attr )) {
$attrFulfillment = $attr['pa_fulfillment'];
}
if (isset($attrFulfillment)) {
$attrFulfillmentOptions = $attrFulfillment['options'];
}
if ($woocommerce->cart->shipping_total > 0) {
$spfee = (($woocommerce->cart->shipping_total) * $percentage);
}
//only check if fullfillment option is set to warehouse if fulfillment is not null
if (isset($attrFulfillmentOptions)) {
//if the product in cart contains attr id 71
if (in_array($specialfeeattr, $attrFulfillmentOptions )) {
if($currentCurrency == 'USD'){
$spfee += $orderFeeUSD;
} elseif($currentCurrency == 'CAD') {
$spfee += $orderFeeCAD;
} elseif($currentCurrency == 'EUR') {
$spfee += $orderFeeEUR;
} elseif($currentCurrency == 'GBP') {
$spfee += $orderFeeGBP;
}
}
}
}
$woocommerce->cart->add_fee( 'Handling', $spfee, true, 'standard' );
}
?>
Thank you very much for any advice on how to fix this.
You are initializing the $spfee
variable with these lines on each iteration:
if ( $woocommerce->cart->shipping_total > 0 ) {
$spfee = $woocommerce->cart->shipping_total * $percentage;
}
In this way you only get the sum of the percentage on the shipping (if this is greater than zero) and the fee on the last iterated cart item.
Then try to insert the previous lines of code before the start of the loop.
If you want to apply the standard tax rate, assign a blank value to the fourth parameter of the
add_fee
method, as reported in the documentation.
Also there are other optimizations to the code, try this:
// Hook to add a handling fee
add_action( 'woocommerce_cart_calculate_fees','handling_fee' );
function handling_fee( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
global $woocommerce;
$specialfeeattr = 71; // attribute id for the special fee
$spfee = 0.00; // initialize special fee
$percentage = 0.18; // percentage to add to shipping total
$orderFeeUSD = 3.20; //fee per transaction USD
$orderFeeCAD = 4.00; //fee per transaction CAD
$orderFeeEUR = 2.62; //fee per transaction EUR
$orderFeeGBP = 2.26; //fee per transaction GBP
$currentCurrency = get_woocommerce_currency();
if ( $woocommerce->cart->shipping_total > 0 ) {
$spfee = $woocommerce->cart->shipping_total * $percentage;
}
foreach ( $cart_object->cart_contents as $key => $value ) {
$proid = $value['product_id']; //get the product id from cart
$product = wc_get_product( $proid );
$attr = $product->get_attributes();
//check if attributes array has fulfillment attribute included
if ( array_key_exists ( 'pa_fulfillment', $attr ) ) {
$attrFulfillment = $attr['pa_fulfillment'];
}
if ( isset($attrFulfillment) ) {
$attrFulfillmentOptions = $attrFulfillment['options'];
}
// only check if fullfillment option is set to warehouse if fulfillment is not null
if ( isset($attrFulfillmentOptions) ) {
// if the product in cart contains attr id 71
if ( in_array( $specialfeeattr, $attrFulfillmentOptions ) ) {
switch ( $currentCurrency ) {
case 'USD':
$spfee += $orderFeeUSD;
break;
case 'CAD':
$spfee += $orderFeeCAD;
break;
case 'EUR':
$spfee += $orderFeeEUR;
break;
case 'GBP':
$spfee += $orderFeeGBP;
break;
}
}
}
}
$woocommerce->cart->add_fee( 'Handling', $spfee, true, 'standard' );
}
The code should work. Add it to your active theme's functions.php.