PHPwoocommerceintermediate

WooCommerce Custom Checkout Fields

Add custom fields to WooCommerce checkout with validation and order display

Faisal Yaqoob
#woocommerce#checkout#custom-fields#validation#orders
Share this snippet:

Code

php
1// Add custom fields to checkout page
2add_action('woocommerce_after_order_notes', 'custom_checkout_fields');
3function custom_checkout_fields($checkout) {
4 echo '<div id="custom_checkout_fields"><h3>' . __('Additional Information') . '</h3>';
5
6 // Text field
7 woocommerce_form_field('delivery_instructions', array(
8 'type' => 'textarea',
9 'class' => array('form-row-wide', 'delivery-instructions'),
10 'label' => __('Delivery Instructions'),
11 'placeholder' => __('Any special delivery notes?'),
12 'required' => false,
13 ), $checkout->get_value('delivery_instructions'));
14
15 // Select field
16 woocommerce_form_field('gift_wrapping', array(
17 'type' => 'select',
18 'class' => array('form-row-wide'),
19 'label' => __('Gift Wrapping'),
20 'options' => array(
21 '' => __('No gift wrapping', 'woocommerce'),
22 'standard' => __('Standard - $5', 'woocommerce'),
23 'premium' => __('Premium - $10', 'woocommerce'),
24 'deluxe' => __('Deluxe - $15', 'woocommerce'),
25 )
26 ), $checkout->get_value('gift_wrapping'));
27
28 // Checkbox field
29 woocommerce_form_field('newsletter_signup', array(
30 'type' => 'checkbox',
31 'class' => array('form-row-wide'),
32 'label' => __('Sign up for our newsletter'),
33 ), $checkout->get_value('newsletter_signup'));
34
35 // Phone field with validation
36 woocommerce_form_field('alternative_phone', array(
37 'type' => 'tel',
38 'class' => array('form-row-wide'),
39 'label' => __('Alternative Phone Number'),
40 'placeholder' => __('+1 (555) 123-4567'),
41 'required' => false,
42 ), $checkout->get_value('alternative_phone'));
43
44 // Date field
45 woocommerce_form_field('preferred_delivery_date', array(
46 'type' => 'date',
47 'class' => array('form-row-wide'),
48 'label' => __('Preferred Delivery Date'),
49 'required' => false,
50 'custom_attributes' => array(
51 'min' => date('Y-m-d', strtotime('+1 day'))
52 )
53 ), $checkout->get_value('preferred_delivery_date'));
54
55 echo '</div>';
56}

WooCommerce Custom Checkout Fields

Add custom fields to your WooCommerce checkout page with validation, saving, and display in orders and emails.

// Add custom fields to checkout page
add_action('woocommerce_after_order_notes', 'custom_checkout_fields');
function custom_checkout_fields($checkout) {
    echo '<div id="custom_checkout_fields"><h3>' . __('Additional Information') . '</h3>';

    // Text field
    woocommerce_form_field('delivery_instructions', array(
        'type'        => 'textarea',
        'class'       => array('form-row-wide', 'delivery-instructions'),
        'label'       => __('Delivery Instructions'),
        'placeholder' => __('Any special delivery notes?'),
        'required'    => false,
    ), $checkout->get_value('delivery_instructions'));

    // Select field
    woocommerce_form_field('gift_wrapping', array(
        'type'    => 'select',
        'class'   => array('form-row-wide'),
        'label'   => __('Gift Wrapping'),
        'options' => array(
            ''         => __('No gift wrapping', 'woocommerce'),
            'standard' => __('Standard - $5', 'woocommerce'),
            'premium'  => __('Premium - $10', 'woocommerce'),
            'deluxe'   => __('Deluxe - $15', 'woocommerce'),
        )
    ), $checkout->get_value('gift_wrapping'));

    // Checkbox field
    woocommerce_form_field('newsletter_signup', array(
        'type'  => 'checkbox',
        'class' => array('form-row-wide'),
        'label' => __('Sign up for our newsletter'),
    ), $checkout->get_value('newsletter_signup'));

    // Phone field with validation
    woocommerce_form_field('alternative_phone', array(
        'type'        => 'tel',
        'class'       => array('form-row-wide'),
        'label'       => __('Alternative Phone Number'),
        'placeholder' => __('+1 (555) 123-4567'),
        'required'    => false,
    ), $checkout->get_value('alternative_phone'));

    // Date field
    woocommerce_form_field('preferred_delivery_date', array(
        'type'        => 'date',
        'class'       => array('form-row-wide'),
        'label'       => __('Preferred Delivery Date'),
        'required'    => false,
        'custom_attributes' => array(
            'min' => date('Y-m-d', strtotime('+1 day'))
        )
    ), $checkout->get_value('preferred_delivery_date'));

    echo '</div>';
}

