Add Custom Field to WooCommerce Checkout Page

Intermediate
✓ Tested
📅 August 23, 2025
⬇️ 0 Downloads
📋 0 Copies

This comprehensive snippet allows you to easily add custom fields to your WooCommerce checkout page without any plugins. You can add text fields, dropdowns, checkboxes, textareas, and date pickers to collect additional information from customers during checkout.

What does this code do?

The snippet provides a simple configuration array where you can define custom fields that will automatically appear in your checkout form. These fields are validated, saved with the order, displayed in admin, and included in customer emails.

Included Example Fields:

  • VAT/Tax ID Number: Text field for business customers
  • Delivery Instructions: Textarea for special delivery notes
  • Referral Source: Dropdown to track marketing effectiveness
  • Gift Options: Checkbox with conditional gift message field
  • Company Registration: Additional business information
  • Preferred Delivery Date: Date picker for scheduled delivery

Field Types Supported:

  • text: Single line text input
  • textarea: Multi-line text input
  • select: Dropdown selection
  • checkbox: Yes/no option
  • date: Date picker
  • email: Email input with validation
  • tel: Phone number input
  • number: Numeric input

Features:

  • Add fields to billing, shipping, or order sections
  • Make fields required or optional
  • Set custom validation rules
  • Conditional fields (show/hide based on other fields)
  • Display in order admin, emails, and customer account
  • Full translation support
  • Clean, organized code structure

Where fields appear:

  • Checkout page (billing/shipping/order sections)
  • Order admin page in WordPress
  • Order confirmation emails
  • Customer’s My Account → Order details
  • Admin order emails

⚠️ Important Warnings

⚠️ Always backup before modifying checkout fields
⚠️ Required fields will block checkout if not filled - test thoroughly
⚠️ Some payment gateways might not work well with too many custom fields
⚠️ Field keys must be unique - don't use WooCommerce reserved names
⚠️ Validation rules should match your business requirements
⚠️ Date fields require modern browsers (fallback to text in old browsers)
⚠️ Too many fields can hurt conversion rates - add only essential fields
⚠️ Some themes might need CSS adjustments for proper display
⚠️ Test with guest checkout and logged-in users
⚠️ Custom fields won't appear in WooCommerce analytics by default
💻 PHP Code
/**
 * Add custom fields to WooCommerce checkout page
 * Easily add text, select, checkbox, or textarea fields to checkout
 * Prefix: tpsc_ (TP Snippet Collection)
 */

// ============================================
// CONFIGURATION - Customize your fields here
// ============================================

// Define your custom fields
function tpsc_get_custom_checkout_fields() {
    return array(
        // Example Field 1: VAT/Tax ID Number
        'vat_number' => array(
            'type'        => 'text',
            'label'       => __('VAT/Tax ID Number', 'woocommerce'),
            'placeholder' => __('Enter your VAT number', 'woocommerce'),
            'required'    => false,
            'class'       => array('form-row-wide'),
            'priority'    => 25,
            'section'     => 'billing', // billing, shipping, or order
        ),
        
        // Example Field 2: Delivery Instructions
        'delivery_instructions' => array(
            'type'        => 'textarea',
            'label'       => __('Delivery Instructions', 'woocommerce'),
            'placeholder' => __('Special delivery instructions...', 'woocommerce'),
            'required'    => false,
            'class'       => array('form-row-wide'),
            'priority'    => 100,
            'section'     => 'order',
        ),
        
        // Example Field 3: How did you hear about us?
        'referral_source' => array(
            'type'        => 'select',
            'label'       => __('How did you hear about us?', 'woocommerce'),
            'required'    => false,
            'class'       => array('form-row-wide'),
            'priority'    => 110,
            'section'     => 'order',
            'options'     => array(
                ''          => __('Please select...', 'woocommerce'),
                'google'    => __('Google Search', 'woocommerce'),
                'facebook'  => __('Facebook', 'woocommerce'),
                'instagram' => __('Instagram', 'woocommerce'),
                'friend'    => __('Friend/Family', 'woocommerce'),
                'other'     => __('Other', 'woocommerce'),
            ),
        ),
        
        // Example Field 4: Gift Message
        'is_gift' => array(
            'type'        => 'checkbox',
            'label'       => __('This is a gift', 'woocommerce'),
            'required'    => false,
            'class'       => array('form-row-wide'),
            'priority'    => 120,
            'section'     => 'order',
        ),
        
        'gift_message' => array(
            'type'        => 'textarea',
            'label'       => __('Gift Message', 'woocommerce'),
            'placeholder' => __('Enter your gift message here...', 'woocommerce'),
            'required'    => false,
            'class'       => array('form-row-wide'),
            'priority'    => 121,
            'section'     => 'order',
            'conditional' => 'is_gift', // Show only if is_gift is checked
        ),
        
        // Example Field 5: Company Registration Number
        'company_reg_number' => array(
            'type'        => 'text',
            'label'       => __('Company Registration Number', 'woocommerce'),
            'placeholder' => __('Enter registration number', 'woocommerce'),
            'required'    => false,
            'class'       => array('form-row-wide'),
            'priority'    => 26,
            'section'     => 'billing',
        ),
        
        // Example Field 6: Preferred Delivery Date
        'preferred_delivery_date' => array(
            'type'        => 'date',
            'label'       => __('Preferred Delivery Date', 'woocommerce'),
            'required'    => false,
            'class'       => array('form-row-wide'),
            'priority'    => 130,
            'section'     => 'order',
            'custom_attributes' => array(
                'min' => date('Y-m-d', strtotime('+1 day')),
                'max' => date('Y-m-d', strtotime('+30 days')),
            ),
        ),
    );
}

