I cant figure out how to reorder the additional fields, on the checkout page in WooCommerce.
I have added one extra field to the WooCommerce additional information section. I would like to show the time field first then the order notes below it.
This is the code that I am using:
add_filter( 'woocommerce-additional-fields', 'custom_order_fields', 20, 1 );
function custom_order_fields( $fields ) {
$fields['order_comments']['priority'] = 80;
$fields['woocommerce-delivery-time-field']['priority'] = 70;
return $fields;
}
However, this does not have the desired result. Can someone tell me what I'm doing wrong?
If you want to show your custom field first, and then the order notes.
You can either use:
// Add 'delivery time' field before 'order comments'
function filter_woocommerce_checkout_fields( $fields ) {
// Get 'order comments' field
$order_comments = $fields['order']['order_comments'];
// Unset 'order comments' field
unset( $fields['order']['order_comments'] );
// Add 'delivery time' field
$fields['order']['delivery_time'] = array(
'label' => __( 'Delivery time', 'woocommerce' ),
'required' => true,
'type' => 'text',
'class' => array( 'form-row-wide' ),
);
// Add 'order comments' field
$fields['order']['order_comments'] = $order_comments;
return $fields;
}
add_filter( 'woocommerce_checkout_fields' , 'filter_woocommerce_checkout_fields', 10, 1 );
OR use the woocommerce_before_order_notes action hook
function action_woocommerce_before_order_notes( $checkout ) {
// Add field
woocommerce_form_field( 'delivery_time', array(
'type' => 'text',
'class' => array( 'form-row form-row-wide' ),
'label' => __( 'Delivery time', 'woocommerce' ),
'required' => true,
), $checkout->get_value( 'delivery_time' ) );
}
add_action( 'woocommerce_before_order_notes', 'action_woocommerce_before_order_notes', 10, 1 );
You would need to add the field to the WooCommerce Custom Field first before you set the priority likeso.
add_action('woocommerce_checkout_fields', 'add_woocommerce_additional_fields');
// Function to add field
function add_woocommerce_additional_fields( $fields ) {
$fields['order']['delivery_time'] = array(
'type' => 'text',
'label' => __('Delivery time', 'woocommerce'),
'required' => true,
'class' => array('form-row-wide'),
'clear' => true
);
// You can set your priority here
// Just higher than it a bit
$fields['order']['order_comments']['priority'] = 80;
$fields['order']['delivery_time']['priority'] = 70;
return $fields;
}
You can check here for more information on ordering of fields in Woocommerce.
Related
I've added a new field for phone number in WooCommerce checkout form.
Everything is working perfectly except the maxlength = "10". After adding the snippet it shows maxlength = 10 when I inspect element, but the phone field allows me to type n number of characters.
Am I doing anything wrong?
Here is the snippet i used in functions.php
add_action('woocommerce_after_checkout_billing_form', 'custom_checkout_field');
function custom_checkout_field($checkout)
{
woocommerce_form_field('billing_phone_2', array(
'type' => 'number',
'maxlength' => "10",
'id' => 'billing_phone_2',
'class' => array(
'input-text form-row-wide'
) ,
'required' => 'required' === get_option( 'woocommerce_checkout_phone_field', 'required' ),
'label' => __('Phone 2') ,
'placeholder' => __('') ,
) ,
$checkout->get_value('billing_phone_2'));
}
For the type you could use tel, and for the maxlength it is not necessary to put the number between quotes
So you get:
// Display a custom checkout field after billing form
function action_woocommerce_after_checkout_billing_form( $checkout ) {
woocommerce_form_field( 'billing_phone_2', array(
'type' => 'tel',
'maxlength' => 10,
'class' => array( 'form-row-wide' ),
'required' => true,
'label' => __( 'Phone 2', 'woocommerce' ),
'placeholder' => __( 'My placeholder', 'woocommerce' ),
), $checkout->get_value( 'billing_phone_2' ));
}
add_action( 'woocommerce_after_checkout_billing_form', 'action_woocommerce_after_checkout_billing_form', 10, 1 );
Optional: some validation for the custom (required) field
// Custom checkout field validation
function action_woocommerce_checkout_process() {
// Isset
if ( isset( $_POST['billing_phone_2'] ) ) {
$domain = 'woocommerce';
$phone = $_POST['billing_phone_2'];
// Empty
if ( empty ( $phone ) ) {
wc_add_notice( __( 'Please enter a phone number to complete this order', $domain ), 'error' );
}
// Validates a phone number using a regular expression.
if ( 0 < strlen( trim( preg_replace( '/[\s\#0-9_\-\+\/\(\)\.]/', '', $phone ) ) ) ) {
wc_add_notice( __( 'Please enter a valid phone number', $domain ), 'error' );
}
}
}
add_action( 'woocommerce_checkout_process', 'action_woocommerce_checkout_process', 10, 0 );
If type = number, you can use the min and max attributes
// Display a custom checkout field after billing form
function action_woocommerce_after_checkout_billing_form( $checkout ) {
woocommerce_form_field( 'billing_phone_2', array(
'type' => 'number',
'custom_attributes' => array(
'min' => 0,
'max' => 9999999999,
),
'class' => array( 'form-row-wide' ),
'placeholder' => __( 'Phone 2', 'woocommerce' ),
), $checkout->get_value( 'billing_phone_2' ));
}
add_action( 'woocommerce_after_checkout_billing_form', 'action_woocommerce_after_checkout_billing_form', 10, 1 );
Although I wouldn't recommend it for a phone number, there is a reason that the type 'tel' exists, as used in other phonefields in WooCommerce
I can't find the way to ovveride billing state and post code.
How can I edit the other parts of existing billing fields like billing state and post code?
This is what I have in the functions.php file in my child theme (I have included the code affecting the billing part):
<?php
function my_custom_checkout_field( $checkout ) {
global $wpdb;
$check_zone = $wpdb->get_results("select area_name from brick_area where id='".$_SESSION['area']."'",ARRAY_A);
if(!empty($check_zone)){
$check_zoneid = $check_zone['0'];
}
woocommerce_form_field( 'my_field_name', array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'label' => __('Delivery Area'),
'placeholder' => __('Area'),
'readonly' =>'readonly',
'default' => $check_zoneid['area_name']
), $checkout->get_value( 'my_field_name' ));
woocommerce_form_field( 'my_expected_date', array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'required' => true,
'label' => __('Expected Delivery Date'),
'placeholder' => __('Enter expected delivery date.'),
), $checkout->get_value( 'my_expected_date' ));
/*woocommerce_form_field( 'my_expected_time', array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'required' => true,
'label' => __('Expected Delivery Time'),
'placeholder' => __('Enter expected delivery time.'),
), $checkout->get_value( 'my_expected_time' ));*/
woocommerce_form_field( 'site_contact_name', array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'required' => true,
'label' => __('Site Contact Person Name'),
'placeholder' => __('Enter site contact person name.'),
), $checkout->get_value( 'site_contact_name' ));
woocommerce_form_field( 'site_contact_phone', array(
'type' => 'tel',
'class' => array('my-field-class form-row-wide'),
'required' => true,
'label' => __('Site Contact Phone Number'),
'placeholder' => __('Enter site contact phone number.'),
), $checkout->get_value( 'site_contact_phone' ));
}
$fields['billing']['billing_city']['default'] = $_SESSION['cn'];
add_filter( 'woocommerce_default_address_fields' , 'custom_override_default_address_fields' );
function custom_override_default_address_fields( $address_fields ) {
// we are changing here billing_state field to required
$fields['billing']['billing_state']['required'] = true;
return $address_fields;
}
/*$fields['billing']['my_field_name']['default'] = $check_zoneid['area_name'];
$fields['billing']['my_field_name']['label'] = 'Area';*/
return $fields;
}
?>
Thanks
This is the complete way for billing state and billing post code override, keeping the billing selector with options.
Here is the code the fully functional and tested code:
Unsetting billing state and post code checkout fields
add_filter( 'woocommerce_checkout_fields' , 'partial_unsetting_checkout_fields' );
function partial_unsetting_checkout_fields( $fields ) {
unset($fields['billing']['billing_state']);
unset($fields['billing']['billing_postcode']);
return $fields;
}
Reinserting custom billing state and post code checkout fields
add_filter( 'woocommerce_default_address_fields' , 'art_override_default_address_fields' );
function art_override_default_address_fields( $address_fields ) {
// # for state
$address_fields['billing_state']['type'] = 'select';
$address_fields['billing_state']['class'] = array('form-row-wide');
$address_fields['billing_state']['required'] = true;
$address_fields['billing_state']['label'] = __('State', 'my_theme_slug');
$address_fields['billing_state']['placeholder'] = __('Enter state', 'my_theme_slug');
$address_fields['billing_state']['default'] ='Choice 1';
$address_fields['billing_state']['options'] = array(
'option_1' => 'Choice 1',
'option_2' => 'Choice 2',
'option_3' => 'Choice 3'
);
// # for postcode
$address_fields['billing_postcode']['type'] = 'text';
$address_fields['billing_postcode']['class'] = array('form-row-wide');
$address_fields['billing_postcode']['required'] = true;
$address_fields['billing_postcode']['label'] = __('Postcode', 'my_theme_slug');
$address_fields['billing_postcode']['placeholder'] = __('Enter your postcode', 'my_theme_slug');
return $address_fields;
}
Naturally this goes on function.php file of your active child theme or theme
Official reference: WooThemes - Customizing checkout fields using actions and filters
Note concerning the 'class' property
There is 2 ways to handle it:
The field is alone in one line (width 100%), you use: 'form-row-wide'
There is 2 fields side by side on the same line, you use:
'form-row-first' for the first field
'form-row-last' for the second field
//-------------------------- OVERRIDING BILLING STATE FIELD -------------------------------//
//Removing previous one by using unset
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
// Our hooked in function - $fields is passed via the filter!
function custom_override_checkout_fields( $fields ) {
unset($fields['billing']['billing_state']);
return $fields;
}
add_filter( 'woocommerce_default_address_fields' , 'art_override_default_address_fields' );
function art_override_default_address_fields( $address_fields ) {
// # for state
$address_fields['Billing_State']['type'] = 'text';
$address_fields['Billing_State']['class'] = array('form-row-wide');
$address_fields['Billing_State']['required'] = true;
$address_fields['Billing_State']['label'] = __('State', 'my_theme_slug');
$address_fields['Billing_State']['placeholder'] = __('Enter state', 'my_theme_slug');
return $address_fields;
}
I want to edit my billing address at my website, where i need to add and delete some others in my account page, which code shall I edit?
Thank you in advanced
Can you please check below code you can add new custom field example.
add_filter( 'woocommerce_billing_fields', 'custom_woocommerce_billing_fields' );
function custom_woocommerce_billing_fields( $fields ) {
$fields['billing']['billing_options'] = array(
'label' => __('Custom Field', 'woocommerce'), // Add custom field label
'placeholder' => _x('Custom Field', 'placeholder', 'woocommerce'), // Add custom field placeholder
'required' => false, // if field is required or not
'clear' => false, // add clear or not
'type' => 'text', // add field type
'class' => array('own-css-name') // add class name
);
return $fields;
}
To delete an existing field, country for example:
add_filter( 'woocommerce_billing_fields' , 'custom_override_billing_fields' );
function custom_override_billing_fields( $fields ) {
unset($fields['billing_country']);
return $fields;
}
maybe the best way use woocommerce_default_address_fields - is it ?
for example as
#5447232
add_filter( 'woocommerce_default_address_fields', 'add_MyNewOption_address' );
function add_MyNewOption_address( $fields ) {
$fields['MyNewOption'] = array(
'label' => __('Custom Field', 'woocommerce'), // Add custom field label
'placeholder' => _x('Custom Field', 'placeholder', 'woocommerce'), // Add custom field placeholder
'required' => false, // if field is required or not
'clear' => false, // add clear or not
'type' => 'text', // add field type
'class' => array('own-css-name') // add class name
);
return $fields;
}
I have added custom text box field in my add product page in woocommerce. Now i want to make it required (compulsory). I tried it by passing argument "required"=>true. but it is not working. Please see below code
woocommerce_wp_text_input(
array(
'id' => 'special_price',
'label' => __( 'Wholesaler Price *', 'woocommerce' ),
'placeholder' => '',
'desc_tip' => 'true',
'required' => 'true',
'description' => __( 'Enter wholesaler price here.', 'woocommerce' )
)
);
but it is not making textbox compulsory. Please can anyone tell how can i do this?
For the required HTML5 attribute and other custom attributes woocommerce_wp_text_input() function has custom_attributes option.
woocommerce_wp_text_input(
array(
'id' => 'special_price',
'label' => __( 'Wholesaler Price *', 'woocommerce' ),
'placeholder' => '',
'desc_tip' => 'true',
'custom_attributes' => array( 'required' => 'required' ),
'description' => __( 'Enter wholesaler price here.', 'woocommerce' )
)
);
You can modify the following code as per your need.
// Validate when adding to cart
add_filter( 'woocommerce_add_to_cart_validation', 'woocommerce_add_to_cart_validation_custom', 10, 3 );
/ validation
function woocommerce_add_to_cart_validation_custom($passed, $product_id, $qty){
global $woocommerce;
$option = ''; // your custom field's name
if( isset($_POST[sanitize_title($option)]) && $_POST[sanitize_title($option)] == '' )
$passed = false;
if (!$passed)
$woocommerce->add_error( sprintf( __('"%s" is a required field.', 'woocommerce'), $option) );
return $passed;
}
For even more options while adding a product in the cart you may find How to add a custom text box value to cart session array in Woocommerce my this answer helpful.
I've been trying to hook this function in one of the "Order Hooks" of the Woocommerce Checkout page:
add_action( 'woocommerce_checkout_before_order_review', 'add_box_conditional' );
function add_box_conditional ( $checkout ) {
woocommerce_form_field( 'test', array(
'type' => 'checkbox',
'class' => array('test form-row-wide'),
'label' => __('conditional test'),
'placeholder' => __(''),
), $checkout->get_value( 'test' ));
}
If i try to get the value of the custom box in any order hooks, the order info just hangs and stops loading. I've tried with another type of custom fields and the same happens.
Example
If I hook the function outside the order contents works perfectly. The custom check box will be used to add a fee (post validation), as it is a very important option for our shop I want it inside the order details, so it can have a strong focus. Is there a way to make the function work on these hooks, or should I put it anywhere and move it with a simple but not so clean CSS overwritte?
You can't just get the value like that $checkout->get_value( 'test' ));.
Hook woocommerce_checkout_create_order and get the value from $_POST there. Then add a custom fee to the order if the checkbox was checked.
Like this:
function add_box_conditional() {
woocommerce_form_field( 'test', array(
'type' => 'checkbox',
'class' => array( 'test form-row-wide' ),
'label' => __( 'conditional test' ),
'placeholder' => __( '' ),
) );
}
add_action( 'woocommerce_checkout_before_order_review', 'add_box_conditional' );
function edit_order( $order, $data ) {
if( ! isset( $_POST[ 'test' ] ) ) {
return;
}
$checkbox_value = filter_var( $_POST[ 'test' ], FILTER_SANITIZE_NUMBER_INT );
if( $checkbox_value ){
$fee = 20;
$item = new \WC_Order_Item_Fee();
$item->set_props( array(
'name' => __( 'Custom fee', 'textdomain' ),
'tax_class' => 0,
'total' => $fee,
'total_tax' => 0,
'order_id' => $order->get_id(),
) );
$item->save();
$order->add_item( $item );
$order->calculate_totals();
}
}
add_action( 'woocommerce_checkout_create_order', 'edit_order', 10, 2 );