Remove Calculate Fee Action Before Order Process - woocommerce

I have a custom function which i use to add/remove a custom fee to the Cart Totals. The fee works fine during the Cart Ajax Calculations, but for some reason the fee still gets charged to the order after checkout. How can I remove this before the order is processed? Here is what i currently have to calculate the fee:
function woo_add_cart_fee() {
global $woocommerce;
if ( ! $_POST || ( is_admin() && ! is_ajax() ) ) {
return;
}
$checkout = WC()->checkout()->checkout_fields;
parse_str( $_POST['post_data'], $post_data );
// Add Fee if no VAT Number is Provided
if($post_data['vat_number'] == '' OR strlen($post_data['vat_number']) < 1 OR empty($post_data['vat_number'])){
$vat_total = 25; // $25.00 fee
$woocommerce->cart->add_fee( __('VAT Fee', 'woocommerce'), $vat_total );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
The problem is that once the user checks out, the fee is always added, even if they provide a VAT number (my custom field).
So I tried adding this snippet to remove the action completely before the order is processed, but this does not seem to work either:
function action_woocommerce_before_checkout_process( $array ) {
if($_POST['vat_number'] == '' OR strlen($_POST['vat_number']) < 1 OR empty($_POST['vat_number'])){
remove_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee', 1 );
}
}
// add the action
add_action( 'woocommerce_before_checkout_process', 'action_woocommerce_before_checkout_process');
I believe I may be using the wrong hook woocommerce_before_checkout_process because it doesn't seem to be firing.
Any Idea what could be happening? Thanks!

I was able to fix this by adding some control flow for $woocommerce->cart->add_fee It turns out that the calculate_totals function is run again before the thank you page
if(isset($_POST['vat_number'])){
if($_POST['vat_number'] == '' OR empty($_POST['vat_number'])){
$woocommerce->cart->add_fee( __($vat_label, 'woocommerce'), $vat_total );
}
} else {
$woocommerce->cart->add_fee( __($vat_label, 'woocommerce'), $vat_total );
}

Related

Prevent WooCommerce coupon stacking on cart and checkout page

I need to prevent two specific coupons from being used together. I successfully implemented this code, which prevents stacking these coupons on the cart page:
add_action( 'woocommerce_before_cart', 'check_coupon_stack' );
function check_coupon_stack() {
$coupon_code_1 = 'mycode1';
$coupon_code_2 = 'mycode2';
if ( WC()->cart->has_discount( $coupon_code1 ) && WC()->cart->has_discount( $coupon_code2) ) {
WC()->cart->remove_coupon( $coupon_code2 );
$notice_text = 'Discount code '.$coupon_code1.' cannot be combined with code '.$coupon_code2.'. Code '.$coupon_code2.' removed.';
wc_print_notice( $notice_text, 'error' );
wc_clear_notices();
}
}
However, this does not prevent stacking on the checkout page, which follows the cart page.
I have tried simply adding:
add_action( 'woocommerce_before_checkout_form', 'check_coupon_stack' );
But that doesn't make this work on the checkout page. What more is needed?
WooCommerce contains multiple hooks that apply to coupons, woocommerce_applied_coupon is one of them, which is very suitable for your question.
Furthermore, your current code only works in one direction, which is when $coupon_code_1 is used, $coupon_code_2 is removed. However, this is not applied in the reverse direction while you indicate in your question that you want to prevent two specific coupons from being used together.
This is taken into account in my answer, so you get:
function action_woocommerce_applied_coupon( $coupon_code ) {
// Settings
$coupon_code_1 = 'coupon1';
$coupon_code_2 = 'coupon2';
// Initialize
$combined = array( $coupon_code_1, $coupon_code_2 );
// Checks if coupon code exists in an array
if ( in_array( $coupon_code, $combined ) ) {
// Get applied coupons
$applied_coupons = WC()->cart->get_applied_coupons();
// Computes the difference of arrays
$difference = array_diff( $combined, $applied_coupons );
// When empty
if ( empty( $difference ) ) {
// Shorthand if/else - Get correct coupon to remove
$remove_coupon = $coupon_code == $coupon_code_1 ? $remove_coupon = $coupon_code_2 : $remove_coupon = $coupon_code_1;
// Remove coupon
WC()->cart->remove_coupon( $remove_coupon );
// Clear Notices
wc_clear_notices();
// Error message
$error = sprintf( __( 'Discount code "%1$s" cannot be combined with code "%2$s". Code "%2$s" removed.', 'woocommerce' ), $coupon_code, $remove_coupon );
// Show error
wc_print_notice( $error, 'error' );
}
}
}
add_action( 'woocommerce_applied_coupon', 'action_woocommerce_applied_coupon', 10, 1 );

Woocommerce Coupon to Waive Custom Fee

I have the following code that adds a Handling fee to orders with subtotal under $100. I'm trying to make a coupon that will remove the handling fee (or make it $0) that I can give to specific customers, even if their order is under $100. I've made a coupon in Woocommerce and it takes off the $25 from the cart subtotal without changing the Handling. If I don't make a coupon in Woocommerce, I get the "this coupon doesn't exist" message when I try to apply the coupon. Help?
function woo_add_cart_fee() {
global $woocommerce;
$subt = $woocommerce->cart->subtotal;
if ($subt < 100 && $coupon_code == "NOHANDLING" ) {
$handling = 0;
$woocommerce->cart->add_fee( __('Handling', 'woocommerce'), $handling );
}
elseif ($subt < 100 ) {
$handling = 25;
$woocommerce->cart->add_fee( __('Handling', 'woocommerce'), $handling );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
Thanks.

Hide shipping and payment methods in WooCommerce

I'm building a WooCommerce e-shop and I need to tweak my checkout page by doing the following:
Hide a certain shipping method (only one) if the order total > 100€.
Hide the cash on delivery payment method if local pickup is selected.
Does anyone know how to do that? I have the Code Snippets plugin so I can easily add any custom code.
To hide specific shipping method based on the cart total, you can use below code snippet. You need to update your shipping method name in the code.
Disable shipping method as per cart total
Add this snippet in your theme's functions.php file or custom plugin file.
add_filter( 'woocommerce_package_rates', 'shipping_based_on_price', 10, 2 );
function shipping_based_on_price( $rates, $package ) {
$total = WC()->cart->cart_contents_total;
//echo $total;
if ( $total > 100 ) {
unset( $rates['local_delivery'] ); // Unset your shipping method
}
return $rates;
}
Disable Payment Gateway For Specific Shipping Method
Use below code snippet. Update code as per your payment method & shipping method.
add_filter( 'woocommerce_available_payment_gateways', 'x34fg_gateway_disable_shipping' );
function x34fg_gateway_disable_shipping( $available_gateways ) {
global $woocommerce;
if ( !is_admin() ) {
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = $chosen_methods[0];
if ( isset( $available_gateways['cod'] ) && 0 === strpos( $chosen_shipping, 'local_pickup' ) ) {
unset( $available_gateways['cod'] );
}
}
return $available_gateways;
}
There are a number of plugins that will do this for you, take a look at this one WooCommerce Conditional Shipping and Payments
You'll want to tie in to the "woocommerce_payment_gateways" action
Something along these lines:
function alter_payment_gateways( $gateways ){
$chosen_rates = ( isset( WC()->session ) ) ? WC()->session->get( 'chosen_shipping_methods' ) : array();
if( in_array( 'local-pickup:6', $chosen_rates ) ) {
$array_diff = array('cod');
$list = array_diff( $list, $array_diff );
}
return $list;
}
add_action('woocommerce_payment_gateways', 'alter_payment_gateways', 50, 1);
The number on the end of 'local-pickup' on line 4 will depend on your woocommerce setup. You can find the string you need to put in here by adding something to a basket, going to the checkout, right clicking on the "Local Pickup" option in the delivery methods and looking at the value attribute.

Woocommerce skip checkout for free products

I'm building webpage on WP and Woocommerce - I would like to skip cart and also checkout page for free products (or products which ID-s I can specify). These products are free and virtual (no payment needed, no shipping needed). The webpage is only used by registered users - so all the customer info is present.
The result I would like to have is that if you press ORDER button on product page - the order is done and customer is redirected to Thank-You page.
BR,
Kaspar
I applied the same concept, but found a major issue when processing order on the checkout; fields were still required.
The primary issue was processing the order via AJAX ( was using is_ajax() ), and even though it was on the checkout page, it wasn't returning as true. It's possible there was a recent change, or it could be the site's environment (theme).
Here are some of the conditional tags: https://docs.woocommerce.com/document/conditional-tags/
Seeing how things change, the answer can be edited here, but the original concept is located at: https://www.skyverge.com/blog/how-to-simplify-free-woocommerce-checkout/
function wc_free_checkout_fields() {
// Bail we're not at checkout, or if we're at checkout OR AJAX (payment process) but payment is needed.
if ( function_exists( 'is_checkout' ) && ( ! ( is_checkout() || is_ajax() ) || ( ( is_checkout() || is_ajax() ) && WC()->cart->needs_payment() ) ) ) {
return;
}
// Remove coupon forms since it's irrelevant with a free cart?
remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_form', 10 );
// Remove the "Additional Info" order notes.
add_filter( 'woocommerce_enable_order_notes_field', '__return_false' );
// Unset the fields we don't want in a free checkout.
function wc_unset_unwanted_checkout_fields( $fields ) {
// Add or remove billing fields you do not want.
// #link http://docs.woothemes.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/#section-2
$billing_keys = array(
'billing_company',
'billing_phone',
'billing_address_1',
'billing_address_2',
'billing_city',
'billing_postcode',
'billing_country',
'billing_state',
);
// For each unwanted billing key, unset.
foreach( $billing_keys as $key ) {
unset( $fields['billing'][$key] );
}
return $fields;
}
add_filter( 'woocommerce_checkout_fields', 'wc_unset_unwanted_checkout_fields' );
// A tiny CSS tweak for the account fields; this is optional.
function wc_print_custom_css() {
?>
<style>
.create-account {
margin-top: 6em;
}
</style>
<?php
}
add_action( 'wp_head', 'wc_print_custom_css' );
}
add_action( 'wp', 'wc_free_checkout_fields' );
Check if the checkout has no cost with the WC()->cart->needs_payment() check.
see this for more info:
https://www.skyverge.com/blog/how-to-simplify-free-woocommerce-checkout/

Woocommerce 2.5: Hide Shipping Methods when free shipping is available not working anymore

I Had this code
/* !Hide Shipping Options Woocommerce */
add_filter( 'woocommerce_available_shipping_methods', 'hide_shipping_based_on_tag' , 10, 1 );
function check_cart_for_share() {
// load the contents of the cart into an array.
global $woocommerce;
$cart = $woocommerce->cart->cart_contents;
$found = false;
// loop through the array looking for the tag you set. Switch to true if the tag is found.
foreach ($cart as $array_item) {
$term_list = wp_get_post_terms( $array_item['product_id'], 'product_tag', array( "fields" => "names" ) );
if (in_array("Heavy",$term_list)) { // Replace "Heavy" with what ever tag you want
$found = true;
break;
}
}
return $found;
}
function hide_shipping_based_on_tag( $available_methods ) {
// use the function above to check the cart for the tag.
if ( check_cart_for_share() ) {
// remove the rate you want
unset( $available_methods['flat_rate'] ); // Replace "flat_rate" with the shipping option that you want to remove.
}
// return the available methods without the one you unset.
return $available_methods;
}
in my function.php - but since woocommerce 2.5 it's not working anymore.
The other shipping methods need to be hidden when free shipping is available.
Any Ideas?
You're using a hook that was used for WooCommerce version 2.1 and below.
Instead, use the woocommerce_package_rates filter..
This code works perfect for latest woocommerce :
add_filter( 'woocommerce_package_rates', 'hide_shipping_when_free_is_available', 10, 2 );
function hide_shipping_when_free_is_available( $rates, $package ) {
// Only modify rates if free_shipping is present
if ( isset( $rates['free_shipping'] ) ) {
// To unset a single rate/method, do the following. This example unsets flat_rate shipping
unset( $rates['flat_rate'] );
// To unset all methods except for free_shipping, do the following
$free_shipping = $rates['free_shipping'];
$rates = array();
$rates['free_shipping'] = $free_shipping;
}
return $rates;
}
I have unset the flat shipping, you can unset other shipping methods if you enabled. This code works fine for me, i tried it yesterday.

Resources