: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
? $label.after( smartTagList )
: $el.after( smartTagList );
$el.find( 'span' ).text( wpforms_builder.smart_tags_hide );
$wrapper.find( '.smart-tags-list-display' ).slideDown( '', function() {
$el.addClass( 'smart-tag-showing' );
$wrapper.removeClass( 'smart-tags-toggling' );
* Get Smart Tag list markup.
* @param {jQuery} $el Toggle element.
* @param {boolean} isFieldOption Is a field option.
* @return {string} Smart Tags list markup.
getSmartTagsList( $el, isFieldOption ) {
smartTagList = '<ul class="smart-tags-list-display unfoldable-cont">';
smartTagList += app.getSmartTagsListFieldsElements( $el );
smartTagList += app.getSmartTagsListOtherElements( $el, isFieldOption );
* Get Smart Tag fields elements markup.
* @param {jQuery} $el Toggle element.
* @return {string} Smart Tags list elements markup.
getSmartTagsListFieldsElements( $el ) {
const type = $el.data( 'type' );
if ( ! [ 'fields', 'all' ].includes( type ) ) {
const fields = app.getSmartTagsFields( $el );
return '<li class="heading">' + wpforms_builder.fields_unavailable + '</li>';
let smartTagListElements = '';
smartTagListElements += '<li class="heading">' + wpforms_builder.fields_available + '</li>';
for ( const fieldKey in wpf.orders.fields ) {
const fieldId = wpf.orders.fields[ fieldKey ];
if ( ! fields[ fieldId ] ) {
smartTagListElements += app.getSmartTagsListFieldsElement( fields[ fieldId ] );
return smartTagListElements;
* Get fields that possible to create smart tag.
* @param {jQuery} $el Toggle element.
* @return {Array} Fields for smart tags.
getSmartTagsFields( $el ) {
const allowed = $el.data( 'fields' );
const isAllowedRepeater = $el.data( 'allow-repeated-fields' );
const allowedFields = allowed ? allowed.split( ',' ) : undefined;
return wpf.getFields( allowedFields, true, isAllowedRepeater );
* Get field markup for the Smart Tags list.
* @param {Object} field A field.
* @return {string} Smart Tags field markup.
getSmartTagsListFieldsElement( field ) {
const label = field.label
? wpf.encodeHTMLEntities( wpf.sanitizeHTML( field.label ) )
: wpforms_builder.field + ' #' + field.id;
return '<li><a href="#" data-type="field" data-meta=\'' + field.id + '\'>' + label + '</a></li>';
* Get Smart Tag other elements markup.
* @param {jQuery} $el Toggle element.
* @param {boolean} isFieldOption Is a field option.
* @return {string} Smart Tags list elements markup.
getSmartTagsListOtherElements( $el, isFieldOption ) {
const type = $el.data( 'type' );
let smartTagListElements;
if ( type !== 'other' && type !== 'all' ) {
smartTagListElements = '<li class="heading">' + wpforms_builder.other + '</li>';
for ( const smartTagKey in wpforms_builder.smart_tags ) {
if ( isFieldOption && wpforms_builder.smart_tags_disabled_for_fields.indexOf( smartTagKey ) > -1 ) {
smartTagListElements += '<li><a href="#" data-type="other" data-meta=\'' + smartTagKey + '\'>' + wpforms_builder.smart_tags[ smartTagKey ] + '</a></li>';
return smartTagListElements;
* @since 1.6.9 TinyMCE compatibility.
* @param {Event} e Event.
smartTagInsert( e ) { // eslint-disable-line complexity
$list = $this.closest( '.smart-tags-list-display' ),
$wrapper = $list.closest( '.wpforms-panel-field,.wpforms-field-option-row' ),
$toggle = $wrapper.find( '.toggle-smart-tag-display' ),
$input = $wrapper.find( 'input[type=text], textarea' ),
meta = $this.data( 'meta' ),
type = $this.data( 'type' );
let smartTag = type === 'field' ? '{field_id="' + meta + '"}' : '{' + meta + '}',
if ( typeof tinyMCE !== 'undefined' ) {
editor = tinyMCE.get( $input.prop( 'id' ) );
if ( editor && ! editor.hasFocus() ) {
if ( editor && ! editor.isHidden() ) {
editor.insertContent( smartTag );
smartTag = ' ' + smartTag + ' ';
$input.insertAtCaret( smartTag );
// Remove redundant spaces after wrapping smartTag into spaces.
$input.val( $input.val().trim().replace( ' ', ' ' ) );
$input.trigger( 'focus' ).trigger( 'input' );
// Remove the list, all done!
$list.slideUp( '', function() {
$toggle.find( 'span' ).text( wpforms_builder.smart_tags_show );
$wrapper.find( '.toggle-smart-tag-display' ).removeClass( 'smart-tag-showing' );
* Field map table - Delete row.
* @since 1.6.1.2 Registered `wpformsFieldMapTableDeletedRow` trigger.
* @param {Event} e Event.
* @param {Element} el Element.
fieldMapTableDeleteRow( e, el ) {
$row = $this.closest( 'tr' ),
$table = $this.closest( 'table' ),
$block = $row.closest( '.wpforms-builder-settings-block' ),
total = $table.find( 'tr' ).length;
$builder.trigger( 'wpformsFieldMapTableDeletedRow', [ $block ] );
* Field map table - Add row.
* @since 1.6.1.2 Registered `wpformsFieldMapTableAddedRow` trigger.
* @param {Event} e Event.
* @param {Element} el Element.
fieldMapTableAddRow( e, el ) {
$row = $this.closest( 'tr' ),
$block = $row.closest( '.wpforms-builder-settings-block' ),
choice = $row.clone().insertAfter( $row );
choice.find( 'input' ).val( '' );
choice.find( 'select :selected' ).prop( 'selected', false );
choice.find( '.key-destination' ).attr( 'name', '' );
$builder.trigger( 'wpformsFieldMapTableAddedRow', [ $block, choice ] );
* Update field mapped select items on form updates.
* @since 1.6.1.2 Registered `wpformsFieldSelectMapped` trigger.
* @param {Event} e Event.
* @param {Object} fields Fields.
fieldMapSelect( e, fields ) { // eslint-disable-line max-lines-per-function
$( '.wpforms-field-map-select' ).each( function( index, el ) { // eslint-disable-line complexity, no-unused-vars
let allowedFields = $this.data( 'field-map-allowed' ),
placeholder = $this.data( 'field-map-placeholder' );
// Check if custom placeholder was provided.
if ( typeof placeholder === 'undefined' || ! placeholder ) {
placeholder = wpforms_builder.select_field;
// If allowed, fields are not defined, bail.
if ( typeof allowedFields !== 'undefined' && allowedFields ) {
allowedFields = allowedFields.split( ' ' );
const selected = $this.find( 'option:selected' ).val();
// Reset select and add a placeholder option.
$this.empty().append( $( '<option>', { value: '', text: placeholder } ) );
// Loop through the current fields, if we have fields for the form.
if ( fields && ! $.isEmptyObject( fields ) ) {
for ( const key in wpf.orders.fields ) {
if ( ! Object.prototype.hasOwnProperty.call( wpf.orders.fields, key ) ) {
const fieldID = wpf.orders.fields[ key ];
if ( ! fields[ fieldID ] ) {
if ( typeof fields[ fieldID ].label !== 'undefined' && fields[ fieldID ].label.toString().trim() !== '' ) {
label = wpf.sanitizeHTML( fields[ fieldID ].label.toString().trim() );
label = wpforms_builder.field + ' #' + fieldID;
// Add to select if it is a field type allowed.
if ( $.inArray( fields[ fieldID ].type, allowedFields ) >= 0 || $.inArray( 'all-fields', allowedFields ) >= 0 ) {
$this.append( $( '<option>', { value: fields[ fieldID ].id, text: label } ) );
// Restore previous value if found.
$this.find( 'option[value="' + selected + '"]' ).prop( 'selected', true );
// Add a "Custom Value" option if it is supported.
const customValueSupport = $this.data( 'custom-value-support' );
if ( typeof customValueSupport === 'boolean' && customValueSupport ) {
text: wpforms_builder.add_custom_value_label,
class: 'wpforms-field-map-option-custom-value',
$builder.trigger( 'wpformsFieldSelectMapped', [ $this ] );
* Validate email smart tags in Notifications fields.
* @param {Object} $el Input field to check the value for.
validateEmailSmartTags( $el ) {
// Turns '{email@domain.com}' into 'email@domain.com'.
// Email RegEx inspired by http://emailregex.com
val = val.replace( /{(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))}/g, function( x ) {
* Validate From Email in Notification block.
const $field = $( this );
const value = $field.val().trim();
const $fieldWrapper = $field.parent();
const $warning = $fieldWrapper.find( '.wpforms-alert-warning-wide' );
const warningClass = 'wpforms-panel-field-warning';
const blockedSymbolsRegex = /[\s,;]/g;
if ( blockedSymbolsRegex.test( value ) ) {
$fieldWrapper.addClass( warningClass );
app.validationErrorNotificationPopup( wpforms_builder.allow_only_one_email );
form_id: s.formID, // eslint-disable-line camelcase
nonce: wpforms_builder.nonce,
action: 'wpforms_builder_notification_from_email_validate',
wpforms_builder.ajax_url, data, function( res ) {
$fieldWrapper.removeClass( warningClass );
$fieldWrapper.addClass( warningClass );
$warning.replaceWith( res.data );
$fieldWrapper.append( res.data );
.fail( function( xhr, textStatus, e ) { // eslint-disable-line no-unused-vars
// eslint-disable-next-line no-console
console.log( xhr.responseText );
//--------------------------------------------------------------------//
//--------------------------------------------------------------------//
* Icon Choices component.
* Runtime component cache.
* Field "toggle": "Use icon choices" toggle that initiated the installation.
* Field "previousModal": Last open modal that may need to be closed.
* Component configuration settings.
colorPropertyName: '--wpforms-icon-choices-color',
* Initialize the component.
// Extend jquery-confirm plugin with max-height support for the content area.
app.iconChoices.extendJqueryConfirm();
$builder.on( 'wpformsBuilderReady', function( event ) {
// If there are Icon Choices fields but the library is not installed - force install prompt.
if ( wpforms_builder.icon_choices.is_active && ! wpforms_builder.icon_choices.is_installed ) {
app.iconChoices.openInstallPromptModal( true );
// Prevent the Form Builder from getting ready (hold the loading state).
// Toggle Icon Choices on or off.
$builder.on( 'change', '.wpforms-field-option-row-choices_icons input', app.iconChoices.toggleIconChoices );
$builder.on( 'change', '.wpforms-field-option-row-choices_icons_color .wpforms-color-picker', app.iconChoices.changeIconsColor );
// Update field preview when option value is changed (style, size).
$builder.on( 'change', '.wpforms-field-option-row-choices_icons_style select, .wpforms-field-option-row-choices_icons_size select', function() {
const fieldID = $( this ).parent().data( 'field-id' ),
fieldType = $( '#wpforms-field-option-' + fieldID ).find( '.wpforms-field-option-hidden-type' ).val();
app.fieldChoiceUpdate( fieldType, fieldID );
// Open Icon Picker modal.
$builder.on( 'click', '.wpforms-field-option-row-choices .choices-list .wpforms-icon-select', app.iconChoices.openIconPickerModal );
* Turn the feature on or off.
toggleIconChoices() { // eslint-disable-line complexity
checked = $this.is( ':checked' );
// Check if a required icon library is installed.
if ( checked && ! wpforms_builder.icon_choices.is_installed ) {
app.iconChoices.cache.toggle = $this;
app.iconChoices.openInstallPromptModal();
const fieldID = $this.closest( '.wpforms-field-option-row' ).data( 'field-id' );
const $fieldOptions = $( `#wpforms-field-option-${ fieldID }` ),
$imageChoices = $fieldOptions.find( `#wpforms-field-option-${ fieldID }-choices_images` ),
$choicesList = $fieldOptions.find( `#wpforms-field-option-row-${ fieldID }-choices ul` );
// Turn Image Choice off.
if ( checked && $imageChoices.is( ':checked' ) ) {
$imageChoices.prop( 'checked', false ).trigger( 'change' );
// Toggle Advanced > Dynamic Choices on or off.
$fieldOptions.find( `#wpforms-field-option-row-${ fieldID }-dynamic_choices` ).toggleClass( 'wpforms-hidden', checked );
$fieldOptions.find( `#wpforms-field-option-row-${ fieldID }-choices_icons_color` ).toggleClass( 'wpforms-hidden' );
$fieldOptions.find( `#wpforms-field-option-row-${ fieldID }-choices_icons_size` ).toggleClass( 'wpforms-hidden' );
$fieldOptions.find( `#wpforms-field-option-row-${ fieldID }-choices_icons_style` ).toggleClass( 'wpforms-hidden' );
const $colorOption = $fieldOptions.find( `#wpforms-field-option-${ fieldID }-choices_icons_color` ),
colorValue = _.isEmpty( $colorOption.val() ) ? wpforms_builder.icon_choices.default_color : $colorOption.val();
// Set accent color for all choices.
$choicesList.prop( 'style', `${ app.iconChoices.config.colorPropertyName }: ${ colorValue };` );
// Toggle icon selectors with previews for all choices.
$choicesList.toggleClass( 'show-icons', checked );