// ============================================
// ADD FIELDS TO CHECKOUT
// ============================================

// Add fields to billing section
add_filter('woocommerce_billing_fields', 'tpsc_add_billing_fields');
function tpsc_add_billing_fields($fields) {
    $custom_fields = tpsc_get_custom_checkout_fields();
    
    foreach ($custom_fields as $key => $field) {
        if ($field['section'] === 'billing') {
            $fields['billing_' . $key] = $field;
        }
    }
    
    return $fields;
}

// Add fields to shipping section
add_filter('woocommerce_shipping_fields', 'tpsc_add_shipping_fields');
function tpsc_add_shipping_fields($fields) {
    $custom_fields = tpsc_get_custom_checkout_fields();
    
    foreach ($custom_fields as $key => $field) {
        if ($field['section'] === 'shipping') {
            $fields['shipping_' . $key] = $field;
        }
    }
    
    return $fields;
}

// Add fields to order notes section
add_filter('woocommerce_checkout_fields', 'tpsc_add_order_fields');
function tpsc_add_order_fields($fields) {
    $custom_fields = tpsc_get_custom_checkout_fields();
    
    foreach ($custom_fields as $key => $field) {
        if ($field['section'] === 'order') {
            $fields['order'][$key] = $field;
        }
    }
    
    return $fields;
}

// ============================================
// VALIDATE FIELDS
// ============================================

add_action('woocommerce_checkout_process', 'tpsc_validate_custom_fields');
function tpsc_validate_custom_fields() {
    $custom_fields = tpsc_get_custom_checkout_fields();
    
    foreach ($custom_fields as $key => $field) {
        $field_key = $field['section'] . '_' . $key;
        if ($field['section'] === 'order') {
            $field_key = $key;
        }
        
        // Check if field is required and empty
        if (isset($field['required']) && $field['required'] && empty($_POST[$field_key])) {
            wc_add_notice(
                sprintf(__('%s is a required field.', 'woocommerce'), $field['label']),
                'error'
            );
        }
        
        // Additional validation for specific field types
        if (!empty($_POST[$field_key])) {
            // VAT number validation example
            if ($key === 'vat_number') {
                if (!preg_match('/^[A-Z]{2}[0-9]+$/', $_POST[$field_key])) {
                    wc_add_notice(__('Please enter a valid VAT number.', 'woocommerce'), 'error');
                }
            }
            
            // Email validation for email type fields
            if ($field['type'] === 'email' && !is_email($_POST[$field_key])) {
                wc_add_notice(
                    sprintf(__('%s is not a valid email address.', 'woocommerce'), $field['label']),
                    'error'
                );
            }
        }
    }
}

