Reset previous chosen shipping method in Woocommerce checkout page - php

Currently, I am clearing the default shipping selection method using this filter:
add_filter( 'woocommerce_shipping_chosen_method', '__return_false', 99);
However, this only clears it during the initial session of the customer. Once the customer chooses an option even once, it remembers the selection for the future.
I am trying to get the checkout to force the customer to pick a shipping option every time they visit the checkout even in the same session. Is it possible to run this filter every time the checkout page is loaded?

You can reset the last chosen shipping method using in checkout page (for logged in customers):
delete_user_meta( get_current_user_id(), 'shipping_method' );
And also remove the chosen shipping method from session data:
WC()->session->__unset( 'chosen_shipping_methods' );
In a hooked function like:
add_action( 'template_redirect', 'reset_previous_chosen_shipping_method' );
function reset_previous_chosen_shipping_method() {
if( is_checkout() && ! is_wc_endpoint_url() && is_user_logged_in()
&& get_user_meta( get_current_user_id(), 'shipping_method', true ) ) {
delete_user_meta( get_current_user_id(), 'shipping_method' );
WC()->session->__unset( 'chosen_shipping_methods' );
}
}
Or you can also set a default shipping method for everybody in checkout page:
add_action( 'template_redirect', 'reset_previous_chosen_shipping_method' );
function reset_previous_chosen_shipping_method() {
if( is_checkout() && ! is_wc_endpoint_url() && is_user_logged_in() ) {
WC()->session->set( 'chosen_shipping_methods', array('flat_rate:14') );
}
}
To find out the shipping methods rate Ids to be used, you can inspect the shipping method radio buttons in cart or checkout pages, with your browser inspector like:
Code goes on function.php file of your active child theme (or active theme). It should works.

Found this solution, it might be a bit hacky.
Just unsets currently selected shipping method and then checks if it's present while validating the checkout.
add_action(
'woocommerce_before_checkout_form',
'reset_previous_chosen_shipping_method'
);
function reset_previous_chosen_shipping_method()
{
if (is_checkout() && !is_wc_endpoint_url()) {
unset(WC()->session->chosen_shipping_methods);
}
}
add_action('woocommerce_after_checkout_validation', 'validate', 10, 2);
function validate($data, $errors)
{
if (!$data['shipping_method']) {
$errors->add('validation', __('Please select shipping method'));
}
}

Related

Redirection for non checkout guest allowed in WooCommerce

After Allow guest checkout for specific products only in WooCommerce answer to my previous question, the following code redirect users to login page:
add_action( 'template_redirect', 'checkout_redirect_non_logged_to_login_access');
function checkout_redirect_non_logged_to_login_access() {
if( is_checkout() && !is_user_logged_in()){
wp_redirect( get_permalink( get_option('woocommerce_myaccount_page_id') ) );
exit;
}
}
But I have some products which allows guest checkout (see the linked question/answer above). So how could I fix my code for the products which allows guest checkout to disable that code redirection?
You can replace my previous answer code with the following:
// Custom conditional function that checks if checkout registration is required
function is_checkout_registration_required() {
if ( ! WC()->cart->is_empty() ) {
// Loop through cart items
foreach ( WC()->cart->get_cart() as $item ) {
// Check if there is any item in cart that has not the option "Guest checkout allowed"
if ( get_post_meta( $item['product_id'], '_allow_guest_checkout', true ) !== 'yes' ) {
return true; // Found: Force checkout user registration and exit
}
}
}
return false;
}
add_filter( 'woocommerce_checkout_registration_required', 'change_tax_class_user_role', 900 );
function change_tax_class_user_role( $registration_required ) {
return is_checkout_registration_required();
}
Then your current question code will be instead:
add_action( 'template_redirect', 'checkout_redirect_non_logged_to_login_access');
function checkout_redirect_non_logged_to_login_access() {
if( is_checkout() && !is_user_logged_in() && is_checkout_registration_required() ){
wp_redirect( get_permalink( get_option('woocommerce_myaccount_page_id') ) );
exit;
}
}
Code goes in functions.php file of your active child theme (or active theme). It should works.

How do I make it so my customers cart is emptied upon leaving the checkout page?

On my e-commerce store upon clicking the add to cart button you are redirected straight to the checkout page. I want to make it so when you leave the checkout page your cart is emptied. Is there a php code that can make this work?
I tried this code but its very buggy:
add_action( 'wp_head', 'clear_cart' );
function clear_cart() {
if ( wc_get_page_id( 'cart' ) == get_the_ID() || wc_get_page_id( 'checkout' ) == get_the_ID() ) {
return;
}
WC()->cart->empty_cart();
}
Sometimes my session just ends while on the checkout page or my cart is emptied randomly.
I think the below may help you to empty the cart. Please add in your functions.php file.
add_filter( 'woocommerce_add_cart_item_data', 'wdm_empty_cart', 10, 3);
function wdm_empty_cart( $cart_item_data, $product_id, $variation_id ){
global $woocommerce;
$woocommerce->cart->empty_cart();
// Do nothing with the data and return
return $cart_item_data;
}

