How to add custom fields to WooCommerce registration form - php

I have seen similar questions but couldn't find a solution for me.
I am trying to add custom fields to WooCommerce registration form, specifically first and last name field. I have managed to create these fields but the information entered does not pass over to the Account Details page when the user has logged in. Other tutorials have mentioned validating the fields but I am not sure is it relevant to me or not. I am working on a Wordpress child theme.
Please visit to codepad .org to view the code.
I tried to paste the code here by using the code sample option but it doesn't work properly.
Hope I have explained myself clearly. If not please let me know and I will clarify.

I think you have overwrite woocommerce/templates/myaccount/form-login.php template, and by doing that you have managed to show the billing_first_name and billing_last_name but you forget to use woocommerce_created_customer hook which is needed to save those data into your database.
What I'll suggest is that you keep the template as it is and add those field through function.php
Here is the code to add custom fields in WooCommerce registration form:
/**
* To add WooCommerce registration form custom fields.
*/
function text_domain_woo_reg_form_fields() {
?>
<p class="form-row form-row-first">
<label for="billing_first_name"><?php _e('First name', 'text_domain'); ?><span class="required">*</span></label>
<input type="text" class="input-text" name="billing_first_name" id="billing_first_name" value="<?php if (!empty($_POST['billing_first_name'])) esc_attr_e($_POST['billing_first_name']); ?>" />
</p>
<p class="form-row form-row-last">
<label for="billing_last_name"><?php _e('Last name', 'text_domain'); ?><span class="required">*</span></label>
<input type="text" class="input-text" name="billing_last_name" id="billing_last_name" value="<?php if (!empty($_POST['billing_last_name'])) esc_attr_e($_POST['billing_last_name']); ?>" />
</p>
<div class="clear"></div>
<?php
}
add_action('woocommerce_register_form_start', 'text_domain_woo_reg_form_fields');
Coming to your second part of your question on validation it is totally optional and depends on your business logic that what you want, in general most of the site has First Name and the Last Name required but again it totally depends upon you, If you don't want to validate this then remove <span class="required">*</span> from above code and skip this section.
/**
* To validate WooCommerce registration form custom fields.
*/
function text_domain_woo_validate_reg_form_fields($username, $email, $validation_errors) {
if (isset($_POST['billing_first_name']) && empty($_POST['billing_first_name'])) {
$validation_errors->add('billing_first_name_error', __('<strong>Error</strong>: First name is required!', 'text_domain'));
}
if (isset($_POST['billing_last_name']) && empty($_POST['billing_last_name'])) {
$validation_errors->add('billing_last_name_error', __('<strong>Error</strong>: Last name is required!.', 'text_domain'));
}
return $validation_errors;
}
add_action('woocommerce_register_post', 'text_domain_woo_validate_reg_form_fields', 10, 3);
Now this is a main part and this what you was had missed, below code is needed to save the custom data:
/**
* To save WooCommerce registration form custom fields.
*/
function text_domain_woo_save_reg_form_fields($customer_id) {
//First name field
if (isset($_POST['billing_first_name'])) {
update_user_meta($customer_id, 'first_name', sanitize_text_field($_POST['billing_first_name']));
update_user_meta($customer_id, 'billing_first_name', sanitize_text_field($_POST['billing_first_name']));
}
//Last name field
if (isset($_POST['billing_last_name'])) {
update_user_meta($customer_id, 'last_name', sanitize_text_field($_POST['billing_last_name']));
update_user_meta($customer_id, 'billing_last_name', sanitize_text_field($_POST['billing_last_name']));
}
}
add_action('woocommerce_created_customer', 'text_domain_woo_save_reg_form_fields');
All the above code goes in function.php file of your active child theme (or theme). Or also in any plugin php files.
The code is tested and fully functional.
Hope this helps!

