Complete Guide: Adding Custom Fields to WooCommerce Checkout
In this comprehensive guide, I'll show you how to add custom fields to your WooCommerce checkout page and display them in the order details, admin area, and emails. This solution is fully reusable - you can easily add any type of field by simply modifying a configuration array.
functions.php
file or a custom plugin.
Why Add Custom Checkout Fields?
Custom checkout fields allow you to collect additional information from customers during checkout. Common uses include:
- Special delivery instructions
- Gift messages
- Business registration numbers
- Preferred delivery time slots
- Custom product personalization
Step 1: Add Custom Fields to Checkout Page
This code adds a text field and a select dropdown to your checkout page. You can easily add more fields by extending the $checkout_fields
array.
/**
* Add custom fields to WooCommerce checkout
*/
add_action('woocommerce_after_order_notes', 'add_custom_checkout_fields');
function add_custom_checkout_fields($checkout) {
echo '<div id="custom_checkout_fields"><h3>' . __('Additional Information', 'text-domain') . '</h3>';
// Define your fields here (modify as needed)
$checkout_fields = array(
'custom_text_field' => array(
'type' => 'text',
'label' => __('Custom Text Field', 'text-domain'),
'placeholder' => __('Enter your text here...', 'text-domain'),
'required' => false,
'class' => array('form-row-wide'),
),
'custom_select_field' => array(
'type' => 'select',
'label' => __('Custom Select Field', 'text-domain'),
'options' => array(
'' => __('Select an option...', 'text-domain'),
'option1' => __('Option 1', 'text-domain'),
'option2' => __('Option 2', 'text-domain'),
),
'required' => true,
'class' => array('form-row-wide'),
),
// Add more fields as needed
);
// Loop through and render fields
foreach ($checkout_fields as $field_key => $field_args) {
woocommerce_form_field($field_key, $field_args, $checkout->get_value($field_key));
}
echo '</div>';
}
Field Configuration Options
Parameter | Description | Example Values |
---|---|---|
type | The type of form field | text, textarea, select, checkbox, radio, etc. |
label | The field label displayed to customers | __('Gift Message', 'text-domain') |
placeholder | Placeholder text inside the field | __('Enter your message...', 'text-domain') |
required | Whether the field is mandatory | true or false |
class | CSS classes for styling | array('form-row-wide'), array('form-row-first') |
options | For select fields - key/value pairs | array('option1' => 'Value 1', 'option2' => 'Value 2') |
Step 2: Save Custom Checkout Fields
/**
* Save custom checkout fields to order meta
*/
add_action('woocommerce_checkout_create_order', 'save_custom_checkout_fields', 10, 2);
function save_custom_checkout_fields($order, $data) {
$checkout_fields = array(
'custom_text_field',
'custom_select_field',
// Add more field keys here
);
foreach ($checkout_fields as $field_key) {
if (!empty($_POST[$field_key])) {
$order->update_meta_data('_' . $field_key, sanitize_text_field($_POST[$field_key]));
}
}
}
Step 3: Display Fields in Frontend Order Details
/**
* Display custom fields in frontend order view
*/
add_action('woocommerce_order_details_after_order_table', 'display_custom_fields_frontend_order');
function display_custom_fields_frontend_order($order) {
$custom_fields = array(
'_custom_text_field' => __('Custom Text Field', 'text-domain'),
'_custom_select_field' => __('Custom Select Field', 'text-domain'),
// Add more fields here
);
echo '<h3>' . __('Additional Information', 'text-domain') . '</h3>';
echo '<table class="woocommerce-table shop_table additional_info">';
echo '<tbody>';
foreach ($custom_fields as $meta_key => $label) {
$value = $order->get_meta($meta_key);
if ($value) {
echo '<tr>';
echo '<th>' . esc_html($label) . ':</th>';
echo '<td>' . esc_html($value) . '</td>';
echo '</tr>';
}
}
echo '</tbody></table>';
}
Step 4: Display Fields in Admin Order View
/**
* Display custom fields in admin order view
*/
add_action('woocommerce_admin_order_data_after_billing_address', 'display_custom_fields_admin_order');
function display_custom_fields_admin_order($order) {
$custom_fields = array(
'_custom_text_field' => __('Custom Text Field', 'text-domain'),
'_custom_select_field' => __('Custom Select Field', 'text-domain'),
// Add more fields here
);
echo '<div class="order_data_column" style="width:100%;">';
echo '<h3>' . __('Additional Information', 'text-domain') . '</h3>';
foreach ($custom_fields as $meta_key => $label) {
$value = $order->get_meta($meta_key);
if ($value) {
echo '<p><strong>' . esc_html($label) . ':</strong> ' . esc_html($value) . '</p>';
}
}
echo '</div>';
}
Step 5: Display Fields in Order Emails
/**
* Display custom fields in order emails
*/
add_filter('woocommerce_email_order_meta_fields', 'display_custom_fields_in_emails', 10, 3);
function display_custom_fields_in_emails($fields, $sent_to_admin, $order) {
$custom_fields = array(
'_custom_text_field' => __('Custom Text Field', 'text-domain'),
'_custom_select_field' => __('Custom Select Field', 'text-domain'),
// Add more fields here
);
foreach ($custom_fields as $meta_key => $label) {
$value = $order->get_meta($meta_key);
if ($value) {
$fields[$meta_key] = array(
'label' => $label,
'value' => $value,
);
}
}
return $fields;
}
Advanced Customizations
Adding Different Field Types
Here are examples of different field types you can add:
Checkbox Field
'newsletter_optin' => array(
'type' => 'checkbox',
'label' => __('Subscribe to newsletter', 'text-domain'),
'required' => false,
'class' => array('form-row-wide'),
)
Textarea Field
'special_instructions' => array(
'type' => 'textarea',
'label' => __('Special Instructions', 'text-domain'),
'placeholder' => __('Any special delivery instructions...', 'text-domain'),
'required' => false,
'class' => array('form-row-wide'),
)
Conditional Fields
You can show/hide fields based on other selections using JavaScript:
// Add this to your theme's JS file
jQuery(document).ready(function($) {
$('#custom_select_field').change(function() {
if ($(this).val() === 'special_option') {
$('#custom_text_field').closest('.form-row').show();
} else {
$('#custom_text_field').closest('.form-row').hide();
}
}).trigger('change');
});
Practical Example: Advanced Select Field Implementation
Let's explore a more practical example of a select field that customers might actually use during checkout - a "Delivery Time Preference" selector.
This example shows how to create a time slot selection dropdown with grouped options.
/**
* Add delivery time preference field to checkout
*/
add_action('woocommerce_after_order_notes', 'add_delivery_time_field');
function add_delivery_time_field($checkout) {
echo '<div id="delivery_time_selection"><h3>' . __('Delivery Preferences', 'text-domain') . '</h3>';
woocommerce_form_field('delivery_time_preference', array(
'type' => 'select',
'label' => __('Preferred Delivery Time', 'text-domain'),
'required' => true,
'class' => array('form-row-wide'),
'options' => array(
'' => __('Select your preferred time...', 'text-domain'),
'morning' => __('Morning (8am-12pm)', 'text-domain'),
'afternoon' => __('Afternoon (12pm-5pm)', 'text-domain'),
'evening' => __('Evening (5pm-9pm)', 'text-domain'),
'specific' => __('Specific Time (We\'ll call to confirm)', 'text-domain'),
),
), $checkout->get_value('delivery_time_preference'));
echo '</div>';
// Add conditional field for specific time
woocommerce_form_field('delivery_phone_number', array(
'type' => 'tel',
'label' => __('Contact Number for Specific Time', 'text-domain'),
'placeholder' => __('+1 (123) 456-7890', 'text-domain'),
'required' => false,
'class' => array('form-row-wide', 'conditional-field'),
), $checkout->get_value('delivery_phone_number'));
}
/**
* Show/hide conditional field with JavaScript
*/
add_action('wp_footer', 'delivery_time_conditional_logic');
function delivery_time_conditional_logic() {
if (!is_checkout()) return;
?>
<script>
jQuery(document).ready(function($) {
// Hide initially
$('.conditional-field').closest('.form-row').hide();
// Show when specific time is selected
$('#delivery_time_preference').change(function() {
if ($(this).val() === 'specific') {
$('.conditional-field').closest('.form-row').slideDown();
} else {
$('.conditional-field').closest('.form-row').slideUp();
}
}).trigger('change');
});
</script>
<?php
}
/**
* Validate the conditional field when needed
*/
add_action('woocommerce_checkout_process', 'validate_delivery_fields');
function validate_delivery_fields() {
if ($_POST['delivery_time_preference'] === 'specific' && empty($_POST['delivery_phone_number'])) {
wc_add_notice(__('Please provide a contact number for specific time delivery', 'text-domain'), 'error');
}
}
Key Features of This Implementation
Feature | Description | Implementation |
---|---|---|
Grouped Time Options | Logical grouping of delivery windows | Morning/Afternoon/Evening options |
Special Case Option | "Specific Time" with different handling | Triggers additional field |
Conditional Logic | Show phone field only when needed | JavaScript toggle |
Validation | Require phone when specific time selected | woocommerce_checkout_process hook |
Frontend Display Enhancement
To make the selected option more visible in order details, modify the display function:
// In your display_custom_fields_frontend_order function
if ($meta_key === '_delivery_time_preference') {
$time_options = array(
'morning' => __('Morning (8am-12pm)', 'text-domain'),
'afternoon' => __('Afternoon (12pm-5pm)', 'text-domain'),
'evening' => __('Evening (5pm-9pm)', 'text-domain'),
'specific' => __('Specific Time', 'text-domain'),
);
$value = isset($time_options[$value]) ? $time_options[$value] : $value;
if ($value === __('Specific Time', 'text-domain')) {
$phone = $order->get_meta('_delivery_phone_number');
if ($phone) {
$value .= ' (' . esc_html($phone) . ')';
}
}
}
woocommerce_email_after_order_table
hook to ensure store staff see it immediately.
Troubleshooting
If your fields aren't appearing:
- Clear WooCommerce transients (WooCommerce → Status → Tools)
- Check for JavaScript errors in browser console
- Verify field keys match between all functions
- Test with a default theme to rule out theme conflicts
Conclusion
This complete solution gives you full control over custom checkout fields in WooCommerce. The modular approach makes it easy to add, remove, or modify fields by simply updating the configuration arrays. The fields will appear consistently throughout the order process - from checkout to order confirmation to admin management.
Remember to:
- Replace 'text-domain' with your actual text domain
- Test thoroughly after making changes
- Consider field validation for complex requirements
- Backup your site before making significant changes
0 Comments