Woocommerce shipping cost based on item quantity for specific shipping class - php

I posted this code a few hours ago. I managed to get through one of the issues, but i have only one question now. This code works well but I need to multiply the cost for every single item using an specific shipping class and then add it to the regular shipping cost.
Example if I have 5 products in the cart:
2 of them use shipping-class-1 ($70 extra shipping cost for product)
3 of them use shipping-class-2 ($50 extra shipping cost for product)
So if (for example) the regular shipping costs $120 then the shipping should be ($120 + $290) = $410
add_filter( 'woocommerce_package_rates', 'ph_add_extra_cost_based_on_shipping_class', 10, 2);
if( ! function_exists('ph_add_extra_cost_based_on_shipping_class') ) {
function ph_add_extra_cost_based_on_shipping_class( $shipping_rates, $package ){
$handling_fee_based_on_shipping_class = array(
array(
'shipping_classes' => array( 'shipping-class-1'), // Shipping Class slug array
'adjustment' => 70, // Adjustment
),
array(
'shipping_classes' => array( 'shipping-class-2' ),
'adjustment' => 50,
),
);
$shipping_method_ids = array( 'cologistics-shipping' ); // Shipping methods on which adjustment has to be applied
$adjustment = null;
foreach( $package['contents'] as $line_item ) {
$line_item_shipping_class = $line_item['data']->get_shipping_class();
if( ! empty($line_item_shipping_class) ) {
foreach( $handling_fee_based_on_shipping_class as $adjustment_data ) {
if( in_array( $line_item_shipping_class, $adjustment_data['shipping_classes']) ) {
$adjustment = ( $adjustment_data['adjustment'] > $adjustment ) ? $adjustment_data['adjustment'] : $adjustment;
}
}
}
}
if( ! empty($adjustment) ) {
foreach( $shipping_rates as $shipping_rate ) {
$shipping_method_id = $shipping_rate->get_method_id();
if( in_array($shipping_method_id, $shipping_method_ids) ) {
$shipping_rate->set_cost( (float) $shipping_rate->get_cost() + $adjustment );
}
}
}
return $shipping_rates;
}
}
I will really appreciate your help.
Thanks in advance!

This doesn't require any code normally… You should set your shipping method as follow (so first remove your code and save):
1) So you will keep 120 as global cost in your shipping method.
2) Then for each related desired shipping class you will add in the corresponding field:
[qty]*70 for shipping-class-1
[qty]*50 for shipping-class-2
Calculation type: Per class: Charge shipping for each shipping class individually
This will work and will add to the cost an amount by chipping class based on cart item quantity.
For a custom shipping method based on your code, you should use the following to handle item quantity:
add_filter( 'woocommerce_package_rates', 'ph_add_extra_cost_based_on_shipping_class', 10, 2);
if( ! function_exists('ph_add_extra_cost_based_on_shipping_class') ) {
function ph_add_extra_cost_based_on_shipping_class( $shipping_rates, $package ){
$handling_fee_based_on_shipping_class = array(
array(
'shipping_classes' => array( 'shipping-class-1'), // Shipping Class slug array
'adjustment' => 70, // Adjustment
),
array(
'shipping_classes' => array( 'shipping-class-2' ),
'adjustment' => 50,
),
);
$shipping_method_ids = array( 'cologistics-shipping' ); // Shipping methods on which adjustment has to be applied
$adjustment = 0;
foreach( $package['contents'] as $line_item ) {
$line_item_shipping_class = $line_item['data']->get_shipping_class();
if( ! empty($line_item_shipping_class) ) {
foreach( $handling_fee_based_on_shipping_class as $adjustment_data ) {
if( in_array( $line_item_shipping_class, $adjustment_data['shipping_classes']) ) {
$adjustment += $adjustment_data['adjustment'] * $line_item['quantity'];
}
}
}
}
if( $adjustment > 0 ) {
foreach( $shipping_rates as $shipping_rate ) {
$shipping_method_id = $shipping_rate->get_method_id();
if( in_array($shipping_method_id, $shipping_method_ids) ) {
$shipping_rate->set_cost( (float) $shipping_rate->get_cost() + $adjustment );
}
}
}
return $shipping_rates;
}
}
It should work handling car item quantity additional cost…
Don't forget to refresh shipping methods going to shipping settings, then disable/save and re-enable/save any shipping method in the related shipping zone.
Other answer threads related to woocommerce_package_rates hook.

Related

woocommerce function issue with wc_add_notice