<?php
/**
* Add new register fields for WooCommerce registration
* To add WooCommerce registration form custom fields.
*/
add_action( 'woocommerce_register_form', 'misha_add_register_form_field' );
function misha_add_register_form_field(){
woocommerce_form_field(
'billing_first_name',
array(
'type' => 'text',
'required' => true, // just adds an "*"
'label' => 'First name'
),
( isset($_POST['billing_first_name']) ? $_POST['billing_first_name'] : '' )
);
woocommerce_form_field(
'billing_last_name',
array(
'type' => 'text',
'required' => true, // just adds an "*"
'label' => 'Last name'
),
( isset($_POST['billing_last_name']) ? $_POST['billing_last_name'] : '' )
);
woocommerce_form_field(
'billing_phone',
array(
'type' => 'tel',
'required' => true, // just adds an "*"
'label' => 'Phone'
),
( isset($_POST['billing_phone']) ? $_POST['billing_phone'] : '' )
);
}
/**
* To validate WooCommerce registration form custom fields.
*/
add_action( 'woocommerce_register_post', 'misha_validate_fields', 10, 3 );
function misha_validate_fields( $username, $email, $errors ) {
if ( empty( $_POST['billing_first_name'] ) ) {
$errors->add( 'billing_first_name_error', 'First name is required!' );
}
if ( empty( $_POST['billing_last_name'] ) ) {
$errors->add( 'billing_last_name_error', 'Last name is required!' );
}
if ( empty( $_POST['billing_phone'] ) ) {
$errors->add( 'billing_phone_error', 'Phone is required!' );
}
}
/**
* To save WooCommerce registration form custom fields.
*/
add_action( 'woocommerce_created_customer', 'misha_save_register_fields' );
function misha_save_register_fields( $customer_id ){
//First name field
if ( isset( $_POST['billing_first_name'] ) ) {
//update_user_meta( $customer_id, 'country_to_visit', wc_clean( $_POST['country_to_visit'] ) );
update_user_meta($customer_id, 'first_name', sanitize_text_field($_POST['billing_first_name']));
update_user_meta($customer_id, 'billing_first_name', sanitize_text_field($_POST['billing_first_name']));
}
//Last name field
if (isset($_POST['billing_last_name'])) {
update_user_meta($customer_id, 'last_name', sanitize_text_field($_POST['billing_last_name']));
update_user_meta($customer_id, 'billing_last_name', sanitize_text_field($_POST['billing_last_name']));
}
// WooCommerce billing phone
if ( isset( $_POST['billing_phone'] ) ) {
update_user_meta( $customer_id, 'billing_phone', sanitize_text_field( $_POST['billing_phone'] ) );
}
}
?>

Adding Woocommerce registration form custom fields using filter hook woocommerce_forms_field and saving data with nonce verification.
/**
* Adding more fields to Woocommerce Registration form and My account page
*/
function how_woocommerce_registration_form_fields() {
return apply_filters( 'woocommerce_forms_field', array(
'billing_company' => array(
'type' => 'text',
'label' => __( 'Company Name', ' how' ),
'required' => false,
),
'how_user_job_title' => array(
'type' => 'text',
'label' => __( 'Job Title', ' how' ),
'required' => false,
),
'how_user_industry' => array(
'type' => 'select',
'label' => __( 'Industry', 'how' ),
'options' => array(
'' => __( 'Select an Industry', 'how' ),
'Lending' => __( 'Lending', 'how' ),
'Real Estate' => __( 'Real Estate', 'how' ),
'Investment' => __( 'Investment', 'how' ),
'Servicing' => __( 'Servicing', 'how' ),
'Other' => __( 'Other', 'how' ),
'Mortgage Servicing' => __( 'Mortgage Servicing', 'how' ),
'Mortgage Lending' => __( 'Mortgage Lending', 'how' ),
)
)
) );
}
function how_woocommerce_edit_registration_form() {
$fields = how_woocommerce_registration_form_fields();
foreach ( $fields as $key => $field_args ) {
woocommerce_form_field( $key, $field_args );
}
}
add_action( 'woocommerce_register_form', 'how_woocommerce_edit_registration_form', 15 );
/**
* Save registration form custom fields
*/
function wooc_save_extra_register_fields( $customer_id ) {
if( wp_verify_nonce( sanitize_text_field( $_REQUEST['woocommerce-register-nonce'] ), 'woocommerce-register' ) ) {
if ( isset( $_POST['billing_company'] ) ) {
update_user_meta( $customer_id, 'billing_company', sanitize_text_field( $_POST['billing_company'] ) );
update_user_meta( $customer_id, 'shipping_company', sanitize_text_field( $_POST['billing_company'] ) );
}
if ( isset( $_POST['how_user_job_title'] ) ) {
update_user_meta( $customer_id, 'how_user_job_title', sanitize_text_field( $_POST['how_user_job_title'] ) );
}
if ( isset( $_POST['how_user_industry'] ) ) {
update_user_meta( $customer_id, 'how_user_industry', sanitize_text_field( $_POST['how_user_industry'] ) );
}
}
}
add_action( 'woocommerce_created_customer', 'wooc_save_extra_register_fields' );

