: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @param {jQuery} $field Field element.
* @return {number} Quantity value.
getPaymentFieldQuantity( $field ) {
const fieldId = $field.attr( 'id' ),
$quantityInput = $( `#${ fieldId }-quantity` );
if ( $quantityInput.length ) {
return Number( $quantityInput.val() );
* Sanitize amount and convert to standard format for calculations.
* @param {string} amount Amount to sanitize.
* @return {string} Sanitized amount.
// eslint-disable-next-line complexity
amountSanitize( amount ) {
const currency = app.getCurrency();
amount = amount.toString().replace( /[^0-9.,]/g, '' );
if ( currency.decimal_sep === ',' ) {
if ( currency.thousands_sep === '.' && amount.indexOf( currency.thousands_sep ) !== -1 ) {
amount = amount.replace( new RegExp( '\\' + currency.thousands_sep, 'g' ), '' );
} else if ( currency.thousands_sep === '' && amount.indexOf( '.' ) !== -1 ) {
amount = amount.replace( /\./g, '' );
amount = amount.replace( currency.decimal_sep, '.' );
} else if ( currency.thousands_sep === ',' && ( amount.indexOf( currency.thousands_sep ) !== -1 ) ) {
amount = amount.replace( new RegExp( '\\' + currency.thousands_sep, 'g' ), '' );
return app.numberFormat( amount, currency.decimals, '.', '' );
* @param {string|number} amount Amount to format.
* @return {string} Formatted amount.
const currency = app.getCurrency();
amount = String( amount );
if ( ',' === currency.decimal_sep && ( amount.indexOf( currency.decimal_sep ) !== -1 ) ) {
const sepFound = amount.indexOf( currency.decimal_sep ),
whole = amount.substr( 0, sepFound ),
part = amount.substr( sepFound + 1, amount.length - 1 );
amount = whole + '.' + part;
// Strip "," from the amount (if set as thousands separator)
if ( ',' === currency.thousands_sep && ( amount.indexOf( currency.thousands_sep ) !== -1 ) ) {
amount = amount.replace( /,/g, '' );
if ( app.empty( amount ) ) {
return app.numberFormat( amount, currency.decimals, currency.decimal_sep, currency.thousands_sep );
* Format amount with the currency symbol.
* @param {string|number} amount Amount to format.
* @return {string} Formatted amount.
amountFormatSymbol( amount ) {
const currency = app.getCurrency(),
amountFormatted = app.amountFormat( amount );
if ( currency.symbol_pos === 'left' ) {
return currency.symbol + amountFormatted;
return amountFormatted + ' ' + currency.symbol;
* Get site currency settings.
* @return {Object} Currency data object.
getCurrency() { // eslint-disable-line complexity
thousands_sep: ',', // eslint-disable-line camelcase
decimal_sep: '.', // eslint-disable-line camelcase
symbol_pos: 'left', // eslint-disable-line camelcase
// Backwards compatibility.
if ( typeof wpforms_settings.currency_code !== 'undefined' ) {
currency.code = wpforms_settings.currency_code;
if ( typeof wpforms_settings.currency_thousands !== 'undefined' ) {
currency.thousands_sep = wpforms_settings.currency_thousands; // eslint-disable-line camelcase
if ( typeof wpforms_settings.currency_decimals !== 'undefined' ) {
currency.decimals = wpforms_settings.currency_decimals;
if ( typeof wpforms_settings.currency_decimal !== 'undefined' ) {
currency.decimal_sep = wpforms_settings.currency_decimal; // eslint-disable-line camelcase
if ( typeof wpforms_settings.currency_symbol !== 'undefined' ) {
currency.symbol = wpforms_settings.currency_symbol;
if ( typeof wpforms_settings.currency_symbol_pos !== 'undefined' ) {
currency.symbol_pos = wpforms_settings.currency_symbol_pos; // eslint-disable-line camelcase
* @see http://locutus.io/php/number_format/
* @param {string} number Number to format.
* @param {number} decimals How many decimals should be there.
* @param {string} decimalSep What is the decimal separator.
* @param {string} thousandsSep What is the thousand separator.
* @return {string} Formatted number.
numberFormat( number, decimals, decimalSep, thousandsSep ) { // eslint-disable-line complexity
number = ( number + '' ).replace( /[^0-9+\-Ee.]/g, '' );
const n = ! isFinite( +number ) ? 0 : +number;
const precision = ! isFinite( +decimals ) ? 0 : Math.abs( decimals );
const sep = ( 'undefined' === typeof thousandsSep ) ? ',' : thousandsSep;
const dec = ( 'undefined' === typeof decimalSep ) ? '.' : decimalSep;
const toFixedFix = function( n, prec ) {
const k = Math.pow( 10, prec );
return '' + ( Math.round( n * k ) / k ).toFixed( prec );
// @todo: for IE parseFloat(0.55).toFixed(0) = 0;
const s = ( precision ? toFixedFix( n, precision ) : '' + Math.round( n ) ).split( '.' );
if ( s[ 0 ].length > 3 ) {
s[ 0 ] = s[ 0 ].replace( /\B(?=(?:\d{3})+(?!\d))/g, sep );
if ( ( s[ 1 ] || '' ).length < precision ) {
s[ 1 ] += new Array( precision - s[ 1 ].length + 1 ).join( '0' );
* Empty check similar to PHP.
* @see http://locutus.io/php/empty/
* @param {any} mixedVar Variable to check.
* @return {boolean} Whether the var is empty or not.
const emptyValues = [ undef, null, false, 0, '', '0' ];
for ( i = 0, len = emptyValues.length; i < len; i++ ) {
if ( mixedVar === emptyValues[ i ] ) {
if ( 'object' === typeof mixedVar ) {
for ( key in mixedVar ) {
if ( mixedVar.hasOwnProperty( key ) ) {
* Set cookie container user UUID.
setUserIdentifier() { // eslint-disable-line complexity
if ( ( ( ! window.hasRequiredConsent && typeof wpforms_settings !== 'undefined' && wpforms_settings.uuid_cookie ) || ( window.hasRequiredConsent && window.hasRequiredConsent() ) ) && ! app.getCookie( '_wpfuuid' ) ) {
// Generate UUID - http://stackoverflow.com/a/873856/1489528
const s = new Array( 36 ),
hexDigits = '0123456789abcdef';
for ( let i = 0; i < 36; i++ ) {
s[ i ] = hexDigits.substr( Math.floor( Math.random() * 0x10 ), 1 );
// eslint-disable-next-line no-bitwise
s[ 19 ] = hexDigits.substr( ( s[ 19 ] & 0x3 ) | 0x8, 1 );
s[ 8 ] = s[ 13 ] = s[ 18 ] = s[ 23 ] = '-';
const uuid = s.join( '' );
app.createCookie( '_wpfuuid', uuid, 3999 );
* @param {string} name Cookie name.
* @param {string} value Cookie value.
* @param {number} days Whether it should expire and when.
createCookie( name, value, days ) {
if ( wpforms_settings.is_ssl ) {
// If we have a "days" value, set it in the expiry of the cookie.
// If -1 is our value, set a session-based cookie instead of a persistent cookie.
date.setTime( date.getTime() + ( days * 24 * 60 * 60 * 1000 ) );
expires = ';expires=' + date.toGMTString();
expires = ';expires=Thu, 01 Jan 1970 00:00:01 GMT';
document.cookie = name + '=' + value + expires + ';path=/;samesite=strict' + secure;
* @param {string} name Cookie name.
* @return {string|null} Cookie value or null when it doesn't exist.
const nameEQ = name + '=',
ca = document.cookie.split( ';' );
for ( let i = 0; i < ca.length; i++ ) {
while ( ' ' === c.charAt( 0 ) ) {
c = c.substring( 1, c.length );
if ( 0 === c.indexOf( nameEQ ) ) {
return c.substring( nameEQ.length, c.length );
* @param {string} name Cookie name.
app.createCookie( name, '', -1 );
* Get user browser preferred language.
* @return {string} Language code.
getFirstBrowserLanguage() { // eslint-disable-line complexity
const nav = window.navigator,
browserLanguagePropertyKeys = [ 'language', 'browserLanguage', 'systemLanguage', 'userLanguage' ];
// Support for HTML 5.1 "navigator.languages".
if ( Array.isArray( nav.languages ) ) {
for ( i = 0; i < nav.languages.length; i++ ) {
language = nav.languages[ i ];
if ( language && language.length ) {
// Support for other well-known properties in browsers.
for ( i = 0; i < browserLanguagePropertyKeys.length; i++ ) {
language = nav[ browserLanguagePropertyKeys[ i ] ];
if ( language && language.length ) {
* Asynchronously fetches country code using current IP
* and executes a callback provided with a country code parameter.
* @param {Function} callback Executes once the fetch is completed.
currentIpToCountry( callback ) {
const fallback = function() {
$.get( 'https://ipapi.co/jsonp', function() {}, 'jsonp' )
.always( function( resp ) {
let countryCode = resp?.country ? resp.country : '';
const lang = app.getFirstBrowserLanguage();
countryCode = lang.indexOf( '-' ) > -1 ? lang.split( '-' ).pop() : '';
$.get( 'https://geo.wpforms.com/v3/geolocate/json' )
.done( function( resp ) {
if ( resp && resp.country_iso ) {
callback( resp.country_iso );
.fail( function( resp ) {
* @since 1.7.6 Allow canceling form submission.
* @param {jQuery} $form Form element.
// Form element was passed from vanilla JavaScript.
if ( ! ( $form instanceof jQuery ) ) {
const event = WPFormsUtils.triggerEvent( $form, 'wpformsBeforeFormSubmit', [ $form ] );
// Allow callbacks on `wpformsBeforeFormSubmit` to cancel form submission by triggering `event.preventDefault()`.
if ( event.isDefaultPrevented() ) {
app.restoreSubmitButton( $form, $form.closest( '.wpforms-container' ) );
if ( $form.hasClass( 'wpforms-ajax-form' ) && typeof FormData !== 'undefined' ) {
app.formSubmitAjax( $form );
app.formSubmitNormal( $form );
* Restore default state for the form submit button.
* @param {jQuery} $form Form element.
* @param {jQuery} $container Form container.
restoreSubmitButton( $form, $container ) {
const $submit = $form.find( '.wpforms-submit' ),
submitText = $submit.data( 'submit-text' );
$submit.text( submitText );
$submit.prop( 'disabled', false );
WPFormsUtils.triggerEvent( $form, 'wpformsFormSubmitButtonRestore', [ $form, $submit ] );
$container.css( 'opacity', '' );
$form.find( '.wpforms-submit-spinner' ).hide();
* Normal submit of a form with page reload.
* @param {jQuery} $form Form element.
formSubmitNormal( $form ) {
const $submit = $form.find( '.wpforms-submit' ),
recaptchaID = $submit.get( 0 ).recaptchaID;
if ( ! app.empty( recaptchaID ) || recaptchaID === 0 ) {
$submit.get( 0 ).recaptchaID = false;
$form.append( '<input type="hidden" name="end_timestamp" value="' + Date.now() + '">' );
* Does the form have a captcha?
* @param {jQuery} $form Form element.
* @return {boolean} True when the form has a captcha.
formHasCaptcha( $form ) {
if ( ! $form || ! $form.length ) {
if ( typeof hcaptcha === 'undefined' && typeof grecaptcha === 'undefined' && typeof turnstile === 'undefined' ) {
const $captchaContainer = $form.find( '.wpforms-recaptcha-container' );
return Boolean( $captchaContainer.length );
* @since 1.6.4 Added hCaptcha support.
* @param {jQuery} $form Form element.
resetFormRecaptcha( $form ) { // eslint-disable-line complexity
if ( ! app.formHasCaptcha( $form ) ) {