Validate Custom Fields

// Validate custom checkout fields
add_action('woocommerce_checkout_process', 'validate_custom_checkout_fields');
function validate_custom_checkout_fields() {
    // Validate alternative phone if provided
    if (isset($_POST['alternative_phone']) && !empty($_POST['alternative_phone'])) {
        $phone = sanitize_text_field($_POST['alternative_phone']);

        // Basic phone validation
        if (!preg_match('/^[\d\s\-\+\(\)]+$/', $phone)) {
            wc_add_notice(__('Please enter a valid alternative phone number.'), 'error');
        }
    }

    // Validate delivery date if provided
    if (isset($_POST['preferred_delivery_date']) && !empty($_POST['preferred_delivery_date'])) {
        $delivery_date = sanitize_text_field($_POST['preferred_delivery_date']);
        $min_date = strtotime('+1 day');

        if (strtotime($delivery_date) < $min_date) {
            wc_add_notice(__('Preferred delivery date must be at least 1 day from now.'), 'error');
        }
    }

    // Make delivery instructions required for specific shipping methods
    if (isset($_POST['shipping_method']) && in_array('local_pickup', $_POST['shipping_method'])) {
        if (empty($_POST['delivery_instructions'])) {
            wc_add_notice(__('Please provide pickup instructions.'), 'error');
        }
    }
}

Save Custom Fields to Order

// Save custom fields to order meta
add_action('woocommerce_checkout_update_order_meta', 'save_custom_checkout_fields');
function save_custom_checkout_fields($order_id) {
    // Save delivery instructions
    if (!empty($_POST['delivery_instructions'])) {
        update_post_meta($order_id, 'delivery_instructions',
            sanitize_textarea_field($_POST['delivery_instructions']));
    }

    // Save gift wrapping
    if (!empty($_POST['gift_wrapping'])) {
        update_post_meta($order_id, 'gift_wrapping',
            sanitize_text_field($_POST['gift_wrapping']));

        // Add fee for gift wrapping
        $order = wc_get_order($order_id);
        $wrapping_costs = array(
            'standard' => 5,
            'premium'  => 10,
            'deluxe'   => 15,
        );

        $wrapping_type = sanitize_text_field($_POST['gift_wrapping']);
        if (isset($wrapping_costs[$wrapping_type])) {
            $order->add_fee(__('Gift Wrapping'), $wrapping_costs[$wrapping_type]);
            $order->calculate_totals();
            $order->save();
        }
    }

    // Save newsletter signup
    if (isset($_POST['newsletter_signup'])) {
        update_post_meta($order_id, 'newsletter_signup', 1);

        // Add customer to newsletter list (example)
        $order = wc_get_order($order_id);
        $email = $order->get_billing_email();
        // add_to_newsletter($email); // Your newsletter function
    }

    // Save alternative phone
    if (!empty($_POST['alternative_phone'])) {
        update_post_meta($order_id, 'alternative_phone',
            sanitize_text_field($_POST['alternative_phone']));
    }

    // Save preferred delivery date
    if (!empty($_POST['preferred_delivery_date'])) {
        update_post_meta($order_id, 'preferred_delivery_date',
            sanitize_text_field($_POST['preferred_delivery_date']));
    }
}

Display in Admin Order Page

// Display custom fields in admin order details
add_action('woocommerce_admin_order_data_after_billing_address', 'display_custom_fields_in_admin');
function display_custom_fields_in_admin($order) {
    $order_id = $order->get_id();

    echo '<div class="custom-checkout-fields"><h3>' . __('Additional Order Information') . '</h3>';

    // Delivery instructions
    $delivery_instructions = get_post_meta($order_id, 'delivery_instructions', true);
    if ($delivery_instructions) {
        echo '<p><strong>' . __('Delivery Instructions:') . '</strong><br>' .
             esc_html($delivery_instructions) . '</p>';
    }

    // Gift wrapping
    $gift_wrapping = get_post_meta($order_id, 'gift_wrapping', true);
    if ($gift_wrapping) {
        echo '<p><strong>' . __('Gift Wrapping:') . '</strong> ' .
             esc_html(ucfirst($gift_wrapping)) . '</p>';
    }

    // Alternative phone
    $alt_phone = get_post_meta($order_id, 'alternative_phone', true);
    if ($alt_phone) {
        echo '<p><strong>' . __('Alternative Phone:') . '</strong> ' .
             esc_html($alt_phone) . '</p>';
    }

    // Preferred delivery date
    $delivery_date = get_post_meta($order_id, 'preferred_delivery_date', true);
    if ($delivery_date) {
        echo '<p><strong>' . __('Preferred Delivery Date:') . '</strong> ' .
             esc_html(date('F j, Y', strtotime($delivery_date))) . '</p>';
    }

    // Newsletter signup
    $newsletter = get_post_meta($order_id, 'newsletter_signup', true);
    if ($newsletter) {
        echo '<p><strong>' . __('Newsletter Signup:') . '</strong> Yes ✓</p>';
    }

    echo '</div>';
}

