For a WooCommerce shop, based on a Shipping Zone I have three custom fieldgroups showing at checkout. I want to hide two of those fieldgroups depending on the total weight of the Cart.
By default the checkout shows all three fieldgroups because they are tied to the same shipping zone.
Three weight categories:
upto 500kg (Should just show this fieldgroup meta name)
_review_order_before_payment_blue_zone_500)
501-1000kg (Should just show this fieldgroup meta name) _review_order_before_payment_collection_blue_zone_500_1000
1001+kg (Should just show this fieldgroup meta name)
_review_order_before_payment_collection_blue_zone_1001
This is the code I've cobbled together, but its not hiding the fieldgroup. Any ideas?
// Unset checkout field based on cart weight
add_filter('woocommerce_checkout_fields', 'remove_custom_checkout_field', 999 );
function remove_custom_checkout_field( $fields ) {
if ( WC()->cart->get_cart_contents_weight() >= 500 ) {
unset($fields['_review_order_before_payment_collection_blue_zone_500_1000']); // Unset field
}
if ( WC()->cart->get_cart_contents_weight() >= 1001 ) {
unset($fields['_review_order_before_payment_collection_blue_zone_1001']); // Unset field
}
return $fields;
}
Expected fieldgroups to disappear when weight was calculated.
This is how you should declare field based on if its billing, shipping, order etc. Read more about here - https://woocommerce.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/
In my case my weight is set to kg and testing product is 0.5kg. You can add your condition in custom_woocommerce_billing_fields and skip remove_checkout_fields_by_weight function.
add_filter('woocommerce_billing_fields', 'custom_woocommerce_billing_fields');
function custom_woocommerce_billing_fields($fields)
{
$fields['billing_test'] = array(
'label' => __('Test field', 'woocommerce'),
'placeholder' => _x('', 'placeholder', 'woocommerce'),
'required' => false,
'clear' => false,
'type' => 'text',
'class' => array('my-css')
);
return $fields;
}
function remove_checkout_fields_by_weight( $fields ) {
if ( WC()->cart->get_cart_contents_weight() >= 0.5 ) {
unset( $fields['billing']['billing_test'] );
}
return $fields;
}
add_filter( 'woocommerce_checkout_fields', 'remove_checkout_fields_by_weight' );
Related
Using Wordpress/Woocommerce.
I have this code which adds a custom billing field in checkout page called: "NIF/CIF". It works fine but its value it not saved in the customer account "Billing Address" data.
Once the customer makes a first order all billing address values are saved in his account: Address, State, Country, etc. But my custom field is not saved.
I guess that in my function is missing a line of code to save its value in the database, but I don't know how to start with this.
/*******************************
CUSTOM BILLING FIELD
*********************************/
add_filter('woocommerce_billing_fields', 'custom_woocommerce_billing_fields');
function custom_woocommerce_billing_fields($fields)
{
$fields['nif_cif'] = array(
'label' => __('NIF/CIF', 'woocommerce'), // Add custom field label
'placeholder' => _x('NIF/CIF', 'placeholder', 'woocommerce'), // Add custom field placeholder
'required' => true, // if field is required or not
'clear' => false, // add clear or not
'type' => 'text', // add field type
'class' => array('my-css') // add class name
);
return $fields;
}
Here is an example of how to save your custom field:
add_action( 'woocommerce_checkout_order_processed', 'prefix_save_field_on_checkout', 11, 2 );
function checkout_order_processed_add_referral_answer( $order_id, $posted ) {
if ( ! isset( $_POST['nif_cif'] ) ) {
return;
}
$order = wc_get_order( $order_id );
// WC < 3.0
update_post_meta( $order->id, 'order_meta_field_name', wc_clean( $_POST['nif_cif'] ) );
// WC > 3.0
$order->add_meta_data( 'order_meta_field_name', wc_clean( $_POST['nif_cif'] ), true );
$order->save();
}
Adding an extra field through 'woocommerce_billing_fields' hook is not enough. you are missing out two things.
Proper validation of NIF/CIF field using
'woocommerce_after_checkout_validation' hook
Saving data in order
using 'woocommerce_checkout_order_processed' hook
I use hooks to remove or return payment fields, depending on which delivery method is selected.
add_filter( 'woocommerce_default_address_fields' , 'custom_override_default_address_fields', 20, 1 );
// Our hooked in function - $address_fields is passed via the filter!
function custom_override_default_address_fields( $address_fields) {
unset($address_fields['company']);
unset($address_fields['address_2']);
unset($address_fields['country']);
unset($address_fields['state']);
unset($address_fields['postcode']);
$shipping_method ='local_pickup:1'; // Set the desired shipping method to hide the checkout field(s).
global $woocommerce;
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = $chosen_methods[0];
if ($chosen_shipping == $shipping_method) {
// Delete address_1 field
unset($address_fields['address_1']);
} else {
// Return address_1 field
$address_fields['city'] = array(
'type' => 'text',
'label' => __('House number and street name', 'woocommerce'),
'required' => true,
'class' => array('form-row-wide'),
'clear' => true
);
}
return $address_fields;
}
After changing the delivery method, I need to reload the order page with AJAX, in order to delete or return the address_1
I am using wordpress and woocommerce. In checkout page, how do I restrict to only 1 country only? Say Australia.
Hello you can restrict to only one country by plugin settings
you can find in Woocommerce->Settings-> Genral tab
Just override the class by hook,
function woo_override_checkout_fields_billing( $fields ) {
$fields['billing']['billing_country'] = array(
'type' => 'select',
'label' => __('My New Country List', 'woocommerce'),
'options' => array('AU' => 'Australia')
);
return $fields;
}
add_filter( 'woocommerce_checkout_fields' , 'woo_override_checkout_fields_billing' );
function woo_override_checkout_fields_shipping( $fields ) {
$fields['shipping']['shipping_country'] = array(
'type' => 'select',
'label' => __('My New Country List', 'woocommerce'),
'options' => array('AU' => 'Australia')
);
return $fields;
}
add_filter( 'woocommerce_checkout_fields' , 'woo_override_checkout_fields_shipping' );
This will help you to show only 1 country in dropdown. Add this code to functions.php in theme.
Also maybe you want to sell to several countries but also you want to show ONLY the country where the user is connecting from (geolocated from IP address). Thus, in this way, a french user will only see France in the country dropdown, an australian user will only see Australia in the country dropdown and so on... Here is the code:
/**
* #param array $countries
* #return array
*/
function custom_update_allowed_countries( $countries ) {
// Only on frontend
if( is_admin() ) return $countries;
if( class_exists( 'WC_Geolocation' ) ) {
$location = WC_Geolocation::geolocate_ip();
if ( isset( $location['country'] ) ) {
$countryCode = $location['country'];
} else {
// If there is no country, then return allowed countries
return $countries;
}
} else {
// If you can't geolocate user country by IP, then return allowed countries
return $countries;
}
// If everything went ok then I filter user country in the allowed countries array
$user_country_code_array = array( $countryCode );
$intersect_countries = array_intersect_key( $countries, array_flip( $user_country_code_array ) );
return $intersect_countries;
}
add_filter( 'woocommerce_countries_allowed_countries', 'custom_update_allowed_countries', 30, 1 );
Thanks to the filter "WooCommerce admin billing fields" I have ordered the billing fields in the notificiación footer by email but when I try to insert my custom billing field does not appear.
add_filter( 'woocommerce_order_formatted_billing_address' , 'woo_reorder_billing_fields', 10, 2 );
function woo_reorder_billing_fields( $address, $wc_order ) {
$address = array(
'first_name' => $wc_order->billing_first_name,
'last_name' => $wc_order->billing_last_name,
'company' => $wc_order->billing_company,
'my_field' => $wc_order->billing_my_field,
'country' => $wc_order->billing_country
);
return $address;
}
In order admin edit I can show my custom billing field thanks to the filter "woocommerce_admin_billing_fields", first adding the field and then reordering the Array.
I note that I added before and I have reordered this field in my checkout with the filter "woocommerce_checkout_fields".
Why not show my custom field if "$ wc_order" object stores the field in the checkout?
Any ideas?
Thanks in advance!
Yes, here the explanation:
We will register the new cusotm field, in this example the field "VAT" to store the fiscal document for companies in the European Union. There is a lot of documentation on how to register the custom fields and display them in the admin / user panel.
add_filter( 'woocommerce_default_address_fields', 'woo_new_default_address_fields' );
function woo_new_default_address_fields( $fields ) {
$fields['vat'] = array(
'label' => __( 'VAT number', 'woocommerce' ),
'class' => array( 'form-row-wide', 'update_totals_on_change' ),
);
return $fields;
}
Then add the new field "VAT" only to the registration of billing fields for mails, we do not want it to appear in the address fileds section.
add_filter( 'woocommerce_order_formatted_billing_address' , 'woo_custom_order_formatted_billing_address', 10, 2 );
function woo_custom_order_formatted_billing_address( $address, $WC_Order ) {
$address = array(
'first_name' => $WC_Order->billing_first_name,
'last_name' => $WC_Order->billing_last_name,
'vat' => $WC_Order->billing_vat,
'company' => $WC_Order->billing_company,
'address_1' => $WC_Order->billing_address_1,
'address_2' => $WC_Order->billing_address_2,
'city' => $WC_Order->billing_city,
'state' => $WC_Order->billing_state,
'postcode' => $WC_Order->billing_postcode,
'country' => $WC_Order->billing_country
);
return $address;
}
The following code customizes the appearance of the addresses, this is where we must add the call to the new VAT field. This allows us to customize the address view for each country independently.
add_filter( 'woocommerce_formatted_address_replacements', function( $replacements, $args ){
$replacements['{vat}'] = $args['vat'];
return $replacements;
}, 10, 2 );
add_filter( 'woocommerce_localisation_address_formats' , 'woo_includes_address_formats', 10, 1);
function woo_includes_address_formats($address_formats) {
$address_formats['ES'] = "{name}\n{company}\n{vat}\n{address_1}\n{address_2}\n{postcode} {city}\n{state}\n{country}";
$address_formats['default'] = "{name}\n{company}\n{vat}\n{nif}\n{address_1}\n{address_2}\n{city}\n{state}\n{postcode}\n{country}";
return $address_formats;
}
Any questions ask!
I am using Woocommerce WordPress plugin
Added one custom field at checkout page, called - Address Type which is drop down contains 2 values. Business/Commercial and Residential
I have total 3 shipping methods - International Flat Rate, Flat Rate, Free Shipping
Now, condition that I want when end user select residential then and then they will get all 3 shipping methods but once user select a business option then hide/remove International Flat Rate and Flat Rate shipping methods (I mean show only Free Shipping).
add_filter( 'woocommerce_checkout_fields' , 'add_address_type_field' );
function add_address_type_field( $fields ) {
$address_type_field = array(
'type' => 'select',
'label' => __('Address Type', 'woocommerce'),
'required' => false,
'class' => array('address-field', 'form-row-wide', 'validate-addresstype'),
'clear' => true,
'options' => array(
'residential' => 'Residential',
'business' => 'Business/Commercial'
),
);
$fields['billing']['billing_address_type'] = $address_type_field;
$fields['shipping']['shipping_address_type'] = $address_type_field;
return $fields;
}
add_filter('woocommerce_package_rates', 'display_shipping_method_based_on_state', 10, 2);
if(!function_exists('display_shipping_method_based_on_state')) {
function display_shipping_method_based_on_state($rates) {
global $woocommerce;
$state = WC()->customer->shipping_state;
$address_type = WC()->customer->shipping_address_type;
$free_shipping = $rates['free_shipping'];
if($address_type == 'business')
{
$rates = array();
$rates['free_shipping'] = $free_shipping;
}
return $rates;
}
}
This is my code that I am trying. Let me know where I am wrong?
Thanks in advance!