Tax based on cart subtotal - php

I'm trying with the code below to set to zero rate the tax when selling to a European Union state an order of value above 150 euro but I can't get it to work. Any idea what I'm doing wrong?
add_filter( 'woocommerce_product_get_tax_class', 'eu_tax_rate_based_on_subtotal', 1, 2 );
function eu_tax_rate_based_on_subtotal( $tax_class, $product ) {
$EU_countries = array('AT','BE','BG','CY','CZ','DE','DK','EE','ES','FI','FR','GR','HR','HU','IE','IT','LT','LU','LV','MT','NL','PL','PT','RO','SE','SI','SK');
if ( in_array( WC()->customer->get_shipping_country(), $EU_countries ) ){
if ( WC()->cart->subtotal >= 150 )
$tax_class = 'zero';
}
return $tax_class;
}

Use this filter if you want to remove taxes without a dynamic requirements.
function sto_calc_tax($taxes, $price, $rates, $price_includes_tax, $deprecated){
if (WC()->cart->subtotal >= 150 && in_array( WC()->customer->get_shipping_country(), array('AT','BE','BG','CY','CZ','DE','DK','EE','ES','FI','FR','GR','HR','HU','IE','IT','LT','LU','LV','MT','NL','PL','PT','RO','SE','SI','SK') ) ){
foreach ($taxes as $index => $tax) {
$taxes[$index] = 0;
}
}
return $taxes;
}
add_filter('woocommerce_calc_tax', 'sto_calc_tax', 10, 5);

Related

PHP How to disable shipping methods based on subtotal

