I've tried researching an answer for this problem now for the last 4 hours and I haven't managed to find an answer.
I have a custom fee added to my woocommerce checkout page. this is due to complicated delivery calculations which woocommerce shipping was unable to provide.
I now need to create a coupon to set this custom fee to zero if the coupon is entered.
This is setting my my custom fee
WC()->cart->add_fee( __('Shipping', 'woocommerce'), $shipping_price );
This is what I need to achieve.
if($coupon_code == "this-string"){
$shipping_price = 0;
}
I need a way to check if the coupon code submitted is equal to "this-string" and if it is I need to set $shipping Fee to zero.
Please all help will be appreciated.
You can call WC()->cart->get_applied_coupons() to get all the coupons applied to the cart. Then you can check if your coupon code is in that array. Something like this:
if(in_array($coupon_code, WC()->cart->get_applied_coupons())) {
// Do something
}
Untested, but I think you would want to do something when the code is applied, so the woocommerce_applied_coupon hook is relevant.
function so_46429329_applied_coupon( $coupon_code ) {
if( $coupon_code == "this-string" ){
$shipping_price = 0;
WC()->cart->add_fee( __('Shipping', 'woocommerce'), $shipping_price );
}
}
add_action( 'woocommerce_applied_coupon', 'so_46429329_applied_coupon' );
The part that I haven't tested is whether this overrides an existing 'Shipping Fee' or if you need to find a way to remove that first.
the below Function will add a shipping fee to your woo-commerce Cart which adds to the checkout price afterwards.
// ADD SHIPPING COST
function woo_add_cart_fee() {
WC()->cart->add_fee( __('Shipping', 'woocommerce'), 100 );
}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
If you want to apply a custom coupon to the shipping fee you could do something along the lines of this
// ADD SHIPPING COST
function woo_add_cart_fee() {
$custom_coupon = $_GET["coupon_name"];
if ($custom_coupon = 'discount_code_half') {
WC()->cart->add_fee( __('Shipping', 'woocommerce'), 100 );
}elseif ($custom_coupon = 'discount_code_more_than_half') {
WC()->cart->add_fee( __('Shipping', 'woocommerce'), 50 );
}elseif ($custom_coupon = 'discount_code_free') {
WC()->cart->add_fee( __('Shipping', 'woocommerce'), 0 );
}else ( ! $custom_coupon) {
WC()->cart->add_fee( __('Shipping', 'woocommerce'), 200 );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
For this method to work you will need to have a coupon button to submit a coupon name to the cart page.
Either from the previous page or you could just have it submit to the same page it is on. Either way your page will have to refresh so you can use the
$custom_coupon = $_GET["coupon_name"];
Hope this answer helps. :)
Related
I applied a 5% discount to the Woocommerce cart, based on cart amount and shipping method, which seems to be working fine. But I cannot manage to change the shipping method title when the rule applies, i need to add a message "5% discount" to all local-pickup methods.
I found a workarround using conditional shipping, but that won´t work in this website, I need to use the same method, but adding a message to the title.
Any ideas?
This is my code:
function local_pickup_discount( $cart ) {
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$carrito_total = WC()->cart->get_cart_contents_total();
$chosen_shipping_no_ajax = $chosen_methods[0];
if ( 0 === strpos( $chosen_shipping_no_ajax, 'local_pickup' ) && $carrito_total < 60000) {
$discount = $cart->subtotal * 0.05; // 5% discount applied here
$cart->add_fee( __( 'Descuento por retiro en sucursal', 'yourtext-domain' ) , -$discount ); // Fee descripton
}
}
add_action( 'woocommerce_cart_calculate_fees', 'local_pickup_discount');
Thanks in advance, i know this must be a very simple thing to do, but i am not used to work with php.
You have to use this hook to rename your label woocommerce_cart_shipping_method_full_label. Inside you can apply any conditional logic you want and output label with custom one.
Note: This label is used in both cart and checkout. So if you want it only on checkout add condition is_checkout() or is_cart() if you want to limit it.
function wc_change_local_pickup_label( $label, $method ) {
$carrito_total = WC()->cart->get_cart_contents_total();
if ( $carrito_total < 60000 && 'local_pickup' === $method->method_id) {
$label = "Local pickup 5% discount";
}
return $label;
}
add_filter( 'woocommerce_cart_shipping_method_full_label', 'wc_change_local_pickup_label', 10, 2 );
Is there any way to remove a fee from an Woocommerce order before saving it to the database?
I have tried the following hooks, to no success
woocommerce_before_save_order_items
woocommerce_calculate_totals
wp_insert_post_data
I also tried to edit the fee total as below, but the fee still gets saved to the database
add_action( 'woocommerce_review_order_before_payment', 'cst_my_hook_1', 10, 3);
function cst_my_hook_1() {
WC()->cart->set_fee_total(0);
}
I am sharing a screenshot to make my requirements more clear. Woocommerce cart class (class-wc-cart.php) contains a public function to add fees, so I think there should be ways to remove it too.
I used the hook "woocommerce_cart_calculate_fees" to add the fee shown in the screenshot. Now I want to remove it before saving to DB.
I am using Wordpress 5.7.1, Woocommerce 5.2.1
To disable fees from order once checking out, use this simple following hooked function, that will clean all fees from orders and email notifications:
add_action( 'woocommerce_checkout_order_created', 'order_created_disable_fees' );
function order_created_disable_fees( $order ) {
$targeted_item_name = __( "Total Tax Payment", "woocommerce" );
foreach( $order->get_items( 'fee' ) as $item_id => $item ) {
if( $targeted_item_name === $item['name'] ) {
$order->remove_item($item_id);
}
}
$order->calculate_totals();
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Now if you want to remove the fees, but keep original total order amount, use the following:
add_action( 'woocommerce_checkout_order_created', 'order_created_disable_fees' );
function order_created_disable_fees( $order ) {
$targeted_item_name = __( "Total Tax Payment", "woocommerce" );
foreach( $order->get_items( 'fee' ) as $item_id => $item ) {
if( $targeted_item_name === $item['name'] ) {
$order->remove_item($item_id);
}
}
$order->save();
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
If you want to remove a fee from an order before saving it in the database you can use the woocommerce_create_order hook that fires before the order is created within the create_order method of the WC_Checkout class.
Based on this answer:
Remove applied specific fee from Cart programmatically
you will be able to remove the fee from the cart.
However, you will also have to recalculate the totals and taxes (it works whether the fee is taxable or not, and even with multiple tax classes).
REMOVE A FEE FROM CART AND RECALCULATE TOTALS
// removes a specific fee by name before creating the order and recalculates the totals
add_filter( 'woocommerce_create_order', 'remove_specific_fee_from_cart_before_creating_order', 10, 2 );
function remove_specific_fee_from_cart_before_creating_order( $order_id = null, $order ) {
// get the fees added to the cart
$fees = WC()->cart->get_fees();
// initialize taxes (if the fee is not taxable)
$fee_tax = 0;
$fee_tax_data = array();
foreach ( $fees as $key => $fee ) {
// replace "Total Tax Payment" with the name of the fee you added to the cart
if ( $fee->name == 'Total Tax Payment' ) {
// gets the data to recalculate the cart total
$fee_amount = $fee->amount;
if ( $fee->taxable ) {
$fee_tax = $fee->tax;
$fee_tax_data = $fee->tax_data;
}
// removes the fee
unset( $fees[$key] );
break;
}
}
// updates the cart fees
WC()->cart->fees_api()->set_fees( $fees );
// gets the current values of the cart to be recalculated
$cart_total = WC()->cart->get_total(''); // returns the float value instead of HTML code
$cart_total_tax = WC()->cart->get_total_tax();
$cart_fee_taxes = WC()->cart->get_fee_taxes();
// if the fee is taxable
// recalculates the taxes by removing the taxes of the removed fee
if ( ! empty( $fee_tax_data ) ) {
foreach ( $cart_fee_taxes as $fee_tax_key => $fee_tax ) {
if ( array_key_exists( $fee_tax_key, $fee_tax_data ) ) {
$cart_fee_taxes[$fee_tax_key] = $fee_tax - $fee_tax_data[$fee_tax_key];
}
}
}
// updates the cart totals
WC()->cart->set_total( $cart_total - $fee_amount - $fee_tax );
WC()->cart->set_total_tax( $cart_total_tax - $fee_tax );
WC()->cart->set_fee_taxes( $cart_fee_taxes );
return $order_id;
}
REMOVES A FEE FROM CART WITHOUT RECALCULATING THE TOTALS
// removes a specific fee by name before creating the order
add_filter( 'woocommerce_create_order', 'remove_specific_fee_from_cart_before_creating_order', 10, 2 );
function remove_specific_fee_from_cart_before_creating_order( $order_id = null, $order ) {
// get the fees added to the cart
$fees = WC()->cart->get_fees();
foreach ( $fees as $key => $fee ) {
// replace "Total Tax Payment" with the name of the fee you added to the cart
if ( $fee->name == 'Total Tax Payment' ) {
// removes the fee
unset( $fees[$key] );
break;
}
}
// updates the cart fees
WC()->cart->fees_api()->set_fees( $fees );
return $order_id;
}
The code has been tested and works. Add it to your active theme's functions.php.
I would like to ask how to add a custom fee to the woocommerce subscription recurring total?
Found this on the web:
function woo_add_cart_fee() {
global $woocommerce;
$woocommerce->cart->add_fee( __('Custom', 'woocommerce'), 5 );
}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
However that certain function is just for the regular product. NOT SUBSCRIPTION — it doesn't add the fee to the recurring totals.
As of right now, WooCommerce subscriptions doesn't support adding fees to recurring totals.
This may be too late to be of any use to you, but you might find this useful: https://docs.woocommerce.com/document/subscriptions/develop/recurring-cart-fees/
I believe this example would be relevant to your question:
In some cases, you may require the fee to only apply to the on-going
recurring payment for any subscriptions. To achieve this, you need to ... add a condition to check whether
the cart being passed into your callback is a recurring cart, or the
standard WooCommerce cart.
Recurring carts have a $recurring_cart_key property we can use to
determine if the cart is a recurring cart.
add_filter( 'woocommerce_cart_calculate_fees', 'add_recurring_postage_fees', 10, 1 );
function add_recurring_postage_fees( $cart ) {
// Check to see if the recurring_cart_key is set
if ( ! empty( $cart->recurring_cart_key ) ) {
$cart->add_fee( 'Postage', 5 );
}
}
If someone comes by this question, you can solve it in the following way:
add_filter( 'woocommerce_subscriptions_is_recurring_fee', '__return_true' );
add_filter( 'woocommerce_cart_calculate_fees', 'add_fees', 10 );
function add_fees($cart) {
$total_fee = $cart->get_subtotal();
WC()->cart->add_fee( 'Fee', $total_fee * 0.2 );
}
or
add_filter( 'woocommerce_subscriptions_is_recurring_fee', '__return_true' );
add_filter( 'woocommerce_cart_calculate_fees', 'add_fees', 10 );
function add_fees($cart) {
WC()->cart->add_fee( 'Fee', '10' );
}
I am trying to add some additional discounts to the cart total and I tried this code but it's not quite working for me.
function mysite_box_discount( ) {
global $woocommerce;
$total_disc = 10;
// Alter the cart discount total
$woocommerce->cart->discount_total = $total_disc;
}
add_action('woocommerce_calculate_totals', 'mysite_box_discount');
I also tried adding $cart as an argument to the function, but it didn't work.
I also tried $cart->discount_total but it is not working for me either.
Try this code
function custom_wc_add_discount() {
$total_disc = 10;
WC()->cart->add_fee( 'Discount note', -$total_disc );
}
add_action( 'woocommerce_cart_calculate_fees','custom_wc_add_discount' );
I want to have the cash on delivery option only for price below 100$ and hide it automatically when cart is above 100$. The problem is that, I have 3 different payment methods right now. Paypal, cheque and COD. When a person buy something, and choose cash on delievry method, I've written a description there saying "you can choose COD if your order is below 100$". But some people neglect it and still choose COD even their purchase is above 100$. So, I want to hide COD automatically, when a purchase is above 100$. Hence, when a purchase is above 100$, there would be just two options, Paypal and Cheque.
Hope I could clarify it a bit more.
Thanks
You can use the woocommerce_available_payment_gateways hook to edit woocommerce gateways.
add_filter( 'woocommerce_available_payment_gateways' , 'change_payment_gateway', 20, 1);
/**
* remove cod gateway if cart total > 100
* #param $gateways
* #return mixed
*/
function change_payment_gateway( $gateways ){
// Compare cart subtotal (without shipment fees)
if( WC()->cart->subtotal > 100 ){
// then unset the 'cod' key (cod is the unique id of COD Gateway)
unset( $gateways['cod'] );
}
return $gateways;
}
add_filter( 'woocommerce_available_payment_gateways' , 'hide_payment_gateway', 20, 1);
function hide_payment_gateway( $gateways ){
//change whatever amount you want
if( WC()->cart->subtotal < 699 ){
// then unset the 'cod' key (cod is the unique id of COD Gateway)
unset( $gateways['cod'] );
add_action( 'woocommerce_review_order_before_payment', 'COD_exceed_amount_before_paying_notice' );
}
return $gateways;
}
function COD_exceed_amount_before_paying_notice() {
wc_print_notice( __( 'COD option not available on orders below 699.00', 'woocommerce' ), 'notice' );
}