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.

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 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.

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 then loop through the fields and prepare the data for saving.

Firstly, 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.

Finally, we use update_user_meta to assign that data to the user.

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 get_user_meta() (described in the next 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.

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.

You can access the data of each field by using it’s key.

get_user_meta() accepts 3 parameters:

  • $user_id
    The ID of your user. you could use $user_id = get_current_user_id() to get the ID of the currently logged in user.
  • $key
    The field key we want to fetch.
  • $single
    If true return value of meta data field, if false return an array.

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.


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.

  • Thomas Rainer

    This was fantastic! Thank you very much for your time and effort in putting this all together. I do have a question: 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.

    • Hey, thanks!

      Yes, url is the correct key to use. Have you tried downloading the complete script? It could be some part that was missed. I tested with the URL field when writing this up, so you shouldn’t have any issues!

  • 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?

    • Hey, nice!

      Yep, you can use get_user_meta( $user_id, ‘text-field’, true ); to get your data. You’ll need to modify the email template or hook into it.