Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Woocommerce Checkout - Display custom inline error messages (including custom validation messages)
<?php
/**
* adds custom js file to handle inline error messages
*/
add_action( 'woocommerce_after_checkout_form', 'add_custom_validation_script', 20 );
function add_custom_validation_script() {
wp_enqueue_script(
'inline_validation_script',
get_stylesheet_directory_uri() . '/js/inline-validation.js',
['jquery']
);
}
/**
* adds error message field element to get inline error messages working
*
* @param array $fields
* @param object $errors
*/
add_filter( 'woocommerce_form_field', 'add_inline_error_messages_element', 10, 4 );
function add_inline_error_messages_element( $field, $key, $args, $value ) {
if ( strpos( $field, '</span>' ) !== false ) {
$error = '<span class="js-custom-error-message" style="display:none"></span>';
$field = substr_replace( $field, $error, strpos( $field, '</span>' ), 0);
}
return $field;
}
/**
* process custom checkout validations
*
* @param array $fields
* @param object $errors
*/
add_action('woocommerce_after_checkout_validation', 'custom_checkout_validations', 10, 2);
function custom_checkout_validations($data, $errors)
{
$your_custom_checkout_field = filter_input(INPUT_POST, 'your_custom_input_field');
// your custom validations goes here
// this is an example to check for the length of the string
if ( !empty($your_custom_checkout_field) && strlen($your_custom_checkout_field) > 50 ) {
$errors->add('your_custom_input_field', __('This field needs to be max 50 chars', 'YourThemeName'));
}
// this loop adds a data array to all error messages which will be applied as a "data-error-for" HTML attribute
// to read out the corresponding field ids with javascript and display the error messages inline
foreach( $errors->errors as $original_key => $error ) {
$field_key = $original_key;
// filter and rewrite the field id for native woocommerce error messages with a key containing _required
if(strpos($original_key, '_required') !== false) {
$field_key = str_replace('_required','', $original_key);
$error[0] = __('This is a required field', 'YourThemeName');
}
// switch out the old error messages with the ones including a spiced up data array
// to display with javascript
$errors->remove($original_key);
$errors->add($original_key, trim($error[0]), ['error-for' => $field_key . '_field']);
}
}
jQuery(function ($) {
'use strict';
addInlineMessages();
// Implementation
// Listen to js event
$(document.body).on('updated_checkout', function() {
addInlineMessages();
});
function addInlineMessages() {
var woocommerceErrorsEl = $('.woocommerce-error');
var woocommerceInlineErrorsEl = $('li[data-error-for]', woocommerceErrorsEl);
var inlineErrorMessagesEl = $('.js-custom-error-message');
// as we use ajax submitting hide old validation messages
if(inlineErrorMessagesEl.length) {
inlineErrorMessagesEl.hide();
}
if(woocommerceInlineErrorsEl.length) {
woocommerceInlineErrorsEl.each(function () {
var errorEl = $(this);
var errorText = $.trim(errorEl.text());
var targetFieldId = errorEl.data('error-for');
if(errorText && targetFieldId) {
var targetFieldEl = $('#' + targetFieldId);
var errorMessageField = $('.js-custom-error-message', targetFieldEl);
if(targetFieldEl.length && errorMessageField.length) {
targetFieldEl.removeClass('woocommerce-validated');
targetFieldEl.addClass('woocommerce-invalid');
errorMessageField.text(errorText);
errorMessageField.show();
errorEl.hide();
}
}
});
if(woocommerceInlineErrorsEl.filter(':visible').length === 0) {
woocommerceErrorsEl.hide();
if(inlineErrorMessagesEl.filter(':visible').length > 0) {
scrollToElement(inlineErrorMessagesEl.filter(':visible').first());
}
} else {
$('li:not([data-error-for])', woocommerceErrorsEl).hide();
scrollToElement(woocommerceErrorsEl);
}
}
}
function scrollToElement(el) {
if(el.length) {
$([document.documentElement, document.body]).animate({
scrollTop: el.offset().top - 100
}, 2000);
}
}
// event listeners
$(document.body).on('checkout_error', function (event) {
jQuery('html, body').stop();
addInlineMessages();
});
});
@Broder1991
Copy link

Broder1991 commented Feb 28, 2022

Same for me Lucas, the js file is loaded on checkout and error message is set. When .js-custom-error-message is manually set to display block you can see the error messages below the field. However they aren't toggled automatically when clicking place order with empty fields.

@jemsz
Copy link

jemsz commented Jun 22, 2022

@lucasjahn this is amazing! Thank you for the help putting it together :)
Question - is it possible to apply this to the 'my account' forms section of WooCommerce? Default links for the below billing address and edit account forms
my-account/edit-address/billing/
my-account/edit-account/

Thanks!

@lucasjahn
Copy link
Author

lucasjahn commented Jun 27, 2022

Hey @jemsz so I think this should be possible but I'm right now not sure as you would have to adjust the validation function and when it triggers. Im thinking about to stuff this thing in a little plugin so maybe I could have a look at the my account validation as well.

@Z1pas
Copy link

Z1pas commented Nov 8, 2022

Hello, is it possible to validate the custom checkbox field in your code? I have added a privacy policy agreement to my site, but I can't get it to show an inline error if the client doesn't check the field.

Privacy policy code: https://www.businessbloomer.com/woocommerce-additional-acceptance-checkbox-checkout/.

Thanks for your help!

@lucasjahn
Copy link
Author

lucasjahn commented Nov 8, 2022

@Z1pas this is totally possible. This is done in my code in the custom_checkout_validations function.

Basically you can add any validation you want and it will add it to the corresponding fields if it is created with the woocommerce_form_field method.

Anyway, I think I have to have a little overhaul of the code above as some people have some problems with it (probably due to other themes/plugins) enabled etc. but the basic I idea stays.

Cheers.

@Z1pas
Copy link

Z1pas commented Nov 8, 2022

@lucasjahn thank you so much for your help and quick response. I finally validated my checkbox field! The code works perfectly!

All the best to you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment