Woocommerce payment options only for certain countries - php

I am trying to enable and disable certain payment functions for certain countries in Woocommerce. I had placed the following code in my functions:
function payment_gateway_disable_by_country( $available_gateways ) {
// Abort if in admin area
if ( is_admin() ) {
return $available_gateways;
}
$billing_country = WC()->customer->get_country();
$shipping_country = ! empty( WC()->customer->get_shipping_country() ) ? WC()->customer->get_shipping_country() : $billing_country;
if ( isset( $available_gateways['invoice'] ) && $billing_country != 'DE' ) {
unset( $available_gateways['invoice'] );
}
if ( isset( $available_gateways['cod'] ) && $shipping_country != 'DE' ) {
unset( $available_gateways['cod'] );
}
return $available_gateways;
}
add_filter( 'woocommerce_available_payment_gateways','payment_gateway_disable_by_country');
but then I am getting a white screen with the following error message:
Fatal error: Can't use method return value in write context in /home/www/mysite/html/wordpress/wp-content/themes/mytheme/functions.php on line 10.
Is there anything wrong with my code?

Related

WooCommerce Subscriptions - Changing the wording/removing subscription terms (eg /month)

I found this older post: How to change the "/ month" on a woocommerce subscription product page
'''
add_filter('woocommerce_subscriptions_product_price_string_inclusions',
'remove_subscription_inclusions', 10, 2);
function remove_subscription_inclusions( $include, $product ) {
$include['subscription_length'] = '';
return $include;
}
'''
That code works great for the product pages, but it doesn't remove the "/month" ('term' I guess would be the correct term) in the cart/checkout pages.
Does anyone have any idea how to apply the same thing as in the other post the cart/checkout pages as well?
// Line items pricing
add_filter( 'woocommerce_subscriptions_product_price_string', 'wc_subscriptions_product_price_string', 10, 3 );
function wc_subscriptions_product_price_string( $price_string, $product, $args ) {
if ( is_cart() || ( is_checkout() && ! is_wc_endpoint_url() ) ) {
return $args['price'];
}
return $price_string;
}
// Total line items
add_filter( 'woocommerce_subscription_price_string', 'wc_subscription_recurring_price_string', 10, 2 );
function wc_subscription_recurring_price_string( $subscription_string, $subscription_details ) {
if ( is_cart() || ( is_checkout() && ! is_wc_endpoint_url() ) ) {
$recurring_amount = $subscription_details['recurring_amount'];
if( is_numeric( $recurring_amount ) ) {
return strip_tags( wc_price($recurring_amount) );
}
else {
return $recurring_amount;
}
}
return $subscription_string;
}

Show cash on delivery (COD) based on applied coupons in WooCommerce

