I have this issue where I want for members to receive free delivery. I have figured out how to do that, but now I get an error on the page.
The error is:
The WC_Cart->taxes function is deprecated since version 3.2. Replace
with getters (WC_Cart::get_cart_contents_taxes()) and setters
(WC_Cart::set_cart_contents_taxes())., referer:
This is the code that generates the problem:
add_filter('woocommerce_package_rates','test_overwrite_fedex', 100, 2);
function test_overwrite_fedex($rates,$package)
{
$memberships = wc_memberships_get_user_active_memberships();
if (WC()->customer->get_shipping_country() === 'DK' && !empty($memberships))
{
foreach ($rates as $rate)
{
//Set the TAX
$rate->taxes[1] = 0;
}
}
return $rates;
}
I have tried with:
$rate->set_shipping_total('0');
WC()->cart->set_shipping_total('0');
$rate = WC()->cart->get_shipping_total();
And still no luck.
The Taxes for shipping methods rates are set in a more complex multidimensional array, so your code make an error. Also you just forgot to null the rate cost.
You may have to "Enable debug mode" in general shipping settings under "Shipping options" tab, to disable temporarily shipping caches.
Try the following code that will null any shipping method cost for a specific country (DK) and for active members:
add_filter('woocommerce_package_rates', 'conditionally_remove_shipping_rates_cost', 25, 2);
function conditionally_remove_shipping_rates_cost( $rates, $package ){
$memberships = wc_memberships_get_user_active_memberships();
if ( WC()->customer->get_shipping_country() === 'DK' && !empty($memberships) ) {
// Loop through the shipping taxes array
foreach ( $rates as $rate_key => $rate ){
$has_taxes = false;
// Not for free shipping
if( 'free_shippping' !== $rate->method_id ){
// Taxes rate cost (if enabled)
$taxes = [];
// Null the shippin cost
$rates[$rate_key]->cost = 0;
// Loop through the shipping taxes array (as they can be many)
foreach ($rates[$rate_key]->taxes as $key => $tax){
if( $rates[$rate_key]->taxes[$key] > 0 ){
// Null tax cost
$taxes[$key] = 0;
$has_taxes = true;
}
}
if( $has_taxes )
$rates[$rate_key]->taxes = $taxes;
}
}
}
return $rates;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works (without the membership function).
Don't forget to enable back shipping cache.
Related
Based on Set custom shipping rates programmatically in Woocommerce 3 answer code, I modified it in order to add a discount on shipping rates for each seller.
add_filter( 'woocommerce_package_rates', 'custom_shipping_methods', 10, 2 );
function custom_shipping_methods( $rates, $package ) {
$reduction_cost_percentage = 30; // Discount percentage
foreach( WC()->cart->get_cart() as $cart_item ){
$in_cart_product_id = $cart_item['product_id'];
$cart_seller_id = get_post_field('post_author', $in_cart_product_id);
$cart_seller_meta = get_userdata($cart_seller_id);
$cart_seller_roles = $cart_seller_meta->roles;
if($cart_seller_roles[0] == 'seller'){
foreach( $rates as $rate_key => $rate ){
if( $rate->method_id != 'free_shipping'){
$rates[$rate_key]->cost = $rates[$rate_key]->cost * ((100-$reduction_cost_percentage) / 100);
return $rates;
}
}
}
}
}
Now I want to exclude this discount from a certain role for example seller_2. How can I do this?
There are some mistakes and oversights in your code, try the following instead:
add_filter( 'woocommerce_package_rates', 'custom_shipping_methods', 10, 2 );
function custom_shipping_methods( $rates, $package ) {
// Loop through cart items for the current package
foreach( $package['contents'] as $cart_item ){
$seller_id = get_post_field('post_author', $cart_item['product_id']);
$seller_data = get_userdata($seller_id);
// Excluding product 'seller' user role
if ( ! empty($seller_data) && is_array($seller_data->roles) && in_array('seller', $seller_data->roles) ) {
return $rates; // stop the loop and return normally the shipping rates
}
}
$percentage = 30; // <== Set your discount percentage
$discount_rate = $percentage / 100;
// Loop through shipping rates for the current package when seller user role is not found
foreach( $rates as $rate_key => $rate ){
// Not for free shipping
if( $rate->method_id != 'free_shipping' ){
// Change rate cost
$rates[$rate_key]->cost = $rate->cost * $discount_rate;
$taxes = array(); // Initializing
// change taxes rate cost (if enabled)
foreach ($rate->taxes as $key => $tax){
if( $tax > 0 ){
$taxes[$key] = $tax * $discount_rate;
$has_taxes = true;
}
}
// Change taxes cost
if( $has_taxes ) {
$rates[$rate_key]->taxes = $taxes;
}
}
}
return $rates;
}
Code goes in function.php file of your active child theme (active theme). It should works.
Clearing shipping caches:
You will need to empty your cart, to clear cached shipping data
Or In shipping settings, you can disable / save any shipping method, then enable back / save.
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.
We're selling sample products on our Woocommerce site, which is just a variable product. The product has a unique shipping class that allows it to be delivered for 1.99.
Actually this cost is always set when if item belongs to that unique shipping class, even if there is other items.
I would like if possible to enable that shipping cost only if that specific item (from that unique shipping class) is alone in cart.
Any help is appreciated.
The following hooked function will set the shipping cost to 0 if an items with a specific shipping class are melted to other items:
add_filter('woocommerce_package_rates', 'conditional_shipping_class_cost', 15, 2);
function conditional_shipping_class_cost( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
// HERE define the targeted shipping method
$shipping_class = 'Extra';
// Initializing variables
$found = $others = false;
// Loop through cart items and checking for the specific product
foreach( $package['contents'] as $item ) {
if( $item['data']->get_shipping_class() == sanitize_title($shipping_class) ){
$found = true; // Has the shipping class
} else {
$others = true; // NOT the shipping class
}
}
// When items with the defined shipping are not alone in cart
if( $found && $others ){
// Loop through shipping rates
foreach ( $rates as $rate_key => $rate ){
// For Flat rate and Local pickup shipping methods
if( $rate->method_id == 'flat_rate' ) {
// Set the cost to zero
$rates[$rate_key]->cost = 0;
$rates[$rate_key]->label = 'f: '.$found.' | o: '.$others.' ';
// Initializing variables
$has_taxes = false;
$taxes = [];
// Loop through the shipping taxes array (as they can be many)
foreach ($rates[$rate_key]->taxes as $key => $tax){
if( $rates[$rate_key]->taxes[$key] > 0 ){
// Set the tax cost to zero
$taxes[$key] = 0;
$has_taxes = true;
}
}
// Set new taxes cost array
if( $has_taxes )
$rates[$rate_key]->taxes = $taxes;
}
}
}
return $rates;
}
This code goes on function.php file of your active child theme (or theme). Tested and works.
I have a specific coupon which is special50. When someone applied this coupon on the store then a new shipping method need to add. When current shipping method price is $50 (flat rate) and after applying coupon new shipping method, pricing will be $25. In a word, if you apply this coupon you will receive 50% OFF on products(which WooCommerce has already provided to us) and 50% OFF on shipping(which really I need).
add_action( 'woocommerce_flat_rate_shipping_add_rate', 'add_another_custom_flat_rate', 10, 2 );
function add_another_custom_flat_rate( $method, $rate ) {
$new_rate = $rate;
$new_rate['id'] .= ':' . 'custom_rate_name';
$new_rate['label'] = 'Shipping and handling';
global $woocommerce, $wpdb;
$coupon = "SELECT post_title FROM {$wpdb->posts} WHERE post_title='special50' AND post_type ='shop_coupon' AND post_status ='publish'";
if(in_array($coupon_id, $woocommerce->cart->applied_coupons)){
$cost = 25;
}
$new_rate['cost'] = $cost;
$method->add_rate( $new_rate );
}
This can be done using the following custom function hooked in woocommerce_package_rates filter hook, without any need of creating an additional discounted flat rate. The following code will change the "flat rate" shipping method cost when 'special50' coupon is applied.
You should first "Enable debug mode" in Woocommerce settings > shipping > Shipping options.
The code:
add_filter('woocommerce_package_rates', 'coupon_discount_on_flat_rate', 10, 2);
function coupon_discount_on_flat_rate( $rates, $package ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
// Checking for 'special50' in applied coupons
if( in_array( 'special50', WC()->cart->get_applied_coupons() ) ){
foreach ( $rates as $rate_key => $rate ){
$has_taxes = false;
// Targeting "flat rate" shipping method
if( $rate->method_id === 'flat_rate' ){
// Set 50% of the cost
$rates[$rate_key]->cost = $rates[$rate_key]->cost / 2;
// Taxes rate cost (if enabled)
foreach ($rates[$rate_key]->taxes as $key => $tax){
if( $rates[$rate_key]->taxes[$key] > 0 ){
$has_taxes = true;
// set 50% of the cost
$taxes[$key] = $rates[$rate_key]->taxes[$key] / 2;
}
}
if( $has_taxes )
$rates[$rate_key]->taxes = $taxes;
}
}
}
return $rates;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Dont forget to disable "Enable debug mode" once this has been tested and works.
I calculate my flat rate shipping cost like this: x * [qty]
I also want to use this method for my local pickup methods but using the function like shown above, does not work.
How can I achieve a shipping cost calculation based on the item quantity?
WordPress: 4.8.4 / WooCommerce: 3.1.1
Link to the page: http://www.minimoto.me/
UPDATE:
After the first helpful answer, this is the code I'm using:
add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
function hide_shipping_method_based_on_shipping_class( $rates, $package )
{
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
## ----- 1. Hiding shipping methods based on shipping class 92 ----- ##
// HERE define your shipping class to find
$class = 92;
// HERE define the shipping methods you want to hide
$method_key_ids = array('local_pickup:8');
// Checking in cart items
foreach( WC()->cart->get_cart() as $cart_item ){
// If we find the shipping class
if( $cart_item['data']->get_shipping_class_id() == $class ){
foreach( $method_key_ids as $method_key_id ){
unset($rates[$method_key_id]); // Remove the targeted methods
}
break; // Stop the loop
}
}
## ----- 2. Hiding shipping methods based on shipping class 132 ----- ##
// HERE define your shipping class to find
$class = 132;
// HERE define the shipping methods you want to hide
$method_key_ids = array('local_pickup:2', 'local_pickup:3', 'local_pickup:4');
// Checking in cart items
foreach( WC()->cart->get_cart() as $cart_item ){
// If we find the shipping class
if( $cart_item['data']->get_shipping_class_id() == $class ){
foreach( $method_key_ids as $method_key_id ){
unset($rates[$method_key_id]); // Remove the targeted methods
}
break; // Stop the loop
}
}
## ------- 3. Charge local pickup costs per item quantity ------- ##
$cart_items_count = WC()->cart->get_cart_contents_count(); // Cart items count
// Iterating through Shipping Methods
foreach ( $rates as $rate_key => $rate ) {
$method_id = $rate_values->method_id;
$rate_id = $rate_values->id;
// For "Local pickup" Shipping" Method only
if ( 'local_pickup' === $method_id ) {
if( ! empty( $rates[$rate_id]->cost && $rates[$rate_id]->cost > 0 ) ) {
// Set the rate calculated cost based on cart items count
$rates[$rate_id]->cost = number_format($rates[$rate_id]->cost * $cart_items_count, 2);
// Taxes rate cost (if enabled)
foreach ($rates[$rate_id]->taxes as $key => $tax){
if( $rates[$rate_id]->taxes[$key] > 0 ){ // set the new tax cost
$taxes[$key] = number_format( $rates[$rate_id]->taxes[$key] * $cart_items_count, 2 );
$has_taxes = true;
} else {
$has_taxes = false;
}
}
if( $has_taxes )
$rates[$rate_id]->taxes = $taxes;
}
}
}
return $rates;
}
You can make this in your existing customized code from this answer, using the custom function hooked in woocommerce_package_rates action hook.
With the following code, Your local pickup shipping methods costs will be multiplied by the total cart items count:
add_filter( 'woocommerce_package_rates', 'customizing_shipping_methods', 10, 2 );
function customizing_shipping_methods( $rates, $package )
{
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
## ----- 1. Hiding shipping methods based on shipping class ----- ##
// HERE define your shipping class to find
$class = 92;
// HERE define the shipping methods you want to hide
$method_key_ids = array('flat_rate:7', 'local_pickup:3');
// Checking in cart items
foreach( WC()->cart->get_cart() as $cart_item ){
// If we find the shipping class
if( $cart_item['data']->get_shipping_class_id() == $class ){
foreach( $method_key_ids as $method_key_id ){
unset($rates[$method_key_id]); // Remove the targeted methods
}
break; // Stop the loop
}
}
## ------- 2. Charge local pickup costs per item quantity ------- ##
$cart_items_count = WC()->cart->get_cart_contents_count(); // Cart items count
// Iterating through Shipping Methods
foreach ( $rates as $rate_key => $rate_values ) {
$method_id = $rate_values->method_id;
$rate_id = $rate_values->id;
// For "Local pickup" Shipping" Method only
if ( 'local_pickup' === $method_id ) {
if( ! empty( $rates[$rate_id]->cost && $rates[$rate_id]->cost > 0 ) ) {
// Set the rate calculated cost based on cart items count
$rates[$rate_id]->cost = number_format($rates[$rate_id]->cost * $cart_items_count, 2);
// Taxes rate cost (if enabled)
foreach ($rates[$rate_id]->taxes as $key => $tax){
if( $rates[$rate_id]->taxes[$key] > 0 ){ // set the new tax cost
$taxes[$key] = number_format( $rates[$rate_id]->taxes[$key] * $cart_items_count, 2 );
$has_taxes = true;
} else {
$has_taxes = false;
}
}
if( $has_taxes )
$rates[$rate_id]->taxes = $taxes;
}
}
}
return $rates;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works
Sometimes, you should may be need to refresh shipping methods going to shipping areas, then disable / save and re-enable / save your "flat rate" and "local pickup" shipping methods.