Show Cash on delivery (COD) based on specific cities in Woocommerce - php

In Woocommerce I am showing Cash on delivery payment method only for a particular city using the following code:
function payment_gateway_disable_city( $available_gateways ) {
global $woocommerce;
if ( isset( $available_gateways['cod'] ) && $woocommerce->customer->get_shipping_city() == 'New York') {
unset( $available_gateways['cod'] );
}
return $available_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'payment_gateway_disable_city' );
It works fine. Now I need to handle multiple cities like Washington, San Francisco etc...
So I tried the following:
function payment_gateway_disable_city( $available_gateways ) {
global $woocommerce;
if ( isset( $available_gateways['cod'] ) && $woocommerce->customer->get_shipping_city() == 'New York', 'San Fransisco' ) {
unset( $available_gateways['cod'] );
}
return $available_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'payment_gateway_disable_city' );
But it doesn't work… I get "WordPress experiencing technical difficulties".
Any help is appreciated.

Updated
The following code will enable COD payments for specific defined cities.
You need to use an array of allowed cities with in_array() PHP conditional function like:
add_filter( 'woocommerce_available_payment_gateways', 'cities_based_payment_gateway_cod' );
function cities_based_payment_gateway_cod( $available_gateways ) {
if ( is_admin() ) return $available_gateways; // Only on frontend
// HERE define the allowed cities in this array
$cities = array( 'New York', 'San Francisco' );
if ( isset( $available_gateways['cod'] ) && ! in_array( WC()->customer->get_shipping_city(), $cities ) ) {
unset( $available_gateways['cod'] );
}
return $available_gateways;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Related

Keep only a specific payment method for Local Pickup shipping method in WooCommerce

function my_custom_available_payment_gateways( $gateways ) {
$chosen_shipping_rates = WC()->session->get( 'chosen_shipping_methods' );
// When 'local delivery' has been chosen as shipping rate
if ( in_array( 'local_delivery', $chosen_shipping_rates ) ) :
// Remove bank transfer payment gateway
unset( $gateways['bacs'] );
endif;
return $gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'my_custom_available_payment_gateways' );
This code doesn't work for me. How can I achieve that?
Try the following instead:
add_filter( 'woocommerce_available_payment_gateways', 'my_custom_available_payment_gateways', 10, 1 );
function my_custom_available_payment_gateways( $available_gateways ) {
if( is_admin() ) return $available_gateways; // Only for frontend
$local_found = false; // Initializing
// Loop through chosen shipping method rates
foreach ( WC()->session->get( 'chosen_shipping_methods' ) as $chosen_shipping_rate_id ) {
if( strpos( $chosen_shipping_rate_id, 'local_pickup' ) !== false || strpos( $chosen_shipping_rate_id, 'local_delivery' ) !== false ) {
$local_found = true; // Local pickup/delivery found
break; // Stop the loop
}
}
// If Local pickup/delivery is the chosen shipping method
if( $local_found ) {
// Loop through available payment methods
foreach ( $available_gateways as $payment_method_id => $payment_label ) {
// Remove all payement methods except "cheque"
if ( 'cheque' !== $payment_method_id ) {
unset( $available_gateways[$payment_method_id] );
}
}
}
return $available_gateways;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.

Woocommerce - Hide payment gateway “cod - cash on delivery” and show bacs - Bank Transfer

Please Guys,
I use two payment gateways on the checkout page:
1° bacs = Bank transfer
2° cod = Cash on Delivery
i need to hide the payment gateway COD = Cash on Delivery, If the user has No Admin Profile (!is_user_admin()), || or it's not logged, || ! is_user_logged_in() then hide.
This is the code that i'm using and it's working.
add_filter( 'woocommerce_available_payment_gateways', 'bbloomer_cod_hide' );
function bbloomer_cod_hide( $available_gateways ) {
if ( isset( $available_gateways['cod']) && !is_user_admin() ) {
unset( $available_gateways['cod'] );
}
return $available_gateways;
}
The problem is...the payment gateway bacs = Bank transfer is also affected and hidden : )
so i tried with this another hook
add_filter( 'woocommerce_available_payment_gateways', 'transfer_enable_bacs' );
function transfer_enable_bacs( $available_gateways ) {
if ( isset( $available_gateways['bacs']) && !is_user_admin() ) {
//unset( $available_gateways['bacs'] );
}
return $available_gateways;
}
But this is not the correct solution. Both payment gateways are hidden.
What am i doing wrong please?
Gratitude!
I think you need to replace is_user_admin with current_user_can
add_filter( 'woocommerce_available_payment_gateways', 'bbloomer_cod_hide' );
function bbloomer_cod_hide( $available_gateways ) {
if ( isset( $available_gateways['cod'] ) && ! current_user_can( 'administrator' ) ) {
unset( $available_gateways['cod'] );
}
return $available_gateways;
}
is_user_admin does not check if the user is an administrator; use current_user_can() for checking roles and capabilities.
https://developer.wordpress.org/reference/functions/is_user_admin/
try the following code:
add_filter( 'woocommerce_available_payment_gateways', 'bbloomer_cod_hide' );
function bbloomer_cod_hide( $available_gateways ) {
if ( !is_user_logged_in() ) || !current_user_can( 'install_themes' ) ) {
unset( $available_gateways['cod'] );
}
return $available_gateways;
}