Display in Order Emails

// Add custom fields to order emails
add_filter('woocommerce_email_order_meta_fields', 'custom_fields_in_emails', 10, 3);
function custom_fields_in_emails($fields, $sent_to_admin, $order) {
    $order_id = $order->get_id();

    $delivery_instructions = get_post_meta($order_id, 'delivery_instructions', true);
    if ($delivery_instructions) {
        $fields['delivery_instructions'] = array(
            'label' => __('Delivery Instructions'),
            'value' => $delivery_instructions,
        );
    }

    $gift_wrapping = get_post_meta($order_id, 'gift_wrapping', true);
    if ($gift_wrapping) {
        $fields['gift_wrapping'] = array(
            'label' => __('Gift Wrapping'),
            'value' => ucfirst($gift_wrapping),
        );
    }

    $delivery_date = get_post_meta($order_id, 'preferred_delivery_date', true);
    if ($delivery_date) {
        $fields['preferred_delivery_date'] = array(
            'label' => __('Preferred Delivery Date'),
            'value' => date('F j, Y', strtotime($delivery_date)),
        );
    }

    return $fields;
}

Update Order Details on My Account Page

// Display custom fields on order details page (customer account)
add_action('woocommerce_order_details_after_order_table', 'display_custom_fields_on_order_details');
function display_custom_fields_on_order_details($order) {
    $order_id = $order->get_id();

    $delivery_instructions = get_post_meta($order_id, 'delivery_instructions', true);
    $gift_wrapping = get_post_meta($order_id, 'gift_wrapping', true);
    $delivery_date = get_post_meta($order_id, 'preferred_delivery_date', true);

    if ($delivery_instructions || $gift_wrapping || $delivery_date) {
        echo '<section class="woocommerce-order-custom-fields">';
        echo '<h2>' . __('Additional Information') . '</h2>';
        echo '<table class="woocommerce-table">';

        if ($delivery_instructions) {
            echo '<tr><th>' . __('Delivery Instructions:') . '</th>';
            echo '<td>' . esc_html($delivery_instructions) . '</td></tr>';
        }

        if ($gift_wrapping) {
            echo '<tr><th>' . __('Gift Wrapping:') . '</th>';
            echo '<td>' . esc_html(ucfirst($gift_wrapping)) . '</td></tr>';
        }

        if ($delivery_date) {
            echo '<tr><th>' . __('Preferred Delivery Date:') . '</th>';
            echo '<td>' . esc_html(date('F j, Y', strtotime($delivery_date))) . '</td></tr>';
        }

        echo '</table>';
        echo '</section>';
    }
}

Styling

#custom_checkout_fields {
    margin: 20px 0;
    padding: 20px;
    background: #f9f9f9;
    border-radius: 5px;
}

#custom_checkout_fields h3 {
    margin-top: 0;
}

.custom-checkout-fields {
    margin: 20px 0;
    padding: 15px;
    background: #f9f9f9;
    border: 1px solid #e0e0e0;
    border-radius: 4px;
}

.custom-checkout-fields p {
    margin: 10px 0;
}

Features

  • Multiple Field Types: Text, textarea, select, checkbox, date, and tel inputs
  • Validation: Built-in validation for phone numbers and dates
  • Order Integration: Saves to order meta and displays everywhere
  • Email Display: Shows custom fields in order confirmation emails
  • Admin Display: Shows fields in WooCommerce admin order page
  • Customer Display: Shows on order details in My Account
  • Dynamic Pricing: Can add fees based on field selections (gift wrapping example)
  • Conditional Logic: Can make fields required based on other selections

Dependencies

  • WooCommerce

Related Snippets