How to Allow Customers to Choose the Delivery Date and Time in WooCommerce?

Ever wished your WooCommerce store could let customers pick their preferred delivery date and time? Good news—it can! With a simple code snippet, you can add this feature to your checkout page, giving your customers more control and improving their shopping experience.

In this post, I’ll walk you through what the code does, how to use it, and why using the Code Snippets plugin is the way to go.

What Does This Code Do?

This code adds two new fields to your WooCommerce checkout page:

1. Preferred Delivery Date: A calendar date picker where customers can select a delivery date within a specified range.

2. Preferred Delivery Time: A dropdown menu of time slots based on your defined schedule.

How to Allow Customers to Choose the Delivery Date and Time in WooCommerce?

Here’s what the code handles:

  • Configurable Delivery Schedule: You set the start and end times, the interval between time slots (like every 15 minutes), and how many days ahead customers can book.
  • Disable Weekends: Option to disable deliveries on weekends.
  • Validation: Ensures customers select both a date and time within the allowed range before placing an order.
  • Order Integration: Saves the selected date and time with the order details, so you can see it in the admin dashboard and include it in emails to customers.

Video: How to Allow Customers to Choose the Delivery Date and Time in WooCommerce?

How to Add This Feature to Your Store

You can add this functionality to your WooCommerce store by adding the provided code. There are two main ways to do this:

Option 1: Using the functions.php File

1. Access Your Theme’s Files: Go to your WordPress dashboard, navigate to Appearance > Theme Editor, and open the functions.php file.

2. Backup First: Always make a backup of your functions.php file before making changes.

3. Add the Code: Paste the entire code snippet at the end of the functions.php file.

4. Save Changes: Click “Update File” to save.

Important: Editing the functions.php file can be risky. A small error can break your site, and updates to your theme might overwrite your changes.

Option 2: Using the Code Snippets Plugin (Recommended)

1. Install the Plugin: From your WordPress dashboard, go to Plugins > Add New, search for “Code Snippets,” install, and activate it.

2. Add a New Snippet: Navigate to Snippets > Add New.

3. Name Your Snippet: Give it a descriptive name like “Delivery Date and Time Picker.”

4. Paste the Code: Copy the entire code snippet into the code area.

5. Save and Activate: Click “Save Changes and Activate.”

Use this code:

if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly
}

// Delivery Time Configuration
define('DELIVERY_START_TIME', '10:00');  // Format: 'HH:mm' (24-hour format)
define('DELIVERY_END_TIME', '18:00');    // Format: 'HH:mm' (24-hour format)
define('DELIVERY_INTERVAL', 15);         // in minutes (30 = half hour slots, 60 = hour slots)

// Delivery Date Configuration
define('DELIVERY_DAYS_AHEAD', 90);       // number of days ahead to allow booking
define('DELIVERY_MIN_DAYS_AHEAD', 1);    // minimum days ahead for delivery (1 = next day, 0 = today)
define('DELIVERY_DISABLE_WEEKENDS', true); // set to false to allow weekend deliveries

// Disabled Days Configuration (0 = Sunday, 6 = Saturday)
global $DELIVERY_DISABLED_DAYS;
$DELIVERY_DISABLED_DAYS = array(); // Initialize empty array

if (DELIVERY_DISABLE_WEEKENDS) {
    $DELIVERY_DISABLED_DAYS = array(0, 6); // 0 = Sunday, 6 = Saturday
}

// Calculate date range
function wpsh_get_delivery_date_range() {
    static $dates = null;
    if ($dates === null) {
        $dates = array(
            'start' => date('Y-m-d', strtotime('+' . DELIVERY_MIN_DAYS_AHEAD . ' day')),
            'end' => date('Y-m-d', strtotime('+' . DELIVERY_DAYS_AHEAD . ' days'))
        );
    }
    return $dates;
}

