The Ultimate Guide to Adding Custom WooCommerce User Account Fields

The default account registration form in WooCommerce is fairly limited; you simply enter an email address and a password.

In some ways this is great, as there’s little friction for your customers to create an account, but there are a number of cases where you may want to add some additional fields. For example, you could add some fields to populate the rest of their profile, like their website address, or social media information. Or perhaps you want to add some custom fields relevant only to your specific WooCommerce store.

In this tutorial I’m going to show you how to add a number of different field types to the WooCommerce account registration form, and then save this information to the customer’s profile. As a bonus, I will also show you how to add these fields when your customers sign up for an account at checkout, and to their account page once logged in.

It might be a long one, so I’ll index the important sections:

Where do I add this code?

The code from this tutorial should be added to your WooCommerce website as feature plugin. You can download an example plugin below or at the end of this post. Simply upload the files in Plugins > Add New, or to the wp-content/plugins directory. You can then modify the code to suit your needs.

Want to download the code from this tutorial as an example plugin?

Simply enter your name and email to receive the complete and formatted version of this code as a feature plugin for FREE.

You will receive occasional emails from Iconic, but you're more than welcome to unsubscribe at any time. I won't spam or share your details with anyone, ever.

Note: The code I provide here as an example plugin will not be supported or updated.

Enable the Account Registration Form

Firstly, you’ll want to ensure the registration form is enabled on the account login page.

Go to WooCommerce > Settings > Accounts and check Enable customer registration on the “My account” page.

Now the account login page should look like this:

To ease ourselves into this, we’ll start by adding a single text field to the registration form. As it already exists in the WordPress user profile, let’s start with the Website field.

Overview of the woocommerce_form_field() Function

WooCommerce comes with a fantastic function for outputting form field HTML. The function is named woocommerce_form_field().

Rather than writing our own HTML (with a minor exception, explained shortly), we might as well use this function.

The function accepts 3 parameters:

  • $key
    String. This is your field key which will be used for the input’s name parameter and ID. The ID can also be overridden in the $args parameter.
  • $args
    Array. This is an array of options for your field. It is here where you can set the field type, placeholder, options, class, and more. The available arguments are:
  • $value
    Mixed. This is the default value for the field.

This function sets us up nicely to be able to create custom WooCommerce account registration fields without repeating ourselves.

Setup Additional Registration Fields

We’re going to reference our custom fields in multiple functions; displaying the fields, saving the fields, and getting the saved field data.

As such, it makes sense for us to build an array of fields containing all the data we need for every scenario; then all of our data is easily accessible in a single place.

We’ll start by building the array with our single Website field.

There’s a few things going on here. Firstly, we setup a function which we can then reference later on, iconic_get_account_fields().

Within this function we’re returning a multi-dimensional array. You’ll notice we’re also running the array through a filter, iconic_account_fields. This means we can modify the array later on to update the field values.

Let’s strip it back a bit. The array contains one value (line 10) with a key of user_url (this is the key used for the Website field in WordPress). Its associated value is an array of data which we’ll be passing to the $args parameter of the woocommerce_form_field() function. We will also be adding some additional key/value pairs for use in our own functions.

Add Additional User Account Fields to WooCommerce

There’s 4 areas where we want our additional user account fields to be displayed; the registration form, the edit account page, the checkout, and the WordPress admin area.

Add Custom Fields to the Registration Form

Now that we’ve set up our Website field, we want to add it to the registration form.

To do that, we’re going to hook into the registration form layout using the woocommerce_register_form hook. This will add our new field(s) just before the Register button.

I’ll walk you through what’s going on here. We’ve created a function named iconic_print_user_frontend_fields(). At the end of the code you can see we’re calling that function when the woocommerce_register_form hook is called.

Within the function, we firstly assign our fields to the $fields variable using the function we created previously. We know that this will return an array, so we jump straight in and loop through the array of fields.

We’re using the array key (which will be url) as the form key, and then passing the array value as our $field_args. Let’s take a look at the registration form now:

Great! Our Website field has been added. However, currently, it won‘t do anything.

We’ll need to validate the input when the form is submitted, and then save it to the user profile. We’ll also want to display this field once the customer is logged in so they can edit it later on.

