Skip to content

Instantly share code, notes, and snippets.

@lucasjahn
Last active June 19, 2024 08:03
Show Gist options
  • Save lucasjahn/2da5405d3bd7d3e12555e902c25ed784 to your computer and use it in GitHub Desktop.
Save lucasjahn/2da5405d3bd7d3e12555e902c25ed784 to your computer and use it in GitHub Desktop.
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();
});
});
@lucasjahn
Copy link
Author

Thanks, everyone, for your questions here. Actually, I did not receive notifications here anymore, so I overlooked your messages. Sorry for that. I’ve put it on my plate to prepare a more tested and documented script for you to try out, and maybe write a little post about it to have it more detailed.

I’ll keep you posted!

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