Sync additional Billing registration fields with default Wordpress fields in WooCommerce
Asked Answered
A

1

4

I Have added the below codes into Woocommerce user registration form to get the Billing Details on the registration page.

Now what is happening when a new user register, the first and last name will get registered in the database of billing details & as well as in the default wordpress user account. If the user update his first name & last name on his account (wordpress user account), the same should update on the billing details.

Woocommerce settings:

Guest checkout is disabled. Checkout page user registration is enabled. Login Page Registration is enabled. Only Registered user can make purchases.

  1. This is the user registration form where I'm pulling these additional billing details from checkout process.

User Registration Form

  1. On "Account Details" I updated the "First Name", it worked here but i didn't get the same update on "Billing Details". I want the same "First Name" & "Last Name" update on the "Billing Details" if a user update these 2 fields and his email address on his "Account Details".

Updates "First Name" & "Last Name" on "Account Details

  1. Now after updating the "First Name" & "Last Name" on "Account Details", I came back to "Billing Details" but it is still displaying the old "First Name" & "Last Name" which were used during registeration process. Also, I want to hide these 3 fields from Billing details, "First Name", "Last Name" & "Email Address"- to not to confuse the registered users. I need these updates on "Billing Details" in database only because these information will be printed on the invoices & Emails

Scrrenshot of "Billing Details" After Updates on "Account Details"

The data will only sync/update if an administrator or store manager go to the user profile (from back-end) and manually press the "update" button then only it will take the effects. I want the data to sync/update automatically when a registered user made any changes from his account (front-end).

Any help will be highly appreciated.

Please check the below code:

// Custom function to display the Billing Address form to registration page
add_action('woocommerce_register_form_start','zk_add_billing_form_to_registration');
function zk_add_billing_form_to_registration(){
    $checkout = WC()->checkout;
    foreach ( $checkout->get_checkout_fields( 'billing' ) as $key => $field ) :
        if($key!='billing_email')
            woocommerce_form_field( $key, $field, $checkout->get_value( $key ) );
    endforeach;
}

// Custom function to save Usermeta or Billing Address of registered user
add_action('woocommerce_created_customer','zk_save_billing_address');
function zk_save_billing_address($user_id){
    $address = $_POST;
    foreach ($address as $key => $field){
        // Only billing fields values
        if( strpos( $key, 'billing_' ) !== false ){
            // Condition to add firstname and last name to user meta table
            if($key == 'billing_first_name' || $key == 'billing_last_name'){
                $new_key = str_replace( 'billing_', '', $key );
                update_user_meta( $user_id, $new_key, $_POST[$key] );
            }
            update_user_meta( $user_id, $key, $_POST[$key] );
        }
    }
}

// Checking & validation of the additional fields in registration form.
add_action('woocommerce_register_post','zk_validation_billing_address', 10, 3 );
function zk_validation_billing_address( $username, $email, $validation_errors ){
    foreach ($_POST as $key => $field) :
        // Validation: Required fields
        if( strpos( $key, 'billing_' ) !== false ){
            if($key == 'billing_country' && empty($field) ){
                $validation_errors->add( $key.'_error',  __( 'Please select a country.', 'woocommerce' ));
            }
            if($key == 'billing_first_name' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter first name.', 'woocommerce' ) );
            }
            if($key == 'billing_last_name' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter last name.', 'woocommerce' ) );
            }
            if($key == 'billing_address_1' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter address.', 'woocommerce' ) );
            }
            if($key == 'billing_city' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter city.', 'woocommerce' ) );
            }
            if($key == 'billing_state' && empty($field) ){
                if(count( WC()->countries->get_states($_POST['billing_country']) ) > 0)
                    $validation_errors->add( $key.'_error', __( 'Please enter state.', 'woocommerce' ) );
            }
            if($key == 'billing_postcode' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter a postcode.', 'woocommerce' ) );
            }
            /*
            if($key == 'billing_email' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter billing email address.', 'woocommerce' ) );
            }
            */
            if($key == 'billing_phone' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter phone number.', 'woocommerce' ) );
            }

        }
    endforeach;
}

