: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
/* global wpforms_builder, wpforms_builder_providers, wpf */
var WPForms = window.WPForms || {};
WPForms.Admin = WPForms.Admin || {};
WPForms.Admin.Builder = WPForms.Admin.Builder || {};
* WPForms Providers module.
WPForms.Admin.Builder.Providers = WPForms.Admin.Builder.Providers || ( function( document, window, $ ) {
* Private functions and properties.
* Internal cache storage, do not use it directly, but app.cache.{(get|set|delete|clear)()} instead.
* Key is the provider slug, value is a Map, that will have its own key as a connection id (or not).
* @type {Object.<string, Map>}
* Config contains all configuration properties.
* @type {Object.<string, *>}
* List of default templates that should be compiled.
'wpforms-providers-builder-content-connection-fields',
'wpforms-providers-builder-content-connection-conditionals',
* Form fields for the current state.
* Public functions and properties.
form: $( '#wpforms-builder-form' ),
spinner: '<i class="wpforms-loading-spinner wpforms-loading-inline"></i>',
* All ajax requests are grouped together with own properties.
* Merge custom AJAX data object with defaults.
* @since 1.5.9 Added a new parameter - provider
* @param {string} provider Current provider slug.
* @param {object} custom Ajax data object with custom settings.
* @returns {object} Ajax data.
_mergeData: function( provider, custom ) {
id: app.form.data( 'id' ),
// eslint-disable-next-line camelcase
revision_id: app.form.data( 'revision' ),
nonce: wpforms_builder.nonce,
action: 'wpforms_builder_provider_ajax_' + provider,
$.extend( data, custom );
* Make an AJAX request. It's basically a wrapper around jQuery.ajax, but with some defaults.
* @param {string} provider Current provider slug.
* @param {*} custom Object of user-defined $.ajax()-compatible parameters.
request: function( provider, custom ) {
var $holder = app.getProviderHolder( provider ),
$lock = $holder.find( '.wpforms-builder-provider-connections-save-lock' ),
$error = $holder.find( '.wpforms-builder-provider-connections-error' );
url: wpforms_builder.ajax_url,
$holder.addClass( 'loading' );
custom.data = app.ajax._mergeData( provider, custom.data || {} );
$.extend( params, custom );
.fail( function( jqXHR, textStatus, errorThrown ) {
* Right now we are logging into browser console.
* In future that might be something better.
console.error( 'provider:', provider );
console.error( textStatus );
.always( function( dataOrjqXHR, textStatus, jqXHROrerrorThrown ) {
$holder.removeClass( 'loading' );
if ( 'success' === textStatus ) {
// Update the cache when the provider data is unlocked.
wpf.savedState = wpf.getFormState( '#wpforms-builder-form' );
* Temporary in-memory cache handling for all providers.
* Get the value from cache by key.
* @since 1.5.9 Added a new parameter - provider.
* @param {string} provider Current provider slug.
* @param {string} key Cache key.
* @returns {*} Null if some error occurs.
get: function( provider, key ) {
typeof __private.cache[ provider ] === 'undefined' ||
! ( __private.cache[ provider ] instanceof Map )
return __private.cache[ provider ].get( key );
* Get the value from cache by key and an ID.
* Useful when Object is stored under key, and we need specific value.
* @since 1.5.9 Added a new parameter - provider.
* @param {string} provider Current provider slug.
* @param {string} key Cache key.
* @param {string} id Cached object ID.
* @returns {*} Null if some error occurs.
getById: function( provider, key, id ) {
if ( typeof this.get( provider, key )[ id ] === 'undefined' ) {
return this.get( provider, key )[ id ];
* Save the data to cache.
* @since 1.5.9 Added a new parameter - provider.
* @param {string} provider Current provider slug.
* @param {string} key Intended to be a string, but can be everything that Map supports as a key.
* @param {*} value Data you want to save in cache.
* @returns {Map} All the cache for the provider. IE11 returns 'undefined' for an undefined reason.
set: function( provider, key, value ) {
typeof __private.cache[ provider ] === 'undefined' ||
! ( __private.cache[ provider ] instanceof Map )
__private.cache[ provider ] = new Map();
return __private.cache[ provider ].set( key, value );
* Add the data to cache to a particular key.
* @since 1.5.9 Added a new parameter - provider.
* @example app.cache.as('provider').addTo('connections', connection_id, connection);
* @param {string} provider Current provider slug.
* @param {string} key Intended to be a string, but can be everything that Map supports as a key.
* @param {string} id ID for a value that should be added to a certain key.
* @param {*} value Data you want to save in cache.
* @returns {Map} All the cache for the provider. IE11 returns 'undefined' for an undefined reason.
addTo: function( provider, key, id, value ) {
typeof __private.cache[ provider ] === 'undefined' ||
! ( __private.cache[ provider ] instanceof Map )
__private.cache[ provider ] = new Map();
this.set( provider, key, {} );
var data = this.get( provider, key );
* Delete the cache by key.
* @since 1.5.9 Added a new parameter - provider.
* @param {string} provider Current provider slug.
* @param {string} key Cache key.
* @returns boolean|null True on success, null on data holder failure, false on error.
delete: function( provider, key ) {
typeof __private.cache[ provider ] === 'undefined' ||
! ( __private.cache[ provider ] instanceof Map )
return __private.cache[ provider ].delete( key );
* Delete particular data from a certain key.
* @since 1.5.9 Added a new parameter - provider.
* @example app.cache.as('provider').deleteFrom('connections', connection_id);
* @param {string} provider Current provider slug.
* @param {string} key Intended to be a string, but can be everything that Map supports as a key.
* @param {string} id ID for a value that should be deleted from a certain key.
* @returns {Map} All the cache for the provider. IE11 returns 'undefined' for an undefined reason.
deleteFrom: function( provider, key, id ) {
typeof __private.cache[ provider ] === 'undefined' ||
! ( __private.cache[ provider ] instanceof Map )
var data = this.get( provider, key );
* Clear all the cache data.
* @since 1.5.9 Added a new parameter - provider.
* @param {string} provider Current provider slug.
clear: function( provider ) {
typeof __private.cache[ provider ] === 'undefined' ||
! ( __private.cache[ provider ] instanceof Map )
__private.cache[ provider ].clear();
* Start the engine. DOM is not ready yet, use only to init something.
// Do that when DOM is ready.
* Should be hooked into in addons, that need to work with DOM, templates etc.
* @since 1.6.1.2 Added initialization for `__private.fields` property.
// Save a current form fields state.
__private.fields = $.extend( {}, wpf.getFields( false, true ) );
app.panelHolder = $( '#wpforms-panel-providers, #wpforms-panel-settings' );
app.Templates = WPForms.Admin.Builder.Templates;
app.Templates.add( __private.config.templates );
app.panelHolder.trigger( 'WPForms.Admin.Builder.Providers.ready' );
* Process all generic actions/events, mostly custom that were fired by our API.
* @since 1.6.1.2 Added a calling `app.updateMapSelects()` method.
bindActions: function() {
// On Form save - notify user about required fields.
$( document ).on( 'wpformsSaved', function() {
var $connectionBlocks = app.panelHolder.find( '.wpforms-builder-provider-connection' );
if ( ! $connectionBlocks.length ) {
// We need to show him "Required fields empty" popup only once.
$connectionBlocks.each( function() {
var isRequiredEmpty = false;
// Do the actual required fields check.
$( this ).find( 'input.wpforms-required, select.wpforms-required, textarea.wpforms-required' ).each( function() {
if ( _.isEmpty( value ) && ! $this.closest( '.wpforms-builder-provider-connection-block' ).hasClass( 'wpforms-hidden' ) ) {
$( this ).addClass( 'wpforms-error' );
$( this ).removeClass( 'wpforms-error' );
if ( isRequiredEmpty && ! isShownOnce ) {
var $titleArea = $( this ).closest( '.wpforms-builder-provider' ).find( '.wpforms-builder-provider-title' ).clone();
$titleArea.find( 'button' ).remove();
var msg = wpforms_builder.provider_required_flds;
title: wpforms_builder.heads_up,
content: msg.replace( '{provider}', '<strong>' + $titleArea.text().trim() + '</strong>' ),
icon: 'fa fa-exclamation-circle',
text: wpforms_builder.ok,
// Save that we have already showed the user, so we won't bug it anymore.
// On "Fields" page additional update provider's field mapped items.
if ( 'fields' === wpf.getQueryString( 'view' ) ) {
app.updateMapSelects( $connectionBlocks );
* Update form state when each connection is loaded into the DOM.
* This will prevent a please-save-prompt to appear, when navigating
* out and back to Marketing tab without doing any changes anywhere.
app.panelHolder.on( 'connectionRendered', function() {
if ( wpf.initialSave === true ) {
wpf.savedState = wpf.getFormState( '#wpforms-builder-form' );