Related

How do I re-order or add priority to a custom field on WooCommerce "My Account" page

I have multiple fields in "My Account" page, so, I wanted to add additional field for Date of Birth.
I am using part of Add birthday field to my account and admin user page
The field shows up but it come in the bottom.
I wanted to add DOB field after my 2 existing fields, I tried using 'priority => 20,' but it doesn't work.
// Add field - my account
function action_woocommerce_edit_account_form() {
woocommerce_form_field( 'birthday_field', array(
'type' => 'date',
'label' => __( 'My Birth Date', 'woocommerce' ),
'placeholder' => __( 'Date of Birth', 'woocommerce' ),
'required' => true,
), get_user_meta( get_current_user_id(), 'birthday_field', true ));
}
add_action( 'woocommerce_edit_account_form', 'action_woocommerce_edit_account_form' );
// Validate - my account
function action_woocommerce_save_account_details_errors( $args ){
if ( isset($_POST['birthday_field']) && empty($_POST['birthday_field']) ) {
$args->add( 'error', __( 'Please provide a birth date', 'woocommerce' ) );
}
}
add_action( 'woocommerce_save_account_details_errors','action_woocommerce_save_account_details_errors', 10, 1 );
// Save - my account
function action_woocommerce_save_account_details( $user_id ) {
if( isset($_POST['birthday_field']) && ! empty($_POST['birthday_field']) ) {
update_user_meta( $user_id, 'birthday_field', sanitize_text_field($_POST['birthday_field']) );
}
}
add_action( 'woocommerce_save_account_details', 'action_woocommerce_save_account_details', 10, 1 );
As can be seen in myaccount/form-edit-account.php template file the woocommerce_edit_account_form action hook is executed after the already existing fields are added.
So if you want to add the field between the existing fields you will have to edit the template file
This template can be overridden by copying it to yourtheme/woocommerce/myaccount/form-edit-account.php
You have to delete the code you currently use
Add this code between 2 existing fields (at the place where you want to add the new field) in the myaccount/form-edit-account.php template file
<p class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide">
<label for="account_birthday"><?php esc_html_e( 'Birth day', 'woocommerce' ); ?> <span class="required">*</span></label>
<input type="date" class="woocommerce-Input woocommerce-Input--text input-text" name="account_birthday" id="account_birthday" value="<?php echo get_user_meta( get_current_user_id(), 'account_birthday', true ); ?>"/>
</p>
<div class="clear"></div>
For validation and saving then add the following code to functions.php (
or the way you prefer to add snippets)
// Validate - my account
function action_woocommerce_save_account_details_errors( $args ){
if ( isset( $_POST['account_birthday'] ) && empty( $_POST['account_birthday'] ) ) {
$args->add( 'error', __( 'Please provide a birth date', 'woocommerce' ) );
}
}
add_action( 'woocommerce_save_account_details_errors','action_woocommerce_save_account_details_errors', 10, 1 );
// Save - my account
function action_woocommerce_save_account_details( $user_id ) {
if( isset( $_POST['account_birthday'] ) && ! empty( $_POST['account_birthday'] ) ) {
update_user_meta( $user_id, 'account_birthday', sanitize_text_field( $_POST['account_birthday'] ) );
}
}
add_action( 'woocommerce_save_account_details', 'action_woocommerce_save_account_details', 10, 1 );

