We just moved and merged the WooCommerce account password field on the checkout page from the "Account" group to the "Billing" field group. This works nicely. Also, we create a new checkbox field and add this to the billing section. Without that, the "Create an account" checkbox will still be at the default position. To do so, we created a new checkbox with jQuery.
Thanks to the following articles:
How to move the create account checkbox on Woocommerce checkout page
Reordering checkout fields in WooCommerce 3
With our current code, the moved password field is always visible. We want to have it the same way as WooCommerce default works. This means the password field should only be visible when the checkbox is active. WooCommerce by default has an excellent hide & Show CSS in place. However, I'm not able to use the identical CSS (or maybe script?!).
How can we connect the custom checkbox with the account password field?
// Move Account password field into billing section
function move_password_field($checkout_fields){
// Move Account Password into Billing
$checkout_fields['billing']['account_password'] = $checkout_fields['account']['account_password'];
// Remove Password from Billing
unset($checkout_fields['account']['account_password']);
return $checkout_fields;
}
add_filter('woocommerce_checkout_fields', 'move_password_field', 999);
// CSS rules
add_action( 'woocommerce_before_checkout_billing_form', 'move_checkout_create_an_account_css' );
function move_checkout_create_an_account_css() {
if( ! is_user_logged_in() ) :
?><style>
.woocommerce-account-fields label.woocommerce-form__label-for-checkbox {display: none !important;}
#account_cb_field {margin-top: 32px;}
#account_cb_field input {margin-right: 6px;}
</style>
<?php
endif;
}
// Add a checkbox to billing section
add_filter( 'woocommerce_checkout_fields', 'move_checkout_create_an_account_checkbox' );
function move_checkout_create_an_account_checkbox( $fields ) {
if( ! is_user_logged_in() ) {
// Make email field on half on left side
$fields['billing']['billing_email']['class'] = array('form-row-wide');
// Custom checkbox on half right side
$fields['billing']['account_cb'] = array(
'type' => 'checkbox',
'label' => __("Create an account?", "woocommerce"),
'class' => array('form-row-wide'),
);
}
return $fields;
}
// remove "(optional)" from the new checkbox
add_filter( 'woocommerce_form_field' , 'remove_checkout_optional_fields_label', 10, 4 );
function remove_checkout_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page
if ( is_checkout() && ! is_wc_endpoint_url() && $key === 'account_cb' ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// The jQuery code
add_action( 'wp_footer', 'move_checkout_create_an_account_js' );
function move_checkout_create_an_account_js() {
if ( ! is_user_logged_in() && is_checkout() && ! is_wc_endpoint_url() ) :
?><script>
(function($){
$('input[name=account_cb]').on( 'click', function() {
$('input[name=createaccount]').trigger('click');
});
})(jQuery);
</script>
<?php
endif;
}
Related
With the help of these 2 posts (WooCommerce editable custom checkout field and displayed in formatted address)( Add additional fields to Admin User under Customer shipping section in Woocommerce), I added the custom field in the checkout, my account, single order, admin, and email. but there are 3 more area I would like to show this custom field and I couldn't find the hook needed to show them. I searched online but with no luck at all. I would love it if someone could guide me on this.
1- under shipping address table in thank you page
2- under shipping address table in order view on my account page
3- I would like to show the field in the address on my account. but its only visible when I click edit
this is the code I used to add the extra field and its working so far
// HOUSE NUMBER EXTRA FIELD
// display shipping House Number in checkout and my account edit shipping address
add_filter( 'woocommerce_shipping_fields', 'add_shipping_house_number_field' );
function add_shipping_house_number_field( $fields ) {
$fields['shipping_house_number'] = array(
'label' => __( 'House Number', 'woocommerce' ),
//'required' => true,
'class' => array( 'form-row-first' ),
'priority' => 61,
);
return $fields;
}
// Display editable custom fields on admin single order pages (backend new order) edit pages inside edit shipping section
add_filter( 'woocommerce_admin_shipping_fields' , 'add_order_admin_edit_shipping_house_number' );
function add_order_admin_edit_shipping_house_number( $fields ) {
// Include shipping house_number as editable field
$fields['house_number'] = array( 'label' => __( 'House Number', 'woocommerce' ), 'show' => '0' );
return $fields;
}
// Load Ajax custom field data as customer billing/shipping address fields in backend new order (data will be pulled from the database)
add_filter( 'woocommerce_ajax_get_customer_details' , 'add_custom_fields_to_ajax_customer_details', 10, 3 );
function add_custom_fields_to_ajax_customer_details( $data, $customer, $user_id ) {
$data['shipping'][house_number] = $customer->get_meta('shipping_house_number');
return $data;
}
// Display reordered editable custom fields on admin single User pages
add_filter( 'woocommerce_customer_meta_fields', 'house_number_customer_meta_fields', 10, 1 );
function house_number_customer_meta_fields( $fields ) {
$fields['shipping']['fields']['shipping_house_number'] = array(
'label' => __( 'House Number', 'woocommerce' ),
);
return $fields;
}
// Adding custom placeholder to woocommerce formatted address only on Backend
add_filter( 'woocommerce_localisation_address_formats', 'admin_localisation_address_formats', 50, 1 );
function admin_localisation_address_formats( $address_formats ){
// Only in backend (Admin)
if( is_admin() || ! is_wc_endpoint_url() ) {
foreach( $address_formats as $country_code => $address_format ) {
$address_formats[$country_code] .= "\n{house_number}";
}
}
return $address_formats;
}
// Custom placeholder replacement to woocommerce formatted address
add_filter( 'woocommerce_formatted_address_replacements', 'custom_formatted_address_replacements', 10, 2 );
function custom_formatted_address_replacements( $replacements, $args ) {
$replacements['{house_number}'] = ! empty($args['house_number']) ? $args['house_number'] : '';
return $replacements;
}
// Add the shipping house number value to be displayed on email notifications under shipping address
add_filter( 'woocommerce_order_formatted_shipping_address', 'add_shipping_house_number_to_formatted_shipping_address', 100, 2 );
function add_shipping_house_number_to_formatted_shipping_address( $shipping_address, $order ) {
global $pagenow, $post_type;
// Not on admin order edit pages (as it's already displayed).
if( ! ( $pagenow === 'post.php' && $post_type === 'shop_order' && isset($_GET['action']) && $_GET['action'] === 'edit' ) ) {
// Include shipping phone on formatted shipping address
$shipping_address['house_number'] = $order->get_meta('_shipping_house_number');
}
return $shipping_address;
}
For thank you page and my account view order you can use WC woocommerce_order_get_formatted_shipping_address filter hook.
function add_woocommerce_order_get_formatted_shipping_address( $address, $empty_content, $raw_address, $order ){
$address .= '<br/> this is custom text';
return $address;
}
add_filter( 'woocommerce_order_get_formatted_shipping_address', 'add_woocommerce_order_get_formatted_shipping_address', 10, 4 );
Thank you Page
My Account View Order.
My Account edit address
You need to override. woocommerce\templates\myaccount\my-address.php
to your theme or plugin.
On my current checkout page I have the "create account" checkbox after the email field. What I am attempting to do is to move the create account checkbox inline and next to the email field. So I would have the email field on the left and the created account checkbox to the right.
I am able to move the create account checkbox but I just cannot figure out how to achieve the look I described. Any help would be appreciated. Thank you!
Checkout page here :
https://www.dailymutt.com/checkout/
This can be done adding a new similar checkbox field to billing form and hiding the real checkbox one with CSS. Then with the help of jQuery, you can trigger the hidden checkbox from the duplicated one.
Here is that code:
// CSS rules
add_action( 'woocommerce_before_checkout_billing_form', 'move_checkout_create_an_account_css' );
function move_checkout_create_an_account_css() {
if( ! is_user_logged_in() ) :
?><style>
.woocommerce-account-fields label.woocommerce-form__label-for-checkbox {display: none !important;}
#account_cb_field {margin-top: 32px;}
#account_cb_field input {margin-right: 6px;}
</style>
<?php
endif;
}
// Add a checkbox to billing section
add_filter( 'woocommerce_checkout_fields', 'move_checkout_create_an_account_checkbox' );
function move_checkout_create_an_account_checkbox( $fields ) {
if( ! is_user_logged_in() ) {
// Make email field on half on left side
$fields['billing']['billing_email']['class'] = array('form-row-first');
// Custom checkbox on half right side
$fields['billing']['account_cb'] = array(
'type' => 'checkbox',
'label' => __("Create an account?", "woocommerce"),
'class' => array('form-row-last'),
);
}
return $fields;
}
// remove "(optional)" from the new checkbox
add_filter( 'woocommerce_form_field' , 'remove_checkout_optional_fields_label', 10, 4 );
function remove_checkout_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page
if ( is_checkout() && ! is_wc_endpoint_url() && $key === 'account_cb' ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// The jQuery code
add_action( 'wp_footer', 'move_checkout_create_an_account_js' );
function move_checkout_create_an_account_js() {
if ( ! is_user_logged_in() && is_checkout() && ! is_wc_endpoint_url() ) :
?><script>
(function($){
$('input[name=account_cb]').on( 'click', function() {
$('input[name=createaccount]').trigger('click');
});
})(jQuery);
</script>
<?php
endif;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
The following code add a custom field to admin product settings to manage guest checkout at product level:
// Display Guest Checkout Field
add_action( 'woocommerce_product_options_general_product_data', 'woo_add_custom_general_fields' );
function woo_add_custom_general_fields() {
global $woocommerce, $post;
echo '<div class="options_group">';
// Checkbox
woocommerce_wp_checkbox( array(
'id' => '_allow_guest_checkout',
'wrapper_class' => 'show_if_simple',
'label' => __('Checkout', 'woocommerce' ),
'description' => __('Allow Guest Checkout', 'woocommerce' )
) );
echo '</div>';
}
// Save Guest Checkout Field
add_action( 'woocommerce_process_product_meta', 'woo_add_custom_general_fields_save' );
function woo_add_custom_general_fields_save( $post_id ){
$woocommerce_checkbox = isset( $_POST['_allow_guest_checkout'] ) ? 'yes' : 'no';
update_post_meta( $post_id, '_allow_guest_checkout', $woocommerce_checkbox );
}
// Enable Guest Checkout on Certain products
add_filter( 'pre_option_woocommerce_enable_guest_checkout', 'enable_guest_checkout_based_on_product' );
function enable_guest_checkout_based_on_product( $value ) {
if ( WC()->cart ) {
$cart = WC()->cart->get_cart();
foreach ( $cart as $item ) {
if ( get_post_meta( $item['product_id'], '_allow_guest_checkout', true ) == 'yes' ) {
$value = "yes";
} else {
$value = "no";
break;
}
}
}
return $value;
}
But it doesn't work actually. What I am doing wrong? How can I fix it?
I am trying to allow guest purchases for specific products. The admin custom field display and save custom field value is working (the 2 first functions), But login/register never comes up on checkout page, even if there are products in cart that doesn't allow guest checkout.
The filter hook enable_guest_checkout_based_on_product doesn't exist anymore and has been replaced by another hook a bit different.
So your code is going to be:
add_filter( 'woocommerce_checkout_registration_required', 'change_tax_class_user_role', 900 );
function change_tax_class_user_role( $registration_required ) {
if ( ! WC()->cart->is_empty() ) {
$registration_required = false; // Initializing (allowing guest checkout by default)
// Loop through cart items
foreach ( WC()->cart->get_cart() as $item ) {
// Check if there is any item in cart that has not the option "Guest checkout allowed"
if ( get_post_meta( $item['product_id'], '_allow_guest_checkout', true ) !== 'yes' ) {
return true; // Found: Force checkout user registration and exit
}
}
}
return $registration_required;
}
Code goes in functions.php file of your active child theme (or active theme). It should works.
Related continuation: Redirection for non checkout guest allowed in WooCommerce
I've been looking for a solution to this for a while now... I am trying to show or hide specific shipping rates based on a radio button option added to the Woocommerce checkout page. But I don't know anything about Ajax & JQuery which I believe it requires.
Basically if a user selects radio option_1 it will ONLY show 'flat_rate:1' & 'flat_rate:2'. If the user selects radio option_2 it will ONLY show 'flat_rate:3' & 'flat_rate:4'
Click here for example of checkout screen
Here is the code for my radio buttons displayed on checkout page:
add_action( 'woocommerce_review_order_before_payment','tc_checkout_radio_choice' );
function tc_checkout_radio_choice() {
$businesstype = array(
'type' => 'radio',
'class' => array( 'business_residential' ),
'required' => true,
'options' => array(
'option_1' => 'Business',
'option_2' => 'Residential',
),
);
echo '<div id="checkout-radio">';
echo '<h3>Select Your Business Type</h3>';
woocommerce_form_field( 'radio_choice', $businesstype );
echo '</div>';
}
The closest example I've seen comes from an answer provided by 'LoicTheAztec' in this post here: Show/hide shipping methods based on a WooCommerce checkout field value
I'm completely lost with this and the more I try to solve it, the more I get confused.
Here is the correct way to show hide shipping methods based on multiple radio buttons choice on checkout page, that requires to use PHP, Ajax, jQuery and WC Session.
When "Business" radio button is selected (default choice), flat_rate:3 and flat_rate:4 shipping methods will be hidden, so customer will only be able to choose flat_rate:1 or flat_rate:2 shipping methods.
If "Residential" radio button is selected then flat_rate:1 and flat_rate:2 shipping methods will be hidden, so customer will only be able to choose flat_rate:3 or flat_rate:4 shipping methods.
The code:
// Display a Custom radio buttons fields for shipping options
add_action( 'woocommerce_review_order_before_payment','checkout_customer_type_radio_buttons' );
function checkout_customer_type_radio_buttons() {
$field_id = 'customer_type';
echo '<div id="customer-type-radio">';
echo '<h3>' . __("Select Your Business Type", "woocommerce") . '</h3>';
// Get the selected radio button value (if selected)
$field_value = WC()->session->get( $field_id );
// Get customer selected value on last past order
if( empty($field_value) )
$field_value = WC()->checkout->get_value( $field_id );
// The default value fallback
if( empty($field_value) )
$field_value = 'Business';
woocommerce_form_field( $field_id, array(
'type' => 'radio',
'class' => array( $field_id ),
'required' => true,
'options' => array(
'Business' => __('Business', 'woocommerce'),
'Residential' => __('Residential', 'woocommerce'),
),
), $field_value );
echo '</div>';
}
// Conditionally show/hide shipping methods
add_filter( 'woocommerce_package_rates', 'shipping_package_rates_filter_callback', 100, 2 );
function shipping_package_rates_filter_callback( $rates, $package ) {
$customer_type = WC()->session->get( 'customer_type' ); // Get the customere type
if ( $customer_type === 'Business' ) {
if( isset( $rates['flat_rate:3'] ) )
unset( $rates['flat_rate:3'] );
if( isset( $rates['flat_rate:4'] ) )
unset( $rates['flat_rate:4'] );
}
elseif ( $customer_type === 'Residential' ) {
if( isset( $rates['flat_rate:1'] ) )
unset( $rates['flat_rate:1'] );
if( isset( $rates['flat_rate:2'] ) )
unset( $rates['flat_rate:2'] );
}
return $rates;
}
// function that gets the Ajax data
add_action( 'wp_ajax_get_customer_type', 'wc_get_customer_type' );
add_action( 'wp_ajax_nopriv_get_customer_type', 'wc_get_customer_type' );
function wc_get_customer_type() {
$field_id = 'customer_type';
if ( isset($_POST[$field_id]) && ! empty($_POST[$field_id]) ){
WC()->session->set($field_id, $_POST[$field_id] );
}
echo json_encode( WC()->session->get( $field_id ) );
die(); // (required)
}
// The Jquery Ajax script
add_action( 'wp_footer', 'custom_checkout_ajax_jquery_script' );
function custom_checkout_ajax_jquery_script() {
$field_id = 'customer_type';
if( WC()->session->__isset($field_id) )
WC()->session->__unset($field_id);
// Only on checkout when billing company is not defined
if( is_checkout() && ! is_wc_endpoint_url() ):
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
var fieldId = 'p#customer_type_field input';
function userTypeTriggerAjax( customerType ){
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'get_customer_type',
'customer_type': customerType,
},
success: function (result) {
// Trigger refresh checkout
$('body').trigger('update_checkout');
console.log(result);
}
});
}
// On start
if( $(fieldId).val() != '' ) {
userTypeTriggerAjax( $(fieldId).val() );
}
// On change
$(fieldId).change( function () {
userTypeTriggerAjax( $(this).val() );
});
});
</script>
<?php
endif;
}
// Enabling, disabling and refreshing session shipping methods data
add_action( 'woocommerce_checkout_update_order_review', 'refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods( $post_data ){
$bool = true;
if ( in_array( WC()->session->get('customer_type' ), ['Business', 'Residential'] ) )
$bool = false;
// Mandatory to make it work with shipping methods
foreach ( WC()->cart->get_shipping_packages() as $package_key => $package ){
WC()->session->set( 'shipping_for_package_' . $package_key, $bool );
}
WC()->cart->calculate_shipping();
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Code based on this related threads:
Remove shipping cost if custom checkbox is checked in WooCommerce Checkout
Show/hide shipping methods based on a WooCommerce checkout field value
If anyone wants to know how to make this a required option with an error notification before payment, this is what I did...
To de-select the radio buttons I removed the value from:
//if( empty($field_value) )
$field_value = '';
And added this code to the checkout process at the end of the code from Loic, which adds a notification message if a radio button has not been selected:
// Show notice if customer does not select a business type
add_action( 'woocommerce_checkout_process', 'business_type_error_message' );
function business_type_error_message() {
if ( ! (int) isset( $_POST['customer_type'] ) ) {
wc_add_notice( __( 'Please select an order type to calculate the correct shipping and proceed with your order.' ), 'error' );
}
}
Hope this helps others out there!
In Woocommerce checkout page, I have managed to show or hide "Order notes" field when "ship-to-different-address" checkbox is checked or unchecked, using "Show hide Order notes field based on a checkbox in Woocommerce checkout" answer code to one of my questions.
I would like "Order notes" field to be required only when it's visible.
How can I make this "Order notes" field required when it's visible (not hidden) and enable the validation for it?
Any help is welcome.
The following code will make "Order notes" field to be required only when it's not hidden and will enable in this case the field validation.
Note (mandatory): The "Order notes" field has to be optional (just as in default Woocommerce), without that the code will not work properly.
The complete code:
// Remove "(optional)" label on "Order notes" field
add_filter( 'woocommerce_form_field' , 'remove_order_comments_optional_fields_label', 10, 4 );
function remove_order_comments_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'order_comments' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// The jQuery script that show hide "Order notes" field
add_action( 'woocommerce_after_order_notes', 'custom_checkout_scripts_js_script', 10, 1 );
function custom_checkout_scripts_js_script( $checkout ) {
$required = esc_html__( 'required', 'woocommerce' );
?>
<script type="text/javascript">
(function($){
var required = '<abbr class="required" title="<?php echo $required; ?>">*</abbr>',
notesField = '#order_comments_field',
shipCheckbox = '#ship-to-different-address-checkbox';
function actionRequire( actionToDo='yes', selector='' ){
if ( actionToDo == 'yes' ) {
$(selector).addClass("validate-required");
$(selector+' label').append(required);
} else {
$(selector).removeClass("validate-required");
$(selector+' label > .required').remove();
}
$(selector).removeClass("woocommerce-validated");
$(selector).removeClass("woocommerce-invalid woocommerce-invalid-required-field");
}
// On load and on form change
$('form.checkout').on( 'change', shipCheckbox, function(){
if( $(this).prop('checked') === true ) {
$(notesField).hide(); // Show
actionRequire( 'no' ,notesField );
} else {
$(notesField).show(); // Hide
actionRequire( 'yes' ,notesField );
}
});
})(jQuery);
</script>
<?php
}
// "Order notes" field validation
add_action('woocommerce_checkout_process', 'order_comments_field_validation');
function order_comments_field_validation() {
if ( isset($_POST['order_comments']) && empty($_POST['ship_to_different_address']) )
wc_add_notice( __( 'Please fill in "Order notes" required field.' ), 'error' );
}
Code goes on function.php file of your active child theme (or active theme). Tested and works.
Similar: Make Woocommerce checkout phone field optional based on shipping country
Related: Show hide Order notes field based on a checkbox in Woocommerce checkout