Changing currency on checkout with WooCommerce Multilingual Plugin - php

I'm trying to implement currency change on checkout with WooCommerce Multilingual Plugin. I need a country with COP and the rest of countries with USD. First I tried to use the wcml_client_currency hook.
function modify_client_currency( $currency ) {
$country = WC()->customer->get_billing_country();
if ($country === 'CO') {
return 'COP';
} else {
return 'USD';
}
}
add_filter( 'wcml_client_currency', 'modify_client_currency', 10, 1 );
If I start with Colombia selected, the currency is in COP, but if I change to another country, the currency stay on COP. I need to change the country again to see the change.
I tried another approach with the woocommerce_checkout_update_order_review and analyzing how the multilingual plugin works.
function action_woocommerce_checkout_update_order_review( $post_data ) {
// This part will change dynamically based on the country contained in $post_data
$currency = 'COP';
global $woocommerce_wpml;
$woocommerce_wpml->multi_currency->set_client_currency($currency);
global $woocommerce, $current_user;
if(empty($woocommerce->session->data) && empty($current_user->ID)){
$woocommerce->session->set_customer_session_cookie(true);
}
do_action('wcml_switch_currency', $currency );
WC()->cart->calculate_totals();
}
add_action('woocommerce_checkout_update_order_review', 'action_woocommerce_checkout_update_order_review', 10, 1);
With this approach I have exactly the same problem, I need to change the country twice to see the currency change.

Related

Get active currency and unset countries WooCommerce

I am using WooCommerce with WooCommerce Multilingual.
So I am using different currencies. I want to unset billing and shipping countries based on the current active currency.
I found this function to unset countries:
function woo_remove_specific_country( $country ) {
unset($country["US"]);
unset($country["GB"]);
return $country;
}
add_filter( 'woocommerce_countries', 'woo_remove_specific_country', 10, 1 );
But I want to change this function so there is conditional logic in it. So for example when EUR is the active current currency US and GB has to be the unset countries. If GBP is the current active currency only US needs to be unset.
So I found this to get the current active currency:
$currency = get_woocommerce_currency();
When using this to test it inside a shortcode it gives me the right active currency.
So I rewrote the function:
function woo_remove_specific_country( $country ) {
$currency = get_woocommerce_currency();
if ($currency == 'EUR') {
unset($country["US"]);
unset($country["GB"]);
}
if ($currency == 'GBP') {
unset($country["US"]);
}
return $country;
}
add_filter( 'woocommerce_countries', 'woo_remove_specific_country', 10, 1 );
But this doesn't work. It looks like it always takes the way of the if with EUR while my currency is GBP at that moment.

Show prices only for a specific customer's country in Woocommerce