// ============================================
// SAVE FIELD VALUES
// ============================================

add_action('woocommerce_checkout_create_order', 'tpsc_save_custom_fields', 10, 2);
function tpsc_save_custom_fields($order, $data) {
    $custom_fields = tpsc_get_custom_checkout_fields();
    
    foreach ($custom_fields as $key => $field) {
        $field_key = $field['section'] . '_' . $key;
        if ($field['section'] === 'order') {
            $field_key = $key;
        }
        
        if (!empty($_POST[$field_key])) {
            $order->update_meta_data('_' . $field_key, sanitize_text_field($_POST[$field_key]));
        }
    }
}

// ============================================
// DISPLAY IN ORDER ADMIN
// ============================================

add_action('woocommerce_admin_order_data_after_billing_address', 'tpsc_display_admin_order_meta', 10, 1);
function tpsc_display_admin_order_meta($order) {
    $custom_fields = tpsc_get_custom_checkout_fields();
    
    echo '<div class="tpsc-custom-fields-admin">';
    echo '<h3>' . __('Additional Information', 'woocommerce') . '</h3>';
    
    foreach ($custom_fields as $key => $field) {
        $field_key = $field['section'] . '_' . $key;
        if ($field['section'] === 'order') {
            $field_key = $key;
        }
        
        $value = $order->get_meta('_' . $field_key);
        
        if ($value) {
            echo '<p><strong>' . $field['label'] . ':</strong> ';
            
            // Format display based on field type
            if ($field['type'] === 'checkbox') {
                echo $value ? __('Yes', 'woocommerce') : __('No', 'woocommerce');
            } elseif ($field['type'] === 'select' && isset($field['options'][$value])) {
                echo $field['options'][$value];
            } else {
                echo $value;
            }
            
            echo '</p>';
        }
    }
    
    echo '</div>';
}

// ============================================
// DISPLAY IN CUSTOMER EMAILS
// ============================================

add_filter('woocommerce_email_order_meta_fields', 'tpsc_email_order_meta_fields', 10, 3);
function tpsc_email_order_meta_fields($fields, $sent_to_admin, $order) {
    $custom_fields = tpsc_get_custom_checkout_fields();
    
    foreach ($custom_fields as $key => $field) {
        $field_key = $field['section'] . '_' . $key;
        if ($field['section'] === 'order') {
            $field_key = $key;
        }
        
        $value = $order->get_meta('_' . $field_key);
        
        if ($value) {
            $display_value = $value;
            
            // Format display based on field type
            if ($field['type'] === 'checkbox') {
                $display_value = $value ? __('Yes', 'woocommerce') : __('No', 'woocommerce');
            } elseif ($field['type'] === 'select' && isset($field['options'][$value])) {
                $display_value = $field['options'][$value];
            }
            
            $fields[] = array(
                'label' => $field['label'],
                'value' => $display_value,
            );
        }
    }
    
    return $fields;
}

// ============================================
// DISPLAY IN ORDER DETAILS (MY ACCOUNT)
// ============================================

add_action('woocommerce_order_details_after_order_table', 'tpsc_display_order_meta_in_account');
function tpsc_display_order_meta_in_account($order) {
    $custom_fields = tpsc_get_custom_checkout_fields();
    $has_custom_fields = false;
    
    // Check if there are any custom fields with values
    foreach ($custom_fields as $key => $field) {
        $field_key = $field['section'] . '_' . $key;
        if ($field['section'] === 'order') {
            $field_key = $key;
        }
        
        if ($order->get_meta('_' . $field_key)) {
            $has_custom_fields = true;
            break;
        }
    }
    
    if (!$has_custom_fields) {
        return;
    }
    
    echo '<h2>' . __('Additional Information', 'woocommerce') . '</h2>';
    echo '<table class="woocommerce-table woocommerce-table--custom-fields shop_table">';
    echo '<tbody>';
    
    foreach ($custom_fields as $key => $field) {
        $field_key = $field['section'] . '_' . $key;
        if ($field['section'] === 'order') {
            $field_key = $key;
        }
        
        $value = $order->get_meta('_' . $field_key);
        
        if ($value) {
            echo '<tr>';
            echo '<th>' . $field['label'] . '</th>';
            echo '<td>';
            
            if ($field['type'] === 'checkbox') {
                echo $value ? __('Yes', 'woocommerce') : __('No', 'woocommerce');
            } elseif ($field['type'] === 'select' && isset($field['options'][$value])) {
                echo $field['options'][$value];
            } else {
                echo nl2br($value);
            }
            
            echo '</td>';
            echo '</tr>';
        }
    }
    
    echo '</tbody>';
    echo '</table>';
}

