Disallow customer to change country in WooCommerce checkout - php

I am looking for solution where I can find user's country in woocommerce checkout page. I am doing it via geolocation. However, the user can change that. I want to restrict it.
I am using a paid plugin to give coupons to users from a specific country. The country gets loaded perfectly and coupon is applied or rejected based on country. However, the user manually can change the country at the checkout page and avail the discount. My service is online thus there is no delivery of physical goods so entering wrong country wouldn't cause anything to the user.
I have tried 2-3 different coupon restriction plugins but all has the same problem. Does anyone has faced similar issue?

Updated
You can make checkout country dropdown fields disabled (read only) as follows:
add_filter( 'woocommerce_checkout_fields', 'checkout_country_fields_disabled' );
function checkout_country_fields_disabled( $fields ) {
$fields['billing']['billing_country']['custom_attributes']['disabled'] = 'disabled';
$fields['billing']['shipping_country']['custom_attributes']['disabled'] = 'disabled';
return $fields;
}
As disabled select fields doesn't get posted, you need additionally the following duplicated hidden fields with the correct values set in. It will avoid an error notice notifying that country required fields values are empty. So add this too:
// Mandatory for disable fields (hidden billing and shipping country fields with correct values)
add_filter( 'woocommerce_after_checkout_billing_form', 'checkout_country_hidden_fields_replacement' );
function checkout_country_hidden_fields_replacement( $fields ) {
$billing_country = WC()->customer->get_billing_country();
$shipping_country = WC()->customer->get_shipping_country();
?>
<input type="hidden" name="billing_country" value="<?php echo $billing_country; ?>">
<input type="hidden" name="shipping_country" value="<?php echo $shipping_country; ?>">
<?php
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Notes:
You will need to disable shipping calculator in cart page, if it's not done.
If you want to make country dropdown read only in Checkout and in My account Edit Address too, use the following instead:
add_filter( 'woocommerce_billing_fields', 'checkout_billing_country_field_disabled' );
function checkout_billing_country_field_disabled( $fields ) {
$fields['billing_country']['custom_attributes']['disabled'] = 'disabled';
return $fields;
}
add_filter( 'woocommerce_shipping_fields', 'checkout_shipping_country_field_disabled' );
function checkout_shipping_country_field_disabled( $fields ) {
$fields['shipping_country']['custom_attributes']['disabled'] = 'disabled';
return $fields;
}
// Mandatory for disable fields (hidden billing and shipping country fields with correct values)
add_filter( 'woocommerce_after_checkout_billing_form', 'checkout_country_hidden_fields_replacement' );
function checkout_country_hidden_fields_replacement( $fields ) {
$billing_country = WC()->customer->get_billing_country();
$shipping_country = WC()->customer->get_shipping_country();
?>
<input type="hidden" name="billing_country" value="<?php echo $billing_country; ?>">
<input type="hidden" name="shipping_country" value="<?php echo $shipping_country; ?>">
<?php
}

Related

Woocommerce autofocus on input fields "billing_first_name"

I have custom checkout page. First I'm showing content with added to cart items and than using this action to show billing form
<?php do_action( 'woocommerce_checkout_billing' ); ?>
Page scrolls down because of the autofocus on first name field.
Tried to use filters like this one
add_filter('woocommerce_billing_fields','disable_autofocus_billing_firstname');
function disable_autofocus_billing_firstname($fields) {
$fields['billing_first_name']['autofocus'] = false;
return $fields;
}
Also tried to blur the field with jQuery and vanila JS no effect. Is there is some updates for Woo that I'm missing? Thanks!
For overriding core fields need to use the hook 'woocommerce_checkout_fields'
You need to use the snippet below in order to disable the autofocus on checkout field:
/* Disable autofocus at checkout */
function custom_checkout_disable_autofocus_firstname( $fields ) {
$fields['billing']['billing_first_name']['autofocus'] = false;
return $fields;
}
add_filter( 'woocommerce_checkout_fields', 'custom_checkout_disable_autofocus_firstname' );

How to unset WooCommerce custom delivery checkout fields programmatically?

I am unsetting some checkout fields in Woocommerce via code and I am a little stumped on how to unset some custom checkout fields (not default Woocommerce checkout fields). Note that I am using Custom WooCommerce Checkout Fields Editor and Delivery & Pickup Date Time for WooCommerce third party plugins.
Below is the code I am writing that unsets some of the woocommerce related fields (billing, shipping and order):
/**
Remove following checkout fields
**/
function wc_remove_checkout_fields( $fields ) {
// Billing fields
unset( $fields['billing']['billing_company'] );
unset( $fields['billing']['billing_state'] );
// Shipping fields
unset( $fields['shipping']['shipping_company'] );
unset( $fields['shipping']['shipping_state'] );
unset( $fields['shipping']['shipping_country'] );
// Order fields
unset( $fields['order']['order_comments'] );
return $fields;
}
add_filter( 'woocommerce_checkout_fields', 'wc_remove_checkout_fields' );
HTML of delivery data field:
<input type="text" class="input-text flatpickr-input active" name="coderockz_woo_delivery_date_field" id="coderockz_woo_delivery_date_datepicker" placeholder="Delivery Date" value="" data-selectable_dates="365" data-disable_week_days="[]" data-date_format="F j, Y" data-disable_dates="[]" data-week_starts_from="0" data-default_date="1" readonly="readonly">
But how do I unset some custom checkout fields added via a third party plugin?
••• Edit •••
$hide_pickup_date_time = array('coderockz_woo_delivery_delivery_date_field');
foreach($hide_pickup_date_time as $pickup_date_time ) {
if ($chosen_shipping_pickup == $shipping_method_pickup) {
$fields_pickup['order'][$pickup_date_time]['required'] = false;
}
}
Plugin screenshot

Save custom checkout delivery time field value in WooCommerce order details

On the checkout page, there are delivery methods, if a specific delivery method (only 1) is selected, then a drop-down list with the delivery time should appear. This field is implemented using the ACF plugin with Repeater and the field type is Text. The time selected by the user should be displayed in the order details in the WooCommerce admin panel.
Based on the theme code that I got, I wrote the next code:
In the woocommerce / checkout / form-shipping.php file the following code:
<div id="delivery_times" class="form-group d-none">
<label class="text-bold" for="select_time">Delivery time: </label>
<select id="select_time" class="form-control mb-1">
<option value="" selected>Select time</option>
<?php
$delivery_times = get_field('delivery_times', 'options');
$count = 0;
foreach ($delivery_times as $delivery_time):
echo '<option value="'.$delivery_time['range_time'].'" data-pickup="'.$count.'">'.$delivery_time['range_time'].'</option>';
$count++;
endforeach;
?>
</select>
</div>
There is a common theme-checkout.js file, in which I added the code:
$("#shipping_speed").change(function(){
var delivery_time = $(this).children("option:selected").data("type");
if(delivery_time == "tomorrow"){
$("#delivery_times").removeClass("d-none");
}else{
$("#delivery_times").addClass("d-none");
$("#select_time option[value='']").prop('selected',true);
}
});
And now I need to save the selected data and display it somehow in the order details for the administrator, but I don’t found the implementation of something similar in my theme. Please tell me how I can save this data from the ACF field to the order details?
Updated:
First on your html <select> the attibute name="select_time" is missing, so replace the line:
<select id="select_time" class="form-control mb-1">
by this line:
<select id="select_time" name="select_time" class="form-control mb-1">
Now you can use the following code snippet to save the chosen value as order meta data:
// Save the custom checkout field as the order meta
add_action( 'woocommerce_checkout_create_order', 'custom_checkout_field_update_order_meta', 10, 2 );
function custom_checkout_field_update_order_meta( $order, $data ) {
if ( isset($_POST['select_time']) ) {
$order->update_meta_data( 'delivery_time', esc_attr($_POST['select_time']) );
}
}
Then to display it in admin single order pages under shipping address:
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_admin_order_select_time_custom_field' );
function display_admin_order_select_time_custom_field( $order ){
$delivery_time = $order->get_meta('delivery_time');
if( ! empty($delivery_time) ) {
echo '<p class="delivery_time"><strong>'. __("Delivery time", "woocommerce").'</strong>: '.$delivery_time.'</p>';
}
}
Then you can display this delivery time on customer orders and email notifications:
add_filter( 'woocommerce_get_order_item_totals', 'delivery_time_as_order_item_total_row', 10, 3 );
function delivery_time_as_order_item_total_row( $total_rows, $order, $tax_display ){
$delivery_time = $order->get_meta( 'delivery_time' ); // Get delivery time
$new_total_rows = array(); // Initializing
if( empty($delivery_time) ) {
return $total_rows; // Exit
}
// Loop through total rows
foreach( $total_rows as $key => $value ){
if( 'payment_method' == $key ) {
$new_total_rows['delivery_time'] = array(
'label' => __("Delivery time", "woocommerce"),
'value' => $delivery_time,
);
}
$new_total_rows[$key] = $total_rows[$key];
}
return $new_total_rows;
}
Code goes in functions.php file of the active child theme (or active theme). It should work.
Data probably it's saved on another php file, it's using the MVC model.
One thing I would say you is that it's a form, so it does have already other data processed, I would suggest you to find where it does process other data and add some properties there...
Makes sense?

Disable or make read only the fields from edit account pages in Woocommerce

Currently the Edit Account Details page have these fields: First Name, Last Name, Email address, Current Password & New Password.
Now I need to disable the First Name, Last Name, Email address fields for customers user only. I am using Flatsome WP theme and Woocommerce plugins.
How can I do this?
Update
For edit "Account details" fields (email field), you will need to edit myaccount/form-edit-account.php template file as those fields are hard coded in the template
You will have to add a readonly attribute to the related input fields like in this extract example:
<p class="woocommerce-form-row woocommerce-form-row--first form-row form-row-first">
<label for="account_first_name"><?php esc_html_e( 'First name', 'woocommerce' ); ?> <span class="required">*</span></label>
<input type="text" class="woocommerce-Input woocommerce-Input--text input-text" name="account_first_name" id="account_first_name" autocomplete="given-name" value="<?php echo esc_attr( $user->first_name ); ?>" readonly />
</p>
Official documentation: Overriding templates via a theme
For My account > edit billing address, the following code will make readonly the billing fields first name, last name and email:
add_filter( 'woocommerce_billing_fields', 'readonly_billing_account_fields', 25, 1 );
function readonly_billing_account_fields ( $billing_fields ) {
// Only my account billing address for logged in users
if( is_account_page() ){
$readonly = ['readonly' => 'readonly'];
$billing_fields['billing_first_name']['custom_attributes'] = $readonly;
$billing_fields['billing_last_name']['custom_attributes'] = $readonly;
$billing_fields['billing_email']['custom_attributes'] = $readonly;
}
return $billing_fields;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Note: To enable that on checkout page too, Just remove if( is_account_page() ){ and the closing bracket } before return $billing_fields;.
To remove those 3 fields you will use:
add_filter( 'woocommerce_billing_fields', 'remove_billing_account_fields', 25, 1 );
function remove_billing_account_fields ( $billing_fields ) {
// Only my account billing address for logged in users
if( is_account_page() ){
unset($billing_fields['billing_first_name']);
unset($billing_fields['billing_last_name']);
unset($billing_fields['billing_email']);
}
return $billing_fields;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
You can easily disable various fields from the WooCommerce Account Page by adding this to your theme's functions.php
function my_remove_checkout_fields($fields) {
unset( $fields ['billing'] ['billing_first_name'] );
unset( $fields ['billing'] ['billing_last_name'] );
unset( $fields ['billing'] ['billing_email'] );
// Any other fields you want to unset...
return $fields;
}
add_filter( 'woocommerce_checkout_fields', 'my_remove_checkout_fields' );
The documentation for customizing fields can be found here.

How do I retain the user preference in WooCommerce Checkout - Ship to different address

In the WooCommerce cart, you can set the default to ship to the billing address. The user can then check a box to enable a different shipping address. For returning customers it is a nuisance that you have to check the box again. I would like to remember the state of the checkbox for logged in users, so that not only the address information is shown, but also the state of the checkbox is the same as for the last order.
There are snippets published where you can add extra fields to shipping or billing, and let WooCommerce handle the storage. Other examples show custom fields where the data is stort in post. This is maintained on the order, but not available on the next order.
So I answered my own question above with the following. First have an action in functions.php of your child theme that saves the state of the checkbox in the user meta:
/**
* Update the user meta with checkbox setting
*/
add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );
function my_custom_checkout_field_update_order_meta( $order_id ) {
$order = new WC_Order( $order_id );
update_user_meta( $order->user_id , 'shipping_different',$_POST['ship_to_different_address']) ;
}
Then add an action to retrieve the stored checkbox value and update the checkbox:
/*
* Get the user meta to set the checkbox if needed
*/
add_action( 'woocommerce_after_checkout_billing_form', 'my_checkout_fields', 10,1 );
function my_checkout_fields( $checkout ) {
$user_id = get_current_user_id();
if ($user_id !=0 ) {
if (get_user_meta($user_id, 'shipping_different', true ) == 1)
add_filter( 'woocommerce_ship_to_different_address_checked', '__return_true' );
}
}
Comments? Improvements?

Categories