add_filter( 'woocommerce_billing_fields', 'sv_required_billing_fields' );
function sv_required_billing_fields( $fields ) {
    $fields['billing_phone']['required'] = true;
    $fields['billing_city']['required'] = true;
    $fields['billing_country']['required'] = true;
    $fields['billing_address_1']['required'] = true;
    return $fields;
}

// Hidding some billing fields (Wordpress edit user pages)
add_action( 'edit_user_profile', 'user_profile_hide_some_fields_css', 1, 1 );
function user_profile_hide_some_fields_css( $user ){
    ?>
    <style>
    .user-edit-php table#fieldset-billing tr:first-child,
    .user-edit-php table#fieldset-billing tr:nth-child(2),
    .user-edit-php table#fieldset-billing tr:last-child {
        display:none;
    }
    </style>
    <?php
}

// Sync hidden billing fields (Wordpress edit user pages)
add_action( 'personal_options_update', 'sync_user_data_wp_and_billing_wc', 100, 1 );
add_action( 'edit_user_profile_update', 'sync_user_data_wp_and_billing_wc', 100, 1 );
function sync_user_data_wp_and_billing_wc( $user_id )
{
    if( ! empty($_POST['first_name']) ) {
        update_user_meta( $user_id, 'billing_first_name', sanitize_text_field( $_POST['first_name'] ) );
    }

    if( ! empty($_POST['last_name']) ) {
        update_user_meta( $user_id, 'billing_last_name', sanitize_text_field( $_POST['last_name'] ) );
    }

    if( ! empty($_POST['email']) ) {
        update_user_meta( $user_id, 'billing_email', sanitize_text_field( $_POST['email'] ), sanitize_text_field( $_POST['billing_email'] ) );
    }
}
Artificial answered 13/11, 2017 at 21:35 Comment(0)
A
6

I have revisited your code a bit, as for example the 4 last functions can be merged in one, and other things…

Data update and sync

Now when a customer updates his data on his my account pages, all data is synched by woocommerce everywhere, except on his existing past Orders

If a customer change checkout fields and process checkout, the data is also updated everywhere…

So you don't need to worry about customer synched data.

Note: The function hooked in woocommerce_billing_fields will be enabled either in your additional registration fields and in checkout fields, as you are using checkout object to generate additional registration fields… You can use the conditional ! is_checkout() to only target my account registration fields.

Here is your revisited code:

// Custom function to display the Billing Address form to registration page
add_action('woocommerce_register_form_start','zk_add_billing_form_to_registration');
function zk_add_billing_form_to_registration(){
    $checkout = WC()->checkout;
    foreach ( $checkout->get_checkout_fields( 'billing' ) as $key => $field ) :
        if($key!='billing_email')
            woocommerce_form_field( $key, $field, $checkout->get_value( $key ) );
    endforeach;
}

// Custom function to save Usermeta or Billing Address of registered user
add_action('woocommerce_created_customer','zk_save_billing_address');
function zk_save_billing_address($user_id){
    $address = $_POST;
    foreach ($address as $key => $field){
        // Only billing fields values
        if( strpos( $key, 'billing_' ) !== false ){
            // Condition to add firstname and last name to user meta table
            if($key == 'billing_first_name' || $key == 'billing_last_name'){
                $new_key = str_replace( 'billing_', '', $key );
                update_user_meta( $user_id, $new_key, $_POST[$key] );
            }
            update_user_meta( $user_id, $key, $_POST[$key] );
        }
    }
}

