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.