Brian Edelman Brian Edelman - 2 months ago 50
PHP Question

Add a custom field to checkout and to my_account user details on registration

I have a woocommerce site I am building and I want to add the user's birthdate to the usermeta in the database as well as display it in the wp-admin under their profile.

I have limited experience with messing with PHP.

I have pulled from the Woocommerce docs here to display it on checkout, which it is doing correctly.

The Woocommerce docs show you how to add it to the order info but not to the user account itself. It is correctly being added to the order but not the account.

Here is what I have so far:

/**
* Add the field to the checkout
*/
add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' );

function my_custom_checkout_field( $checkout ) {

echo '<div id="my_custom_checkout_field">';

woocommerce_form_field( 'birthdate', array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'label' => __('Date of Birth'),
'placeholder' => __('mm/dd/yyyy'),
), $checkout->get_value( 'birthdate' ));

echo '</div>';

}

/**
* Process the checkout
*/
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');

function my_custom_checkout_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST['birthdate'] )
wc_add_notice( __( 'Please enter your date of birth.' ), 'error' );
}

/**
* update order meta with field value
*/

add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );


function my_custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['birthdate'] ) ) {
update_post_meta( $order_id, 'Birthdate', sanitize_text_field( $_POST['birthdate'] ) );
}
}

/**
* update user meta with birthdate
*/

add_action ( 'personal_options_update', 'my_save_extra_profile_fields' );
add_action ( 'edit_user_profile_update', 'my_save_extra_profile_fields' );

function my_save_extra_profile_fields( $user_id )
{
if ( ! empty( $_POST['birthdate'] ) ) {
update_usermeta( $user_id, 'Birthdate', sanitize_text_field( $_POST['birthdate'] ) );
}
}