// Generate time slots function
function wpsh_generate_time_slots($include_empty = true) {
    static $time_slots = null;
    if ($time_slots === null) {
        $slots = array();
        $current = strtotime(DELIVERY_START_TIME);
        $end = strtotime(DELIVERY_END_TIME);
        
        while ($current <= $end) {
            $time_formatted = date('H:i', $current);
            $time_display = date('g:i A', $current);
            $slots[$time_formatted] = $time_display;
            $current = strtotime('+' . DELIVERY_INTERVAL . ' minutes', $current);
        }
        $time_slots = $slots;
    }
    
    if ($include_empty) {
        return array_merge(
            array('' => __('Select a time slot', 'woocommerce')),
            $time_slots
        );
    }
    
    return $time_slots;
}

// Add custom date and time picker fields on the checkout page
add_action('woocommerce_after_checkout_billing_form', 'wpsh_add_delivery_fields');
function wpsh_add_delivery_fields($checkout) {
    global $DELIVERY_DISABLED_DAYS;
    $date_range = wpsh_get_delivery_date_range();
    
    // Ensure $DELIVERY_DISABLED_DAYS is an array
    if (!is_array($DELIVERY_DISABLED_DAYS)) {
        $DELIVERY_DISABLED_DAYS = array();
    }
    
    // Convert PHP array to JavaScript array
    $disabled_days_json = json_encode($DELIVERY_DISABLED_DAYS);
    ?>
    <!-- Load flatpickr resources -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.6.13/flatpickr.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.6.13/flatpickr.min.js"></script>

    <script type="text/javascript">
    jQuery(document).ready(function($) {
        // Define disabled days array
        const disabledDays = <?php echo json_encode($DELIVERY_DISABLED_DAYS); ?>;
        
        // Initialize flatpickr
        flatpickr("#arrival_date", {
            enableTime: false,
            dateFormat: "Y-m-d",
            minDate: "<?php echo esc_js($date_range['start']); ?>",
            maxDate: "<?php echo esc_js($date_range['end']); ?>",
            disable: [
                function(date) {
                    // Get day of week (0-6)
                    const day = date.getDay();
                    // Check if this day should be disabled
                    return disabledDays.includes(day);
                }
            ],
            locale: {
                firstDayOfWeek: 1 // Start with Monday
            },
            onOpen: function(selectedDates, dateStr, instance) {
                console.log('Calendar opened');
                console.log('Disabled days:', disabledDays);
            },
            onChange: function(selectedDates, dateStr, instance) {
                console.log('Selected date:', dateStr);
            }
        });

        // Form validation
        $('form.checkout').on('checkout_place_order', function() {
            const selectedDate = $('#arrival_date').val();
            const selectedTime = $('#arrival_time').val();

            if (!selectedDate) {
                alert('Please select a preferred delivery date.');
                return false;
            }

            if (!selectedTime) {
                alert('Please select a preferred delivery time.');
                return false;
            }

            return true;
        });
    });
    </script>

    <style type="text/css">
    /* Ensure the date input has sufficient width */
    #arrival_date {
        min-width: 100%;
        background: #fff !important;
        cursor: pointer;
    }
    /* Make the calendar icon visible */
    .flatpickr-calendar {
        background: #fff;
    }
    /* Improve the calendar appearance */
    .flatpickr-day.disabled {
        cursor: not-allowed;
        color: #ddd;
    }
    .flatpickr-day.selected {
        background: #2271b1;
        border-color: #2271b1;
    }
    </style>
    <?php

    // Add delivery date field
    woocommerce_form_field('arrival_date', array(
        'type' => 'text',
        'class' => array('form-row-wide'),
        'label' => __('Preferred delivery date', 'woocommerce'),
        'required' => true,
        'id' => 'arrival_date',
        'placeholder' => __('Click to select a date', 'woocommerce'),
        'custom_attributes' => array(
            'autocomplete' => 'off',
            'readonly' => 'readonly'
        )
    ), $checkout->get_value('arrival_date'));

    // Add delivery time field
    woocommerce_form_field('arrival_time', array(
        'type' => 'select',
        'class' => array('form-row-wide'),
        'label' => __('Preferred delivery time', 'woocommerce'),
        'required' => true,
        'id' => 'arrival_time',
        'options' => wpsh_generate_time_slots()
    ), $checkout->get_value('arrival_time'));
}

