Extra fee on WooCommerce checkout page not added to subtotal - php

I need to add Handling fee in checkout page for some state. For this I am using woocommerce add_fee option. But my problem is on checkout page the handling fee is showing but not add to subtotal. Here is my code
add_action( 'woocommerce_cart_calculate_fees','xa_custom_surcharge' );
function xa_custom_surcharge() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$state= array('MH');
$surcharge = 10;
if ( in_array( WC()->customer->shipping_state, $state ) ) {
$woocommerce->cart->add_fee( 'Additional Charge', $surcharge, true, '' );
}
}
Can anyone please help me.

Your code is outdated since WooCommerce 3:
Properties can't not be accessed anymore on CRUD objects, so you should use instead methods like get_shipping_state() in your case.
global $woocommerce and $woocommerce->cart are outdated & replaced directly by WC()->cart
The WC_Cart Object $cart variable is available in the hooked function as an argument.
The correct code is:
add_action( 'woocommerce_cart_calculate_fees','add_custom_surcharge', 10, 1 );
function add_custom_surcharge( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$state = array('MH');
$surcharge = 10;
if ( in_array( WC()->customer->get_shipping_state(), $state ) ) {
$cart->add_fee( 'Additional Charge', $surcharge, true );
}
}
Now when using the Fee API, the fee amount is displayed as a total and added to gran total at the end, but NOT to the subtotal:
The subtotal in WooCommerce is made only from cart items subtotals…

Related

Change WooCommerce shipping method full label based on product shipping class

I want to add a custom message on the cart page in WooCommerce. The message should appear depending on the shipping class assigned to the product, in the woocommerce_cart_shipping_method_full_label hook.
I already have code that does it, but it doesn't work when I assign it to that hook, it only works if I assign it to the woocommerce_before_calculate_totals hook.
When I want to add it to the woocommerce_cart_shipping_method_full_label hook, I get the message:
Fatal error: Uncaught Error: Call to a member function get_cart()
Could someone advise me on what I'm doing wrong? I am using the storefront template with a child theme.
Based on Cart Message for a Specific Shipping Class in WooCommerce answer code, this is the code I'm using in the functions.php:
add_action( 'woocommerce_cart_shipping_method_full_label', 'cart_items_shipping_class_message', 20, 1 );
function cart_items_shipping_class_message( $cart ){
if ( ! is_cart() || ( is_admin() && ! defined( 'DOING_AJAX' ) ) )
return;
if ( did_action( 'woocommerce_cart_shipping_method_full_label' ) >= 2 )
return;
$shipping_class_id = '28'; // Your shipping class Id
// Loop through cart items
foreach( $cart->get_cart() as $cart_item ) {
// Check cart items for specific shipping class, displaying a notice
if( $cart_item['data']->get_shipping_class_id() == $shipping_class_id ){
wc_clear_notices();
wc_add_notice( sprintf( __('My custom message.', 'woocommerce'), '' . __("Pallet Shipping", "woocommerce") . ''), 'notice' );
break;
}
}
}
Mapping code written for one hook to another hook sometimes takes some tweaking, depending on the original hook and the newly mapped hook:
For example, $cart is not passed to the callback function, and hence the error message you get
wc_clear_notices() and wc_add_notice() are not applicable, as the hook you wish to use is to change the $label
if ( did_action( 'woocommerce_cart_shipping_method_full_label' ) >= 2 )
does not exist
So you get:
function filter_woocommerce_cart_shipping_method_full_label( $label, $method ) {
// Your shipping class Id
$shipping_class_id = 28;
// WC Cart
if ( WC()->cart ) {
// Get cart
$cart = WC()->cart;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Check cart items for specific shipping class
if ( $cart_item['data']->get_shipping_class_id() == $shipping_class_id ) {
$label = __( 'My custom message', 'woocommerce' );
break;
}
}
}
return $label;
}
add_filter( 'woocommerce_cart_shipping_method_full_label', 'filter_woocommerce_cart_shipping_method_full_label', 10, 2 );

Add a fee based on chosen shipping method in WooCommerce