// Checking & validation of the additional fields in registration form.
add_action('woocommerce_register_post','zk_validation_billing_address', 10, 3 );
function zk_validation_billing_address( $username, $email, $validation_errors ){
    foreach ($_POST as $key => $field) :
        // Validation: Required fields
        if( strpos( $key, 'billing_' ) !== false ){
            if($key == 'billing_country' && empty($field) ){
                $validation_errors->add( $key.'_error',  __( 'Please select a country.', 'woocommerce' ));
            }
            if($key == 'billing_first_name' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter first name.', 'woocommerce' ) );
            }
            if($key == 'billing_last_name' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter last name.', 'woocommerce' ) );
            }
            if($key == 'billing_address_1' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter address.', 'woocommerce' ) );
            }
            if($key == 'billing_city' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter city.', 'woocommerce' ) );
            }
            if($key == 'billing_state' && empty($field) ){
                if(count( WC()->countries->get_states($_POST['billing_country']) ) > 0)
                    $validation_errors->add( $key.'_error', __( 'Please enter state.', 'woocommerce' ) );
            }
            if($key == 'billing_postcode' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter a postcode.', 'woocommerce' ) );
            }
            /*
            if($key == 'billing_email' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter billing email address.', 'woocommerce' ) );
            }
            */
            if($key == 'billing_phone' && empty($field) ){
                $validation_errors->add( $key.'_error', __( 'Please enter phone number.', 'woocommerce' ) );
            }

        }
    endforeach;
}

add_filter( 'woocommerce_billing_fields', 'sv_required_billing_fields' );
function sv_required_billing_fields( $fields ) {
    $fields['billing_phone']['required'] = true;
    $fields['billing_city']['required'] = true;
    $fields['billing_country']['required'] = true;
    $fields['billing_address_1']['required'] = true;
    return $fields;
}

The customer can't access (never) to WordPress backend User edit pages. Only shop Manager and administrators can do it…
To sync Wordpress user data in backend you need to choose which fields will have the priority:

  • the Wordpress default fields (or)
  • the billing fields (from WooCommerce).

Is better to give the priority to WordPress default fields and hide necessary billing fields…

This code will hide the 3 billing fields (first name, last name and email) and will sync them with default fields updated values:

// Hidding some billing fields (Wordpress edit user pages)
add_action( 'edit_user_profile', 'user_profile_hide_some_fields_css', 1, 1 );
function user_profile_hide_some_fields_css( $user ){
    ?>
    <style>
    .user-edit-php table#fieldset-billing tr:first-child,
    .user-edit-php table#fieldset-billing tr:nth-child(2),
    .user-edit-php table#fieldset-billing tr:last-child {
        display:none;
    }
    </style>
    <?php
}

// Sync hidden billing fields (Wordpress edit user pages)
add_action( 'personal_options_update', 'sync_user_data_wp_and_billing_wc', 100, 1 );
add_action( 'edit_user_profile_update', 'sync_user_data_wp_and_billing_wc', 100, 1 );
function sync_user_data_wp_and_billing_wc( $user_id )
{
    if( ! empty($_POST['first_name']) ) {
        update_user_meta( $user_id, 'billing_first_name', sanitize_text_field( $_POST['first_name'] ) );
    }

    if( ! empty($_POST['last_name']) ) {
        update_user_meta( $user_id, 'billing_last_name', sanitize_text_field( $_POST['last_name'] ) );
    }

    if( ! empty($_POST['email']) ) {
        update_user_meta( $user_id, 'billing_email', sanitize_text_field( $_POST['email'] ), sanitize_text_field( $_POST['billing_email'] ) );
    }
}

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

Tested and works…

Andris answered 13/11, 2017 at 23:42 Comment(5)
I tried your codes and it worked perfectly. I will need some more help from you. I have edited the question. Can you please check again and give a solution? ThanksArtificial
I updated my question above. Can you please go through it and help me out? ThanksArtificial
@AdnanAli This is becoming too complicated and blurry… Meaning that you are making confusions and you worry too much about user data… WooCommerce is a strong and stable system where the "customer data is synched. The important thing in woocommerce, is the billing and shipping information that is always used by woocommerce. The customer never access to backend and doesn't see the WP user edit pages… WooCommerce sync the data itself very well… So you should rethink your position in this… Usually developers don't use checkout forms in my account customer pages. … / …Andris
@AdnanAli (2) … So you should better rollback here to your initial question… and ask a new question, rethinking completely your position, as you will not get any real complete answer on this, with your actual position. As someone known says "think different"…Andris
That code works for me! But... how it's possible to update State selected based on Country selection or change field as text box if there no State/Provice related to country?Fp

© 2022 - 2024 — McMap. All rights reserved.