Custom WooCommerce product fields not saving in database

I made a custom field for a WooCommerce product but when I am trying to save it, Its value is not saving in the database
function product_certification_number() {
$args = array(
'id' => 'product_certification_number',
'label' => sanitize_text_field( 'Product Certification Number' ),
);
woocommerce_wp_text_input( $args );
}
add_action('woocommerce_product_options_general_product_data','product_certification_number' );
function product_certification_number_save( $post_id ) {
if ( ! ( isset( $_POST['woocommerce_meta_nonce'], $_POST[ 'product_certification_number' ] ) || wp_verify_nonce( sanitize_key( $_POST['woocommerce_meta_nonce'] ), 'woocommerce_save_data' ) ) ) {
return false;
}
$product_teaser = sanitize_text_field(
wp_unslash( $_POST[ 'product_certification_number' ] )
);
update_post_meta(
$post_id,
'product_certification_number',
esc_attr( $product_teaser )
);
}
add_action('woocommerce_process_product_meta','product_certification_number_save');
EDIT: used woocommerce_admin_process_product_object to save instead of outdated woocommerce_process_product_meta. Thnx to: #LoicTheAztec
// Add field
function product_certification_number() {
$args = array(
'id' => '_product_certification_number',
'label' => __( 'Product Certification Number', 'woocommerce' ),
'class' => 'custom-field',
'desc_tip' => true,
'description' => __( 'My description', 'woocommerce' ),
);
woocommerce_wp_text_input( $args );
}
add_action('woocommerce_product_options_general_product_data','product_certification_number', 10, 0 );
// Save
function product_certification_number_save( $product ){
if( isset($_POST['_product_certification_number']) ) {
$product->update_meta_data( '_product_certification_number', sanitize_text_field( $_POST['_product_certification_number'] ) );
}
}
add_action( 'woocommerce_admin_process_product_object', 'product_certification_number_save', 10, 1 );
I've wasted my two hours in this problem.
I finally found out that you need to call save_meta_data after update_meta_data:
/** #var WC_Product */
$product->update_meta_data($key, $value);
$product->save_meta_data();

Woocommerce confirm password not showing

I have added the following code to my functions.php file to allow password confirmation on the checkout page.
add_action( 'woocommerce_checkout_init', 'wc_add_confirm_password_checkout', 10, 1 );
function wc_add_confirm_password_checkout( $checkout ) {
if ( get_option( 'woocommerce_registration_generate_password' ) == 'no' ) {
$checkout->checkout_fields['account']['account_password2'] = array(
'type' => 'password',
'label' => __( 'Confirm password', 'woocommerce' ),
'required' => true,
'placeholder' => _x( 'Confirm Password', 'placeholder', 'woocommerce' )
);
}
}
// Check the password and confirm password fields match before allow checkout to proceed.
add_action( 'woocommerce_after_checkout_validation', 'wc_check_confirm_password_matches_checkout', 10, 2 );
function wc_check_confirm_password_matches_checkout( $posted ) {
$checkout = WC()->checkout;
if ( ! is_user_logged_in() && ( $checkout->must_create_account || ! empty( $posted['createaccount'] ) ) ) {
if ( strcmp( $posted['account_password'], $posted['account_password2'] ) !== 0 ) {
wc_add_notice( __( 'Passwords do not match.', 'woocommerce' ), 'error' );
}
}
}
Here is the link to the site checkout page. You will have to add a product to the cart and then go back to the checkout page. Once a product is in the cart and you are on the Checkout page you will notice that the password field has been highlighted red and there is no password confirmation field. This is broken.
http://staging.vawk.ca/checkout/
However if you go to the following url and do the same thing the password confirmation is there and everything works correctly. As far as I am concerned all of the code is the same and the database is the same.
http://jolangreen.com/other/clients/vawk/checkout/
How can I get the password confirmation to work on http://staging.vawk.ca/checkout/
Please try the modified code below, working on WordPress 4.7.3+ with WooCommerce 3.0.3+.
logicdigger
**
* Add a confirm password field to the checkout registration form.
*/
function o_woocommerce_confirm_password_checkout( $checkout ) {
if ( get_option( 'woocommerce_registration_generate_password' ) == 'no' ) {
$fields = $checkout->get_checkout_fields();
$fields['account']['account_confirm_password'] = array(
'type' => 'password',
'label' => __( 'Confirm password', 'woocommerce' ),
'required' => true,
'placeholder' => _x( 'Confirm Password', 'placeholder', 'woocommerce' )
);
$checkout->__set( 'checkout_fields', $fields );
}
}
add_action( 'woocommerce_checkout_init', 'o_woocommerce_confirm_password_checkout', 10, 1 );
/**
* Validate that the two password fields match.
*/
function o_woocommerce_confirm_password_validation( $posted ) {
$checkout = WC()->checkout;
if ( ! is_user_logged_in() && ( $checkout->must_create_account || ! empty( $posted['createaccount'] ) ) ) {
if ( strcmp( $posted['account_password'], $posted['account_confirm_password'] ) !== 0 ) {
wc_add_notice( __( 'Passwords do not match.', 'woocommerce' ), 'error' );
}
}
}
add_action( 'woocommerce_after_checkout_validation', 'o_woocommerce_confirm_password_validation', 10, 2 );

