WooCommerce Customize Checkout Fields

Collect extra customer details at checkout

Note: This was updated for compatibility with WooCommerce 3.0+. This will cause fatal errors if used with older versions of WooCommerce.

I was digging around in WooCommerce while trying to come up with a quote for a client. Part of the scope had me wondering if you could remove some fields from the checkout process. If you aren’t selling physical products a billing address can be too much information and could even be off-putting to potential customers.

I eventually tracked the fields down from the checkout template, to the checkout class to the get_address_fields() method in the WC_Countries class.

Removing Billing Address

Like a lot of things in WooCommerce you can modify values via filter. To remove all the physical address fields from the billing address here is the code I used:

// Remove some checkout billing fields
function kia_filter_billing_fields($fields){
    unset( $fields["billing_country"] );
    unset( $fields["billing_company"] );
    unset( $fields["billing_address_1"] );
    unset( $fields["billing_address_2"] );
    unset( $fields["billing_city"] );
    unset( $fields["billing_state"] );
    unset( $fields["billing_postcode"] );
    unset( $fields["billing_phone"] );
    return $fields;
add_filter( 'woocommerce_billing_fields', 'kia_filter_billing_fields' );

Yes this could go in functions.php but that kind of locks you into a specific theme. If this is a permanent change then you probably want to create a site-specific plugin and put it in the wp-content/mu-plugins/ folder.

Add a Custom Checkout Field

While I was fooling around I figured I would see if I could add a custom checkout field. Turns out this is a bit more complex, but ultimately do-able. The following code will add the field to the checkout page, save the data to order meta and display the order meta in the orders admin.

Update: After receiving multiple contacts about adding more than one field I have modified the sample code to add 2 fields.

// Add a new checkout field
function kia_filter_checkout_fields($fields){
    $fields['extra_fields'] = array(
            'some_field' => array(
                'type' => 'text',
                'required'      => true,
                'label' => __( 'Some field' )
            'another_field' => array(
                'type' => 'select',
                'options' => array( 'a' => __( 'apple' ), 'b' => __( 'bacon' ), 'c' => __( 'chocolate' ) ),
                'required'      => true,
                'label' => __( 'Another field' )

    return $fields;
add_filter( 'woocommerce_checkout_fields', 'kia_filter_checkout_fields' );

// display the extra field on the checkout form
function kia_extra_checkout_fields(){ 

    $checkout = WC()->checkout(); ?>

    <div class="extra-fields">
    <h3><?php _e( 'Additional Fields' ); ?></h3>

    // because of this foreach, everything added to the array in the previous function will display automagically
    foreach ( $checkout->checkout_fields['extra_fields'] as $key => $field ) : ?>

            <?php woocommerce_form_field( $key, $field, $checkout->get_value( $key ) ); ?>

        <?php endforeach; ?>

<?php }
add_action( 'woocommerce_checkout_after_customer_details' ,'kia_extra_checkout_fields' );

Note: there is no foreach() in the rest of the function so we must save and display each field individually

Save the extra data on checkout

function kia_save_extra_checkout_fields( $order, $data ){

    // don't forget appropriate sanitization if you are using a different field type
    if( isset( $data['some_field'] ) ) {
        $order->update_meta_data( '_some_field', sanitize_text_field( $data['some_field'] ) );
    if( isset( $data['another_field'] ) && in_array( $data['another_field'], array( 'a', 'b', 'c' ) ) ) {
        $order->update_meta_data( '_another_field', $data['another_field'] );
add_action( 'woocommerce_checkout_create_order', 'kia_save_extra_checkout_fields', 10, 2 );

Display the extra data to users

// display the extra data on order received page and my-account order review
function kia_display_order_data( $order_id ){  
    $order = wc_get_order( $order_id ); ?>
    <h2><?php _e( 'Additional Info' ); ?></h2>
    <table class="shop_table shop_table_responsive additional_info">
                <th><?php _e( 'Some Field:' ); ?></th>
                <td><?php echo $order->get_meta( '_some_field' ); ?></td>
                <th><?php _e( 'Another Field:' ); ?></th>
                <td><?php echo $order->get_meta( '_another_field' ); ?></td>
<?php }
add_action( 'woocommerce_thankyou', 'kia_display_order_data', 20 );
add_action( 'woocommerce_view_order', 'kia_display_order_data', 20 );

Display extra data in admin

// display the extra data in the order admin panel
function kia_display_order_data_in_admin( $order ){  ?>
    <div class="order_data_column">
        <h4><?php _e( 'Extra Details', 'woocommerce' ); ?></h4>
            echo '<p><strong>' . __( 'Some field' ) . ':</strong>' . $order->get_meta( '_some_field' ) . '</p>';
            echo '<p><strong>' . __( 'Another field' ) . ':</strong>' . $order->get_meta( '_another_field' ) . '</p>'; ?>
<?php }
add_action( 'woocommerce_admin_order_data_after_order_details', 'kia_display_order_data_in_admin' );

Alternatively, display extra data as editable data (and save)

This should function like the shipping and billing address data and reveal inputs when the little pencil icon is clicked. Make sure to delete the previous function as two functions with the same name will cause a PHP error.

// display the extra data in the order admin panel
function kia_display_order_data_in_admin( $order ){  ?>
    <div class="order_data_column">

        <h4><?php _e( 'Extra Details', 'woocommerce' ); ?><a href="#" class="edit_address"><?php _e( 'Edit', 'woocommerce' ); ?></a></h4>
        <div class="address">
            echo '<p><strong>' . __( 'Some field' ) . ':</strong>' . $order->get_meta( '_some_field' ) . '</p>';
            echo '<p><strong>' . __( 'Another field' ) . ':</strong>' . $order->get_meta( '_another_field' ) . '</p>'; ?>
        <div class="edit_address">
            <?php woocommerce_wp_text_input( array( 'id' => '_some_field', 'label' => __( 'Some field' ), 'wrapper_class' => '_billing_company_field' ) ); ?>
            <?php woocommerce_wp_text_input( array( 'id' => '_another_field', 'label' => __( 'Another field' ), 'wrapper_class' => '_billing_company_field' ) ); ?>
<?php }
add_action( 'woocommerce_admin_order_data_after_order_details', 'kia_display_order_data_in_admin' );

function kia_save_extra_details( $order_id, $post ){
    $order = wc_get_order( $order_id );
    $order->update_meta_data( '_some_field', wc_clean( $_POST[ '_some_field' ] ) );
    $order->update_meta_data( '_another_field', wc_clean( $_POST[ '_another_field' ] ) );
add_action( 'woocommerce_process_shop_order_meta', 'kia_save_extra_details', 45, 2 );

Add the field to order emails

The easiest way to add data to the emails is to add our meta to the list of meta that WooCommerce will print out automatically. For WooCommerce 2.3 and after, you will do it the following way:

// WooCommerce 3.0+
function kia_email_order_meta_fields( $fields, $sent_to_admin, $order ) {
    $fields['some_field'] = array(
                'label' => __( 'Some field' ),
                'value' => $order->get_meta( '_some_field' ),
    $fields['another_field'] = array(
                'label' => __( 'Another field' ),
                'value' => $order->get_meta( '_another_field' ),
    return $fields;
add_filter( 'woocommerce_email_order_meta_fields', 'kia_email_order_meta_fields', 10, 3 );

If you’d rather customize the output in the emails you can add some text to any of the hooks available in the email templates.

function kia_display_email_order_meta( $order, $sent_to_admin, $plain_text ) { 
	$some_field = $order->get_meta( '_some_field' ); 
	$another_field = $order->get_meta( '_another_field' ); 
	if( $plain_text ){ 
		echo 'The value for some field is ' . $some_field . ' while the value of another field is ' . $another_field;
	} else { 
		echo 'The value for <strong>some field</strong> is ' . $some_field. ' while the value of <strong>another field</strong> is ' . $another_field . ';
add_action('woocommerce_email_customer_details', 'kia_display_email_order_meta', 30, 3 );

Hope that helps you. I think there are a few plugins out there now if this was too intimidating, so I would suggest trying the WooCommerce Checkout Field Editor plugin which will provide a code-free user interface for editing the checkout fields.


  1. Igi Manaloto on November 7, 2014 at 4:11 am

    Thanks for this! I was desperately searching for the woocommerce_admin_order_data_after_order_details hook implementation then found your awesome article. <3

    • kathy on November 7, 2014 at 11:14 am

      You’re welcome! Glad it could be useful to you. I’ve been meaning to post a few more WooCommerce articles, but I keep procrastinating.

  2. GCW on November 20, 2014 at 11:15 am

    Hi Kathy, I found this very interesting!
    But, what if I want to add a checkout field only for some specified product IDs? (or catgories).

    • kathy on November 20, 2014 at 11:59 am

      Hi Giovanni. If you mean adding custom data to a specific product? That is an entirely different tutorial (that I haven’t written). If you mean to only show these fields if certain items are in the cart, then you will need to write some conditional logic.

  3. sanjay on December 1, 2014 at 6:47 am

    i have used this code for option box custom checkout page it’s working good but i am not able to send that custom field in order email.

    • kathy on December 1, 2014 at 11:29 am

      Sanjay, Please see my updates to the post.

  4. Clare on December 30, 2014 at 3:30 am


    Could you help me with a drop down select input box for an extra field on the WooCommerce page? It would have to be just the same as you have above, but with a few options in the drop down. Like: “How did you hear about us?”
    Option 1
    Option 2
    Option 3
    Option 4

    Thank you!!

    • kathy on December 30, 2014 at 2:49 pm

      You could try switching the form field type to select and supplying some options? I don’t know if everything will work, but it’s worth a shot:

      $fields['extra_fields'] = array(
                  'some_field' => array(
                      'type' => 'select',
                      'required'      => true,
                      'label' => __( 'Some field' ),
                      'options' => array( 'key' => 'Label',
                                  'key2'  => 'Label 2' )
  5. Noxtifer on January 19, 2015 at 3:47 pm

    Hi, is it possible to save the extra field data in admin orders AND in the user profile in back-end?

    • kathy on January 19, 2015 at 4:12 pm

      The data (as shown above anyway) is saved as post meta for the order. You could therefore display it in the My Account/My Orders section. Or if you really wanted I suppose it would be possible to save data as user meta. See update_user_meta().

      • Marc on August 10, 2015 at 2:15 pm

        Would saving as user_meta just be a simple case of copying the above code and changing post_meta to user_meta and order_id to user_id?

        • kathy on January 4, 2016 at 3:20 am

          I lost a lot of comments to an over-aggressive spam-queue. Doubtful you need this any longer, but for anyone else the answer is yes. Assuming you have the user ID (which is available in the order object as the $order->user_id property, you can save user-specific data with update_user_meta().

  6. karkunum on January 21, 2015 at 12:48 pm

    May I know how to add more than 1 custom fields. I have no experience in php. The above code I can just copy and paste but it will show only 1 custom field. What about more than one? I also need textarea…
    Thanks in advance.

    • kathy on January 21, 2015 at 9:14 pm

      You will need to add additional keys to the $extra_fields array. kia_extra_checkout_fields() already has a foreach() so it will loop through all the fields in the array, but the rest of the functions would need to be updated accordingly. Sorry, but I can’t really want to get into providing custom support in my comments. I hope that helps. Good luck. Trying to dig into WooCommerce when you are new to PHP is a brave thing to be doing.

  7. Dan Humphrey on January 24, 2015 at 11:34 pm

    Hi Kathy,

    First off – fantastic post, I’ve scoured Google and not found such an in-depth example. I was wondering if you’d be able to assist.

    I’m trying to take your example but convert it to do the following;

    Add 4 new fields to the registration page in woocommerce as well as checkout and my account. I can add the fields in but where I’m struggling is, making the data save to the database and showing that data in the account section.

    Here is a link to my modification of your code, you’d be a life saver if you can tell me where I’m going wrong.

    Link: codepen


    • kathy on January 25, 2015 at 9:44 am

      Thanks Dan. I’m glad you dig the post. Unfortunately, I can’t get into providing support in the comments, but if I had to quickly guess:

      add_action( 'woocommerce_checkout_after_customer_details' ,'kia_extra_checkout_fields' );
      add_action( 'woocommerce_after_customer_login_form' ,'kia_extra_checkout_fields' ); 
      add_action( 'woocommerce_after_my_account' ,'kia_extra_checkout_fields' ); 

      I don’t think WC()->checkout means anything after the order is placed (so in my account areas). You need to pull fields from the $order. Same with

      add_action( 'woocommerce_thankyou', 'kia_display_order_data', 20 );
      add_action( 'woocommerce_view_order', 'kia_display_order_data', 20 );

      Look again at my code. The $order_id is passed to those hooks, not $customer_id.

      The user ID is part of the order object: $order->user_id

  8. Kevin on February 4, 2015 at 2:40 am

    Hi, how can i add these custom fields value to my account details like in billing and shipping address? or in order details?

    many thanks

    • kathy on February 4, 2015 at 9:21 am

      kia_display_order_data() already displays in the my account area under order details. If you don’t like where it is displaying then attach the display function to another hook.

      • Kevin on February 4, 2015 at 9:33 am

        thank you very much :D

  9. Tobias on February 26, 2015 at 11:20 pm

    Thank you Kathy- that was an easy fix, very helpful! At some point in the future I would love to see the article that allows us to require the removed field based on certain items in the cart.

    • kathy on February 27, 2015 at 2:12 am

      You’re welcome Tobias. I’m glad you found it useful. Do you have an example of what you mean? Maybe I can write a follow up post.

  10. Peter Hadorn on March 14, 2015 at 3:32 pm

    Thanks a LOT, Kathy! Fortunately this still works in WooCommerce 2.3.6 :)

    • kathy on March 26, 2015 at 2:42 pm

      You’re welcome, Peter. It should work for a while until Woo comes out with a crazy mega overhaul. Even then, they tend to maintain backward compatibility and throw in deprecation notices so you have time to get updated.

  11. Chris Ng on March 27, 2015 at 10:53 pm

    Does the “required” attribute trigger any validation? Or does it simply add an asterisk to the field label?

  12. Jeff Shamley on May 15, 2015 at 3:55 am

    Even though I am using Woo 2.3.8 I was only able to get the emails working using the deprecated version. I am still digging into why that is, but at least it all works!

    The website tells the truth, Kathy is awesome! Thanks for the tutorial.

    • kathy on May 15, 2015 at 5:34 am

      Hi Jeff, glad you liked the tutorial. The woocommerce_email_order_meta_fields filter is definitely available in WooCommerce 2.3.8. Unfortunately, I am moving and travelling so I can’t look in to it. As a first thought you should make sure that if you are overriding the email templates, they are up to date and include the woocommerce_email_order_meta action hook: do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text );.

      • Jeff Shamley on May 15, 2015 at 2:06 pm

        Hi Kathy – thanks for the response. I wondered the same thing about the email templates as I had moved them all to my theme for customization. However, I never ended up customizing any of them except the email-header.php file. So I removed them all from my theme but that didn’t change anything with implementing the newer hook.

        • kathy on May 17, 2015 at 9:26 pm

          Jeff, I’m afraid I’m out of ideas. I’m also going to Cuba for an international handball tournament with Team USA, so I can’t look any further into this right now. I hope you figure it out. If you do, please let me know what the trouble was.

  13. Yasser Taha on June 6, 2015 at 4:20 pm

    Hi All,

    And thank you for your support

    I have a different issue and i hoped that you can help me.

    If you can check the website above and in the check out page there is one additional field i added “How did you know about us?” and its required field.

    The issue is everytime you checkout you need to enter this field details i can’t keep the data saved.

    Kindly advice

    • kathy on June 6, 2015 at 5:17 pm

      Hi Yasser,

      The article covers how to save the data from custom checkout fields. Look carefully at the kia_save_extra_checkout_fields() function. If you need further customization you can hire me via the contact page.


  14. achin kishore on June 9, 2015 at 7:01 pm

    Hi Kathy,
    A very detailed and informative post. I was wondering if I wanted users to upload image files during checkout then how would i be able to achieve the same?
    I have been searching for over a week but have a feeling ill get an answer on this forum.

    • kathy on July 22, 2015 at 3:45 pm

      During checkout? Well you would need a script that handled image uploads, store that image on your server, and save the URL as meta for the order. It would be complicated. If you are trying to attach images to a specific product then I would recommend Product Addons.

  15. Rai on June 26, 2015 at 2:35 pm

    Hi Kathy,

    So you are adding this code as a plugin to your webpage?
    I need the part of adding the new field to the checkout and to the admin area, just that.


    • kathy on July 22, 2015 at 3:42 pm

      Hi Rai, Yes I would add this as a plugin. You are free to adjust the code as you need for your own purposes.

  16. mrityunjay on July 6, 2015 at 6:50 am

    hi kathy,
    thank you for great article.

    I need a little help in changing few fields in checkout page. Actually I need to change their language using language switcher of qtranslate X plugin. So, I need to add shorcode for each fields. I managed to change it for all but it is not working for address, zip code and Town/city. Even this is not working for cart too i.e., they are not translated to Danish from English.

    Any help would be appreciated.


    • kathy on July 22, 2015 at 3:40 pm

      Hi Mrityunjay, sorry but I am not familiar with that plugin. However if you create a plugin from what I have written and add proper text-domains,

      for example, changing

      <?php _e( 'Some Field:' ); ?>


      <?php _e( 'Some Field:', 'your-text-domain' ); ?>

      Then the strings should all be translatable by most all translation plugins.

  17. Aurélien Debord on July 9, 2015 at 4:25 pm

    Thanks Kathy for sharing these tips :)

    • kathy on July 22, 2015 at 3:30 pm

      Avec plaisir!

  18. Jason Meddle on July 10, 2015 at 6:14 pm

    Interestingly, _transaction_id meta key, which is saved into the database upon successful transaction, won’t be returned by your function kia_display_email_order_meta. Any idea why?

    • kathy on July 22, 2015 at 3:36 pm

      Sorry, not really. You are sure that your gateway is setting a transaction id? something like: $order->payment_complete( $txn_id );

  19. Mayank Gupta on August 1, 2015 at 1:31 pm

    Wonderful tips, Kathy :) Many thanks to you…

    Using these tips i could add 2 custom dates & 1 radio button, Pickup Date, Delivery Date and Order Type, to the checkout page. However, I want to add few validations, such as if Order Type –> “XXX” then Delivery Date picker should not allow user to select day before the Pickup Date selected by user.
    Can you please suggest how this can be done??

    • kathy on January 4, 2016 at 3:25 am

      My apologies, I just discovered quite a few comments in my spam queue. What you are describing is kind of beyond the scope of this tutorial. I know there are plugins for handling delivery dates, so I hope you found one of them.

  20. Marc on August 5, 2015 at 1:53 pm

    Thanks for this. Really helpful. I’m just wondering how I can now go about positioning the extra field(s)? Currently this just places a full length field at the bottom of the checkout page. I’d like it above a couple other fields in the first column. Cheers!

    • kathy on August 5, 2015 at 2:12 pm

      Hi Marc, I’m glad this was helpful to you. If you look closely you will see that the checkout fields are being added to the woocommerce_checkout_after_customer_details hook. If you want the fields to display somewhere else you need to pick a different hook. You can see the hooks available in the templates/checkout/form-checkout.php template.

  21. Michelangelo on August 8, 2015 at 10:27 am

    Hi Kathy,
    congratulations for your site.

    I have a question…what if I need to put some data (a link for example) in the order confirmation email? Only if it has been bought a specific product?

    I have some products which need image upload. I would put the upload link in the confirmation mail, only if there is the right product into the order…

    • kathy on January 4, 2016 at 3:27 am

      You would need to loop through the items in the order. If you have the order object you can retrieve all the items with the $order->get_items() method.

  22. Vanessa on August 12, 2015 at 6:09 pm


    It would be helpful for us to see the option they chose besides the “a,b,c” options – but instead say “a – website” or “b – friend”.

    Is there a way to have this translate out to the order details on the backend?

    • kathy on August 12, 2015 at 7:17 pm

      Hi Vanessa, thanks for stopping by. You aren’t obligated to echo out the post meta directly.

      instead of

      echo get_post_meta( $order_id, '_another_field', true );

      you could do

      $another_field = get_post_meta( $order_id, '_another_field', true );
      switch( $another_field ){
      case a:
         $print = __( 'Apple',' 'text-domain' );
      case b:
        $print = __( 'Bacon',' 'text-domain' );
      case c:
        $print = __( 'Cookie',' 'text-domain' );


      $another_field = get_post_meta( $order_id, &#039;_another_field&#039;, true );
      $options = WC()-&gt;checkout()-&gt;checkout_fields[&#039;extra_fields&#039;];
      if( isset( $options[$another_field] ) ){
         echo $options[$another_field];

      I didn't test any of that, so it is all just suggestion.

      good luck, -k

  23. Mykz on August 13, 2015 at 9:53 am

    Hi Kathy,
    Thanks for the tut.
    how can I apply ‘checked’ feature in check box created by this method?.

  24. Wim Wennekes on August 14, 2015 at 11:35 am

    Hi Kathy,

    Thanks for this brilliante article.

    I am looking for a solution in our situation but could not retrieve it from above.
    Ik hope you will help me with this.

    The situation is as folowing:
    I am trying to make a tenniscourt reservation site with woocommerce and a plugin called woocommerce bookings.
    When i receive a booking form a tennis player i need to confirm this booking with an extra selectfield:
    Court 1, court 2, court 3 and court 4.
    This field may only apear in the admin section.
    So the tennisplayer get an extra conformation email with the court on wich he may play, court 4 (as an example).

    Thanks in advance,


    • kathy on August 14, 2015 at 1:39 pm

      Hi Wim, I’m glad you liked the article. It sounds like you are in need of some custom development. Unfortunately, I’m not free right now, but if you still need the work done at the end of August I might be able to fit you in then. You can use the contact page to get in touch and discuss the project scope and costs.

  25. Rob Goss on August 15, 2015 at 1:51 am

    Hello Kathy, Nice write up but how would I setup this payment method? it seems kind of complicated. I use Paypal for my Gateway so would I be able to use it also with this method. Thanks so much

    • kathy on August 15, 2015 at 12:47 pm

      Hi Rob. This tutorial has nothing to do with payment gateways so PayPal is not effected.

      • Rob Goss on August 15, 2015 at 1:28 pm

        Hello Kathy, thank you so much for your fast reply. I’m trying to setup a payment method to collect payments and give my customers access to a page were they can download themes I build. Thanks for any help on this.

        • kathy on August 15, 2015 at 6:15 pm

          Sounds like you just need to set up a simple product and set it to be downloadable. If it is a bespoke client theme that’s all you need. If you want to sell it to the public and handle licensing you might want to look into WooTheme’s Software Add-on or Easy Digital Downloads Software Licensing.

          • Rob Goss on August 15, 2015 at 6:43 pm

            Hello Kathy, I’m developing WordPress themes and will be displaying them on my website for customers to buy.

  26. Marc on August 16, 2015 at 9:51 am

    I’ve set this up using user id and meta instead and it all works great. When a user returns to checkout though the field is blank. How do I pull in the previously stored data just as woocommerce does with name fields etc. Cheers!

    • kathy on August 16, 2015 at 1:58 pm

      Hi Marc, WooCommerce pulls its field data from user meta and/or session data.

      • Marc on August 16, 2015 at 2:33 pm

        Thanks Kathy. I’m not sure if this is the correct way but I got it working with:

        function set_default_passport_value($fields){
        $current_user = wp_get_current_user();
        return $fields;
        add_filter( 'woocommerce_checkout_fields', 'set_default_passport_value' );

        • Hiro on June 28, 2016 at 8:21 am

          Hi Marc, Can you please share your complete code, i’m trying to achieve something similar, thank you!

  27. Farhan on August 20, 2015 at 3:39 am

    Hi Kathy,

    Is there a way to add an expiry “from” and “to” date into the database once the customer checks out? The date of expiry would be from the date of purchase till the same date next year. How do I add it to the database once the customer has paid and checked out? Wondering if you could point me in the right direction with this.


    • kathy on August 20, 2015 at 2:34 pm

      Hi Farhan,

      You can add any meta you’d like to the order in the kia_save_extra_checkout_fields function. Though if you are going to be dealing with expiry dates (and presumably renewing) then you will want to consider WooCommerce Subscriptions.


      • Farhan on September 2, 2015 at 8:46 pm

        Thanks Kathy, you are awesome! :)

  28. Nana Yaw on August 27, 2015 at 3:25 pm

    Wow, Kathy you are soo good, i’m amazed on your extensive knowledge of woocommerce. I’m glad there is someone like you out here. I would like a little help here though. I want to change some fields on checkout page based on country selected. Could you pleasssssssse help me out on it. Thank You.

  29. Nana Yaw on September 1, 2015 at 1:45 pm

    Ok Kathy, thanks. You are great.

  30. J on September 2, 2015 at 7:31 pm

    Hey Kathy, amazing blog, thanks a lot for sharing. Hopefully you know the answer to my problem.
    I have added a custom field to my orders, specifically it is some tracking info that my site’s administrator will manually add to each order when marking them as “COMPLETED” and it will be displayed in the email my clients will receive.

    My problem is that this custom field is only stored after saving the order, so the field is not populated until the email has already been sent. The only way to effectively send all the info is to fill in this custom field, save the order, then marking it as completed and saving again! This is rather confusing and I want to know if there is a way to mark the order as completed and check for fields that have been filled in before sending the email and storing them, so all info is sent :) I appreciate any thoughts that can point me to the right direction!

    • kathy on September 3, 2015 at 1:28 pm

      J, glad the article helped you. Without looking too hard, I can see that order data meta is saved via this action. You can see the function here which includes an $order->update_status() call… which is what would trigger the completed email. Therefore, I assume that if you process your meta on woocommerce_process_shop_order_meta with an earlier priority (earlier than 40, so try default 10) that your meta will be already stored and available when the email is sent. Give me a shout via the contact page if you need a quick bit of premium support to get it all working.

  31. thanku on September 9, 2015 at 1:09 pm

    Hello Kathy, Its Soo Good And Really helpful. And is it Possible to Hide Some Checkout Form Fields When Its Free(0$).

    • kathy on September 9, 2015 at 1:32 pm

      Hi Thanku, I’m glad it was helpful. Yes, I’m sure that it is possible to hide fields when the cart total is $0, but it isn’t something I can get into right now. Good luck.

  32. thanku on September 9, 2015 at 1:34 pm

    Thank You

  33. fabio on September 12, 2015 at 10:25 am

    Thank you. This is a very fantastic tutorial!
    How can i add the extra field after the code:

    in order to have <div class="address-field"></div><div class="extra-field"></div>?

    Best regards

    • kathy on September 12, 2015 at 1:56 pm

      Hi Fabio. Take a look at the checkout-form.php template. You can see all the different hooks available. If you want to display your fields right after the address fields you should add your function to the woocommerce_checkout_after_customer_details hook. cheers, -k

      • fabio on September 14, 2015 at 9:28 am

        Thank you! last code for admin email works also on woocommerce 2.4.6?

        • fabio on September 14, 2015 at 12:27 pm

          I tested and code // pre-WooCommerce 2.3 works well also for 2.4.6 =)

          I have last question and i hope you can help me. How can i display this custom field under customer detail (Dettagli cliente) with telephone and email?
          Now it’s above “Dettagli clienti”.. Thank you!

          • kathy on September 14, 2015 at 2:30 pm

            Fabio, you should definitely use the post 2.3 code. The other code is deprecated and will eventually stop working. In fact, I am going to delete it from this tutorial as it is no longer relevant.

            As far as where the field displays, again I urge you to take a look at the checkout-form.php template. You can see all the different hooks available. If you want to display your fields right after the address fields you should add your function to the woocommerce_checkout_after_customer_details hook.

  34. Marcio on October 5, 2015 at 5:35 am

    I created a dropdown question (Do you have insurance?) to our checkout page. I am trying to do some conditional logic like, but not related to a product, just about this first question.


    add_action( ‘woocommerce_before_checkout_form’, ‘question_insurance’ );

    function question_insurance( $checkout ) {

    echo '<div id="question_insurance"><h2>' . __('Do you have Insurance?') . '</h2>';

    woocommerce_form_field ( 'question_insurance', array(

    'type' => 'select',
    'class' => array('question-insurance-class form-row-wide'),
    'label' => __('Do you have insurance?'),
    'placeholder' => __('none', 'woocommerce'),

    'options' => array(
    'option_a' => __('No', 'no' ),
    'option_b' => __( 'Yes','yes' ),
    'required' => true,

    ), $checkout->get_value( 'question_insurance' ));

    echo ”;

    add_action( ‘woocommerce_before_checkout_form’, ‘insurance_yes’ );

    function insurance_yes( $checkout ) {

    if (option_b) === true {
    echo ‘

    ‘ . __(‘its working’) . ”;
    # code…
    echo ‘


    Any thoughts, tips, recommendations or responses WILL BE APPRECIATED !

    Thank you!

    • kathy on January 4, 2016 at 3:33 am

      In all these comments there are about 3 requests for conditional checkout fields. I might consider writing a tutorial on that. In the mean time, maybe Checkout Field Editor would be helpful.

  35. Sureshraj on October 5, 2015 at 1:03 pm

    Just i want add personal details in my account page with save and edit option, Also i want to edit in dashboard. thanks..

    • kathy on October 5, 2015 at 5:08 pm

      Hi Sureshraj,

      I think that’s a different tutorial all together. Maybe some day I might take it on, but not in the immediate future.

      Good luck,

  36. Kev on October 18, 2015 at 12:49 am

    Hi Kathy,

    Your code works great in 2.4.6 but I cannot seem to get the information to show in the admin email. It shows fine in the admin panel but not in the emails. Any thoughts?

    • kathy on October 18, 2015 at 12:56 am

      Are you sure your theme isn’t using modified email templates? The woocommerce_email_customer_details hook and woocommerce_email_order_meta_fields filter are still in use, so the code ought to still work.

      • Kev on October 18, 2015 at 1:24 am

        Thanks for the response Kathy. The theme does not have modified email templates. Seems a bit odd. I’m not sure what is causing it.

  37. Ellery on October 20, 2015 at 4:07 pm


    If I edited and added some billing fields into checkout, how can I show this modifications into the admin profile panel

    Thank you so much for your time

    • kathy on October 20, 2015 at 4:57 pm

      Ellery, I covered that in my tutorial. Double-check the kia_display_order_data_in_admin() function.

  38. pater on October 30, 2015 at 10:16 am

    Hello Kathy,

    I have pdf books which has password protected. how i can set custom field send when order is completed. so only completed order email has password which i have set in custom field in Woocommerce product.

    Please help me asap.


    • kathy on January 4, 2016 at 3:40 am

      Sorry that this (and about 20 other comments) got lost in my spam queue. I presume you have this figured out by now, but the woocommerce_email_customer_details hook sends a fourth parameter, $email. In your callback you can then test the email’s id and only include the info on specific email. If I remember, I added that to WooCommerce myself! So for example, I think this would appear only on the completed email:

      function kia_display_email_order_meta( $order, $sent_to_admin, $plain_text, $email ) {
          if( $email->id == 'customer_completed_order' ){
              if( $plain_text ){
                  echo 'The password is bacon';
              } else {
                  echo '<p>The password is <strong>bacon</strong></p>';
      add_action('woocommerce_email_customer_details', 'kia_display_email_order_meta', 30, 4 );
  39. Jasper on November 2, 2015 at 11:22 am

    small error in your e-mail code. It says this:


    while I think it must be


    • kathy on November 2, 2015 at 1:52 pm

      You’re right. Thanks for the heads up. I have fixed it now.

      • Jasper on November 5, 2015 at 9:53 am

        great! Thanks for writing this btw, it helped me a lot when I needed an additional field in my billing fields on checkout. Stay Awesome :)

  40. Davi Assumpção on November 16, 2015 at 7:04 pm

    Awesome ! Thank you !

  41. Josh on December 28, 2015 at 7:19 am

    I’d like to display the info from the custom field on a separate (public) page, basically using this as a list of attendees. How would I go about doing this?

    • kathy on December 28, 2015 at 3:58 pm

      Hi Josh. I try to stay away from support questions in the comments. The data is all saved as post meta for the order. So anywhere you can get the order ID you can use get_post_meta() to retrieve the data.

  42. Elisabeth on January 6, 2016 at 2:52 pm

    Hi !

    It seems great and exactly what I need but I don’t know why it doesn’t work on mine.

    I’ve tried the paste the code to add a chechout field first on function.php.. bug.., and form-checking.php…bug too.
    So I’m lost. Maybe I’ve missed something ? Or haven’t understood where to paste the code ?

    • kathy on January 6, 2016 at 3:23 pm

      The code belongs in your active theme’s functions.php… or better still as its own plugin (or a site-specific snippets plugin). I just confirmed that this still displays the new checkout fields, even on WC2.5beta. I would check it against a default theme like Twenty Sixteen (all the more reason for this to be in a plugin so you can switch themes without losing functionality).

      • Elisabeth on January 8, 2016 at 11:02 am

        Perfect !

        I’ve used a dropdown. I would like to be sure the customer choose one option by himself, and not let it by default. Actually it must be empty by defaut to be sure customer choose one option.

        In your exemple :
        *’options’ => array( ‘a’ => __( ‘apple’ ), ‘b’ => __( ‘bacon’ ), ‘c’ => __( ‘chocolate’ ) )*
        Have I let *’a’* empty (*’a’ => __( ‘ ‘ )*) and maybe add an other code ?

        Also, code for adding field in order and customer email doesn’t work on mine.
        Maybe I forgot a <?php … ? php> or something else ?

        • kathy on January 8, 2016 at 1:41 pm

          Please try again with kia_display_email_order_meta(). I was missing some ;. You can always enable WP_DEBUG to locate such errors. and I highly advise enabling debug mode when in development.

          If you don’t want to force a select option then add an option to the beginning of the array with a 0 or default value and check for that when processing.

          • Elisabeth on January 8, 2016 at 2:39 pm

            Are you talking about this code, isn’t ?

            When I paste it in function.php my checkout page bug
            When I paste it directly in customer-precessing-order.php, the code appears in the order email.

            I don’t understand what’s wrong.

          • kathy on January 8, 2016 at 3:32 pm

            I’m sorry, I have no idea what you are referring to. Nothing in my tutorial is meant to be pasted into customer-precessing-order.php.

          • Elisabeth on January 8, 2016 at 3:53 pm

            Ok I actually don’t understand where to paste the code to add the field to order email..

          • kathy on January 8, 2016 at 4:06 pm

            Reiterating that all the code in this tutorial “belongs in your active theme’s functions.php or better still as its own plugin (or a site-specific snippets plugin).”

          • Elisabeth on January 8, 2016 at 5:19 pm

            Cool ! It’s OK ! Many Thanks !

  43. Maria Maso on February 20, 2016 at 12:13 am

    Your contact form doesn’t appear to be working. :(

    • kathy on March 5, 2016 at 2:52 pm

      Could you try again? It should be working now.

  44. Veedi on March 5, 2016 at 9:03 am

    Thank you for this tutorial.

    I’d like to collect an additional customer detail of the amount of money spent goes above a certain limit.

    Could you please help with how i could go about inserting this on the checkout form?

    • kathy on March 5, 2016 at 2:45 pm

      If you are calculating an amount spent over a certain limit, it seems like you could do that automatically on checkout without inserting any new fields. If you want to shoot me an email via my contact form we can discuss hiring me for a bit of paid support.

      • Veedi on March 5, 2016 at 11:53 pm

        Thank you for your reply.
        Just noticed the typo in the comment. I meant to type:

        I’d like to collect an additional customer detail if the amount of money spent goes above a certain limit.

        The site is for a non-profit organisation collecting donations. If the amount donated is above a certain amount, the checkout form needs to collect their income tax reference number for tax filing purposes.

        Just looking for some pointers on how this can be done.

        • kathy on March 6, 2016 at 12:17 am

          You can show the fields conditionally, by wrapping the fields in an if() statement. You should be able to get the cart’s total to use in your comparison. WC()->cart->get_total() should get you the total. Good luck.

          • Veedi on March 6, 2016 at 3:05 am

            Much appreciated Kathy! Shall work with your suggestion :)

  45. Simon on March 10, 2016 at 11:22 am

    Hey Kathy, great tutorial just what I needed!

    Quick question – if I wanted to display the new fields as part of the Billing Details – so lets say: First Name; Last Name; Company; NEW FIELD… is there any way of doing this?

    I’ve looked at all the hooks but all I am able to do is display either before or after customer details.

    Your help is appreciated :)

    • kathy on March 10, 2016 at 2:10 pm

      Thanks, I am glad it was helpful. To answer your question, I’m not sure, but I presume that you could filter them in via woocommerce_checkout_fields. (review my kia_filter_checkout_fields() function). Instead of creating a new extra_fields key in the $fields array, you would want to access the billing_fields key. You might need to do some array manipulation to get the new field in between existing fields, but it would be possible. Then WooCommerce should display it automatically and I don’t believe you’d need my kia_extra_checkout_fields() function. Just a guess. Good luck.

  46. Tali on March 24, 2016 at 7:30 am

    Just wanted to say well done. Your article is almost 2 years old and you’re still responding to every comment! Kudos on being a great teacher and a patient human being.

    • kathy on March 24, 2016 at 9:51 am

      Hi Tali, thank you for the lovely comment! It really made my morning. This article is 2 years old? My goodness, I’m probably due for a new blog post but I don’t know what to write about. Any ideas?

  47. Anders Ringnér on March 28, 2016 at 7:14 am

    Great tutorial and quite helpful!

  48. congnghia on March 28, 2016 at 1:20 pm

    Hi! i have a question.
    in my checkout page, i want to set: When a customer select a states in the States field, the City field will appear in the respective cities with that States. can you tell me how to do that?

    • kathy on March 29, 2016 at 9:06 am

      Hi, that question goes well beyond what this tutorial covers. You would need javascript to respond to the state selection and ajax to retrieve the cities. I’d suggest hiring a developer. Good luck.

  49. xonek on April 5, 2016 at 3:33 pm

    Hello Kathy! Thank you very very much for this tutorial. Worked like a charm :)

    I understand this is no support forum, but I would be very grateful if you could answer my question.
    Can you please tell me what the options should be if I also want the new info to be added to sent user e-mail ?

    Thanks in advance!

    Best Regards

    • kathy on April 5, 2016 at 7:53 pm

      Hi Xonek, I’m glad the tutorial was helpful. I’m not sure what you are asking. If you add some data to the woocommerce_email_customer_details hook then it will display in all emails. -k

      • xonek on April 6, 2016 at 9:38 am

        Hello, thanks for the quick response. What I would like to do is include the new added fields to the e-mail of the user which makes an order. So that he can see in his e-mail all the information he has filled.
        Where exactly do you suggest I add the hook?

        Thanks! :)

        • kathy on April 6, 2016 at 10:33 am

          This should already be happening with either the kia_email_order_meta_fields or kia_display_email_order_metafunctions from the tutorial.

          • xonek on April 12, 2016 at 10:58 am

            Yes, it is! Tahnk you very much!

            Amazing :)

  50. Danila on April 8, 2016 at 12:13 pm

    Thank you Kathy, very useful code.
    Anybody knows how to put values (default ones or meta) in these fields?

  51. noureddine on April 17, 2016 at 4:11 pm

    I want to know how add Custom Fields to date type .??
    thank you

    • kathy on April 17, 2016 at 8:21 pm

      Sorry, but I don’t understand your question.

      • Fabio on May 6, 2016 at 8:25 am

        Hi, congratulations for your article.
        I have added a custom field to my orders and I also see it in my admin order page.
        The problem is that I can’t edit the filed from the dashboard. Is it possibile to do it?
        Thanks a lot.

        • kathy on May 6, 2016 at 4:52 pm

          Yes it is possible. Please check the revised post. And if that helps you then please consider buying me a cocktail.

  52. Paul Simmons on May 20, 2016 at 11:11 am

    Good work,

    Could you please update the email code…facing an issue while displaying the custom fields data in invoice email & shipping PDFs on WooComm 2.4.7.

    Currently issue fixed with this plugin.. https://www.fmeaddons.com/woocommerce-plugins-extensions/additional-checkout-fields.html

    • kathy on June 2, 2016 at 3:25 am

      What is the issue you are facing? And I never promised that this would work with PDFs. I presume you have another plugin generating those?

  53. ed on June 2, 2016 at 2:33 am

    everything works great but my order page (admin) is returning the array i.e. b

    so it looks like this


    • kathy on June 2, 2016 at 3:24 am

      Sorry, I don’t see the problem in your screenshot. It looks like it says “Another field: B” which is exactly what it should say (assuming the field’s value was entered as B). Can you re-phrase what you are asking?

  54. ed on June 2, 2016 at 4:08 pm

    for example: I don’t want it to say B…I want it to say “bacon”

    • kathy on June 2, 2016 at 9:54 pm

      Well it is saving the value as b. You can either change the array so that it is no longer associative (so use array( 'apple', 'bacon', 'chocolate') ). If you are doing a multi-lingual site this isn’t the best idea b/c you’d save different values per language. But if you did it this way then you can save the value as bacon and the display will be automatic.

      Or what I’d probably do is keep saving the value as b and write a little helper function to convert b back into bacon wherever you need to display it. Example:

      function kia_get_another_option_string( $string = '' ){
          $options = array( 'a' => __( 'apple' ), 'b' => __( 'bacon' ), 'c' => __( 'chocolate' ) );
          if( $string && isset( $options[$string] ) ){
              return $options[$string]; // return the translatable string
          } else {
              return $options; // return the whole array (useful for defining the options)
  55. Ezequiel on June 8, 2016 at 4:44 pm

    Hello Many thanks for your help. I have my checkout page and I want to place the field in the billing address: “Vat Number” the problem is that the field goes automatically to the bottom and I need this field near “Company Name” for the billing address. So do you know how can I place this behind company name? This was the function I used:

    // Hook in
    add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
    // Our hooked in function - $fields is passed via the filter!
    function custom_override_checkout_fields( $fields ) {
    $fields['billing']['billing_VAT Number'] = array( 'label' => __('VAT / P.IVA', 'woocommerce'), 'placeholder' => _x('VAT / P.IVA', 'placeholder', 'woocommerce'), 'required' => false, 'class' => array ('form-row-wide'), 'clear' => true );
    return $fields;

    Plesae it will be nice if you can help me. Regards EZEQUIEL

    • kathy on June 28, 2016 at 10:18 pm

      I’m not really sure. My best guess would be that you will need to manipulate the $fields array, splitting it, inserting the new key, and then merging it back together. Good luck.

  56. WU on June 17, 2016 at 6:10 pm

    Hi, All works great but I need to show one of the extra_field in wp user admin page (not woocommerce). Coul’d you help me?

    • kathy on June 28, 2016 at 10:13 pm

      You want to add fields to the user profile admin page? That’s beyond the scope of this tutorial. Maybe try this

Leave a Reply Cancel Reply