I've developed a catalogue using woocommerce, however I need to be able to hide product prices from users who are visiting the site from outside of the UK due to reasons outside of my control.
I've found plugins that allow me to change product prices based on visitor location, but nothing allows me to hide the prices.
Is there any plugins that I've missed or anything I can add in to the woocommerce files to achieve this?
There are various web APIs that will help you. For example http://ipinfo.io
ip = $_SERVER['REMOTE_ADDR'];
$details = json_decode(file_get_contents("http://ipinfo.io/{$ip}"));
echo $details->country; // -> "US"
If you have to do many checks a local database is better. MaxMind offer a free database that you can use with various PHP libraries, including GeoIP.
The following will hide prices outside United kingdom based on customer geolocated country:
add_filter( 'woocommerce_get_price_html', 'country_geolocated_based_hide_price', 10, 2 );
function country_geolocated_based_hide_price( $price, $product ) {
// Get an instance of the WC_Geolocation object class
$geo_instance = new WC_Geolocation();
// Get geolocated user geo data.
$user_geodata = $geo_instance->geolocate_ip();
// Get current user GeoIP Country
$country = $user_geodata['country'];
return $country !== 'GB' ? '' : $price;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
If you want to enable that geolocated feature only for unlogged customers, use the following:
add_filter( 'woocommerce_get_price_html', 'country_geolocated_based_hide_price', 10, 2 );
function country_geolocated_based_hide_price( $price, $product ) {
if( get_current_user_id() > 0 ) {
$country = WC()->customer->get_billing_country();
} else {
// Get an instance of the WC_Geolocation object class
$geo_instance = new WC_Geolocation();
// Get geolocated user geo data.
$user_geodata = $geo_instance->geolocate_ip();
// Get current user GeoIP Country
$country = $user_geodata['country'];
}
return $country !== 'GB' ? '' : $price;
}
An updated version of this code is available on this answer avoiding a backend bug.
I have added in the function on start:
if ( is admin() ) return $price;
Code goes in function.php file of your active child theme (or active theme). Tested and works.

WooCommerce: Pre-select and restrict to one state and city on checkout

I'm setting up a store that only sells to one city. I'm trying to figure out how I can restrict the city option to a pre-filled field.
I've already limited the country and using the following code in my functions.php:
add_filter( 'default_checkout_country', 'change_default_checkout_country' );
add_filter( 'default_checkout_state', 'change_default_checkout_state' );
function change_default_checkout_country() {
return 'PK'; // country code
}
function change_default_checkout_state() {
return 'SD'; // state code
}
And I've pre-selected the state using the following:
add_filter( 'woocommerce_states', 'bbloomer_custom_woocommerce_states' );
function bbloomer_custom_woocommerce_states( $states ) {
$states['PK'] = array(
'SD' => 'Sindh',
);
return $states;
}
But... Now comes the city and I am lost. I've tried using $fields['billing']['billing_city'] as well as $fields['billing']['billing_city']['value'] to no avail.
I want the customer to be limited to Karachi. I am not very familiar with WooCommerce filters, so I need help on achieving this.
Since woocommerce 3, default_checkout_country and default_checkout_state filter hooks are now deprecated and replaced.
Also in your last function, if you want to restrict just to one city, you should not include your city in the array of states. Instead you should return only one possible value.
So this will be your code:
// default checkout country
add_filter( 'default_checkout_billing_country', 'change_default_checkout_country' );
add_filter( 'default_checkout_shipping_country', 'change_default_checkout_country' );
function change_default_checkout_country() {
return 'PK'; // country code
}
// default checkout state
add_filter( 'default_checkout_billing_state', 'change_default_checkout_state' );
add_filter( 'default_checkout_shipping_state', 'change_default_checkout_state' );
function change_default_checkout_state() {
return 'SD'; // state code
}
// Setting one state only
add_filter( 'woocommerce_states', 'custom_woocommerce_state', 10, 1 );
function custom_woocommerce_state( $states ) {
// Returning a unique state
return array('PK' => array('SD' => 'Sindh'));
}
// Only one city at checkout
add_filter( 'woocommerce_checkout_fields', 'custom_checkout_fields', 10, 1 );
function custom_checkout_fields( $fields ) {
$fields['billing']['billing_city']['type'] = 'select';
$fields['billing']['billing_city']['options'] = array('Karachi' => 'Karachi');
$fields['shipping']['shipping_city']['type'] = 'select';
$fields['shipping']['shipping_city']['options'] = array('Karachi' => 'Karachi');
return $fields;
}
The 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 for wooCommerce versions 3+
Once added the code above and saved, you will need in WooCommerce > Settings > General to set locations this way:
Then you will get something like this on checkout:
Both dropdown have only one value… So you get what you are expecting.

WooCommerce checkout - how to give free shipping for a specific address

The following code will allow free shipping for a specific product:
function wcs_my_free_shipping( $is_available ) {
global $woocommerce;
// set the product ids that are eligible
$eligible = array( '360' );
// get cart contents
$cart_items = $woocommerce->cart->get_cart();
// loop through the items looking for one in the eligible array
foreach ( $cart_items as $key => $item ) {
if( in_array( $item['product_id'], $eligible ) ) {
return true;
}
}
// nothing found return the default value
return $is_available;
}
add_filter( 'woocommerce_shipping_free_shipping_is_available', 'wcs_my_free_shipping', 20 );
What I would like to do is allow free shipping not for a product, but for a specific street and zip code combination in the delivery address. I found out how to check this for a logged-in user, but can't seem to find the right variables that have this information at checkout. Any help would be greatly appreciated.
Thanks in advance,
-Ben
There are Shipping zones available in Woocommerce already. For each specific zone you can set the shipping method either "Flat rate" or "Free Shipping". You can check it under Woocommerce->Settings. Find Shipping tab.
Screenshot for shipping tab
Yes you can, there is an extra parameter you can pass into this hook names $package.
for eg.
add_filter( 'woocommerce_shipping_free_shipping_is_available', 'wcs_my_free_shipping', 20,2 );
function wcs_my_free_shipping( $is_available, $package){
//Your code for free shipping for a selected address found in $package
return $is_available
}
$package contains the address you entered so you can use this to apply free shipping for selected zip codes or streets

update woocommerce cart after changing shipping method

I am currently working on an online shop with WooCommerce. I faced the problem that I want to grant a discount to customers who chose a specific shipping method. The discount is 0.50 for every single product. I basically solved this problem with the following code in my "functions.php":
add_action('woocommerce_before_calculate_totals', 'woo_add_cart_fee');
function woo_add_cart_fee() {
global $woocommerce;
$cart = $woocommerce->cart->get_cart();
//Calculating Quantity
foreach ($cart as $cart_val => $cid) {
$qty += $cid['quantity'];
}
if ($woocommerce->cart->shipping_label == "specific shipping method") {
$woo_fee = $qty * (-0.5);
$woo_name = "discount for specific shipping method";
}
$woocommerce->cart->add_fee(__($woo_name, 'woocommerce'), $woo_fee, true);
}
The code technically works, the only problem I have now is that if a customer changes the shipping method i.e. from the "specific shipping method" to a "normal one" (without any discount) or the other way round, it always displays and calculates the discount value from the previously chosen shipping method. In other words it is always one step back and therefore displays the customer the wrong total amount.
Does anyone has an idea to solve this problem?
This solutions is for Woocommerce 2.1.X!
I am not sure if this might help. I was facing a similar problem, where I needed to retrieve the chosen shipping method. In the file \wp-content\plugins\woocommerce\includes\wc-cart-functions.php I found a method called wc_cart_totals_shipping_html().
Within this method there is a check of the current selected shipping method that contains the following code:
$packages = WC()->shipping->get_packages();
foreach ( $packages as $i => $package ) {
$chosen_method = isset( WC()->session->chosen_shipping_methods[ $i ] ) ? WC()->session->chosen_shipping_methods[ $i ] : '';
}
I used this code in my own functions.php to check for the currently selected shipping method and it works. Example:
add_filter( 'woocommerce_billing_fields', 'wc_change_required_fields');
function wc_change_required_fields($address_fields) {
$packages = WC()->shipping->get_packages();
foreach ( $packages as $i => $package ) {
$chosen_method = isset( WC()->session->chosen_shipping_methods[ $i ] ) ? WC()->session->chosen_shipping_methods[ $i ] : '';
}
if ($chosen_method == 'local_delivery') {
$address_fields['billing_address_1']['required'] = true;
// place your changes that depend on the shipping method here...
}
}
Hope that helps!
This is very old, but I ran into this issue myself and had to work out the solution.
Woocommerce stores pre-calculated cart totals in the database, rather than calculating them on the fly. But the shipping method choice is stored as a session variable. So shipping changes are not reflected immediately at checkout without a visit or refresh of a cart page.
With the original posted code, the shipping changes were not reflected because they aren't recalculated and stored. To do this, the function needs to be tricked into thinking it's a cart page first, and then recalculating the totals to be stored.
GLOBAL $woocommerce;
if ( ! defined('WOOCOMMERCE_CART') ) {
define( 'WOOCOMMERCE_CART', true );
}
And then at the end of the function, after all the desired changes have been made refresh and store.
WC()->cart->calculate_totals();
See also CODEX for WC_AJAX::update_shipping_method()
http://docs.woothemes.com/wc-apidocs/source-class-WC_AJAX.html#148-174
Mark's answer worked for me, however I had to delete all transient values prior to running the code. Otherwise, it would simply restore the saved values.
public function clear_shipping_transients() {
global $wpdb;
$wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_cp_quote_%') OR `option_name` LIKE ('_transient_timeout_cp_quote_%') OR `option_name` LIKE ('_transient_wc_ship_%')" );
}

Categories