I have some custom code in my functions.php file that changes the shipping class from 343 to 344 if more than one product with the shipping class 343 is in the cart during checkout. However, I need to add weight in grams to the total order as well, based on the same conditions.
Namely, when only 1 product with the class 343 is in the cart during checkout, I want to add 14 grams to the total weight of the order. In any other condition, namely if there is at least 1 product with shipping class 344 in the cart, OR more than 1 product with the shipping class 343 in the cart, I want to add 54 grams to the total weight of the order.
Currently, if there is only one product shipping class 343 in the cart during checkout, it's calculated as being in this shipping class. However, if two products with shipping class are in the cart during checkout, they're changed to shipping class 344. And I want to add the aforementioned weight to the order based on this same condition.
//This turns 2 letter-box items into 1 standard package
add_action( 'woocommerce_before_calculate_totals', 'adjust_shipping_class_based_on_quantity' );
function adjust_shipping_class_based_on_quantity( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return; // Exit
if ( ! $cart->needs_shipping() )
return; // Exit
$count = 0; // Initialize
// Count items from a specific shipping class
foreach( $cart->get_cart() as $item ) {
if ( $item['data']->get_shipping_class_id() === 343 ) {
// Increment count for each item with shipping class ID 343
$count += $item['quantity'];
}
}
// Check that there are at least 2 items from the specific shipping class
if ( $count < 2 )
return; // Exit
// Loop through cart items to change the shipping class of items with the targeted shipping class
foreach( $cart->get_cart() as $item ) {
if ( $item['data']->get_shipping_class_id() === 343 ) {
$item['data']->set_shipping_class_id( 344 ); // Change the shipping class
}
}
}
While I'd yet come to the point where I could test any code conditional on the shipping class, I did try and see if this code below could add weight to the total order, but it caused an error instead.
add_action( 'woocommerce_cart_calculate_fees', 'add_extra_weight_to_order', 10, 1 );
function add_extra_weight_to_order( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
$extra_weight = 14;
$total_weight = $cart->get_cart_contents_weight();
$total_weight += $extra_weight;
$cart->set_cart_contents_weight( $total_weight );
}
How should I go about solving my problem?
Updated
Note that WC_Cart
set_cart_contents_weight()
method doesn't exist, so this is why you get an error in your last function.
The following, based on specific cart item shipping class ID quantity count:
// Utility function: Count items in cart from a specific shipping class Id
function get_cart_shipping_class_count( $targeted_class_id, $cart = null ) {
if ( ! $cart ) {
$cart = WC()->cart;
}
$count = 0; // Initialize
foreach( $cart->get_cart() as $item ) {
$product = wc_get_product($item['variation_id'] > 0 ? $item['variation_id'] : $item['product_id']);
if ( $product->get_shipping_class_id() === $targeted_class_id ) {
$count += $item['quantity'];
}
}
return $count;
}
// Increase cart content weight conditionally (handles weight unit conversion)
add_filter( 'woocommerce_cart_contents_weight', 'increase_conditionally_cart_contents_weight' );
function increase_conditionally_cart_contents_weight( $weight ) {
$qty_count = get_cart_shipping_class_count( 343 ); // Get shipping class qty count
$weight_unit = strtolower( get_option( 'woocommerce_weight_unit' ) ); // get weight unit
$conv_rate = $weight_unit === 'kg' ? 0.001 : 1; // Conversion rate from grams to kilos
if ( $qty_count === 1 && WC()->cart->get_cart_contents_count() === 1 ) {
$weight += 14 * $conv_rate;
} else {
$weight += 52 * $conv_rate;
}
return $weight;
}
// Change conditionally cart item shipping class
add_action( 'woocommerce_before_calculate_totals', 'adjust_shipping_class_based_on_quantity' );
function adjust_shipping_class_based_on_quantity( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return; // Exit
if ( ! $cart->needs_shipping() )
return; // Exit
// If there is only 1 items from the specific shipping class, we exit.
if ( get_cart_shipping_class_count( 343, $cart ) < 2 )
return; // Exit
// Loop through cart items to change the shipping class of items with the targeted shipping class
foreach( $cart->get_cart() as $item ) {
if ( $item['data']->get_shipping_class_id() === 343 ) {
$item['data']->set_shipping_class_id( 344 ); // Change the shipping class
}
}
}
Code goes in functions.php file of your child theme (or in a plugin). It should work.
Note: WC_Cart
Related: WooCommerce: Change Shipping Class conditionally for specific Zone