For the sake of keeping things together in this post, let’s take a look at how we can display this field once the customer has logged into their account.

Add Custom Fields to the Account Area

This is actually very simple. We can use exactly the same function we created before, iconic_print_user_frontend_fields(), and just call it on a different hook.

Again, this hook is triggered just before the form’s submit button. This particular form is located in My Account > Account Details, or /my-account/edit-account/ by default.

Add Custom Fields to the WooCommerce Checkout

When a customer is checking out, they have the option to create an account (assuming you have that setting enabled). We probably want to show our additional fields there too.

We do this in a slightly different way. The checkout fields in WooCommerce are run through a filter; woocommerce_checkout_fields. They are split into groups, billing, shipping, and account. We want to add our fields to the account group.

Fortunately, the array of fields we built up earlier makes it easy for us to hook into the aforementioned filter and add our fields to the checkout.

woocommerce_checkout_fields provides one parameter. As with any filter in WordPress, the first parameter is also what any function that hooks in should be expected to return.

Note: It was pointed out that in WooCommerce 3.5.1 the fields require a priority parameter. As such, I’ve updated the code above to include a method of setting the default priority to 0. The password field in WooCommerce core has no priority either, so I’ve ensured it’s set in the above function too.

We fetch our fields array, loop through it, and assign each of our fields to the account group. Then we return the new $checkout_fields variable.

Add Custom Fields to the WordPress Admin Area

Finally, we want to add the custom fields to the WordPress admin area, when editing a user’s profile (or your own profile).

The layout is slightly different in the WordPress admin, as the fields are presented in tables. As such, we need a new function for displaying the fields in the admin area; but don’t forget, we can still use the same fields array we built earlier.

As usual, we fetch our custom fields right at the start. Then we jump into the HTML layout.

I’ve added a title of Additional Information so the fields are easily identifiable in the admin area. below that, we’re going to use a table layout to list the fields. It’s a 2 column table where the left cell is the field label, and the right cell is the field.

Before we output the field, we’re setting the label to false to prevent the label from showing in the right cell, as it already appears in the left.

We’re then using 2 actions to display the fields when editing a user profile. The first, show_user_profile, will add the custom fields to the current user’s profile, and the second, edit_user_profile, will add it to other users’ profiles.

Adding Conditionals to the Custom Fields

OK, so we’ve got our custom field showing in all the places we want it to. However, you may have noticed; we don’t really need to add it to the admin area, as the field already exists there. And what if we didn’t want to add it to the checkout, or the account area?

Well, because we used an array right at the start for building our custom fields list, we’ve made it super easy to add in some conditionals.

Let’s add some extra key/value pairs to our initial fields array to indicate the following conditions:

  • Hide in registration
  • Hide in account
  • Hide in admin
  • Hide in checkout

If any of these values are true, the field should not be displayed in that location. For the purpose of our Website field, we only want to hide it in admin, as it already exists there.

Now we need to modify the functions that display the fields on the registration form, account area, checkout, and WordPress admin area.

I’ve highlighted the modifications to those functions above. We’re essentially adding stoppers, so if any of our conditionals are not empty (i.e. they are “true”) then we skip that field.

As the registration form and account area use the same function to display the fields, we’re also checking whether the user is logged in. if the user is logged in, it’s the account area, if not, it’s the registration form.

Adding Other Field Types to the Fields Array

Now we have full control over where our fields appear; awesome! But what about adding other field types?

There are a number of fields available for us to add by default, and I’ll also add some modifications so we can add radios/checkboxes. Radios are actually already available, but I wasn’t pleased with the way they were presented.

The fields available to add already are:

  • Text
  • Textarea
  • Select
  • Country
  • Checkbox
  • Number
  • Password
  • Email
  • Tel

We’ll then add:

  • Radio
  • Checkboxes

Let’s update our fields array with an example of each field type.

Pretty straight forward, right?

It’s worth noting that multiple choice fields like select, radio, and checkboxes, have an additional options key. Here we can set which options are available for the field.

How does this look on the registration form?

There you can see most of our fields working nicely. However, you’ll notice that the radio field doesn’t look great, and the checkboxes field is completely missing. Let’s correct that by adding some of our own field types.