// Validate the custom fields on checkout submission
add_action('woocommerce_checkout_process', 'wpsh_validate_delivery_fields');
function wpsh_validate_delivery_fields() {
    $arrival_date = sanitize_text_field($_POST['arrival_date'] ?? '');
    $arrival_time = sanitize_text_field($_POST['arrival_time'] ?? '');
    $date_range = wpsh_get_delivery_date_range();

    if (empty($arrival_date)) {
        wc_add_notice(__('Please select a preferred delivery date.', 'woocommerce'), 'error');
        return;
    }

    if (empty($arrival_time)) {
        wc_add_notice(__('Please select a preferred delivery time.', 'woocommerce'), 'error');
        return;
    }

    // Validate date range
    $date_timestamp = strtotime($arrival_date);
    $min_timestamp = strtotime($date_range['start']);
    $max_timestamp = strtotime($date_range['end']);

    if ($date_timestamp < $min_timestamp || $date_timestamp > $max_timestamp) {
        wc_add_notice(sprintf(__('Please select a valid delivery date within the next %d days.', 'woocommerce'), DELIVERY_DAYS_AHEAD), 'error');
        return;
    }

    // Validate time slot
    $valid_slots = wpsh_generate_time_slots(false);
    if (!array_key_exists($arrival_time, $valid_slots)) {
        wc_add_notice(__('Please select a valid delivery time slot.', 'woocommerce'), 'error');
        return;
    }
}

// Save the custom fields data as order item meta
add_action('woocommerce_checkout_create_order_line_item', 'wpsh_save_delivery_fields', 10, 4);
function wpsh_save_delivery_fields($item, $cart_item_key, $values, $order) {
    if (!empty($_POST['arrival_date'])) {
        $date = sanitize_text_field($_POST['arrival_date']);
        $formatted_date = date_i18n(get_option('date_format'), strtotime($date));
        $item->add_meta_data(__('Preferred delivery date', 'woocommerce'), $formatted_date);
    }

    if (!empty($_POST['arrival_time'])) {
        $time = sanitize_text_field($_POST['arrival_time']);
        $formatted_time = date_i18n(get_option('time_format'), strtotime("2000-01-01 $time"));
        $item->add_meta_data(__('Preferred delivery time', 'woocommerce'), $formatted_time);
    }
}

// Display delivery information helper function
function wpsh_display_delivery_information($order) {
    $displayed = false;

    foreach ($order->get_items() as $item_id => $item) {
        $delivery_date = $item->get_meta('Preferred delivery date');
        $delivery_time = $item->get_meta('Preferred delivery time');

        if (!$displayed && ($delivery_date || $delivery_time)) {
            echo '<h3>' . esc_html__('Preferred Delivery Information', 'woocommerce') . '</h3>';
            $displayed = true;
        }

        if ($delivery_date) {
            echo '<p><strong>' . esc_html__('Preferred delivery date', 'woocommerce') . ':</strong> ' 
                 . esc_html($delivery_date) . '</p>';
        }

        if ($delivery_time) {
            echo '<p><strong>' . esc_html__('Preferred delivery time', 'woocommerce') . ':</strong> ' 
                 . esc_html($delivery_time) . '</p>';
        }
    }
}

// Add delivery information to emails and thank you page
add_action('woocommerce_email_order_meta', 'wpsh_add_delivery_fields_to_emails', 20, 3);
function wpsh_add_delivery_fields_to_emails($order, $sent_to_admin = false, $plain_text = false) {
    wpsh_display_delivery_information($order);
}