In WooCommerce, I need to add a fee when user select specific shipping methods.
I have found "Add a fee based on shipping method and payment method in Woocommerce" answer, that looks like what I need.
I have tried the code and removed the pieces about payment method which I don't need.
The problem is that when I change the shipping method the fee is not added, looks like that I just keep the old value in the session.
This is my code:
// Add a conditional fee
add_action( 'woocommerce_cart_calculate_fees', 'add_cod_fee', 20, 1 );
function add_cod_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$chosen_shipping_method_id = WC()->session->get( 'chosen_shipping_methods' )[0];
var_dump($chosen_shipping_method_id); die;
switch($chosen_shipping_method_id){
case 'flat_rate:3': {
$fee_text = __( "Spese per ritiro", "woocommerce" );
$cart->add_fee( $fee_text, 12, false );
break;
}
case 'flat_rate:4': {
$fee_text = __( "Spese per consegna a domicilio", "woocommerce" );
$cart->add_fee( $fee_text, 24, false );
break;
}
}
}
// Refresh checkout on payment method change
add_action( 'wp_footer', 'refresh_checkout_script' );
function refresh_checkout_script() {
// Only on checkout page
if( is_checkout() && ! is_wc_endpoint_url('order-received') ) :
?>
<script type="text/javascript">
jQuery(function($){
// On payment method change
$('form.woocommerce-checkout').on( 'change', '.shipping_method', function(){
// Refresh checkout
$('body').trigger('update_checkout');
});
})
</script>
<?php
endif;
}
It just keep the old value in $chosen_shipping_method_id
Your code works nicely if you comment var_dump($chosen_shipping_method_id); die;. Also the jQuery script is not needed as it was for payment methods that doesn't update checkout by default.
So there is something else that is making trouble in your case.
Now I have revisited a bit your code (it will work too):
// Add a conditional fee
add_action( 'woocommerce_cart_calculate_fees', 'flat_rate_based_fee', 20, 1 );
function flat_rate_based_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
if( in_array( 'flat_rate:3', $chosen_shipping_methods ) ) {
$fee = array( 'text' => __( "Spese per ritiro", "woocommerce" ), 'amount' => 12 );
} elseif ( in_array( 'flat_rate:4', $chosen_shipping_methods ) ) {
$fee = array( 'text' => __( "Spese per consegna a domicilio", "woocommerce" ), 'amount' => 24 );
}
if( isset($fee) ) {
$cart->add_fee( $fee['text'], $fee['amount'], false );
}
}
Code goes in functions.php file of your active child theme (or active theme).
Tested and work (on Woocommerce 3.5.x and 3.6.x). See it working live on this test server.

Shipping rate applied only if a certain coupon is used in WooCommerce

I need to create 2000 coupons to sell, but I would like the customers who will use them to always pay for shipping. Currently the threshold for getting free shipping is set above 69€. I tried to use the code below (taken from here: Applied coupons disable Free shipping conditionally in Woocommerce).
It applies to all coupons though, and I'd like to apply it only on coupons with the prefix 'pd'.
add_filter( 'woocommerce_package_rates', 'coupons_removes_free_shipping', 10, 2 );
function coupons_removes_free_shipping( $rates, $package ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
$applied_coupons = WC()->cart->get_applied_coupons();
if( sizeof($applied_coupons) > 0 ) {
// Loop through shipping rates
foreach ( $rates as $rate_key => $rate ) {
// Targeting "Free shipping" only
if( 'free_shipping' === $rate->method_id ) {
unset($rates[$rate_key]); // Removing current method
}
}
}
return $rates;
}

Conditionally adding a cart fee if no coupons are applied to cart