Add Custom Field Types to woocommerce_form_field()

The woocommerce_form_field() function has a hook within it that allows us to override or add new field types. Let’s take a look at how that’s done.

The hook we’re after is named woocommerce_form_field_{$field_type). So for our circumstances we want 2 filters named wocommerce_form_field_checkboxes and woocommerce_form_field_radio.

You know by now that I don‘t like to repeat code, so we’re going to call the same function for both of these filters.

The filter accepts 4 arguments:

  • $field
    This is the field HTML that is returned.
  • $key
    This is the field key. We set this in our fields array.
  • $args
    This is the field data we associated to the field key in our fields array.
  • $value
    This is the default value for the field.

Within the function, we’re using ob_start() and ob_get_clean(). This allows us to assign code that is usually echoed or printed to a variable for returning.

You can see we’re also calling a new function, iconic_print_list_field(). I’ve decided that checkboxes and radios follow the same format; a list.

This function is essentially replicating the format of other WooCommerce fields, however, we’re spitting our options out into a list ( <ul> ).

So how do those fields look now on the registration page?

That’s better!

Save the Additional Field Data to the User

There’s a few situations where we want to save the data; during registration, during checkout, when editing your own profile via admin, when editing another users profile in admin, and editing your account via the WooCommerce “My Account” area.

Fortunately, we can save the data in all of these scenarios with 1 function. Let’s take a look.

Here we’re using a single function, iconic_save_account_fields(), and we’re calling it 4 times.

  • woocommerce_created_customer
    This hook is called when a user registers using the form on the login page, and also when a user registers during checkout.
  • personal_options_update
    This hook is called when you edit your own profile in the WordPress admin area.
  • edit_user_profile_update
    This hook is called when you edit another user’s profile in the WordPress admin area.
  • woocommerce_save_account_details
    This hook is called when a customer edits their profile via the WooCommerce “My Account” area.

Within the iconic_save_account_fields() function we start off by fetching the field data.

We also create an array named $sanitized_data. We do this because there’s 2 ways we can add data to a user; those that are predefined by WordPress, and our own custom fields. In a moment you’ll see which fields are predefined by WordPress.

We then loop through the fields and prepare the data for saving.

The first thing we do is check whether this field should be saved by seeing if it should be visible on the current page. This will prevent hidden fields saving with blank data. To do this, we’re using iconic_is_field_visible().

This function could be used elsewhere in our code too. It will determine if a field should be visible or not based on the current page and the field arguments.

If the field is to be saved, we decide which sanitization method to use. We check if the field has one set in the main array, and if not, we use wc_clean; this works well for plain text fields. The sanitization method can be set for each field in the array, like this:

We then run the value through the sanitization function and assign it to the $value variable.

Next we run the key through iconic_is_userdata(). This function is going to determine whether this field is one that WordPress has predefined (like user_url).

In iconic_is_userdata() I’ve defined an array of field keys which WordPress has predefined. The function checks whether our $key is in that array and returns true or false.

If the $key was found in that array, we add it to the $sanitized_data array and use continue to proceed to the next field.

If the $key was not found, we use update_user_meta to assign that custom data to the user.

After the loop we check if our $sanitized_data array has any data. If it does, we assign the user ID and then use wp_update_user() to update the predefined user fields with our new values.

Validate Frontend Submission

It’s common to want some fields to be required fields. Or we may want to ensure a field meets a specific format. As such, we want want to hook in just before the fields are saved and validate them.

Firstly, let’s add a required parameter to our fields array. We’ll use iconic-register-text as an example.

Now we can check against this before the field is saved. WooCommerce gives us 2 filters we can use; woocommerce_registration_errors and woocommerce_save_account_details_errors.

We’ll use woocommerce_registration_errors for the registration form and the checkout registration process. Then we’ll use woocommerce_save_account_details_errors for the WooCommerce “My Account” area.

Again, we can use the same function for both filters.

As usual, we start by fetching our fields array.

We loop through the array and then check whether required is empty. If it is, we skip it with continue as it requires no validation.

