Custom WooCommerce Checkout Fields

I have a confession: despite being a WordPress developer since 2010, I’ve rarely used WooCommerce! Where I have I’ve only done the very basics. And now I’m knee deep in a custom WooCommerce project with a lot to figure out.

Creating custom fields on the checkout was a particular area of confusion. Here’s what I needed:

  • A bunch of custom fields…
  • with conditional logic (i.e. some fields are only sometimes visible depending on values of other fields)…
  • that save in the order (and get displayed in the back-end order screen, and, potentially, in emails)…
  • and that can be passed to MailChimp – again, conditionally, based on the values of some fields.

The logic is something like:

  • Ask if a user is over 18.
  • If they are collect their year of birth and send it to MailChimp as part of the ordering process.
  • If they aren’t collect their date of birth, and only let them order if they are over 13, and send the date of birth to MailChimp as part of the ordering process.

Initially I was thinking that I could do this with some custom fields plugin maybe? But I consulted with some expert friends and they encouraged me to code this myself. Which, for this application with two interacting integrations (custom fields and MailChimp) and the conditional logic and stuff was probably a good idea. Bullying off-the-shelf plugins into doing this was never going to work.

It turns out that WooCommerce has a pretty good guide to doing most of this. And they have REALLY EXTENSIVE action and filter hooks – so much so that it’s hard to know what you should be hooking into.

There was one thing that tripped me up along the way though. I was trying to write some JavaScript to work on some markup that was added with the woocommerce_checkout_before_terms_and_conditions hook, just above the button to make the purchase.

Any event handlers added to input in this area were inactive. It was like WooCommerce was removing them or intercepting them somehow, and despite source-diving a little I’ve still not quite figured out what it was doing.

I think that every time the cart updates via AJAX on the checkout page, the HTML elements are re-created. And there is an update when the page first loads. So any event handlers I added during page initialisation were immediately overridden or remvoed.

The solution was to add my event handlers when the updated_checkout event fired in JavaScript. This ensured that after the checkout update, my handlers were added to the elements.

Phew!