In WooCommerce, I am trying to figured out how to add a "Handling Fee" to every order when no coupons or promo codes are applied to cart.
Here's my "Fee" or "Handling Charge" code:
add_action( 'woocommerce_cart_calculate_fees','endo_handling_fee' );
function endo_handling_fee() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$fee = 2.00;
$woocommerce->cart->add_fee( 'Handling', $fee, true, 'standard' );
}
Any ideas?
Thanks
Here I get the array of cart applied coupons and if there is no coupons applied to cart, then a fee is applied to cart.
Here is that code:
add_action( 'woocommerce_cart_calculate_fees','conditional_handling_fee' );
function conditional_handling_fee() {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Get the applied coupons + the count (in cart)
$applied_coupons_arr = WC()->cart->get_applied_coupons();
$applied_coupons_count = count($applied_coupons_arr);
$fee = 2.00;
if( 0 == $applied_coupons_count )
WC()->cart->add_fee( 'Handling - '.$applied_coupons_count, $fee, true, 'standard' );
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works.
Reference: WC_Cart class - get_applied_coupons() method

Add fee based on specific payment methods in WooCommerce

In WooCommerce I need to apply a custom handling fee for a specific payment gateway. I have this piece of code from here: How to Add Handling Fee to WooCommerce Checkout.
This is my code:
add_action( 'woocommerce_cart_calculate_fees','endo_handling_fee' );
function endo_handling_fee() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$fee = 5.00;
$woocommerce->cart->add_fee( 'Handling', $fee, true, 'standard' );
}
This function add a fee to all transactions.
Is it possible to tweak this function and make it apply for specific payment method only ?
The other problem is that I want this fee to be applied on cart. Is it possible?
I will welcome any alternative method as well. I know about the similar "Payment Gateway Based Fees" woo plugin, but I can't afford it.
2021 UPDATE
Note: All payment methods are only available on Checkout page.
The following code will add conditionally a specific fee based on the chosen payment method:
// Add a custom fee (fixed or based cart subtotal percentage) by payment
add_action( 'woocommerce_cart_calculate_fees', 'custom_handling_fee' );
function custom_handling_fee ( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$chosen_payment_id = WC()->session->get('chosen_payment_method');
if ( empty( $chosen_payment_id ) )
return;
$subtotal = $cart->subtotal;
// SETTINGS: Here set in the array the (payment Id) / (fee cost) pairs
$targeted_payment_ids = array(
'cod' => 8, // Fixed fee
'paypal' => 5 * $subtotal / 100, // Percentage fee
);
// Loop through defined payment Ids array
foreach ( $targeted_payment_ids as $payment_id => $fee_cost ) {
if ( $chosen_payment_id === $payment_id ) {
$cart->add_fee( __('Handling fee', 'woocommerce'), $fee_cost, true );
}
}
}
You will need the following to refresh checkout on payment method change, to get it work:
// jQuery - Update checkout on payment method change
add_action( 'woocommerce_checkout_init', 'payment_methods_refresh_checkout' );
function payment_methods_refresh_checkout() {
wc_enqueue_js( "jQuery( function($){
$('form.checkout').on('change', 'input[name=payment_method]', function(){
$(document.body).trigger('update_checkout');
});
});");
}
Code goes in functions.php file of your active child theme (or active theme). tested and works.
How to find a specific payment method ID in WooCommerce Checkout page?
The following will display on checkout payment methods the payment Id just for admins:
add_filter( 'woocommerce_gateway_title', 'display_payment_method_id_for_admins_on_checkout', 100, 2 );
function display_payment_method_id_for_admins_on_checkout( $title, $payment_id ){
if( is_checkout() && ( current_user_can( 'administrator') || current_user_can( 'shop_manager') ) ) {
$title .= ' <code style="border:solid 1px #ccc;padding:2px 5px;color:red;">' . $payment_id . '</code>';
}
return $title;
}
Code goes in functions.php file of your active child theme (or active theme). Once used, remove it.
Similar answer:
Add a custom fee for a specific payment gateway in Woocommerce
Add a fee based on shipping method and payment method in Woocommerce
Percentage discount based on user role and payment method in Woocommerce
First of all there are some key things we need to understand:
We are going to use the only filter hook which is woocommerce_cart_calculate_fees
In order to get user selected payment method we must retrieve it from user sessions using this method WC()->session->get( 'chosen_payment_method' )
calculate_fees() and calculate_totals() methods are not necessary.
We are going to add the fee using cart method WC()->cart->add_fee() which accepts two parameters – the first one, is the fee description, the second one – fee amount.
And one more thing – we will need a payment method slug, the easiest way to get it described in this tutorial https://rudrastyh.com/woocommerce/add-id-column-to-payment-methods-table.html
Let's go now:
add_action( 'woocommerce_cart_calculate_fees', 'rudr_paypal_fee', 25 );
function rudr_paypal_fee() {
if( 'paypal' == WC()->session->get( 'chosen_payment_method' ) ) {
WC()->cart->add_fee( 'PayPal fee', 2 ); // let's add a fee for paypal
}
}
It would be also great to refresh the checkout every time payment gateway is changed, it is easy to do using this code:
jQuery( function( $ ) {
$( 'form.checkout' ).on( 'change', 'input[name^="payment_method"]', function() {
$( 'body' ).trigger( 'update_checkout' );
});
});
That's it. Everything is described in details here as well: https://rudrastyh.com/woocommerce/charge-additional-fees-based-on-payment-gateway.html
For anyone else looking to do this, I wanted to add a fee for Bank Transfers (BACS), here is the method I used:
//Hook the order creation since it is called during the checkout process:
add_filter('woocommerce_create_order', 'my_handle_bacs', 10, 2);
function my_handle_bacs($order_id, $checkout){
//Get the payment method from the $_POST
$payment_method = isset( $_POST['payment_method'] ) ? wc_clean( $_POST['payment_method'] ) : '';
//Make sure it's the right payment method
if($payment_method == "bacs"){
//Use the cart API to add recalculate fees and totals, and hook the action to add our fee
add_action('woocommerce_cart_calculate_fees', 'my_add_bacs_fee');
WC()->cart->calculate_fees();
WC()->cart->calculate_totals();
}
//This filter is for creating your own orders, we don't want to do that so return the $order_id untouched
return $order_id;
}
function my_add_bacs_fee($cart){
//Add the appropriate fee to the cart
$cart->add_fee("Bank Transfer Fee", 40);
}
add_action( 'woocommerce_cart_calculate_fees','cod_fee' );
function cod_fee() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// get your payment method
$chosen_gateway = WC()->session->chosen_payment_method;
//echo $chosen_gateway;
$fee = 5;
if ( $chosen_gateway == 'cod' ) { //test with cash on delivery method
WC()->cart->add_fee( 'delivery fee', $fee, false, '' );
}
}

Categories