We also check if register isn’t set in the posted values and if hide_in_account is true for the specific field. Again, if this evaluates to true we skip it. When register isn’t set it means we’re saving our account fields, and if hide_in_account is true, it means that particular field should not be validated as the field wasn’t visible for us to enter any information in to.

Then, we run the same check as above but check if hide_in_registration is true when registering. We’d skip it for the same reasons as above.

If we get past all of these “stoppers” then the field is required and should contain some posted data. If it is empty, we add an error to the $errors object and carry on with the loop.

We then return our new $errors object, which may or may not contain validation errors, depending on the data that has been posted.

If there is an error, the user will be taken back to the form and the error message we added will be displayed. No data will have been saved.

Set Default Values for the Fields

There’s 2 scenarios when we would want to display a default value for the fields; when viewing the user profile (admin or WooCommerce account area), and when you submit the form but an error occurs.

Default Values for Saved Fields

When we display the fields in the WooCommerce account area, or in the WordPress admin when editing a user profile, we’ll want to populate the field with the submitted data. As such, we need to edit the iconic_print_user_frontend_fields() and iconic_print_user_admin_fields() functions.

We’ve added a check to iconic_print_user_frontend_fields(). If the user is logged in then we get their user ID and fetch the field value using iconic_get_userdata() (described in the section “Accessing the Saved user Data”).

In iconic_print_admin_user_fields() we’re doing the same; fetch the ID of the user we’re currently editing and fetch the data for that field.

We’re also now using the third parameter of woocommerce_form_field() which allows us to pass in the default value for the field.

You’ll notice I’m using a function named iconic_get_edit_user_id(). This function (shown above) will return the user ID if it exists as a URL parameter, or the currently logged in user ID. This means we can use the same function for all scenarios above.

See “Accessing the Saved User Data” for information on the iconic_get_userdata() function.

Default Values after Submission Errors

When we initially set up our fields array, we also ran them through a filter named iconic_account_fields. Well, this is the perfect scenario for us to use that filter.

After a submission error occurs, the user is redirected back to the form. The posted data is still accessible at this point, so it makes sense for us to re-populate the fields with the data they entered.

Let’s hook in to our filter and populate the field values.

First, if the $_POST object is empty we just return the fields as normal.

Otherwise, we loop through each field. If the $_POST value for that key is empty, we set the fields value to empty then skip to the next field using continue;.

If the $_POST value is set, we set it as the field’s value.

In the modified version of iconic_print_user_frontend_fields() above, at line 26 we’re checking if value is set in the $field_args. If it is, we use that, otherwise we use the saved value (if present), or null.

Accessing the Saved User Data

Now that you’ve saved this data to the user, you will want to access it and, most likely, display it or use it somewhere on your WooCommerce store.

Our data can come from 2 places; our custom meta data, or the predefined WordPress data. As such, here’s a function to get the appropriate value:

You can use this function like so: echo iconic_get_userdata( 1, 'user_url' );, where 1 is the user ID and user_url is the field key.

The function checks if the field is a predefined WordPress field using iconic_is_userdata(). If it is not, it fetches the value using get_user_meta(), a function that will fetch our custom user meta data.

If it is a predefined field, we fetch the user data using get_userdata() and pass in our user ID.

We then check if the key is set and return its value.

Want to download the code from this tutorial as an example plugin?

Simply enter your name and email to receive the complete and formatted version of this code as a feature plugin for FREE.

You will receive occasional emails from Iconic, but you're more than welcome to unsubscribe at any time. I won't spam or share your details with anyone, ever.


There we have it! I said it’d be a long post.

To recap, we’ve discussed how to add additional fields to the WooCommerce registration form, checkout registration, account area, and admin user profiles.

We’ve then worked out how to save this data and validate it when submitted.

For the developers reading this, you should have everything you need here. For those of you who are not interested in touching code, I will be working on a plugin for this which will provide an interface for adding the fields via the WordPress admin. If you want to be informed when it’s released, just enter your email to download the code from this tutorial, or leave a comment below.

Let me know in the comments if you have any questions.

Leave a Reply

51 Comments on "The Ultimate Guide to Adding Custom WooCommerce User Account Fields"

newest oldest most voted
Notify of
Thomas Rainer