Hello I am trying to add an error notice when this function is met if a user adds more than 1 item from tv series catergory the shipping method 'flat_rate:3' is removed from the shipping options, it works but I can not get the error notice to display to the user when this happens can you help please
add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
function hide_shipping_method_based_on_shipping_class( $rates, $package ) {
$categories = array('tv-series'); // Defined targeted product categories
$allowed_max_qty = 1; // Max allowed quantity for the shipping class
$shipping_rates_ids = array( // Shipping Method rates Ids To Hide
'flat_rate:3'
);
$related_total_qty = 0;
// Checking cart items for current package
foreach( $package['contents'] as $key => $cart_item ) {
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$related_total_qty += $cart_item['quantity'];
}
}
// When total allowed quantity is more than allowed (for items from defined shipping classes)
if ( $related_total_qty > $allowed_max_qty ) {
// Hide related defined shipping methods
foreach( $shipping_rates_ids as $shipping_rate_id ) {
if( isset($rates[$shipping_rate_id]) ) {
unset($rates[$shipping_rate_id]); // Remove Targeted Methods
}
}
}
return $rates;
{
if ( $allowed_max_qty > 1 ) {
wc_add_notice( '<strong>' . __( 'You are not allowed more than one TV Series on a Disc', 'woocommerce' ) . '</strong> ' . 'error' );
}
}
}

How can I change the shipping class to flat shipping? (woocommerce)

I'm working on hiding free shipping when there is a fixed price shipping amount based on certain products. This code is working and after certain sum is also disabled. But I want this to work with flat shipping conditional, not post class conditional.
I want it: if ( isset( $rates['flat_rate:1'] ) )
But it works: if ( $values[ 'data' ]->get_shipping_class_id() == $shipping_class_target )
add_filter( 'woocommerce_package_rates', 'bbloomer_hide_free_shipping_for_shipping_class', 9999, 2 );
function bbloomer_hide_free_shipping_for_shipping_class( $rates, $package ) {
$shipping_class_target = 261; // shipping class ID (to find it, see screenshot below)
$subtotal = WC()->cart->get_subtotal();
$in_cart = false;
foreach ( WC()->cart->get_cart_contents() as $key => $values ) {
if ( $values[ 'data' ]->get_shipping_class_id() == $shipping_class_target && $subtotal <= 299 ) {
$in_cart = true;
break;
}
}
if ( $in_cart ) {
unset( $rates['free_shipping:2'] ); // shipping method with ID (to find it, see screenshot below)
}
return $rates;
}

Show a custom shipping option when cart item quantity is over 24 items in Woocommerce

I want to show a free shipping option (not the standard woocommerce free shipping) provided by a plugin that's hooked up to a delivery service's api when the number of items in the cart reaches above 24.
I found the code below online that basically does what I'm after, only problem is that I need to specify the rendering of shipping options on the shipping method label and not the actual type of shipping method, like below, i.e. "free_shipping".
add_filter('woocommerce_package_rates', 'show_hide_free_shipping', 10, 2);
function show_hide_free_shipping($available_shipping_methods, $package){
$minimum_number_of_item = 24; //Give here minumum number of items to allow freeshipping
$free_shipping = false;
global $woocommerce;
$item_count = 0;
foreach (WC()->cart->cart_contents as $key => $item) {
$item_count += $item['quantity'];
}
if( $item_count >= $minimum_number_of_item ){
$free_shipping = true;
}
if($free_shipping){
foreach($available_shipping_methods as $shipping_method => $method){
if( strpos( $shipping_method, 'free_shipping' ) === false ) {
unset($available_shipping_methods[$shipping_method]);
}
}
}
else{
foreach($available_shipping_methods as $shipping_method => $method){
if( strpos( $shipping_method, 'free_shipping' ) !== false ) {
unset($available_shipping_methods[$shipping_method]);
}
}
}
return $available_shipping_methods;
}
I'm far from a php/wordpress wiz so I would deeply appreciate any help I could get.

Hide Flat Rate shipping exclusively for a product category in Woocommerce