Enable confirmation password in Woocommerce checkout form

I have enabled 'Enable customer registration on the "Checkout" page' this option in Woocommerce settings. New customer gets registered on website while placing order. There is no other means of registration.
https://dev.clipcertification.com/checkout/
While placing order, there is a field for password.
I want to have 'Confirm Password', I tried using following code in theme's functions.php filr, but Confirm Password field do not show up.
<?php
// place the following code in your theme's functions.php file
// Add a second password field to the checkout page.
add_action( 'woocommerce_checkout_init', 'wc_add_confirm_password_checkout', 10, 1 );
function wc_add_confirm_password_checkout( $checkout ) {
if ( get_option( 'woocommerce_registration_generate_password' ) == 'no' ) {
$checkout->checkout_fields['account']['account_password2'] = array(
'type' => 'password',
'label' => __( 'Confirm password', 'woocommerce' ),
'required' => true,
'placeholder' => _x( 'Confirm Password', 'placeholder', 'woocommerce' )
);
}
}
// Check the password and confirm password fields match before allow checkout
to proceed.
add_action( 'woocommerce_after_checkout_validation',
'wc_check_confirm_password_matches_checkout', 10, 2 );
function wc_check_confirm_password_matches_checkout( $posted ) {
$checkout = WC()->checkout;
if ( ! is_user_logged_in() && ( $checkout->must_create_account || ! empty(
$posted['createaccount'] ) ) ) {
if ( strcmp( $posted['account_password'], $posted['account_password2'] ) !==
0 ) {
wc_add_notice( __( 'Passwords do not match.', 'woocommerce' ), 'error' );
}
}
}
?>
Assuming that the "customer registration" option is **Enabled for customer registration on the "Checkout" page", you could try the similar following:
add_filter( 'woocommerce_checkout_fields' , 'add_confirm_password_checkout_field', 10, 1 );
function add_confirm_password_checkout_field( $fields ) {
if ( get_option( 'woocommerce_registration_generate_password' ) != 'no' )
return $fields;
$fields['account']['account_password']['class'] = array('form-row-first');
$fields['account']['account_password-2'] = array(
'type' => 'password',
'label' => __( 'Password confirmation', 'woocommerce' ),
'required' => true,
'placeholder' => _x('Confirmation', 'placeholder', 'woocommerce'),
'class' => array('form-row-last'),
'label_class' => array('hidden')
);
return $fields;
}
add_action( 'woocommerce_checkout_process', 'confirm_password_checkout_validation' );
function confirm_password_checkout_validation() {
if ( ! is_user_logged_in() && ( WC()->checkout->must_create_account || ! empty( $_POST['createaccount'] ) ) ) {
if ( strcmp( $_POST['account_password'], $_POST['account_password-2'] ) !== 0 )
wc_add_notice( __( "Passwords doesn’t match.", "woocommerce" ), 'error' );
}
}
Code goes in function.php file of your active child theme (or active theme).
Tested and works.
You will get something like:
Now if you don't get the field try to remove or to comment this lines in the first hooked function:
if ( get_option( 'woocommerce_registration_generate_password' ) != 'no' )
return $fields;
This issue could be related to your theme or others plugin customizations.