This was fantastic! Thank you very much for your time and effort in putting this all together. I do have a question: Is it possible to only use the default wordpress “Contact Information” website field? I’ve setup all the code for the Website Field. But the information is not showing for the User under the “Contact Information” section of the “Website” field in the admin. I’ve tried “url” and “user_url”. However, the entered website url does show in the newly added fields from your instructions.

Michelle Britton

Great plugin! Thank you!

I have one question – I am currently using your code to pull in information from three checkboxes and I am using this code to send a new registration email to the admin:

add_action(‘woocommerce_created_customer’, ‘admin_email_on_registration’, 10 , 1);
function admin_email_on_registration( $customer_id) {
wp_new_user_notification( $customer_id );

Is there any way to send the information from the three checkboxes in the email?

Luigi Briganti

There is not a way to add the “date” input type to wordpress user meta?


vote for this


I am loving the Plug-in, and just grasping with creating a view of the User data will all this additional fields added to it, is there a plug in that will be be a view as the admin to the users and the fields that they have completed. Would like to dump the table of users to a CSV file

Hagbard Celine

Hi, would like to download the files for the tutorial. I signed up, but all I got was a newsletter subscription?

Nikos Chatzirafail

Hi, how can I add an input type=”file” field?

Laurent Dagany

Hi !
Very nice… It will help me a lot if… A Question :
you said in the chapter “Add Custom Fields to the WooCommerce Checkout” that there are three group (indeed) to put the new fileds : billing, shipping, and account.
Your exemple is to put in “account”. I’d like to put them in the billing group.
I tried to change the code
$checkout_fields[‘account’][ $key ] = $field_args;
$checkout_fields[‘billing’][ $key ] = $field_args;

But nothing 🙁

Do you have a clue for the trick to put the nex flieds in the billing part ?
Thanks !


Thank you for a great plugin that helped us a lot with our website. We’ve opened registrations yesterday and half of the new user registrations are missing all additional fields data in the back-end. The firstname / surname / email address are always in though. It’s random and I was wondering if you had similar experience?

UgoChukwu Agbams

I used the sample plugin you sent to me, make few editing to remove field sets I don’t want, save it,and all works fine, just that the field are not showing up at checkout page.
Secondly, I will like to make the filed read only once a value is entered and save. Am using only text and number field to set up two fields.

Andre Riis
worked perfect, but now i had to change function iconic_save_account_fields( $customer_id ) { $fields = iconic_get_account_fields(); $sanitized_data = array(); foreach ( $fields as $key => $field_args ) { if ( ! iconic_is_field_visible( $field_args ) ) { continue; } $sanitize = isset( $field_args[‘sanitize’] ) ? $field_args[‘sanitize’] : ‘wc_clean’; $value = isset( $_POST[ $key ] ) ? call_user_func( $sanitize, $_POST[ $key ] ) : ”; if ( iconic_is_userdata( $key ) ) { $sanitized_data[ $key ] = $value; continue; } update_user_meta( $customer_id, $key, $value ); } if ( ! empty( $sanitized_data ) ) { $sanitized_data[‘ID’] = $customer_id; wp_update_user( $sanitized_data ); } }
Fermin June Seva Alegro III
Fermin June Seva Alegro III

These works nicely for fields that are not yet in the My Account and Profile pages.
Im currently in need of being able to add a Username (non changeable) but it seems it is already in the My Account (frontend) and Profile (wp-admin) pages.
How do you override or use already present fields like these and make it non changeable?
Also what are the keys for the fields in the billing address and shipping address?

Sino 21

This has to be one of the best woocommerce articles i ever saw. I wish every publisher have eye for peculiar details like you and i wish everyone describe things like you do. This is a true gem. Thank you.


I’ve been using this guide to create some custom fields for our website and it works wonderfully for a little while. But all of a sudden today a required checkbox on our registration form always throws an error saying that it’s not ticked even when it has been. Do you know if any recent wordpress updates might mess with this code?
Any help would be appreciated,


Hi I have added your code to my website and it works great! Thank you for your work!

One question though, as I am quite new to wordpress, I would like to ask whether there is any code we can use to verify a field, for instance for the telephone number field, I want my users to input 10 digits of numbers only otherwise it would return an error message.


Gijs Palsrok
I’m using custom code to add checkout fields. These are already visible for both users who are paying for their product. It is also visible for me as an administrator in the admin. But I also need it to be visible for users in their own profile page, and preferably adjustable. Because I’m keeping the new European rules on privcay in mind.. Can’t wait for your reply. Here is my code: /* WooCommerce: The Code Below Removes Checkout Fields */ add_filter( ‘woocommerce_checkout_fields’ , ‘custom_override_checkout_fields’ ); function custom_override_checkout_fields( $fields ) { unset($fields[‘billing’][‘billing_company’]); unset($fields[‘billing’][‘billing_address_1’]); unset($fields[‘billing’][‘billing_address_2’]); unset($fields[‘billing’][‘billing_postcode’]); unset($fields[‘billing’][‘billing_country’]); unset($fields[‘billing’][‘billing_state’]); unset($fields[‘billing’][‘billing_phone’]); unset($fields[‘order’][‘order_comments’]); return $fields;… Read more »

Hey James, I’m new to WordPress and i’m trying to start my first store. I’ve had trouble customizing the account page and making a login page. Your plugin is great, but how do I add a username field and most importantly, where can I find the code and edit it?


Thanks for the tutorial!!
Is it possible to set the order that the field appears in the form?
Like: put a custom field before the email field?


Is there a way to use this fields with the REST API?


how display a field information in admin edit order page.
i need to show customer field in edit order page

Reid Horton

How do we add these fields to REST API end-points? I need to expose them to the REST API, but am falling short…any ideas?


Trying to do something really simple, I thought…. I want to add a customer ID number to the user and automatically display in Woocommerce as well.


Greate tutorial! one question, how can i add a new “save changes” button for the new my account site. as a example, i have a page with partner information for the customer and i would like to save this partner information like the own customar details.

Andy Agcaoili

Thank you so much for this post! It is really helpful. Unfortunately, the data does not save when it is entered or when the user wants to update the site. I sent you an email to see if you could help! Thanks!

Anthony Hortin
Thanks for this Guide. It works really well. Just one thing that I noticed though, is that it’s generating a PHP notice about trying to convert an array to a string. In line 11 of the iconic_get_userdata() function, there should be a third parameter when calling get_user_meta(). Currently you’re calling get_user_meta( $user_id, $key ) but that actually returns an array (by default) which generates the notice (an in turn, doesn’t set the default value properly). Instead it should be get_user_meta( $user_id, $key, true ) which will return a string. Passing true as the thrid paramater will ensure get_user_meta() only returns… Read more »
Thank you for this post. It has been immensely helpful. I have a question, though…I’ve added several custom checkout fields, and they save perfectly in admin and when a new account is created (including from the checkout page), but if any of the field inputs for an existing user are changed on the checkout page, those fields are not saved after the order is submitted. That is, the woocommerce_created_customer hook seems to save the info for a new customer, but if a return customer is updating data on the checkout page, this hook does not fire. I’ve tried various other… Read more »

I have the same problem! Anyone has a solution?


I found the solution! We need to use woocommerce_checkout_update_user_meta like so:

add_action( ‘woocommerce_checkout_update_user_meta’, ‘iconic_save_account_fields’); //Checkout process

HongSik, Won

hi James
You are the best!
It was very helpful.

Wildmar Gomes

Alright, thank you for this Tutorial, it was super useful, but I can’t make the arg Maxlenght work in “iconic_get_account_fields()”.
I’m using it this way, but it doesn’t work.
Can you help me? Please!
Thank you again in advance.

Hello James! I have a question, how do I save the fields if i’m putting them on the order section on checkout? All other fields are being saved correctly everywhere, but these aren’t. And they save if I edit them on admin or account area, but not during checkout. Am I missing an action on the save function? Basically I changed billing to “order”: // Add fields to checkout function iconic_checkout_fields( $checkout_fields ) { $fields = iconic_get_account_fields(); foreach ( $fields as $key => $field_args ) { if ( ! empty( $field_args[‘hide_in_checkout’] ) ) { continue; } $checkout_fields[‘order’][ $key ] =… Read more »