I am trying to have cash on delivery (COD) enabled only for customers that use certain type off coupons.
I have an existing code that, when coupons of a certain type are entered, converts the product sales price to the regular product price.
Now I would like to add that cash on delivery (COD) only is available for valid coupons within the same function.
The part that I have tried to add is this:
if ($coupons = WC()->cart->get_applied_coupons() == False )
unset( $available_gateways['cod'] );
Resulting in:
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price( $cart_object) {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$coupon = False;
if ($coupons = WC()->cart->get_applied_coupons() == False )
unset( $available_gateways['cod'] );
if ($coupons = WC()->cart->get_applied_coupons() == False )
$coupon = False;
else {
foreach ( WC()->cart->get_applied_coupons() as $code ) {
$coupons1 = new WC_Coupon( $code );
if ($coupons1->type == 'percent_product' || $coupons1->type == 'percent')
$coupon = True;
}
}
if ($coupon == True)
foreach ( $cart_object->get_cart() as $cart_item )
{
$price = $cart_item['data']->regular_price;
$cart_item['data']->set_price( $price );
}
}
This does not give real error messages, but certainly not the desired result either. Any advice?
First of all I have rewritten your existing code, the part that converts sale prices to regular prices when a certain type of coupon is applied. This because your current code contains outdated methods:
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Initialize
$flag = false;
// Applied coupons only
if ( sizeof( $cart->get_applied_coupons() ) >= 1 ) {
// Loop trough
foreach ( $cart->get_applied_coupons() as $coupon_code ) {
// Get an instance of the WC_Coupon Object
$coupon = new WC_Coupon( $coupon_code );
// Only for certain types, several can be added, separated by a comma
if ( in_array( $coupon->get_discount_type(), array( 'percent', 'fixed_product', 'percent_product' ) ) ) {
$flag = true;
break;
}
}
}
// True
if ( $flag ) {
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get regular price
$regular_price = $cart_item['data']->get_regular_price();
// Set new price
$cart_item['data']->set_price( $regular_price );
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
Then to only make COD active, if coupons of a certain type are applied you can use the woocommerce_available_payment_gateways hook
By default COD will not be available:
// Payment gateways
function filter_woocommerce_available_payment_gateways( $payment_gateways ) {
// Not on admin
if ( is_admin() ) return $payment_gateways;
// Initialize
$flag = false;
// WC Cart
if ( WC()->cart ) {
// Get cart
$cart = WC()->cart;
// Applied coupons only
if ( sizeof( $cart->get_applied_coupons() ) >= 1 ) {
// Loop trough
foreach ( $cart->get_applied_coupons() as $coupon_code ) {
// Get an instance of the WC_Coupon Object
$coupon = new WC_Coupon( $coupon_code );
// Only for certain types, several can be added, separated by a comma
if ( in_array( $coupon->get_discount_type(), array( 'percent', 'fixed_product', 'percent_product' ) ) ) {
$flag = true;
break;
}
}
}
}
// NOT true, so false
if ( ! $flag ) {
// Cod
if ( isset( $payment_gateways['cod'] ) ) {
unset( $payment_gateways['cod'] );
}
}
return $payment_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'filter_woocommerce_available_payment_gateways', 10, 1 );
Both codes go goes in functions.php file of the active child theme (or active theme).
Tested in WordPress 5.8.1 and WooCommerce 5.8.0

WooCommerce: Disable multiple Payment methods based on country

What I am trying to do here is hide payments methods, based on the customer country.
Hide bacs and cheque, when the country is different than US.
When the country is US, hide cod payment method (this is working)
I been trying to do this, but it didn't work
Here is the code:
add_filter( 'woocommerce_available_payment_gateways', 'custom_payment_gateway_disable_country' );
function custom_payment_gateway_disable_country( $available_gateways ) {
if ( is_admin() ) return $available_gateways;
if ( isset( $available_gateways['bacs' && 'cheque'] ) && WC()->customer->get_billing_country() <> 'US' ) {
unset( $available_gateways['bacs' && 'cheque'] );
} else {
if ( isset( $available_gateways['cod'] ) && WC()->customer->get_billing_country() == 'US' ) {
unset( $available_gateways['cod'] );
}
}
return $available_gateways;
}
Can someone push me in the right direction? Any help will be appreciated!
Your if/else statements are wrong. As isset( $available_gateways['bacs' && 'cheque'] will never work.
See: PHP If Statement with Multiple Conditions
So you get:
function filter_woocommerce_available_payment_gateways( $payment_gateways ) {
// Not on admin
if ( is_admin() ) return $payment_gateways;
// Get country
$customer_country = WC()->customer->get_shipping_country() ? WC()->customer->get_shipping_country() : WC()->customer->get_billing_country();
// Country = US
if ( in_array( $customer_country, array( 'US' ) ) ) {
// Cod
if ( isset( $payment_gateways['cod'] ) ) {
unset( $payment_gateways['cod'] );
}
} else {
// Bacs & Cheque
if ( isset( $payment_gateways['bacs'] ) && isset( $payment_gateways['cheque'] ) ) {
unset( $payment_gateways['bacs'] );
unset( $payment_gateways['cheque'] );
}
}
return $payment_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'filter_woocommerce_available_payment_gateways', 10, 1 );

Auto apply coupon based on custom user_meta in Woocommerce

First post here so be gentle. I have done my usual searching and testing but I am stumped.
Anyways here is my code that I am trying to use. I need to apply a coupon code that takes 2% off all orders if the user belongs to a certain buying group which is in their profile.
The coupon also does an exclude on one category at the moment so I don't know exactly how that factors in when automatically applying a code.
Does it just follow the restrictions for the coupon?
add_action( 'woocommerce_before_cart', 'anla_apply_buying_group_discount_coupon' );
function anla_apply_buying_group_discount_coupon() {
global $woocommerce;
global $current_user;
$user_id = get_current_user_id();
$maybe_has_buying_group_discount = get_user_meta( $user_id, 'has_buying_group_discount', true );
if ( '1' === $maybe_has_buying_group_discount ) {
return true;
}
elseif ( '0' === $maybe_has_buying_group_discount ) {
return false;
}
if ($maybe_has_buying_group_discount == true ) {
$woocommerce->cart->add_discount( 'buying group discount (2%)' );
}
elseif ($maybe_has_buying_group_discount == false ) {
$woocommerce->cart->remove_discount( 'buying group discount (2%)' );
$woocommerce->cart->calculate_totals();
}
}
Any help is appreciated.
There are some errors and deprecated methods in your code. The hook that you are using is not the right one. Instead try the following with additional notice messages:
add_action( 'woocommerce_before_calculate_totals', 'apply_group_discount_coupon', 20, 1 );
function apply_group_discount_coupon( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// HERE set your coupon code
$coupon_name = "buying group discount (2%)";
$user_id = get_current_user_id();
$discount_enabled = get_user_meta( $user_id, 'has_buying_group_discount', true );
$coupon_code = sanitize_title( $coupon_name );
if ( $discount_enabled && ! $cart->has_discount( $coupon_code ) ){
$cart->apply_coupon( $coupon_code );
$message = __("You have 2% of discount as Premium user group", 'woocommerce');
} elseif ( ! $discount_enabled && $cart->has_discount( $coupon_code ) ) {
$cart->remove_coupon( $coupon_code );
$message = __("You can't get a discount as Premium user group", 'woocommerce');
} else
return;
// Display a custom notice
if( isset($message) ){
wc_clear_notices();
wc_add_notice( $message, 'notice');
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
The version without message:
add_action( 'woocommerce_before_calculate_totals', 'apply_group_discount_coupon', 20, 1 );
function apply_group_discount_coupon( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// HERE set your coupon code
$coupon_name = "buying group discount (2%)";
$user_id = get_current_user_id();
$discount_enabled = get_user_meta( $user_id, 'has_buying_group_discount', true );
$coupon_code = sanitize_title( $coupon_name );
if ( $discount_enabled && ! $cart->has_discount( $coupon_code ) )
$cart->apply_coupon( $coupon_code );
elseif ( ! $discount_enabled && $cart->has_discount( $coupon_code ) ) {
$cart->remove_coupon( $coupon_code );
else
return;
}

WooCommerce custom code breaks after upgrade to 3.X

After the newer release of WooCommerce 3.X , the code written for WoCommerce 2.X doesn't work anymore without throwing error on the product type line.
function remove_bundled_items_from_cart( $cart_item_key, $instance ) {
if ( ! empty( $instance->removed_cart_contents[$cart_item_key] ) ) {
$product_id = $instance->removed_cart_contents[$cart_item_key]['product_id'];
$product_type = $instance->removed_cart_contents[$cart_item_key]['data']->product_type;
if ( $product_type == 'bundle' ) {
if (is_array($instance->cart_contents) || is_object($instance->cart_contents)) {
foreach ( $instance->cart_contents as $key => $cart_item ) {
if ( isset( $cart_item['is_bundled_item'] ) && $cart_item['is_bundled_item'] == $product_id ) {
WC()->cart->remove_cart_item( $key );
}
}
}
}
}
}
add_action( 'woocommerce_cart_item_removed', 'remove_bundled_items_from_cart', 10, 2 );
Does anybody know what I need to change to be able to have the $product_type stop throwing a error?
I would still need to be able to check if the string is "bundle", so I need somehow to get the information fetched.
As the main error in your code comes from:
$product_type = $instance->removed_cart_contents[$cart_item_key]['data']->product_type;
The $instance->removed_cart_contents[$cart_item_key]['data'] is the WC_Product Object instance and since WC versions 3+ WC_Product properties can't be accessed directly anymore.
Instead you will use the WC_Product method get_type() (or the conditional method is_type())…
As $instance->removed_cart_contents[$cart_item_key]['data'] doesn't exist in simple products, you need to test it in your first condition.
This should avoid throwing errors (on the product type line…):
add_action( 'woocommerce_cart_item_removed', 'remove_bundled_items_from_cart', 10, 2 );
function remove_bundled_items_from_cart( $cart_item_key, $instance ) {
if ( ! empty( $instance->removed_cart_contents[$cart_item_key]['data'] ) ) {
$product_id = $instance->removed_cart_contents[$cart_item_key]['product_id'];
$product = $instance->removed_cart_contents[$cart_item_key]['data']; // The WC_Product object
if ( $product->is_type( 'bundle' ) ) {
if (is_array($instance->cart_contents) || is_object($instance->cart_contents)) {
foreach ( $instance->cart_contents as $key => $cart_item ) {
if ( isset( $cart_item['is_bundled_item'] ) && $cart_item['is_bundled_item'] == $product_id ) {
WC()->cart->remove_cart_item( $key );
}
}
}
}
}
}
BUT I don't see in the raw cart data output any 'is_bundled_item' key…
Instead you can use in your code one of this available cart array keys:
bundled_by key (the parent WC_Bundle_Product cart item key)
bundled_item_id key (the child bundle item ID)
So you could replace in your code 'is_bundled_item' like:
add_action( 'woocommerce_cart_item_removed', 'remove_bundled_items_from_cart', 10, 2 );
function remove_bundled_items_from_cart( $cart_item_key, $instance ) {
if ( ! empty( $instance->removed_cart_contents[$cart_item_key]['data'] ) ) {
$product = $instance->removed_cart_contents[$cart_item_key]['data'];
if ( $product->is_type( 'bundle' ) ) {
if (is_array($instance->cart_contents) || is_object($instance->cart_contents)) {
foreach ( $instance->cart_contents as $key => $cart_item ) {
if ( isset( $cart_item['bundled_item_id'] ) && $cart_item['bundled_by'] == $cart_item_key ) {
WC()->cart->remove_cart_item( $key );
}
}
}
}
}
}
This should work totally…

Categories