Disable WooCommerce payment gateway for guests and specific user roles

I have disabled the invoice payment mehtod for one of the user roles in my site ('customer') but now I need to add another user role ('business') to this rule and I can't figure out how to make it work. When I add the second role, the code stops working altogether and it ends up showing the gateway to all users.
Here's the code I'm using to disable the gateway:
I'm not very experienced with PHP so any help will be tremendously appreciated.
If there's any chance you can correct my code to fit the use case, I would be very grateful.
add_filter( 'woocommerce_available_payment_gateways', 'payment_gateway_disable_private' );
function payment_gateway_disable_private( $available_gateways ) {
$user = wp_get_current_user();
if ( isset( $available_gateways['igfw_invoice_gateway'] ) && !is_user_logged_in() || isset( $available_gateways['igfw_invoice_gateway'] ) && in_array('customer', $user->roles) ) {
unset( $available_gateways['igfw_invoice_gateway'] );
}
return $available_gateways;
}
Thoughts?
There is a mistake in your if statement (also you can use current_user_can() function for user roles) like:
add_filter( 'woocommerce_available_payment_gateways', 'payment_gateway_disable_private' );
function payment_gateway_disable_private( $available_gateways ) {
if ( ( ! is_user_logged_in() || current_user_can('customer') || current_user_can('business') )
&& isset( $available_gateways['igfw_invoice_gateway'] ) ) {
unset( $available_gateways['igfw_invoice_gateway'] );
}
return $available_gateways;
}
or with the global $current_user; and array_intersect() function:
add_filter( 'woocommerce_available_payment_gateways', 'payment_gateway_disable_private' );
function payment_gateway_disable_private( $available_gateways ) {
global $current_user;
// Here define your user roles
$user_roles = array( 'customer', 'business' );
if ( ( ! is_user_logged_in() || array_intersect( $current_user->roles, $user_roles ) )
&& isset( $available_gateways['igfw_invoice_gateway'] ) ) {
unset( $available_gateways['igfw_invoice_gateway'] );
}
return $available_gateways;
}
It should better work now.

Shipping options depending on cart weight and shipping class

I am working on a WordPress site that uses WooCommerce. I found this piece of code that allows me to set a freight shipping option based on weight. It worked great until the client also wanted the same freight shipping option if a freight shipping class is selected on a product.
add_filter( 'woocommerce_package_rates', 'bbloomer_woocommerce_tiered_shipping', 10, 2 );
function bbloomer_woocommerce_tiered_shipping( $rates, $package ) {
if ( WC()->cart->cart_contents_weight < 300 ) {
if ( isset( $rates['fedex:PRIORITY_OVERNIGHT'], $rates['fedex:FEDEX_2_DAY'], $rates['fedex:FEDEX_GROUND'] ) );
} else {
if ( isset( $rates['flat_rate:10'] ) ) unset( $rates['fedex:PRIORITY_OVERNIGHT'], $rates['fedex:FEDEX_2_DAY'],$rates['fedex:FEDEX_GROUND'] );
}
return $rates;
}
Then I found another piece of code that could set a shipping class to a shipping option. The code I found was mean to unset shipping options that are available but I want to isset the freight shipping since we unset it via the cart weight. However, I am running into an issue where the freight shipping class can no longer be set to isset without causing major issues. Below is what I tried to do for the freight shipping.
add_filter( 'woocommerce_package_rates', 'freight_shipping_class_only', 10, 2 );
function freight_shipping_class_only( $rates, $package ) {
$shipping_class_target = 193;
$in_cart = false;
foreach( WC()->cart->cart_contents as $key => $values ) {
if( $values[ 'data' ]->get_shipping_class_id() == $shipping_class_target ) {
$in_cart = true;
break;
}
}
if( $in_cart ) {
unset( $rates['fedex:PRIORITY_OVERNIGHT'], $rates['fedex:FEDEX_2_DAY'],$rates['fedex:FEDEX_GROUND'] ); // shipping method with ID (to find it, see screenshot below)
isset( $rates['flat_rate:10'] );
}
return $rates;
}
Is there a way to set both the cart weight and the freight shipping class in one function? It would be ideal since I want them both to do the exact same thing by unset all FedEx shipping option and isset the freight shipping option.
Let me know if you need me to be clearer or if you have any tips.
Thanks!
As you are using 2 times the same hook, you can simply merge your functions in one.
Now with php [isset()][1] you need to use it in as a condition in an IF statement to check if a variable is set (exist), but it has no effect alone outside your IF statement in your function.
So in your first function the following doesn't has any effect:
if ( isset( $rates['fedex:PRIORITY_OVERNIGHT'], $rates['fedex:FEDEX_2_DAY'], $rates['fedex:FEDEX_GROUND'] ) );
So you can try this compact and efficient code instead:
add_filter( 'woocommerce_package_rates', 'freight_shipping_class_only', 20, 2 );
function freight_shipping_class_only( $rates, $package ) {
// HERE the targeted shipping class ID
$targeted_shipping_class = 193;
// Loop through cart items and checking
$found = false;
foreach( $package['contents'] as $item ) {
if( $item['data']->get_shipping_class_id() == $targeted_shipping_class ){
$found = true;
break;
}
}
// The condition
if ( isset( $rates['flat_rate:10'] ) && ( WC()->cart->get_cart_contents_weight() >= 300 || $found ) ){
unset( $rates['fedex:PRIORITY_OVERNIGHT'], $rates['fedex:FEDEX_2_DAY'], $rates['fedex:FEDEX_GROUND'] );
}
return $rates;
}
Code goes in function.php file of the active child theme (or active theme). It should work.
I found a solution, it isn't exactly what I wanted but it works. What I did was change the cart weight to anything over 300 pounds unset the FedEx shipping options. Then unset FedEx shipping options for the freight shipping class. Which still left the freight shipping option visible on non-freight items, which I hid using CSS.
I am still open for a better way to do this. So if you have suggestions please send them my way.
Below is what I ended up doing.
add_filter( 'woocommerce_package_rates', 'bbloomer_woocommerce_tiered_shipping', 10, 2 );
function bbloomer_woocommerce_tiered_shipping( $rates, $package ) {
if ( WC()->cart->cart_contents_weight < 300 ) {
if ( isset( $rates['fedex:PRIORITY_OVERNIGHT'], $rates['fedex:FEDEX_2_DAY'], $rates['fedex:FEDEX_GROUND'] ) );
} else {
if ( isset( $rates['flat_rate:10'] ) ) unset( $rates['fedex:PRIORITY_OVERNIGHT'], $rates['fedex:FEDEX_2_DAY'],$rates['fedex:FEDEX_GROUND'] );
}
return $rates;
}
/** Freight Shipping Class Only **/
add_filter( 'woocommerce_package_rates', 'freight_shipping_class_only', 10, 2 );
function freight_shipping_class_only( $rates, $package ) {
$shipping_class_target = 193;
$in_cart = false;
foreach( WC()->cart->cart_contents as $key => $values ) {
if( $values[ 'data' ]->get_shipping_class_id() == $shipping_class_target ) {
$in_cart = true;
break;
}
}
if( $in_cart ) {
unset( $rates['fedex:PRIORITY_OVERNIGHT'], $rates['fedex:FEDEX_2_DAY'],$rates['fedex:FEDEX_GROUND'] );
}
return $rates;
}

Woocommerce Role Based Payment and minimum Subtotal

Currently I'm working on a WC-Project and I'm stucked. With this snippet it's showing the payment method "bacs" only when the subtotal is over 100. This works fine!
add_filter( 'woocommerce_available_payment_gateways', 'mmx_remove_bacs', 1 );
function mmx_remove_bacs( $gateways ){
global $woocommerce;
if ( $woocommerce->cart->subtotal < 100 ) {
unset($gateways['bacs']);
}
return $gateways;
}
Now this snippet above should only work when a customer is in the Checkout that has the userrole "customer". For this I have this seperate snippet:
Function enable_payment( $available_gateways ) {
global $woocommerce;
if ( isset( $available_gateways['bacs'] ) && !current_user_can('customer') ) {
unset( $available_gateways['bacs'] );
}
return $available_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'enable_payment' );
My question now is, how can I bring this to snippets together, that it works as I wish?

Categories