: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
app.fieldChoiceBulkAddToggle( this );
$builder.on( 'click', '.toggle-bulk-add-presets', function( e ) {
const $presetList = $( this ).closest( '.bulk-add-display' ).find( 'ul' );
if ( $presetList.css( 'display' ) === 'block' ) {
$( this ).text( wpforms_builder.bulk_add_presets_show );
$( this ).text( wpforms_builder.bulk_add_presets_hide );
$presetList.stop().slideToggle();
$builder.on( 'click', '.bulk-add-preset-insert', function( e ) {
preset = $this.data( 'preset' ),
$container = $this.closest( '.bulk-add-display' ),
$presetList = $container.find( 'ul' ),
$presetToggle = $container.find( '.toggle-bulk-add-presets' ),
$textarea = $container.find( 'textarea' );
$textarea.insertAtCaret( wpforms_preset_choices[ preset ].choices.join( '\n' ) );
$presetToggle.text( wpforms_builder.bulk_add_presets_show );
$builder.on( 'click', '.bulk-add-insert', function( e ) {
app.fieldChoiceBulkAddInsert( this );
// Field Options group tabs.
$builder.on( 'click', '.wpforms-field-option-group-toggle:not(.education-modal)', function( e ) {
const event = WPFormsUtils.triggerEvent( $builder, 'wpformsFieldOptionGroupToggle' );
// Allow callbacks on `wpformsFieldOptionGroupToggle` to cancel tab toggle by triggering `event.preventDefault()`.
if ( event.isDefaultPrevented() ) {
const $group = $( this ).closest( '.wpforms-field-option-group' );
$group.siblings( '.wpforms-field-option-group' ).removeClass( 'active' );
$group.addClass( 'active' );
// Display toggle for an Address field hide address line 2 option.
$builder.on( 'change', '.wpforms-field-option-address input.wpforms-subfield-hide', function( e ) { // eslint-disable-line no-unused-vars
const $optionRow = $( this ).closest( '.wpforms-field-option-row' ),
id = $optionRow.data( 'field-id' ),
subfield = $optionRow.data( 'subfield' );
$( '#wpforms-field-' + id ).find( '.wpforms-' + subfield ).toggleClass( 'wpforms-hide' );
// Real-time updates for the "Label" field option.
$builder.on( 'input', '.wpforms-field-option-row-label input, .wpforms-field-option-row-name input', function( e ) { // eslint-disable-line no-unused-vars
id = $this.parent().data( 'field-id' ),
$preview = $( '#wpforms-field-' + id ),
type = $preview.data( 'field-type' );
showEmptyLabel = value.length === 0;
// Do not modify the label of the HTML field.
value = wpforms_builder.empty_label;
$preview.toggleClass( 'label_empty', showEmptyLabel ).find( '> .label-title .text' ).text( value );
// Real-time updates for "Description" field option
$builder.on( 'input', '.wpforms-field-option-row-description textarea', function() {
value = wpf.sanitizeHTML( $this.val() ),
id = $this.parent().data( 'field-id' ),
// IIF description is not following other fields structure and needs to be selected separately.
$desc = $( `#wpforms-field-${ id } > .description, #wpforms-field-${ id } .wpforms-field-internal-information-row-description` );
app.updateDescription( $desc, value );
$this.trigger( 'wpformsDescriptionFieldUpdated', { id, descField: $desc, value } );
// Real-time updates for "Required" field option
$builder.on( 'change', '.wpforms-field-option-row-required input', function( e ) { // eslint-disable-line no-unused-vars
const id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' );
$( '#wpforms-field-' + id ).toggleClass( 'required' );
// Real-time updates for "Summary" field option
$builder.on( 'change', '.wpforms-field-option-row-summary input', function() {
id = $this.closest( '.wpforms-field-option-row' ).data( 'field-id' );
$( `#wpforms-field-${ id }` ).toggleClass( 'wpforms-summary-enabled' );
$this.closest( '.wpforms-field-option-group-inner' ).find( '.wpforms-total-summary-alert' ).toggleClass( 'wpforms-hidden' );
// Real-time updates for "Confirmation" field option
$builder.on( 'change', '.wpforms-field-option-row-confirmation input', function() {
const id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' );
$( '#wpforms-field-' + id ).find( '.wpforms-confirm' ).toggleClass( 'wpforms-confirm-enabled wpforms-confirm-disabled' );
$( '#wpforms-field-option-' + id ).toggleClass( 'wpforms-confirm-enabled wpforms-confirm-disabled' );
// Real-time updates for "Filter" field option
$builder.on( 'change', '.wpforms-field-option-row-filter_type select', function() {
const id = $( this ).parent().data( 'field-id' ),
$toggledField = $( '#wpforms-field-option-' + id );
$toggledField.removeClass( 'wpforms-filter-allowlist' );
$toggledField.removeClass( 'wpforms-filter-denylist' );
$toggledField.addClass( 'wpforms-filter-' + $( this ).val() );
$toggledField.removeClass( 'wpforms-filter-allowlist' );
$toggledField.removeClass( 'wpforms-filter-denylist' );
$builder.on( 'focusout', '.wpforms-field-option-row-allowlist textarea,.wpforms-field-option-row-denylist textarea', function() {
const $currentField = $( this );
if ( $currentField.val() === '' ) {
const $allowField = $( '.wpforms-field-option-row-allowlist textarea' ),
$denyField = $( '.wpforms-field-option-row-denylist textarea' );
if ( $currentField.is( $denyField ) ) {
wpforms_builder.ajax_url,
nonce: wpforms_builder.nonce,
allow: $allowField.val(),
action: 'wpforms_sanitize_restricted_rules',
$currentField.val( res.data.currentField );
const intersect = res.data.intersect;
if ( intersect.length !== 0 ) {
const content = '<p>' + wpforms_builder.allow_deny_lists_intersect + '</p>' +
'<p class="bold">' + intersect + '</p>';
title: wpforms_builder.heads_up,
icon: 'fa fa-exclamation-circle',
text: wpforms_builder.ok,
// On any click check if we had focusout event.
$builder.on( 'click', function() {
$builder.on( 'focusout', elements.defaultEmailSelector, function() {
elements.$focusOutTarget = $( this );
// Real-time updates for "Size" field option
$builder.on( 'change', '.wpforms-field-option-row-size select', function( e ) { // eslint-disable-line no-unused-vars
id = $this.parent().data( 'field-id' );
$( '#wpforms-field-' + id ).removeClass( 'size-small size-medium size-large' ).addClass( 'size-' + value );
// Real-time updates for "Placeholder" field option.
$builder.on( 'input', '.wpforms-field-option-row-placeholder input', function() { // eslint-disable-line complexity
id = $this.parent().data( 'field-id' ),
$preview = $( '#wpforms-field-' + id ),
$primary = $preview.find( '.primary-input' );
let value = wpf.sanitizeHTML( $this.val() );
// Single Item Field - if placeholder is cleared, set it to "price" placeholder.
if ( $preview.data( 'field-type' ) === 'payment-single' && value === '' ) {
value = $( '#wpforms-field-option-' + id + '-price' ).prop( 'placeholder' );
// Set the placeholder value for `input` fields.
if ( ! $primary.is( 'select' ) ) {
$primary.prop( 'placeholder', value );
if ( app.dropdownField.helpers.isModernSelect( $primary ) ) {
const choiceInstance = app.dropdownField.helpers.getInstance( $primary );
// Additional case for multiple select.
if ( $primary.prop( 'multiple' ) ) {
$( choiceInstance.input.element ).prop( 'placeholder', value );
choiceInstance.setChoiceByValue( '' );
$primary.closest( '.choices' ).find( '.choices__inner .choices__placeholder' ).text( value );
const isDynamicChoices = $( '#wpforms-field-option-' + id + '-dynamic_choices' ).val();
// We need to re-initialize modern dropdown to properly determine and update placeholder.
app.dropdownField.helpers.update( id, isDynamicChoices );
const $placeholder = $primary.find( '.placeholder' );
if ( ! value.length && $placeholder.length ) {
if ( $placeholder.length ) {
$placeholder.text( value );
$primary.prepend( '<option value="" class="placeholder">' + value + '</option>' );
$primary.find( '.placeholder' ).prop( 'selected', ! $primary.prop( 'multiple' ) );
// Real-time updates for "Confirmation Placeholder" field option
$builder.on( 'input', '.wpforms-field-option-row-confirmation_placeholder input', function( e ) { // eslint-disable-line no-unused-vars
id = $this.parent().data( 'field-id' );
$( '#wpforms-field-' + id ).find( '.secondary-input' ).attr( 'placeholder', value );
// Real-time updates for Date/Time, and Name "Placeholder" field options
$builder.on( 'input', '.wpforms-field-option .format-selected input.placeholder', function() {
const value = $this.val();
const $fieldOptionRow = $this.closest( '.wpforms-field-option-row' );
const id = $fieldOptionRow.data( 'field-id' );
const subfield = $fieldOptionRow.data( 'subfield' );
$( '#wpforms-field-' + id ).find( '.wpforms-' + subfield + ' input' ).attr( 'placeholder', value );
// Real-time updates for Address field "Placeholder" field options.
$builder.on( 'input', '.wpforms-field-option-address input.placeholder', function() {
const $fieldOptionRow = $this.closest( '.wpforms-field-option-row' );
const id = $fieldOptionRow.data( 'field-id' );
const subfield = $fieldOptionRow.data( 'subfield' );
const $fieldPreviews = $( '#wpforms-field-' + id + ' .wpforms-' + subfield ).find( 'input, select' );
const $default = $fieldOptionRow.find( '#wpforms-field-option-' + id + '-' + subfield + '_default' );
const defaultValue = $default.val();
const defaultText = $default.find( 'option:selected' ).text();
const placeholderValue = $this.val();
$fieldPreviews.each( function() {
const $fieldPreview = $( this );
if ( $fieldPreview.is( 'select' ) ) {
const $option = $fieldPreview.find( '.placeholder' );
const value = defaultValue === '' && placeholderValue !== '' ? placeholderValue : defaultText;
$fieldPreview.attr( 'placeholder', placeholderValue );
// Real-time updates for "Default" field option.
$builder.on( 'input', '.wpforms-field-option-row-default_value input', function() {
const value = wpf.sanitizeHTML( $this.val() );
const id = $this.closest( '.wpforms-field-option-row' ).data( 'field-id' );
const $preview = $( '#wpforms-field-' + id + ' .primary-input' );
// Real-time updates for "Default" field option of the Name and Address fields.
$builder.on( 'input', '.wpforms-field-options-column input.default', function() {
const value = wpf.sanitizeHTML( $this.val() );
const $fieldOptionRow = $this.closest( '.wpforms-field-option-row' );
const id = $fieldOptionRow.data( 'field-id' );
const subfield = $fieldOptionRow.data( 'subfield' );
const $fieldPreview = $( '#wpforms-field-' + id + ' .wpforms-' + subfield + ' input' );
$fieldPreview.val( value );
// Real-time updates for "Default" select field option of the Address field.
$builder.on( 'change', '.wpforms-field-option-address select.default', function() {
const value = $this.val();
const textValue = $this.find( 'option:selected' ).text();
const $fieldOptionRow = $this.closest( '.wpforms-field-option-row' );
const id = $fieldOptionRow.data( 'field-id' );
const subfield = $fieldOptionRow.data( 'subfield' );
const scheme = $( '#wpforms-field-option-' + id + '-scheme' ).val();
const $placeholder = $fieldOptionRow.find( '#wpforms-field-option-' + id + '-' + subfield + '_placeholder' );
const placeholderValue = $placeholder.val();
const $fieldPreview = $( '#wpforms-field-' + id + ' .wpforms-address-scheme-' + scheme + ' .wpforms-' + subfield + ' .placeholder' );
value === '' && placeholderValue.trim().length > 0
? $fieldPreview.text( placeholderValue )
: $fieldPreview.text( textValue );
// Real-time updates for "Confirmation Placeholder" field option
$builder.on( 'input', '.wpforms-field-option-row-confirmation_placeholder input', function( e ) { // eslint-disable-line no-unused-vars
id = $this.parent().data( 'field-id' );
$( '#wpforms-field-' + id ).find( '.secondary-input' ).attr( 'placeholder', value );
// Real-time updates for "Hide Label" field option.
$builder.on( 'change', '.wpforms-field-option-row-label_hide input', function( e ) { // eslint-disable-line no-unused-vars
const id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' );
$( '#wpforms-field-' + id ).toggleClass( 'label_hide' );
// Real-time updates for a Sub Label visibility field option.
$builder.on( 'change', '.wpforms-field-option-row-sublabel_hide input', function( e ) { // eslint-disable-line no-unused-vars
const id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' );
$( '#wpforms-field-' + id ).toggleClass( 'sublabel_hide' );
// Real-time updates for a Quantity visibility field option.
$builder.on( 'change', '.wpforms-field-option-row-enable_quantity input', function() {
const id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' ),
$preview = $( `#wpforms-field-${ id }` );
$( `#wpforms-field-option-row-${ id }-quantity` ).toggleClass( 'wpforms-hidden' );
$preview.find( '.quantity-input' ).toggleClass( 'wpforms-hidden' );
$preview.toggleClass( 'payment-quantity-enabled' );
// Real-time updates for Quantity preview minimum value.
$builder.on( 'input', '.wpforms-field-option-row-quantity input', function() {
// Allow only a positive integer value less than 9999.
$this.val( Math.min( Math.abs( Math.round( $this.val() ) ), 9999 ) );
const $optionRow = $this.closest( '.wpforms-field-option-row' ),
id = $optionRow.data( 'field-id' ),
isMinInput = $this.hasClass( 'min-quantity-input' ),
$minInput = $optionRow.find( '.min-quantity-input' ),
$maxInput = $optionRow.find( '.max-quantity-input' );
$( '#wpforms-field-' + id ).find( '.quantity-input option' ).text( $this.val() );
$minInput.toggleClass( 'wpforms-error', parseInt( $minInput.val(), 10 ) > parseInt( $maxInput.val(), 10 ) );
// Real-time updates for Date/Time, Name and Single Item "Format" option.
$builder.on( 'change', '.wpforms-field-option-row-format select', function() {
id = $this.parent().data( 'field-id' ),
$sublabelToggle = $( '#wpforms-field-option-row-' + id + '-sublabel_hide' ),
$preview = $( '#wpforms-field-' + id );
$preview.find( '.format-selected' ).removeClass().addClass( 'format-selected format-selected-' + value );
$( '#wpforms-field-option-' + id ).find( '.format-selected' ).removeClass().addClass( 'format-selected format-selected-' + value );
// Show toggle for "Hide Sub labels" only when the field consists of more than one subfield.
if ( [ 'date-time', 'first-last', 'first-middle-last' ].includes( value ) ) {
$sublabelToggle.removeClass( 'wpforms-hidden' );
$sublabelToggle.addClass( 'wpforms-hidden' );
// Hide the label field if it's not a single item.
$( `#wpforms-field-option-row-${ id }-price_label` ).toggleClass( 'wpforms-hidden', value !== 'single' );
// Toggle options based on Single Item "Format".
if ( [ 'single', 'user', 'hidden' ].includes( value ) ) {
const isUserDefined = value === 'user',
isSingle = value === 'single',
isHidden = value === 'hidden',
isQuantityEnabled = $( '#wpforms-field-option-' + id + '-enable_quantity' ).is( ':checked' ),
$minPriceOption = $( '#wpforms-field-option-' + id + '-min_price' ),
minPrice = wpf.amountSanitize( $minPriceOption.val() ),
isValidMinPrice = minPrice >= $minPriceOption.data( 'minimum-price' ),
$minPriceOptionRow = $( '#wpforms-field-option-row-' + id + '-min_price' );
// Toggle Placeholder option.
$( '#wpforms-field-option-row-' + id + '-placeholder' ).toggleClass( 'wpforms-hidden', ! isUserDefined );
// Toggle Quantity options.
$( '#wpforms-field-option-row-' + id + '-enable_quantity' ).toggleClass( 'wpforms-hidden', ! isSingle );
$( '#wpforms-field-option-row-' + id + '-quantities_alert' ).toggleClass( 'wpforms-hidden', ! isSingle );
$( '#wpforms-field-option-row-' + id + '-quantity' ).toggleClass( 'wpforms-hidden', ! isSingle || ! isQuantityEnabled );
$preview.find( '.quantity-input' ).toggleClass( 'wpforms-hidden', ! isSingle || ! isQuantityEnabled );
// Toggle Minimum Price options.
$minPriceOptionRow.toggleClass( 'wpforms-hidden', ! isUserDefined );
$minPriceOptionRow.find( '.wpforms-item-minimum-price-alert' ).toggleClass( 'wpforms-hidden', isValidMinPrice );
$preview.find( '.item-min-price' ).toggleClass( 'wpforms-hidden', isUserDefined && minPrice <= 0 );
$preview.toggleClass( 'min-price-warning', ! isValidMinPrice );
$preview.find( '.fa-exclamation-triangle' ).toggleClass( 'wpforms-hidden', isValidMinPrice );
$( `#wpforms-field-${ id } .item-price-single` ).toggleClass( 'wpforms-hidden', ! isSingle );
$( `#wpforms-field-${ id } .item-price-hidden` ).toggleClass( 'wpforms-hidden', ! isHidden );
// Real-time updates specific for Address "Scheme" option
$builder.on( 'change', '.wpforms-field-option-row-scheme select', function( e ) { // eslint-disable-line no-unused-vars
const value = $this.val();
const fieldId = $this.parent().data( 'field-id' );
const $fieldPreview = $( `#wpforms-field-${ fieldId }` );
const $stateOption = $( `#wpforms-field-option-row-${ fieldId }-state` );
const $countryOption = $( `#wpforms-field-option-row-${ fieldId }-country` );
// Switch the scheme in a Preview panel.
$fieldPreview.find( '.wpforms-address-scheme' ).addClass( 'wpforms-hide' );
$fieldPreview.find( `.wpforms-address-scheme-${ value }` ).removeClass( 'wpforms-hide' );
// Show an or hide country option depending on the scheme.
const $countryPreviewField = $fieldPreview.find( `.wpforms-address-scheme-${ value } .wpforms-country select, .wpforms-address-scheme-${ value } .wpforms-country input` );
$countryPreviewField.length === 0
? $countryOption.addClass( 'wpforms-hidden' )
: $countryOption.removeClass( 'wpforms-hidden' );
// Inputs/selects for a currently selected scheme and the one that we're changing to.
const $currentState = $stateOption.find( '.default .default' ).not( '.wpforms-hidden-strict' );
const $newState = $stateOption.find( `.default [data-scheme="${ value }"]` );
const $currentCountry = $countryOption.find( '.default .default' ).not( '.wpforms-hidden-strict' );
const $newCountry = $countryOption.find( `.default [data-scheme="${ value }"]` );
// Switch the state field type in options to match the scheme.
id: $currentState.attr( 'id' ),
name: $currentState.attr( 'name' ),
} ).removeClass( 'wpforms-hidden-strict' );
$currentState.attr( { id: '', name: '' } ).addClass( 'wpforms-hidden-strict' );
id: $currentCountry.attr( 'id' ),
name: $currentCountry.attr( 'name' ),