WooCommerce code snippet: convert the Order Notes field into an EU VAT ID field

The scenario: My WooCommerce store has no need for the Order Notes field. In fact, up until now I had it hidden on the checkout page. But what my site does need is an EU VAT ID field. The portion of my business that takes place in Europe is, so far, well below the VAT reporting threshold, but I am increasingly being asked by customers to provide an invoice containing their VAT ID.

Well, my site does already produce PDF invoices. But there was no way for customers to include their VAT ID on the invoice. Until now.

A simple code snippet converts the existing WooCommerce Order Notes field into an EU VAT ID field, including changing it from a <textarea> to an <input type="text"> field. Put this in your theme’s functions.php file, or wherever else is appropriate in your setup:

add_filter('woocommerce_checkout_fields', function($fields) {
    $fields['order']['order_comments'] = array_merge(
        $fields['order']['order_comments'],
        array(
            'class' => array('eu-only'),
            'label' => 'EU VAT ID',
            'type' => 'text',
        )
    );
    return $fields;
}, 10, 1);

That’s it. You can stop right here. But you may notice a line in there that seems unnecessary: 'class' => array('eu-only')

What’s that all about? Well, I’m using that with a bit of jQuery to enhance the functionality: only showing my new EU VAT ID field when the user’s selected Billing Country is an EU country.

Here’s a JavaScript function you can use to dynamically show/hide elements with an .eu-only CSS class, depending on a given passed-in value:

function showHideEUOnly(val) {
    var eu = ['AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'PL', 'PT', 'RO', 'SK', 'ES', 'SE', 'GB'];
    if (eu.indexOf(val) != -1) {
        jQuery('.eu-only').show();
    }
    else {
        jQuery('.eu-only').hide();
    }
}

I obtained the list of EU VAT-applicable countries here, and I decided to include 'GB' (the United Kingdom) in the list, despite… y’know, uh… Brexit, because I have the vague impression that UK customers may still be impacted by VAT policies. (Being a dumb American, I don’t know much about it. I think maybe the UK has its own VAT now? Anyway, suffice to say, you may want to modify your list of 2-digit country codes in the eu array, as applicable to your situation.)

This function isn’t going to do anything unless it’s called though, so let’s do that. Here’s a bit of jQuery that will call it both on the initial page load and any time the Billing Country field changes:

jQuery(function() {
    if (jQuery('body').hasClass('woocommerce-checkout')) {
        jQuery('select[name="billing_country"]').on('change', function() {
            showHideEUOnly(jQuery(this).val());
        });
        showHideEUOnly(jQuery('select[name="billing_country"]').val());
    }
});

Both of these JavaScript snippets can go in a script.js file in your theme, or wherever else is appropriate in your setup.

That’s the end of the story, but there’s more…

Incidentally, there’s more to my custom setup. I’ve significantly modified the layout of my checkout page. I’ve got WooCommerce configured for billing addresses only, with this setting in Shipping Options:

I then used CSS to hide everything else in the second column (including, up until now, the Order Notes field) and moved the product summary and payment information up into that space. Explaining all of that is outside the scope of this post, but one thing you may find useful is my CSS for hiding the “Additional Information” <h3> heading. This selector is a bit of overkill, but it works:

body.woocommerce-checkout .woocommerce > form.checkout .col2-set > .col-2 .woocommerce-additional-fields > h3:first-child { display: none; }

There’s context in my CSS file to justify all of that, but you should be able to accomplish the same with just this:

.woocommerce-additional-fields > h3 { display: none; }