Normally, the browser’s HTML5 constraint validation API allows us to set a custom message with setCustomValidity(). However, that only allows text, no HTML. This example shows you how to add an HTML link to the custom validity error message.
This example is specifically for the WooCommerce product quantity input field, and it specifically adds a custom message when the quantity entered exceeds the max allowed. You can modify this, as needed.
The basic method is this:
- Stop the built-in browser form validation for the Add to cart form.
- Add your own custom JavaScript validation for the quantity input field.
- Create your own custom error message to show if validation fails. This allows you to add HTML to the error message. This custom message will have to be styled, so I’ve added some CSS styles on lines 158–163.
You must edit the error message on line 34 to suit your needs. In this example, the error message is:
Limit of {MAX-NUMBER} per order. Please go here.
…in which “go here” is a link.
The HTML for the link on line 34 looks like this:
<a href=\'#\'>go here</a>
- Change the
#to the URL address of the page which you want to link to. Leave the backslashes and single quotes as they are. - Change
go hereto the text for the link.
Here is the entire code, and it goes in your functions.
/**
* Customize the browser's default constraint validation message for exceeding the input max
*/
function isa_wc_max_qty_custom_html_error_msg() {
/* Add JS to frontend wherever woocommerce.js is loaded. */
wp_add_inline_script( 'woocommerce', 'window.onload = function(){
var productForm = document.querySelector( "form.cart" );
var cartForm = document.querySelector( "form.woocommerce-cart-form" );
// Custom validation for the quantity field
var qtyHasError = function (field) {
// Get validity
var validity = field.validity;
// If valid, return null
if (validity.valid) return;
// If number input isn"t a number
if (validity.badInput) return "Please enter a number.";
// If a number value doesn"t match the step interval
if (validity.stepMismatch) return "Please select a valid value.";
// If a number field is over the max
if (validity.rangeOverflow) {
var max = field.getAttribute( "max" );
return "Limit of " + max + " per order. Please <a href=\'#\'>go here</a>.";
}
// If a number field is below the min
if (validity.rangeUnderflow) return "Please select a value that is no less than " + field.getAttribute("min") + ".";
// If all else fails, return a generic catchall error
return "The value you entered for this field is invalid.";
};
// Show the error message
var qtyShowError = function (field, error) {
// Add error class to field
field.classList.add("error");
// Get field id or name
var id = field.id || field.name;
if (!id) return;
// Check if error message field already exists
// If not, create one
var message = field.form.querySelector(".qty-error-message#error-for-" + id );
if (!message) {
message = document.createElement("div");
message.className = "qty-error-message";
message.id = "error-for-" + id;
field.parentNode.insertBefore( message, field.nextSibling );
}
// Add ARIA role to the field
field.setAttribute("aria-describedby", "error-for-" + id);
// Update error message
message.innerHTML = error;
// Show error message
message.style.display = "block";
message.style.visibility = "visible";
};
// Remove the error message
var qtyRemoveError = function (field) {
// Remove error class to field
field.classList.remove("error");
// Remove ARIA role from the field
field.removeAttribute("aria-describedby");
// Get field id or name
var id = field.id || field.name;
if (!id) return;
// Check if an error message is in the DOM
var message = field.form.querySelector(".qty-error-message#error-for-" + id + "");
if (!message) return;
// If so, hide it
message.innerHTML = "";
message.style.display = "none";
message.style.visibility = "hidden";
};
// Validate the quantity field
function validateQtyonBlur( event ) {
// Validate the field
var error = qtyHasError(event.target);
// If there is an error, show it
if (error) {
qtyShowError(event.target, error);
return;
}
// Otherwise, remove any existing error message
qtyRemoveError(event.target);
}
if ( productForm ) {
// Stop the built-in browser form validation for Add to Cart form
productForm.setAttribute("novalidate", true);
// If there is an error, do not submit form
productForm.addEventListener("submit", function (event) {
if ( qtyHasError( event.target.quantity ) ) {
event.preventDefault();
}
}, false);
}
// Stop the built-in browser form validation for Update Cart form
if ( cartForm ) {
cartForm.setAttribute("novalidate", true);
}
// Do custom validation on quantity field
var quantity = document.querySelector( "form.cart .qty" );
var cartQuantity = document.querySelector( "form.woocommerce-cart-form .qty" );
if ( quantity ) { // quantity input on single product page
quantity.addEventListener( "blur", validateQtyonBlur, true );
}
if ( cartQuantity ) { // quantity input on cart page
cartQuantity.addEventListener( "blur", validateQtyonBlur, true );
}
};'
);
/* Add CSS to frontend wherever woocommerce.js is loaded. */
wp_add_inline_style( 'woocommerce-layout', '
.qty-error-message {
padding:1px;
color:#D8000C;background:#ffd2d2;
border:1px solid #D8000C;
border-radius: 5px;
}
' );
}
add_action( 'wp_enqueue_scripts', 'isa_wc_max_qty_custom_html_error_msg', 9999 );
Jaime
May 29th, 2019 at 4:35 am
Fantastic!