// ============================================
// CONDITIONAL FIELD DISPLAY (JavaScript)
// ============================================

add_action('wp_footer', 'tpsc_checkout_conditional_fields_script');
function tpsc_checkout_conditional_fields_script() {
    if (!is_checkout()) {
        return;
    }
    ?>
    <script type="text/javascript">
    jQuery(document).ready(function($) {
        // Handle conditional fields
        $('#is_gift').change(function() {
            if ($(this).is(':checked')) {
                $('#gift_message_field').slideDown();
            } else {
                $('#gift_message_field').slideUp();
                $('#gift_message').val('');
            }
        }).change();
    });
    </script>
    <?php
}

// ============================================
// ADD CSS FOR BETTER STYLING
// ============================================

add_action('wp_head', 'tpsc_custom_checkout_styles');
function tpsc_custom_checkout_styles() {
    if (!is_checkout()) {
        return;
    }
    ?>
    <style>
        .tpsc-custom-fields-admin {
            margin-top: 20px;
            padding: 15px;
            background: #f8f9fa;
            border-left: 4px solid #007cba;
        }
        
        .tpsc-custom-fields-admin h3 {
            margin-top: 0;
            color: #007cba;
        }
        
        /* Optional: Add icons to custom fields */
        #vat_number_field label:before {
            content: "🏢 ";
        }
        
        #delivery_instructions_field label:before {
            content: "📝 ";
        }
        
        #referral_source_field label:before {
            content: "📣 ";
        }
        
        #is_gift_field label:before {
            content: "🎁 ";
        }
        
        #preferred_delivery_date_field label:before {
            content: "📅 ";
        }
    </style>
    <?php
}

📝 Installation Instructions

QUICK START:
1. Copy the entire code
2. The example fields are already configured at the top
3. Paste in functions.php
4. Go to checkout page - new fields will appear immediately!

TO ADD A NEW FIELD:
1. Find the tpsc_get_custom_checkout_fields() function
2. Add a new array item following this template:

'your_field_key' => array(
'type' => 'text', // Field type
'label' => 'Your Field Label', // Display label
'placeholder' => 'Enter value...', // Placeholder text
'required' => false, // true or false
'class' => array('form-row-wide'), // CSS classes
'priority' => 25, // Display order
'section' => 'billing', // billing, shipping, or order
),

FIELD SECTIONS:
- 'billing': Appears in billing details section
- 'shipping': Appears in shipping details section
- 'order': Appears after order notes section

CSS CLASSES OPTIONS:
- 'form-row-wide': Full width field
- 'form-row-first': Half width, left side
- 'form-row-last': Half width, right side

TO CREATE A DROPDOWN FIELD:
'your_dropdown' => array(
'type' => 'select',
'label' => 'Choose Option',
'options' => array(
'' => 'Please select...',
'value1' => 'Option 1',
'value2' => 'Option 2',
),
'section' => 'order',
),

TO MAKE A FIELD REQUIRED:
Change 'required' => false to 'required' => true

TO ADD VALIDATION:
Find the tpsc_validate_custom_fields() function (line 156)
Add your validation logic following the VAT example

TO REMOVE A FIELD:
Simply comment out or delete the field array from tpsc_get_custom_checkout_fields()

PRIORITY VALUES (FIELD ORDER):
- Billing: 10-30 (after standard fields)
- Shipping: 10-30 (after standard fields)
- Order: 100+ (after order notes)

CONDITIONAL FIELDS:
See the gift message example (lines 52-62)
The gift message only shows when "This is a gift" is checked

TESTING:
1. Add items to cart
2. Go to checkout
3. Fill in the new fields
4. Place order
5. Check order in admin to see saved values

📸 Screenshots