add_action('woocommerce_thankyou', 'wpsh_add_delivery_fields_to_thankyou', 20);
function wpsh_add_delivery_fields_to_thankyou($order_id) {
    $order = wc_get_order($order_id);
    if ($order) {
        wpsh_display_delivery_information($order);
    }
}

// Show delivery fields in admin
add_action('woocommerce_admin_order_data_after_billing_address', 'wpsh_show_delivery_fields_in_admin', 10);
function wpsh_show_delivery_fields_in_admin($order) {
    wpsh_display_delivery_information($order);
}

Why Use Code Snippets?

Safety: It prevents errors that can occur from editing core files.

Organization: Keeps all your custom code in one place.

Portability: Snippets remain active even if you change themes.

Easy Management: You can easily enable, disable, or modify snippets without digging into code files.

Configuring the Delivery Options

The code includes some settings at the top that you can customize:

define('DELIVERY_START_TIME', '10:00');  // Delivery start time
define('DELIVERY_END_TIME', '18:00');    // Delivery end time
define('DELIVERY_INTERVAL', 15);         // Time slots in minutes

define('DELIVERY_DAYS_AHEAD', 90);       // How many days ahead customers can book
define('DELIVERY_MIN_DAYS_AHEAD', 1);    // Minimum days ahead for delivery
define('DELIVERY_DISABLE_WEEKENDS', true); // Disable weekend deliveries
  • DELIVERY_START_TIME and DELIVERY_END_TIME: Set the daily delivery window.
  • DELIVERY_INTERVAL: Set the length of each time slot (e.g., 15 minutes).
  • DELIVERY_DAYS_AHEAD: How far into the future customers can schedule a delivery.
  • DELIVERY_MIN_DAYS_AHEAD: Minimum days before the earliest delivery date.
  • DELIVERY_DISABLE_WEEKENDS: Set to true to prevent deliveries on weekends.

Feel free to adjust these settings to match your business hours and policies.

Disabling Specific Days (Like Weekends)

There’s a handy part of the code that lets you disable specific days of the week for deliveries. This is great if, for example, you don’t offer deliveries on weekends.

Here’s the line in the code that does this:

$DELIVERY_DISABLED_DAYS = array(0, 6); // 0 = Sunday, 6 = Saturday

What’s Happening Here?

By customizing the $DELIVERY_DISABLED_DAYS array, you can tailor the delivery date options to perfectly fit your business’s schedule.

$DELIVERY_DISABLED_DAYS: This is an array (a list) that holds the numbers representing the days you want to disable.

Day Numbers: In programming, days of the week are often numbered from 0 to 6, where:

  • 0 = Sunday
  • 1 = Monday
  • 2 = Tuesday
  • 3 = Wednesday
  • 4 = Thursday
  • 5 = Friday
  • 6 = Saturday

In the code above, we’re disabling Sunday (0) and Saturday (6), effectively preventing customers from selecting weekends for delivery.

Customizing Disabled Days

You can easily adjust this to match your delivery schedule. Here are some examples:

Disable only for Sundays:

$DELIVERY_DISABLED_DAYS = array(0); // 0 = Sunday

Disable Wednesdays and Fridays:

$DELIVERY_DISABLED_DAYS = array(3, 5); // 3 = Wednesday, 5 = Friday

Disable Weekdays (Only Deliver on Weekends):

$DELIVERY_DISABLED_DAYS = array(1, 2, 3, 4, 5); // Disables Monday to Friday

How It Affects the Date Picker

When customers go to select a delivery date at checkout:

  • Disabled Days: The days you’ve specified will be grayed out and unselectable in the calendar.
  • Customer Experience: This guides customers to choose only the dates you’re available for deliveries, reducing confusion and potential scheduling issues.

