Skip to content

Instantly share code, notes, and snippets.

@lucasjahn
Last active March 9, 2024 11:30
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • 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

@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!

@kaylikecoding
Copy link

kaylikecoding commented Mar 9, 2024

Hey there, I just wanted to ask i want to show radio button error which is required but its not visible even though i wrote code and in backend it is working its just not visible on frontend please if you can help me solve this issue.

add_filter( 'woocommerce_form_field', 'wtwh_checkout_fields_in_label_error', 10, 4 );

function wtwh_checkout_fields_in_label_error( $field, $key, $args, $value ) {

if ( strpos( $field, '</label>' ) !== false && $args['required'] ) {
    $error = '<span class="error" style="display:none">';
    $error .= sprintf( __( '%s is a required.', 'woocommerce' ), $args['label'], $args['radio'] );
    $error .= '</span>';
    // Append the error message inside the field
    $field = substr_replace( $field, $error, strpos( $field, '</label>' ) + strlen('</label>'), 0);
}

if ($args['type'] === 'radio' && $args['required']) {
    // Add the error message inside the radio button container
    $error = '<span class="error" style="display:none">';
    $error .= sprintf(__(' %s is a required field.', 'woocommerce'), $args['label']);
    $error .= '</span>';
    // Append the error message inside the field
    $field = str_replace('<input', $error . '<input', $field);
}
   
return $field;

}

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