i have a PHP code that counts shipping cost in woocommerce based on quantity steps in addition to another cost based on shipping zone, the sum of two costs give the total shipping cost. what i need now to apply the shipping zone cost to only first item in cart and apply the cost based on quantity steps to the rest of items starting from the second item in cart.
here is my code :
/*
WooCommerce - increase Flat rate shipping based on X quantity steps
*/
add_filter( 'woocommerce_package_rates', 'add_cost_based_on_zone_and_quantity', 10, 2 );
function add_cost_based_on_zone_and_quantity( $rates, $package ) {
$shipping_class_rates = array(
'very-light' => 20, // Shipping class slug => Quantity threshold for a step
'light' => 10,
'pre-medium' => 5,
'medium' => 3,
'post-medium' => 2,
'heavy' => 1,
'very-heavy' => 1/5,
'huge' => 1/10,
'very-huge' => 1,
);
// Define extra costs by shipping zone ID
$zone_costs = array(
'zone_1' => 80, // Adjust these with actual zone IDs and costs
'zone_2' => 100,
'zone_3' => 120,
'zone_4' => 140,
);
// Initialize an array to keep track of item counts for each shipping class
$item_counts = array();
foreach ($shipping_class_rates as $shipping_class => $qty_step) {
$item_counts[$shipping_class] = 0;
}
// Count items per shipping class
foreach ($package['contents'] as $cart_item) {
$class_id = $cart_item['data']->get_shipping_class_id();
foreach ($shipping_class_rates as $shipping_class => $qty_step) {
$term = get_term_by('slug', $shipping_class, 'product_shipping_class');
if ($class_id == $term->term_id) {
$item_counts[$shipping_class] += $cart_item['quantity'];
}
}
}
// Determine the shipping zone and retrieve additional costs
$shipping_zone = WC_Shipping_Zones::get_zone_matching_package($package);
$zone_id = $shipping_zone->get_id();
foreach ($rates as $rate_key => $rate) {
if ('flat_rate' === $rate->method_id) {
$extra_cost = isset($zone_costs['zone_' . $zone_id]) ? $zone_costs['zone_' . $zone_id] : 0;
$total_additional_cost = 0;
// Calculate the additional cost for each shipping class
foreach ($shipping_class_rates as $shipping_class => $qty_step) {
$rate_operand = ceil($item_counts[$shipping_class] / $qty_step);
$total_additional_cost += ($rate->cost * $rate_operand);
}
// Adjust the total cost
$rates[$rate_key]->cost = $total_additional_cost + $extra_cost;
}
}
return $rates;
}
i tried this solution but didn’t work, the wordpress ignored the cost based on quantity steps and add the cost of shipping zone only :
/*
WooCommerce - increase Flat rate shipping based on X quantity steps
*/
add_filter('woocommerce_package_rates', 'add_cost_based_on_zone_and_quantity', 10, 2);
function add_cost_based_on_zone_and_quantity($rates, $package) {
$shipping_class_rates = array(
'very-light' => 20, // Shipping class slug => Quantity threshold for a step
'light' => 10,
'pre-medium' => 5,
'medium' => 3,
'post-medium' => 2,
'heavy' => 1,
'very-heavy' => 0.2, // 1/5 as a fraction
'huge' => 0.1, // 1/10 as a fraction
'very-huge' => 1,
);
// Define extra costs by shipping zone ID
$zone_costs = array(
'zone_1' => 80, // Adjust these with actual zone IDs and costs
'zone_2' => 100,
'zone_3' => 120,
'zone_4' => 140,
);
// Initialize an array to keep track of item counts for each shipping class
$item_counts = array_fill_keys(array_keys($shipping_class_rates), 0);
// Calculate total item count in the cart
$total_items = 0;
foreach ($package['contents'] as $cart_item) {
$total_items += $cart_item['quantity'];
}
// Determine the shipping zone and retrieve additional costs
$shipping_zone = WC_Shipping_Zones::get_zone_matching_package($package);
$zone_id = $shipping_zone->get_id();
$extra_cost = isset($zone_costs['zone_' . $zone_id]) ? $zone_costs['zone_' . $zone_id] : 0;
if ($total_items <= 1) {
// If there is only one item, apply the zone cost only
foreach ($rates as $rate_key => $rate) {
if ('flat_rate' === $rate->method_id) {
$rates[$rate_key]->cost = $extra_cost;
}
}
} else {
// Count items per shipping class, excluding the first item
$first_item_excluded = false;
foreach ($package['contents'] as $cart_item) {
if (!$first_item_excluded) {
// Skip the first item
$first_item_excluded = true;
continue;
}
$class_id = $cart_item['data']->get_shipping_class_id();
foreach ($shipping_class_rates as $shipping_class => $qty_step) {
$term = get_term_by('slug', $shipping_class, 'product_shipping_class');
if ($term && $class_id == $term->term_id) {
$item_counts[$shipping_class] += $cart_item['quantity'];
}
}
}
foreach ($rates as $rate_key => $rate) {
if ('flat_rate' === $rate->method_id) {
$total_additional_cost = 0;
// Calculate the additional cost for each shipping class
foreach ($shipping_class_rates as $shipping_class => $qty_step) {
$rate_operand = ceil($item_counts[$shipping_class] / $qty_step);
$total_additional_cost += ($rate->cost * $rate_operand);
}
// Adjust the total cost
$rates[$rate_key]->cost = $total_additional_cost + $extra_cost;
}
}
}
return $rates;
}