This is an extension of this question: Remove shipping Flat Rate method for particular Category in WooCommerce 2.6 and 3+
Used the Woo Smart Coupons plugin for a Gift Card product. This HAS to be set to Variation, as we have multiple tiers to select from. (this rules out virtual products) The Gift Card has it's own category for distinction. We have two shipping options set up: Flat Rate + Local Pickup. It's pretty silly to have shipping options for a gift card that gets sent to your Inbox, so I used the following snippet found in the link above:
add_filter( 'woocommerce_package_rates', 'conditional_hide_shipping_methods', 100, 2 );
function conditional_hide_shipping_methods( $rates, $package ){
// Define/replace here your correct category slug (!)
$product_category = 'coupons-gift-cards';
$prod_cat = false;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id'];
if ( has_term( $product_category, 'product_cat', $product_id ) ){
$prod_cat = true;
}
}
$rates_arr = array();
if ( $prod_cat ) {
foreach($rates as $key => $rate) {
if ('free_shipping' === $rate->method_id || 'local_pickup' === $rate->method_id || 'local_delivery' === $rate->method_id) {
$rates_arr[ $rate_id ] = $rate;
break;
}
}
}
return !empty( $rates_arr ) ? $rates_arr : $rates;
}
Works like a charm... until you add a product that ISN'T from that category. If someone decides that they want a Gift Card AND a normal product, then the regular shipping options need to be back in place.
EDIT: The checked answer works perfectly! If you want to change the Pickup Label for items like the above situation so they say something like "Download" instead of "Pickup", then add this line after the IF statement that checks which products are matching the categories
foreach( $rates as $rate_key => $rate ) {
//change local_pickup:1 to your shipping method
if ( 'local_pickup:1' == $rate_key){
//set the text for the label
$rates[$rate_key]->label = __( 'Download', 'woocommerce' );
}
}
Here is the correct way to make it work for a unique and exclusive product category, that will hide Flat rate exclusively if there is no others products remaining to this product category:
add_filter( 'woocommerce_package_rates', 'hide_shipping_flat_rate_conditionaly', 90, 2 );
function hide_shipping_flat_rate_conditionaly( $rates, $package ){
// HERE Define your product category (ID, slug or name or an array of values)
$term = 'coupons-gift-cards';
$others = $found = false;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id'];
if ( has_term( $term, 'product_cat', $cart_item['product_id'] ) )
$found = true;
else
$others = true;
}
if ( $found && ! $others ) {
foreach($rates as $rate_id => $rate) {
if ('flat_rate' === $rate->method_id )
unset($rates[ $rate_id ]);
}
}
return $rates;
}
Code goes on function.php file of your active child theme (or active theme).
This code is tested and fully functional (it will work if you have correctly set your shipping zones).
You might need to refresh shipping cached data: disable, save and enable, save related shipping methods for the current shipping zone, in Woocommerce shipping settings.

Unsetting WooCommerce shipping method based on cart items shipping classes

I’m trying to unset Flat Rate shipping method only if cart has products both with and without shipping class. If all product in cart have shipping class then it should stay.
Have this shipping method: Flat Rate - (flat_rate1) (instance_id=1)
And these shipping classes: 50, 100 and so on, with same way named Slugs: 50, 100…
Flat Rate shipping method has costs set up for these shipping classes, Main Cost and No shipping class cost for this method are not set, so it only appears for products in cart that have shipping classes set.
Got it working
add_filter( 'woocommerce_package_rates', 'unset_shipping_for_unmatched_items', 100, 2 );
function unset_shipping_for_unmatched_items( $rates, $package ) {
// Initialisation
$shipping_classes = array( 50, 100, 150, 200, 250, 300 );
$cart_items = WC()->cart->get_cart();
$cart_items_count = WC()->cart->get_cart_contents_count();
$items_match = false;
$inArray = 0;
$notInArray = 0;
foreach( $cart_items as $cart_item ){
if( in_array( $cart_item[ 'data' ]->get_shipping_class(), $shipping_classes ) && $cart_items_count > 1 ) {
$inArray++;
} else {
$notInArray++;
}
}
if( ( $cart_items_count == $notInArray ) || ( $cart_items_count == $inArray ) ){
$items_match = false;
} else {
$items_match = true;
}
if( $items_match )
unset( $rates['flat_rate:6'] );
return $rates;
}
In WooCommerce the shipping methods ID slugs are a little different, I mean there is a typo error. You will need to add : between the name and the number in the slug: 'flat_rate6'.
Also once you get a matching cart item shipping class, you can break the loop.
Last thing: This hook has 2 available arguments: $rates and $package.
So your code will be:
add_filter( 'woocommerce_package_rates', 'hide_shipping_when_class_is_in_cart', 100, 2 );
function hide_shipping_when_class_is_in_cart( $rates, $package ) {
// Initialisation
$shipping_classes = array( 50, 100, 150, 200, 250, 300 );
$class_exists = false;
foreach( WC()->cart->get_cart() as $cart_item )
if( in_array( $cart_item[ 'data' ]->get_shipping_class_id(), $shipping_classes ) ) {
$class_exists = true;
break; // Stop the loop
}
if( $class_exists )
unset( $rates['flat_rate:6'] );
return $rates;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This should work now.

Categories