/**
* 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 );
add_action ( 'show_user_profile', 'my_custom_checkout_field_display_admin_order_meta' );
add_action ( 'edit_user_profile', 'my_custom_checkout_field_display_admin_order_meta' );

function my_custom_checkout_field_display_admin_order_meta($order){
echo '<p><strong>'.__('Birthdate').':</strong> ' . get_post_meta( $order->id, 'Birthdate', true ) . '</p>';
}


I am also getting this error on the user info page:

Notice: WP_User->id was called with an argument that is deprecated since
version 2.1.0! Use WP_User->ID instead. in
/Applications/MAMP/htdocs/tst_dev/wp-includes/functions.php on line 3891


I have also tried this instead of my version of the user update meta.

add_action( 'user_register', 'my_custom_update_user');

function my_custom_update_user( $user_id )
{
if ( $user_id != 0 ) { // check if user is not a guest
update_usermeta( $user_id, 'Birthdate', sanitize_text_field( $_POST['birthdate'] ) );
}
}

Answer

— Light Update — (All data is now updated in database)


1) SOLVING THE ERROR:

You have to use update_user_meta() instead of deprecated update_usermeta() to avoid the error.

2) CLEANING AND CHANGING YOUR CODE:

For custom fields, is better to avoid capitals in the slug.

// Add the field to the checkout
add_action( 'woocommerce_after_order_notes', 'birth_day_checkout_field' );
function birth_day_checkout_field( $checkout ) {

    // if customer is logged in and his birth date is defined
    if(!empty(get_user_meta( get_current_user_id(), 'account_birth_date', true ))){
        $checkout_birht_date = esc_attr(get_user_meta( get_current_user_id(), 'account_birth_date', true ));
    }
    // The customer is not logged in or his birth date is NOT defined
    else {
        $checkout_birht_date = $checkout->get_value( 'birth_date' );
    }

    echo '<div id="my_custom_checkout_field">';

    woocommerce_form_field( 'birth_date', array(
        'type'          => 'text',
        'class'         => array('birth-date form-row-wide'),
        'label'         => __( 'Date of Birth', 'theme_domain_slug' ),
        'placeholder'   => __( 'mm/dd/yyyy', 'theme_domain_slug' ),
        ), $checkout_birht_date);

    echo '</div>';

}


// Process the checkout
add_action('woocommerce_checkout_process', 'birth_day_checkout_field_process');
function birth_day_checkout_field_process() {
    // Check if set, if its not set add an error.
    if ( ! $_POST['birth_date'] )
        wc_add_notice( __( 'Please enter your date of birth.', 'theme_domain_slug' ), 'error' );
}


// update order meta with field value
add_action( 'woocommerce_checkout_update_order_meta', 'birth_day_checkout_field_update_order_meta' );
function birth_day_checkout_field_update_order_meta( $order_id ) {
    if (!empty( $_POST['birth_date'])){
        update_post_meta( $order_id, 'birth_date', sanitize_text_field( $_POST['birth_date'] ) );

        // updating user meta (for customer my account edit details page post data)
        update_user_meta( get_post_meta( $order_id, '_customer_user', true ), 'account_birth_date', sanitize_text_field($_POST['birth_date']) );
    }
}

// update user meta with Birth date (in checkout and my account edit details pages)
add_action ( 'personal_options_update', 'birth_day_save_extra_profile_fields' );
add_action ( 'edit_user_profile_update', 'birth_day_save_extra_profile_fields' );
add_action( 'woocommerce_save_account_details', 'birth_day_save_extra_profile_fields' );
function birth_day_save_extra_profile_fields( $user_id )
{
    // for checkout page post data
    if ( isset($_POST['birth_date']) ) {
        update_user_meta( $user_id, 'account_birth_date', sanitize_text_field($_POST['birth_date']) );
    }
    // for customer my account edit details page post data
    if ( isset($_POST['account_birth_date']) ) {
        update_user_meta( $user_id, 'account_birth_date', sanitize_text_field($_POST['account_birth_date']) );
    }
}


// Display field value on the order edit page
add_action( 'woocommerce_admin_order_data_after_billing_address', 'birth_day_checkout_field_display_admin_order_meta', 10, 1 );
add_action ( 'show_user_profile', 'birth_day_checkout_field_display_admin_order_meta' );
add_action ( 'edit_user_profile', 'birth_day_checkout_field_display_admin_order_meta' );
function birth_day_custom_checkout_field_display_admin_order_meta($order){
    echo '<p><strong>' . __( 'Birth date:', 'theme_domain_slug' ) . '</strong> ' . get_post_meta( $order->id, 'birth_date', true ) . '</p>';
}

3) ADDING THE FIELD TO CUSTOMER MY ACCOUNT EDIT DETAILS:

You could have used the woocommerce_edit_account_form_start hook to insert this custom field in customer my_account edit details page, but you don't have the control in placement and ordering.

It's better to included it your active theme woocommerce template folder my_account/form-edit-account.php (if you don't have this folder yet, read Overriding Templates via a Theme, to understand how you can do it.

Here the Birth Date custom field with be located on right side of the email address in My account edit account details form.

Here is the code of this customized template:

<?php
/**
 * Edit account form
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/myaccount/form-edit-account.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you
 * (the theme developer) will need to copy the new files to your theme to
 * maintain compatibility. We try to do this as little as possible, but it does
 * happen. When this occurs the version of the template file will be bumped and
 * the readme will list any important changes.
 *
 * @see     https://docs.woocommerce.com/document/template-structure/
 * @author  WooThemes
 * @package WooCommerce/Templates
 * @version 2.6.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

do_action( 'woocommerce_before_edit_account_form' ); ?>

<form class="woocommerce-EditAccountForm edit-account" action="" method="post">

    <?php do_action( 'woocommerce_edit_account_form_start' ); ?>

    <p class="woocommerce-FormRow woocommerce-FormRow--first form-row form-row-first">
        <label for="account_first_name"><?php _e( 'First name', 'woocommerce' ); ?> <span class="required">*</span></label>
        <input type="text" class="woocommerce-Input woocommerce-Input--text input-text" name="account_first_name" id="account_first_name" value="<?php echo esc_attr( $user->first_name ); ?>" />
    </p>
    <p class="woocommerce-FormRow woocommerce-FormRow--last form-row form-row-last">
        <label for="account_last_name"><?php _e( 'Last name', 'woocommerce' ); ?> <span class="required">*</span></label>
        <input type="text" class="woocommerce-Input woocommerce-Input--text input-text" name="account_last_name" id="account_last_name" value="<?php echo esc_attr( $user->last_name ); ?>" />
    </p>
    <div class="clear"></div>

    <!-- class modification here in <p> tag -->
    <p class="woocommerce-FormRow woocommerce-FormRow--wide form-row form-row-first"><?php // <== Changed the class from "form-row-wide" to "form-row-first" ?>
        <label for="account_email"><?php _e( 'Email address', 'woocommerce' ); ?> <span class="required">*</span></label>
        <input type="email" class="woocommerce-Input woocommerce-Input--email input-text" name="account_email" id="account_email" value="<?php echo esc_attr( $user->user_email ); ?>" />
    </p>
    <!-- (BEGIN) ADDED: Birth day field -->
    <p class="woocommerce-FormRow woocommerce-FormRow--last form-row form-row-last">
        <label for="account_birth_date"><?php _e( 'Birth date', 'theme_domain_slug' ); ?> <span class="required">*</span></label>
        <input type="text" class="woocommerce-Input woocommerce-Input--email input-text" name="account_birth_date" id="account_birth_date" placeholder="mm/dd/yyyy" value="<?php echo esc_attr(get_user_meta( $user->ID, 'account_birth_date', true )); ?>" />
    </p>
    <div class="clear"></div>
    <!-- (END) Birth day field -->

    <fieldset>
        <legend><?php _e( 'Password Change', 'woocommerce' ); ?></legend>

        <p class="woocommerce-FormRow woocommerce-FormRow--wide form-row form-row-wide">
            <label for="password_current"><?php _e( 'Current Password (leave blank to leave unchanged)', 'woocommerce' ); ?></label>
            <input type="password" class="woocommerce-Input woocommerce-Input--password input-text" name="password_current" id="password_current" />
        </p>
        <p class="woocommerce-FormRow woocommerce-FormRow--wide form-row form-row-wide">
            <label for="password_1"><?php _e( 'New Password (leave blank to leave unchanged)', 'woocommerce' ); ?></label>
            <input type="password" class="woocommerce-Input woocommerce-Input--password input-text" name="password_1" id="password_1" />
        </p>
        <p class="woocommerce-FormRow woocommerce-FormRow--wide form-row form-row-wide">
            <label for="password_2"><?php _e( 'Confirm New Password', 'woocommerce' ); ?></label>
            <input type="password" class="woocommerce-Input woocommerce-Input--password input-text" name="password_2" id="password_2" />
        </p>
    </fieldset>
    <div class="clear"></div>

    <?php do_action( 'woocommerce_edit_account_form' ); ?>

    <p>
        <?php wp_nonce_field( 'save_account_details' ); ?>
        <input type="submit" class="woocommerce-Button button" name="save_account_details" value="<?php esc_attr_e( 'Save changes', 'woocommerce' ); ?>" />
        <input type="hidden" name="action" value="save_account_details" />
    </p>

    <?php do_action( 'woocommerce_edit_account_form_end' ); ?>
</form>

<?php do_action( 'woocommerce_after_edit_account_form' ); ?>

4) THANKS GIVING BONUS GIFT: ADDING THE FIELD TO ADMIN EDIT USER:

enter image description here

// ADDING CUSTOM FIELD TO INDIVIDUAL USER SETTINGS PAGE IN BACKEND
add_action( 'show_user_profile', 'add_extra_birth_date' );
add_action( 'edit_user_profile', 'add_extra_birth_date' );
function add_extra_birth_date( $user )
{
    ?>
        <h3><?php _e("Birth Date", "theme_domain_slug"); ?></h3>
        <table class="form-table">
            <tr>
                <th><label for="birth_date_profile"><?php _e("Date", "theme_domain_slug"); ?> </label></th>
                <td><input type="text" name="account_birth_date" value="<?php echo esc_attr(get_user_meta( $user->ID, 'account_birth_date', true )); ?>" class="regular-text" /></td>
            </tr>
        </table>
        <br />
    <?php
}

add_action( 'personal_options_update', 'save_extra_birth_date' );
add_action( 'edit_user_profile_update', 'save_extra_birth_date' );
function save_extra_birth_date( $user_id )
{
    update_user_meta( $user_id, 'account_birth_date', sanitize_text_field( $_POST['account_birth_date'] ) );
}

All the code goes in function.php file of your active child theme (or theme) or also in any plugin file, (except for the template code).

This code is tested and works.