back home

Adding Optional Extras To Woocommerce Delivery

Written by Bunkers on March 22, 2017

One of the bespoke features I needed for the Mum's Back site was to add options to the checkout process. Technically the options are something that I should associate with the product. But because they concern delivery, for now I've made them part of the checkout process and assumed if people want to order multiple hampers for delivery to different recipients, they'll go through the process twice. I agree that's not a great user experience, but it's good enough for this first version.

Options

The required options concern delivery dates. The hampers that Mum's Back sells are primarily for new mums and so delivery needs to happen after the recipient's has given birth!

There's a fair amount of complexity to this, but to begin with we decided that we simply needed to know whether to deliver straight away or wait. In the case of not delivering immediately we would just contact the customer after they purchased, and arrange the details. They could trigger delivery at any point by emailing us.

This meant we needed one additional option at checkout - a check box saying "Deliver immediately?" with a bit of explanation.

Hooking In

Thankfully Woocommerce has a multitude of different hooks and filters we can use to customise every aspect of the ordering process. This is often a blessing and a curse for me, because knowing the best point to hook in to a process often takes some investigation and I don't always get it right first time.

That may be the case here! It works, but I noticed at one point I was using a deprecated filter, so you may find other examples of this that are better. If you do let me know! Learning is part of the reason for documenting this.

Wrap Up & Plug In

You could do all of this from within your theme's functions.php file which is essentially a WordPress plugin. I think it's better practice to create a plugin in cases like this. As it stands it has some bits and pieces specific to this site hard coded in it, so isn't reusable, but it wouldn't take too much more development to move these to a plugin settings page. If I decide it's needed elsewhere I can do that without having to try and extract bits of code from the theme.

Setting up

The plugin is one file and starts with a standard header:

/*
Plugin Name: Delivery Time Option for Woocommerce
*/

This is the bare minimum information needed in the comment for WordPress to pick it up as a plugin. If I develop this further I would add other information like author and version numbering, but for one of local projects it's fine.

Display the field

add_action('woocommerce_after_order_notes', 'deliver_immediately_field');
 
function deliver_immediately_field( $checkout ) {
 
        echo '<div id="deliver_immediately_field"><h3>'.__('Deliver Immediately').'</h3><p>Check this option to have us dispatch your order straight away.</p>';
 
        woocommerce_form_field( 'deliver_immediately_check', array(
                'type'                  => 'checkbox',
                'class'                 => array('deliver-immediately-option orm-row-wide'),
                'label'                 => __('Deliver immediately?'),
                ), $checkout->get_value( 'deliver_immediately_check' ));
 
        echo '</div>';
}

We first have to display the field on the checkout page. There's hooks that you can use to insert HTML into, before, or after each section of the page. In this instance I'm hooking in to the area after the order notes. You'll notice the hard coded message, but I'm creating a wrapper div and a title with some explanation for the field (the real site has more instructions than this). I then use the Woocommerce helper function to create a checkbox field with the appropriate label and value.

Validation

Because this is a yes/no boolean value, my validation is intrinsic to the process of storing it against the order - all will become clear in a minute! - but you may want to do some further validation. If so, then it looks like the woocommerce_checkout_process hook is the best place.

add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
 
function my_custom_checkout_field_process() {
    global $woocommerce;
 
    if(....Your custom validation code) {
 
        wc_add_notice(__('Error message about what's invalid and what to do to correct it'), 'error' );
    }
}

The fields from the order form are available using the global $_POST array. In our case it would be $_POST['deliver_immediately_check']. There is a later action called woocommerce_after_checkout_validation which passes the checkout object's post variables as a parameter. This may be a better place to hook in for validation and something I'll investigate if I need to do this.

Store Or Update The Data

Orders in Woocommerce are custom post types and it stores data against them using standard post meta data.

add_action('woocommerce_checkout_update_order_meta', 'deliver_immediately_field_update_order_meta');
 
function deliver_immediately_field_update_order_meta( $order_id ) {
        update_post_meta( $order_id, 'Deliver Immediately?', ($_POST['deliver_immediately_check']?'Yes':'No'));
}

Here we hook in to woocommerce_checkout_update_order_meta and simply call update_post_meta to set our value to 'Yes' or 'No'. Having only two value like this prevents anyone being able to inject something nasty. Hopefully there's no situation where looking up a value could cause some bad code to run!

Adding to emails

add_filter('woocommerce_email_order_meta_fields', 'deliver_immediately_order_meta_fields');
 
function deliver_immediately_order_meta_fields( $keys ) {
        $keys[] = 'Deliver Immediately?';
        return $keys;
}

Lastly I'm hooking in to a filter called during the construction of emails so Woocommerce displays our option along with the rest of the order details. The keys here are post meta data values. Woocommerce then displays these either as HTML or plain text depending on the email type.

Future Developments

There's much more to do here! I could display this option better in the orders section of the admin. There are other options we might add here too, like an estimated delivery date. There's other parts to the process where the recipient can receive a gift card to let them know a hamper is on its way once they've given birth. All of this I'll add at a later date, but the principle will remain the same.

To go much further I could turn this in to a generic plugin allowing the addition of arbitrary fields to the orders. I use Advanced Custom Fields for the admin of other post types, so there may be a way to leverage that for the checkout process too.

Anyone got any interest in a plugin like this? If there's enough appetite I'll look in to it.