Email recipient based on a custom field value in WooCommerce

I've added a custom field to the checkout page on my Woocommerce store. The field is 'Restaurant Location'. Upon a customer placing an order, my goal is to use the 'Restaurant Location' field to determine which email to send the order confirmation to.
Here's how I defined the custom field.
/////// Hook custom field in ///////
add_filter( 'woocommerce_checkout_fields', 'custom_checkout_fields' );
function custom_checkout_fields( $fields ) {
$fields['order']['restaurant_location'] = array(
'label' => __('Food options', 'woocommerce'),
'placeholder' => _x('', 'placeholder', 'woocommerce'),
'required' => true,
'clear' => false,
'type' => 'select',
'options' => array(
'no' => __('New Orleans', 'woocommerce' ),
'br' => __('Baton Rouge', 'woocommerce' )
)
);
return $fields;
}
Here's my attempt at the email filter.
add_filter( 'woocommerce_email_recipient_new_order', 'gon_conditional_email_recipient', 10, 2 );
function gon_conditional_email_recipient( $recipient, $order ) {
$gon_order_data = $order->get_data();
$gon_restaurant_location = $gon_order_data['order']['restaurant_location'];
if ( $gon_restaurant_location == 'New Orleans' ) {
$recipient = 'test1#gmail.com';
return $recipient;
}
else if ( $gon_restaurant_location == 'Baton Rouge' ) {
$recipient = 'test2#gmail.com';
return $recipient;
}
return $recipient;
}
The email filter is working, i.e. I can get an email to go to either address, but I can't seem to pull in the '$gon_restaurant_location' variable properly. Any ideas?
Thanks,
pS
Your custom field value is not saved in database, so that's why is not working. Try this complete solution instead:
// Add the custom checkout field
add_filter( 'woocommerce_after_order_notes', 'restaurant_location_checkout_field' );
function restaurant_location_checkout_field( $checkout ) {
woocommerce_form_field( 'restaurant_location', array(
'type' => 'select',
'class' => array('my-field-class form-row-wide'),
'label' => __('Food options', 'woocommerce'),
'required' => true,
'options' => array(
'' => __('Please select an option', 'woocommerce' ),
'New Orleans' => __('New Orleans', 'woocommerce' ),
'Baton Rouge' => __('Baton Rouge', 'woocommerce' )
)
), $checkout->get_value( 'restaurant_location' ));
}
// Process the checkout (checking)
add_action('woocommerce_checkout_process', 'restaurant_location_field_process');
function restaurant_location_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST['restaurant_location'] )
wc_add_notice( __( 'Please select a food option .' ), 'error' );
}
// Update the order meta with field value
add_action( 'woocommerce_checkout_update_order_meta', 'restaurant_location_field_update_order_meta' );
function restaurant_location_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['restaurant_location'] ) ) {
update_post_meta( $order_id, '_restaurant_location', sanitize_text_field( $_POST['restaurant_location'] ) );
}
}
// Display field value on the order edit page
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
echo '<p><strong>'.__('Food options', 'woocommerce').':</strong> ' . get_post_meta( $order->get_id(), '_restaurant_location', true ) . '</p>';
}
// Conditional Email recipient filter based on restaurant location
add_filter( 'woocommerce_email_recipient_new_order', 'conditional_email_recipient', 10, 2 );
function conditional_email_recipient( $recipient, $order ) {
if( is_admin() ) return $recipient;
$location = get_post_meta( $order->get_id(), '_restaurant_location', true );
$recipient = $location == 'New Orleans' ? ',test1#example.com' : ',test1#example.com';
return $recipient;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested on Woocommerce 3+ and works
Based on official developer documentation: Adding a custom special field

Categories