Why This is Useful

  • Control Over Schedule: It gives you full control over which days you’re willing to deliver.
  • Avoids Mistakes: Prevents customers from selecting dates when you’re closed or unavailable.
  • Flexibility: Easily adjustable as your business hours change—just update the array.

Quick Tip

Remember, after changing the disabled days in the code, always test the date picker on your checkout page to ensure it’s working as expected.

What Happens When You Add This Code?

Once the code is active:

Woocommerce Checkout Page:

  • Customers will see two new fields under the billing details—“Preferred delivery date” and “Preferred delivery time.”
  • The date field uses a calendar picker, ensuring customers only select valid dates.
  • The time field provides a dropdown of available time slots.
  • Validation: The checkout won’t proceed unless both fields are filled out correctly.

Order Details:

  • Admin View: You can see the selected date and time in the order details within your dashboard.
  • Customer Emails: The delivery preferences are included in order confirmation emails.
  • Thank You Page: After checkout, customers see their selected delivery date and time.

Final Thoughts

Adding a delivery date and time picker enhances the customer experience by allowing them to choose when they receive their orders. It’s especially useful for businesses offering local delivery or services that require scheduling.

Using the Code Snippets plugin makes this addition easy and safe, even if you’re not a developer. It’s a straightforward way to add custom functionality to your WooCommerce store without the risk of breaking your site.

Do you want to thank me and buy me a beer?

Every donation is entirely welcome but NEVER required. Enjoy my work for free but if you would like to thank me and buy me a beer or two then you can use this form here below.

Donation Form (#2)

Here are some of my favorite WordPress tools

Thanks for reading this article! I hope it's been useful as you work on your own websites and e-commerce sites. I wanted to share some tools I use as a WordPress developer, and I think you'll find them helpful too.

Just so you know, these are affiliate links. If you decide to use any of them, I'll earn a commission. This helps me create tutorials and YouTube videos. But honestly, I genuinely use and recommend these tools to my friends and family as well. Your support keeps me creating content that benefits everyone.

Themes: Over the past few years, I've consistently relied on two primary themes for all sorts of projects: the Blocksy theme and the Kadence Theme. If you explore this website and my YouTube channel, you'll come across numerous tutorials that delve into these themes. If you're interested in obtaining a 10% discount for both of these themes, then:

Code Snippets Manager: WPCodeBox allows you to add code snippets to your site. Not only that, but it also provides you with the capability to construct and oversee your WordPress Code Snippets library right in the cloud. You can grab it with the 20% discount here (SAVE 20% Coupon: WPSH20).

Contact forms: There are hundreds of contact forms out there but Fluent Forms is the one I like the most. If you need a 20% discount then use this link (save 20% coupon is WPSH20).

Gutenberg add-ons: If I need a good Gutenberg blocks add-on then Kadence Blocks is the one I have used the most. You’ll get a 10% discount with the coupon SIMPLEHACKS here.

Website migration: While building a website you probably need a good plugin that can help you with the migration, backups, restoration, and staging sites. Well, WpVivid is the one I have used for the last couple of years. If you use this link along with the WPSH20 coupon you’ll get a 20% discount.

Woocommerce extensions: There are a bunch of Woocommerce extensions that I like but the one that stands out is Advanced Dynamic Pricing. Once again, you’ll get a 20% discount if you use this link here (save 20% coupon is WPSH20)

Web Hosting: If you would like to have a really fast and easy-to-use managed cloud hosting, then I recommend Verpex Hosting (see my review here). By the way, this site is hosted in Verpex.)

To see all my most up-to-date recommendations, check out this resource that I made for you!

Janek T.
Janek T.

Improve this text: {CLIPBOARD}

- I have been passionate about Wordpress since 2011, creating websites and sharing valuable tips on using Wordpress and Woocommerce on my site.
- Be the first to receive notifications about new tutorials by subscribing to my Youtube channel .
- Follow me on Twitter here

Articles: 137