Disable a shipping method for a specific payment method in Woocommerce

On Woocommerce, I have enabled 2 shipping methods: Free shipping or Flat rate. I have enabled 2 payment methods: Bank transfer (bacs) and PayPal (paypal).
What I want to achieve:
If a customer selects PayPal as payment type he should be forced to select "Flat rate" as shipping method. "Free shipping" should be either hidden or greyed out or something like that.
If bank transfer is chosen then both shipping methods should be available.
Any help is appreciated.
If anyone is interested, I found a solution:
function alter_payment_gateways( $list ){
// Retrieve chosen shipping options from all possible packages
$chosen_rates = ( isset( WC()->session ) ) ? WC()->session->get( 'chosen_shipping_methods' ) : array();
if( in_array( 'free_shipping:1', $chosen_rates ) ) {
$array_diff = array('WC_Gateway_Paypal');
$list = array_diff( $list, $array_diff );
}
return $list;
}
add_action('woocommerce_payment_gateways', 'alter_payment_gateways');
This code will deactivate PayPal if a customer selects free shipping.
Update 2: The following code will disable "free_shipping" shipping method (method ID) when "paypal" is the chosen payment method:
add_filter( 'woocommerce_package_rates', 'shipping_methods_based_on_chosen_payment', 100, 2 );
function shipping_methods_based_on_chosen_payment( $rates, $package ) {
// Checking if "paypal" is the chosen payment method
if ( WC()->session->get( 'chosen_payment_method' ) === 'paypal' ) {
// Loop through shipping methods rates
foreach( $rates as $rate_key => $rate ){
if ( 'free_shipping' === $rate->method_id ) {
unset($rates[$rate_key]); // Remove 'Free shipping'shipping method
}
}
}
return $rates;
}
// Enabling, disabling and refreshing session shipping methods data
add_action( 'woocommerce_checkout_update_order_review', 'refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods( $post_data ){
$bool = true;
if ( WC()->session->get('chosen_payment_method' ) ) $bool = false;
// Mandatory to make it work with shipping methods
foreach ( WC()->cart->get_shipping_packages() as $package_key => $package ){
WC()->session->set( 'shipping_for_package_' . $package_key, $bool );
}
WC()->cart->calculate_shipping();
}
// Jquery script for checkout page
add_action('wp_footer', 'refresh_checkout_on_payment_method_change' );
function refresh_checkout_on_payment_method_change() {
// Only checkout page
if( is_checkout() && ! is_wc_endpoint_url() ):
?>
<script type="text/javascript">
jQuery(function($){
// On shipping method change
$('form.checkout').on( 'change', 'input[name^="payment_method"]', function(){
$('body').trigger('update_checkout'); // Trigger Ajax checkout refresh
});
})
</script>
<?php
endif;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
To get the related shipping methods rate IDs, something like flat_rate:12, inspect with your browser code inspector each related radio button attribute name like:
Note: Since WooCommerce new versions changes, sorry, the code doesn't work anymore.

Call a custom user field value in a WooCommerce hooked function

I have created a custom field in the user profile, now I need to call the value of that field into the WooCommerce cart as a discount.
This is the function to add a custom fee in the cart:
add_action('woocommerce_cart_calculate_fees' , 'add_custom_fees');
$descuentototal = get_the_author_meta( 'descuento', $user_id );
function add_custom_fees( WC_Cart $cart ){
if( $descuentototal < 1 ){
return;
}
// Calculate the amount to reduce
$cart->add_fee( 'Discount: ', -$descuentototal);
}
But can't manage to get the value of 'descuento'.
How could I do it?
Thanks.
You need to use WordPress functions get_current_user_id() to get current user Id and get_user_meta() to get the user meta data.
So the correct code for woocommerce_cart_calculate_fees hook will be:
add_action( 'woocommerce_cart_calculate_fees', 'add_custom_fees' );
function add_custom_fees(){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( !is_user_logged_in() )
return;
$user_id = get_current_user_id();
$descuentototal = get_user_meta($user_id, 'descuento', true);
if ( $descuentototal < 1 ) {
return;
} else {
$descuentototal *= -1;
// Enable translating 'Discount: '
$discount = __('Discount: ', 'woocommerce');
// Calculate the amount to reduce (without taxes)
WC()->cart->add_fee( $discount, $descuentototal, false );
}
}
Code goes in any php file of your active child theme (or theme) or also in any plugin php files.
Reference or related:
Wordpress Function Reference/get user meta
WooCommerce - Conditional Progressive Discount based on number of items in cart
WooCommerce class - WC_Cart - add_fee() 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