-
-
Save lucasjahn/2da5405d3bd7d3e12555e902c25ed784 to your computer and use it in GitHub Desktop.
<?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(); | |
}); | |
}); |
Where should I upload the inline-validation.js file?
Lorenzo, you upload it in a directory of your choice on your child-theme folder, in this case /js/. This is the location used by the creator, /js/inline-validation.js
So you would upload it in: /wp-content/themes/child-theme-name/js/inline-validation.js . Can you let me know if this works for you? Mines still not working
Hey @Broder1991 and @lorenzo-zonin I would really like to understand your issues you have. Maybe I will make a really tiny plugin out of it which is extenable easier. But maybe it could be because on my production site is also the astra theme in place which could be that it changes some of the outputs from the hooks BUT if you are interested I would like to have a look into both of your use cases to make it more usabale in general and also to update this gist a bit.
So I would maybe want to talk about one by one via chat/email whatever to maybe also check with you together the case and get it working. What do you think? Just contact me via [email protected] and then we continue the discussion here after we found the issues?
With very much pleasure!
@lorenzo-zonin , @Broder1991 I updated the JS file. There was a class name mistake in it. So please use the new .js file and try it on your end again.
Just pass me some updates here ;)
Ok let me try
Ciao Luca, it doesn't work for me... I may have done something wrong though...
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.
@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!
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.
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!
@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.
@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!
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;
}
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!
Thanks for your quick reply. I tested it. It goes to line 24 then 58 and then jumps up to line 9: $(document.body).on('updated_checkout') and then to a different script content.js:formatted line 14438. When I click continue twice it says there are no breakpoints