I try to disable some shipping methods based on cart subtotal (after discounts).
// Disable Woocommerce shipping methods based on cart subtot
function wpsh_hide_shipping_based_on_subtotal( $rates, $package ) {
// Retrieve cart subtotal
//$cart_subtotal = $package['contents_cost'];
$cart_subtotal = WC()->cart->get_cart_contents_total();
// Shipping rate to be excluded
$shipping_id1 = 'flat_rate:73';
$shipping_id2 = 'flat_rate:75';
$shipping_id3 = 'local_pickup:69';
$shipping_id4 = 'flat_rate:76';
$shipping_id5 = 'local_pickup:79';
if ( $cart_subtotal < 99 ){
unset( $rates[ $shipping_id4 ] );
unset( $rates[ $shipping_id5 ] );
}
if ( $cart_subtotal >= 99 ){
unset( $rates[ $shipping_id1 ] );
unset( $rates[ $shipping_id2 ] );
unset( $rates[ $shipping_id3 ] );
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'wpsh_hide_shipping_based_on_subtotal', 10, 2 );
This seems to work, but sometimes, especially with variable products it doesnt hide shipping methods below 99 subtotal. I dont have any clues why. Can you help me?
Try with woocommerce_shipping_packages to hide the shipping method.
add_filter( 'woocommerce_shipping_packages', array( $this, 'hide_shipping_rates_from_packages'), 10, 1 );
public function hide_shipping_rates_from_packages( $packags ) {
if ( !empty( WC()->cart ) ) {
$cart_subtotal = wc_format_decimal( WC()->cart->get_cart_subtotal( false ) ); // Without include compound taxes.
if ( $cart_subtotal < 80 ) {
foreach( $packags as $index => $package ) {
unset($packags[$index]['rates']['free_shipping:1']);
}
}
}
return $packags;
}
For recurring carts, use the woocommerce_package_rates filter to hide shipping methods. This filter affects the session-stored package details and this filter is not triggered when rates are stored in the WC session data for this package.
add_filter( 'woocommerce_package_rates', array( $this, 'hide_shipping_rates_from_package_rates'), 10, 2 );
public function hide_shipping_rates_from_package_rates( $package_rates, $package ) {
if ( !empty( WC()->cart ) ) {
$cart_subtotal = wc_format_decimal( WC()->cart->get_cart_subtotal( false ) ); // Without include compound taxes.
if ( $cart_subtotal < 80 ) {
unset($packag_rates['free_shipping:1']);
}
}
return $packag_rates;
}

Hide free shipping when subtotal is greater than 0 in WooCommerce

I'm using Free Product Sample for the WooCommerce plugin and trying to set conditional free shipping only for a Sample product, sample product cost is 0 and therefore I'm trying to hide free shipping unless the order subtotal amount is 0.
To put it in a nutshell:
I want to offer free shipping only for sample products and, the free shipping method should only visible for a product having subtotal = 0
Screenshot for further clarification:
My attempted code:
function ts_hide_shipping_for_order_total( $rates ) {
$rate = array();
$order_total = WC()->cart->get_subtotal();
if( $order_total > 0 ) {
foreach ( $rates as $rate_id => $rate ) {
if ( 'free_shipping:20' === $rate->get_method_id() ) {
$rate[ $rate_id ] = $rate;
}
}
}
return ! empty( $free ) ? $free : $rates;
}
add_filter( 'woocommerce_package_rates', 'ts_hide_shipping_for_order_total', 100 );
OR
add_filter( 'woocommerce_package_rates', 'hide_shipping_except_local_when_free_is_available', 100 );
function hide_shipping_except_local_when_free_is_available($rates) {
$free = $local = array();
foreach ( $rates as $rate_id => $rate ) {
if ( 'free_shipping:20' === $rate->method_id ) {
$free[ $rate_id ] = $rate;
}
}
return ! empty( $free ) ? array_merge( $free, $local ) : $rates;
}
But both codes do not give me the desired result. Can anyone point me in the right direction?
To hide/unset the "free shipping", as long as the subtotal is greater than 0, you can use the following.
So you get:
function filter_woocommerce_package_rates( $rates, $package ) {
// Get subtotal
$subtotal = $package['cart_subtotal'];
// Hide free shipping if subtotal > 0
if ( $subtotal > 0 ) {
// Loop trough
foreach ( $rates as $rate_id => $rate ) {
if ( $rate->method_id === 'free_shipping' ) {
unset( $rates[$rate_id] );
}
}
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 10, 2 );
Additional question: Hide the other methods when subtotal <= 0
function filter_woocommerce_package_rates( $rates, $package ) {
// Get subtotal
$subtotal = $package['cart_subtotal'];
// Loop trough
foreach ( $rates as $rate_id => $rate ) {
if ( $rate->method_id === 'free_shipping' ) {
// Hide free shipping if subtotal > 0
if ( $subtotal > 0 ) {
unset( $rates[$rate_id] );
}
} else {
// Hide other methods when subtotal <= 0
if ( $subtotal <= 0 ) {
unset( $rates[$rate_id] );
}
}
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 10, 2 );

WooCommerce remove shipping method based on product IDs & quantity bought

I am trying to remove a shipping method based on two parameters in my cart.
Parameter 1 = Product ID
Parameter 2 = Quantity added for that Product ID.
I have been searching around and combining different solutions, however using the snippet underneath still doesn't give me the correct result. The expected result would be that if any of the products ( 6 , 9, 69 , 71 ) are added 52 times to my cart, the shipping fee (flexible_shipping_2_1) should dissapear.
All suggestions would be appreciated.
add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods', 10, 2 );
function specific_products_shipping_methods( $rates, $package ) {
$product_ids = array( 6 , 9, 69 , 71 ); // HERE set the product IDs in the array
$method_id = 'flexible_shipping_2_1'; // HERE set the shipping method ID
$found = false;
// Loop through cart items Checking for defined product IDs
foreach( WC()->cart->get_cart_contents() as $cart_item_key => $cart_item ) {
if ( in_array( $cart_item['product_id'], $product_ids ) && $cart_item['quantity'] == 52){
$found = true;
break;
}
}
if ( $found )
unset( $rates[$method_id] );
return $rates;
}
Maybe this is what you would like (to get the cumulated quantity for all defined product ids):
add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods', 10, 2 );
function specific_products_shipping_methods( $rates, $package ) {
$product_ids = array( 6 , 9, 69 , 71 ); // HERE set the product IDs in the array
$method_id = 'flexible_shipping_2_1'; // HERE set the shipping method ID
$quantity = 0;
// Get cart items for the current shipping package
foreach( $package['contents'] as $cart_item ) {
if ( in_array( $cart_item['product_id'], $product_ids ) ){
$quantity += $cart_item['quantity'];
}
}
if ( $quantity >= 52 && isset($rates[$method_id]) ) {
unset($rates[$method_id]);
}
return $rates;
}
Don't forget to empty your cart, to refresh shipping cached data…

Change product prices based on a custom rate in Woocommerce

In Woocommerce I am using woocommerce_product_get_price like to alter my product prices and it is working fine… But when I add to cart a product, the cart total and cart item are zero.
That is my code:
add_filter( 'woocommerce_add_cart_item', 'set_custom_cart_item_prices', 20, 2 );
function set_custom_cart_item_prices( $cart_data, $cart_item_key ) {
$new_price = $cart_data['data']->get_price() * 2;
$cart_data['data']->set_price( $new_price );
$cart_data['new_price'] = $new_price;
return $cart_data;
}
add_filter( 'woocommerce_get_cart_item_from_session', 'set_custom_cart_item_prices_from_session', 20, 3 );
function set_custom_cart_item_prices_from_session( $session_data, $values, $key ) {
if ( ! isset( $session_data['new_price'] ) || empty ( $session_data['new_price'] ) )
return $session_data;
$session_data['data']->set_price( $session_data['new_price'] );
return $session_data;
}
Its doesn't work. I have also tried to use woocommerce_before_calculate_totals without success
How to avoid zero prices on cart? Any help is appreciated.
Updated: You are not using the correct hooks and the correct way. The following will replace all your code. The price changes will be done on simple products, variable products and product variations.
The 1st function is the rate to be applied to your product prices (so you will define in it your rate calculation).
The 2nd function will change all products displayed price on all product pages instead of using your custom function hooked in woocommerce_product_get_price filter hook.
The 3rd Function will change the products price in cart items, on cart and checkout pages and in orders items too.
// The price rate to be applied
function get_product_price_rate() {
// HERE define the price rate to be applied
return 1.25; // +25%
}
// Change the product displayed price on product pages
add_filter( 'woocommerce_get_price_html', 'custom_price_html', 10, 2 );
function custom_price_html( $price, $product ){
$rate = get_product_price_rate();
// Simple products and product variations
if( in_array( $product->get_type() , array( 'simple' , 'variation' ) ) ) {
$regular_price = wc_get_price_to_display( $product, array( 'price' => ( $product->get_regular_price() * $rate ) ) );
$active_price = wc_get_price_to_display( $product, array( 'price' => ( $product->get_price() * $rate ) ) );
if ( '' === $product->get_price() ) {
$price = apply_filters( 'woocommerce_empty_price_html', '', $product );
} elseif ( $product->is_on_sale() ) {
$price = wc_format_sale_price( $regular_price, $active_price ) . $product->get_price_suffix();
} else {
$price = wc_price( $active_price ) . $product->get_price_suffix();
}
}
// Variable products
elseif ( 'variable' === $product->get_type() ) {
$prices = $product->get_variation_prices( true );
if ( empty( $prices['price'] ) ) {
$price = apply_filters( 'woocommerce_variable_empty_price_html', '', $this );
} else {
$min_price = current( $prices['price'] ) * $rate;
$max_price = end( $prices['price'] ) * $rate;
$min_reg_price = current( $prices['regular_price'] ) * $rate;
$max_reg_price = end( $prices['regular_price'] ) * $rate;
if ( $min_price !== $max_price ) {
$price = wc_format_price_range( $min_price, $max_price );
} elseif ( $this->is_on_sale() && $min_reg_price === $max_reg_price ) {
$price = wc_format_sale_price( wc_price( $max_reg_price ), wc_price( $min_price ) );
} else {
$price = wc_price( $min_price );
}
$price .= $product->get_price_suffix();
}
}
return $price;
}
// Change cart items prices (and order items prices)
add_action('woocommerce_before_calculate_totals', 'increase_cart_item_prices', 100, 1 );
function increase_cart_item_prices( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop Through cart items
foreach ( $cart->get_cart() as $cart_item ) {
$rate = get_product_price_rate();
$cart_item['data']->set_price( $cart_item['data']->get_price() * $rate );
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Custom Coupon type woocommerce wordpress

I need to create custom coupon type. Because i had custom calculation for custom coupon. Anyone out there help me.
Coupon calculation:
the cart has one product and value is 5000, then custom coupon code applied. The cart total need to change 2000. Similarly the cart has 2 product and value is 7000. If the custom coupon code applied, then cart total need to be 4000.
So the coupon need to make the cart total as flat 2000 for one product
In newer versions of WooCommerce, you will need to
Register a custom coupon type
Validate the coupon
Calculate & Apply the discount
Register custom coupon type
add_filter( 'woocommerce_coupon_discount_types', 'custom_coupon_type',10, 1);
function custom_coupon_type( $discount_types ) {
$discount_types['my_type'] =__( 'My New Coupon Type', 'woocommerce' );
return $discount_types;
}
Validate the coupon
add_filter('woocommerce_coupon_is_valid_for_product', 'validate_custom_coupon', 10, 4);
function validate_custom_coupon($valid, $product, $coupon, $values){
if ( ! $coupon->is_type( array( 'my_type' ) ) ) {
return $valid;
}
$product_cats = wp_get_post_terms( $product->id, 'product_cat', array( "fields" => "ids" ) );
// SPECIFIC PRODUCTS ARE DISCOUNTED
if ( sizeof( $coupon->product_ids ) > 0 ) {
if ( in_array( $product->id, $coupon->product_ids ) || ( isset( $product->variation_id ) && in_array( $product->variation_id, $coupon->product_ids ) ) || in_array( $product->get_parent(), $coupon->product_ids ) ) {
$valid = true;
}
}
// CATEGORY DISCOUNTS
if ( sizeof( $coupon->product_categories ) > 0 ) {
if ( sizeof( array_intersect( $product_cats, $coupon->product_categories ) ) > 0 ) {
$valid = true;
}
}
// IF ALL ITEMS ARE DISCOUNTED
if ( ! sizeof( $coupon->product_ids ) && ! sizeof( $coupon->product_categories ) ) {
$valid = true;
}
// SPECIFIC PRODUCT IDs EXLCUDED FROM DISCOUNT
if ( sizeof( $coupon->exclude_product_ids ) > 0 ) {
if ( in_array( $product->id, $coupon->exclude_product_ids ) || ( isset( $product->variation_id ) && in_array( $product->variation_id, $coupon->exclude_product_ids ) ) || in_array( $product->get_parent(), $coupon->exclude_product_ids ) ) {
$valid = false;
}
}
// SPECIFIC CATEGORIES EXLCUDED FROM THE DISCOUNT
if ( sizeof( $coupon->exclude_product_categories ) > 0 ) {
if ( sizeof( array_intersect( $product_cats, $coupon->exclude_product_categories ) ) > 0 ) {
$valid = false;
}
}
// SALE ITEMS EXCLUDED FROM DISCOUNT
if ( $coupon->exclude_sale_items == 'yes' ) {
$product_ids_on_sale = wc_get_product_ids_on_sale();
if ( isset( $product->variation_id ) ) {
if ( in_array( $product->variation_id, $product_ids_on_sale, true ) ) {
$valid = false;
}
} elseif ( in_array( $product->id, $product_ids_on_sale, true ) ) {
$valid = false;
}
}
return $valid;
}
Calculate & Apply Discount
add_filter('woocommerce_coupon_get_discount_amount', 'wc_cpn_disc', 10, 5);
function wc_cpn_disc($discount, $discounting_amount, $cart_item, $single, $coupon) {
// IF TYPE MATCHES PERFORM CUSTOM CALCULATION
if ($coupon->type == 'my_type')
$discount = $cart_item['quantity'] * 2000;
return $discount;
}
Sources:
#raju_odi's answer on this exact question
#Chris Morris's answer to Woocommerce custom coupon type with custom discount always return 0
Please use below code in your active theme's function.php
function custom_discount_type( $discount_types ) {
$discount_types['custom_discount'] =__( 'custom discount', 'woocommerce' );
return $discount_types;
}
// add the hooks
add_filter( 'woocommerce_coupon_discount_types', 'custom_discount_type',10, 1);
//function to get coupon amount for "custom_discount"
function woocommerce_coupon_get_discount_amount($discount, $discounting_amount, $cart_item, $single, $coupon) {
if ($coupon->code == 'custom'){
//echo "yes custom discount"; //if $coupon->type == 'fixed_cart' or 'percent' or 'fixed_product' or 'percent_product' The code Works
$discount = $cart_item['quantity'] * 2000;
return $discount;
} else {
return $discount;
}
}
//add hook to coupon amount hook
add_filter('woocommerce_coupon_get_discount_amount', 'woocommerce_coupon_get_discount_amount', 10, 5);
Note : Please add your added coupon name here on this line if ($coupon->code == 'your_added_coupon_here')
Working fine and tested.

Categories