Snapshot: MLS sync fixes, image refresh, plugin/theme updates
MLS plugin fixes from this session: - Fix silent insert failures: location column NOT NULL was rejecting wpdb->insert calls, causing ~18k new properties since Dec 2025 to be lost. Inserts now build raw SQL with ST_PointFromText so the spatial column is populated atomically. - Auto-refresh expired media URLs in MLS_Media_Handler::fetch_and_cache(), guarded by a property-level GET_LOCK so concurrent fetches share one API refresh. - Normalize WP_Error to null in mls_get_property_image() so callers can rely on the documented string|null contract. - Support comma-separated property_type filters in MLS_Query and MLS_Cluster so the homepage "View All Commercial" link (?property_type=Commercial+Sale,Land,Farm) actually filters correctly. - Incremental sync now looks back 10 minutes past the latest modification timestamp as a safety margin against missed records. - Smart sync exits silently (info-level, not warning) when a full sync is in progress. Operational: - New cron: weekly full sync Sundays at 3 AM (/usr/local/bin/mls-full-sync). - New cron: hourly 2GB cap on mls-thumbnails/ and cache/transformed-images/ (/usr/local/bin/mls-image-cache-cap). - Logrotate config for wp-content/debug.log (2-day retention, daily rotation, delaycompress). Repo policy: - CLAUDE.md updated with explicit "commit everything except build artifacts" policy. - .gitignore: untrack runtime image caches and debug.log rotations. Other modifications in this snapshot are pre-existing in-flight theme/plugin/db_content_updates work. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+249
@@ -0,0 +1,249 @@
|
||||
/* global wpf, WPFormsBuilder, WPFormsConstantContactV3AuthVars */
|
||||
|
||||
/**
|
||||
* @param window.wpforms_admin
|
||||
* @param window.wpforms_builder
|
||||
* @param WPFormsConstantContactV3AuthVars.auth_url
|
||||
*/
|
||||
|
||||
/**
|
||||
* WPForms Constant Contact V3 Popup.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
const WPFormsConstantContactV3Auth = window.WPFormsConstantContactV3Auth || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
/**
|
||||
* Is the authorization window opened?
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
isOpened : false,
|
||||
|
||||
/**
|
||||
* URL to listen for messages from the window.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
listenURL: '',
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
init: () => {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
ready: () => {
|
||||
const redirectUri = new URL( WPFormsConstantContactV3AuthVars.auth_url ).searchParams.get( 'redirect_uri' );
|
||||
app.listenURL = new URL( redirectUri ).origin;
|
||||
|
||||
$( document )
|
||||
.on( 'click', '.wpforms-constant-contact-v3-auth, .wpforms-builder-constant-contact-v3-provider-sign-up', app.showWindow )
|
||||
.on( 'click', '#wpforms-settings-constant-contact-v3-migration-prompt-link', app.promptMigration );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a window.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {Event} e Click event.
|
||||
*/
|
||||
showWindow: ( e ) => {
|
||||
e.preventDefault();
|
||||
|
||||
if ( app.isOpened ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const authUrl = WPFormsConstantContactV3AuthVars.auth_url,
|
||||
width = 500,
|
||||
height = 600,
|
||||
left = ( screen.width / 2 ) - ( width / 2 ),
|
||||
top = ( screen.height / 2 ) - ( height / 2 ),
|
||||
loginHintEmail = $( '.wpforms-constant-contact-v3-auth' ).data( 'login-hint' ),
|
||||
url = new URL( authUrl );
|
||||
|
||||
if ( loginHintEmail ) {
|
||||
url.searchParams.set( 'login_hint', loginHintEmail );
|
||||
}
|
||||
|
||||
const newWindow = window.open(
|
||||
url.toString(),
|
||||
'authPopup',
|
||||
'width=' + width + ', height=' + height + ', top=' + top + ', left=' + left
|
||||
);
|
||||
|
||||
window.addEventListener( 'message', app.listenResponse );
|
||||
const checkWindowClosed = setInterval( () => {
|
||||
if ( newWindow.closed ) {
|
||||
clearInterval( checkWindowClosed );
|
||||
app.isOpened = false;
|
||||
}
|
||||
}, 1000 );
|
||||
|
||||
app.isOpened = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Listen for response.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {Event} event Message event.
|
||||
*/
|
||||
listenResponse: ( event ) => {
|
||||
if ( event.origin !== app.listenURL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! event.data ) {
|
||||
app.errorModal( WPFormsConstantContactV3AuthVars.strings.error );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.saveAccount( event.data );
|
||||
},
|
||||
|
||||
/**
|
||||
* Save account.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {string} code Authorization code.
|
||||
*/
|
||||
saveAccount: ( code ) => {
|
||||
const modal = app.waitModal();
|
||||
|
||||
$.post(
|
||||
WPFormsConstantContactV3AuthVars.ajax_url,
|
||||
{
|
||||
action: 'wpforms_constant_contact_popup_auth',
|
||||
data: JSON.stringify( { code } ),
|
||||
nonce: WPFormsConstantContactV3AuthVars.nonce,
|
||||
}
|
||||
)
|
||||
.done( ( response ) => {
|
||||
if ( ! response.success ) {
|
||||
modal.close();
|
||||
|
||||
const errorMessage =
|
||||
'<p>' + WPFormsConstantContactV3AuthVars.strings.error + '</p><p><strong>' + wpf.sanitizeHTML( response.data ) + '</strong></p>';
|
||||
|
||||
app.errorModal( errorMessage );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( typeof WPFormsBuilder === 'undefined' ) {
|
||||
modal.close();
|
||||
window.location.href = WPFormsConstantContactV3AuthVars.page_url;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
WPFormsBuilder.formSave( false ).done( () => {
|
||||
WPFormsBuilder.setCloseConfirmation( false );
|
||||
WPFormsBuilder.showLoadingOverlay();
|
||||
location.reload();
|
||||
} );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a waiting modal.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @return {Object} Modal object.
|
||||
*/
|
||||
waitModal: () => {
|
||||
return $.alert( {
|
||||
title: '',
|
||||
content: WPFormsConstantContactV3AuthVars.strings.wait,
|
||||
icon: 'fa fa-info-circle',
|
||||
type: 'blue',
|
||||
buttons: false,
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show an error modal.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {string} content Alert text.
|
||||
*
|
||||
* @return {Object} Modal object.
|
||||
*/
|
||||
errorModal: ( content ) => {
|
||||
const strings = window?.wpforms_builder || window?.wpforms_admin;
|
||||
|
||||
return $.alert( {
|
||||
title: strings.uh_oh,
|
||||
content,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'red',
|
||||
buttons: {
|
||||
cancel: {
|
||||
text: strings.cancel,
|
||||
action: () => {
|
||||
app.isOpened = false;
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Prompt and start migration from v2 to v3 in the notice.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {Object} e Event object.
|
||||
*/
|
||||
promptMigration( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
const modal = app.waitModal();
|
||||
|
||||
$.post( {
|
||||
url: WPFormsConstantContactV3AuthVars.ajax_url,
|
||||
data: {
|
||||
action: 'wpforms_constant_contact_migration_prompt',
|
||||
nonce: WPFormsConstantContactV3AuthVars.nonce,
|
||||
},
|
||||
success: () => {
|
||||
modal.close();
|
||||
window.location.href = WPFormsConstantContactV3AuthVars.page_url;
|
||||
},
|
||||
error: () => {
|
||||
modal.close();
|
||||
app.errorModal( WPFormsConstantContactV3AuthVars.strings.error );
|
||||
},
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsConstantContactV3Auth.init();
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
let WPFormsConstantContactV3Auth=window.WPFormsConstantContactV3Auth||((o,s,i)=>{let c={isOpened:!1,listenURL:"",init:()=>{i(c.ready)},ready:()=>{var t=new URL(WPFormsConstantContactV3AuthVars.auth_url).searchParams.get("redirect_uri");c.listenURL=new URL(t).origin,i(o).on("click",".wpforms-constant-contact-v3-auth, .wpforms-builder-constant-contact-v3-provider-sign-up",c.showWindow).on("click","#wpforms-settings-constant-contact-v3-migration-prompt-link",c.promptMigration)},showWindow:n=>{if(n.preventDefault(),!c.isOpened){var n=WPFormsConstantContactV3AuthVars.auth_url,a=screen.width/2-250,r=screen.height/2-300,e=i(".wpforms-constant-contact-v3-auth").data("login-hint"),n=new URL(n);e&&n.searchParams.set("login_hint",e);let t=s.open(n.toString(),"authPopup","width=500, height=600, top="+r+", left="+a),o=(s.addEventListener("message",c.listenResponse),setInterval(()=>{t.closed&&(clearInterval(o),c.isOpened=!1)},1e3));c.isOpened=!0}},listenResponse:t=>{t.origin===c.listenURL&&(t.data?c.saveAccount(t.data):c.errorModal(WPFormsConstantContactV3AuthVars.strings.error))},saveAccount:t=>{let o=c.waitModal();i.post(WPFormsConstantContactV3AuthVars.ajax_url,{action:"wpforms_constant_contact_popup_auth",data:JSON.stringify({code:t}),nonce:WPFormsConstantContactV3AuthVars.nonce}).done(t=>{t.success?"undefined"==typeof WPFormsBuilder?(o.close(),s.location.href=WPFormsConstantContactV3AuthVars.page_url):WPFormsBuilder.formSave(!1).done(()=>{WPFormsBuilder.setCloseConfirmation(!1),WPFormsBuilder.showLoadingOverlay(),location.reload()}):(o.close(),t="<p>"+WPFormsConstantContactV3AuthVars.strings.error+"</p><p><strong>"+wpf.sanitizeHTML(t.data)+"</strong></p>",c.errorModal(t))})},waitModal:()=>i.alert({title:"",content:WPFormsConstantContactV3AuthVars.strings.wait,icon:"fa fa-info-circle",type:"blue",buttons:!1}),errorModal:t=>{var o=s?.wpforms_builder||s?.wpforms_admin;return i.alert({title:o.uh_oh,content:t,icon:"fa fa-exclamation-circle",type:"red",buttons:{cancel:{text:o.cancel,action:()=>{c.isOpened=!1}}}})},promptMigration(t){t.preventDefault();let o=c.waitModal();i.post({url:WPFormsConstantContactV3AuthVars.ajax_url,data:{action:"wpforms_constant_contact_migration_prompt",nonce:WPFormsConstantContactV3AuthVars.nonce},success:()=>{o.close(),s.location.href=WPFormsConstantContactV3AuthVars.page_url},error:()=>{o.close(),c.errorModal(WPFormsConstantContactV3AuthVars.strings.error)}})}};return c})(document,window,jQuery);WPFormsConstantContactV3Auth.init();
|
||||
+603
@@ -0,0 +1,603 @@
|
||||
/* global WPForms, wpf */
|
||||
|
||||
/**
|
||||
* WPForms Providers Builder ConstantContactV3 module.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
WPForms.Admin.Builder.Providers.ConstantContactV3 = WPForms.Admin.Builder.Providers.ConstantContactV3 || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
/**
|
||||
* CSS selectors.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
selectors: {
|
||||
accountField: '.js-wpforms-builder-constant-contact-v3-provider-connection-account',
|
||||
actionData: '.wpforms-builder-constant-contact-v3-provider-actions-data',
|
||||
actionField: '.js-wpforms-builder-constant-contact-v3-provider-connection-action',
|
||||
connection: '.wpforms-panel-content-section-constant-contact-v3 .wpforms-builder-provider-connection',
|
||||
},
|
||||
|
||||
/**
|
||||
* jQuery elements.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
$elements: {
|
||||
$connections: $( '.wpforms-panel-content-section-constant-contact-v3 .wpforms-builder-provider-connections' ),
|
||||
$holder: $( '#wpforms-panel-providers' ),
|
||||
$panel: $( '#constant-contact-v3-provider' ),
|
||||
},
|
||||
|
||||
/**
|
||||
* Current provider slug.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
provider: 'constant-contact-v3',
|
||||
|
||||
/**
|
||||
* This is a shortcut to the WPForms.Admin.Builder.Providers object,
|
||||
* that handles the parent all-providers functionality.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
Providers: {},
|
||||
|
||||
/**
|
||||
* This is a shortcut to the WPForms.Admin.Builder.Templates object,
|
||||
* that handles all the template management.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
Templates: {},
|
||||
|
||||
/**
|
||||
* This is a shortcut to the WPForms.Admin.Builder.Providers.cache object,
|
||||
* that handles all the cache management.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
Cache: {},
|
||||
|
||||
/**
|
||||
* This is a flag for ready state.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
isReady: false,
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* Run initialization on the providers panel only.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
init() {
|
||||
// We are requesting/loading a Providers panel.
|
||||
if ( wpf.getQueryString( 'view' ) === 'providers' ) {
|
||||
app.$elements.$holder.on( 'WPForms.Admin.Builder.Providers.ready', app.ready );
|
||||
}
|
||||
|
||||
// We have switched to a Providers panel.
|
||||
$( document ).on( 'wpformsPanelSwitched', function( event, panel ) {
|
||||
if ( panel === 'providers' ) {
|
||||
app.ready();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialized once the DOM and Providers are fully loaded.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
ready() {
|
||||
if ( app.isReady ) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.Providers = WPForms.Admin.Builder.Providers;
|
||||
app.Templates = WPForms.Admin.Builder.Templates;
|
||||
app.Cache = app.Providers.cache;
|
||||
|
||||
// Register custom Underscore.js templates.
|
||||
app.Templates.add( [
|
||||
'wpforms-constant-contact-v3-builder-content-connection',
|
||||
'wpforms-constant-contact-v3-builder-content-connection-error',
|
||||
'wpforms-constant-contact-v3-builder-content-connection-select-field',
|
||||
'wpforms-constant-contact-v3-builder-content-connection-conditionals',
|
||||
] );
|
||||
|
||||
// Events registration.
|
||||
app.bindUIActions();
|
||||
app.bindTriggers();
|
||||
|
||||
app.processInitial();
|
||||
|
||||
// Save a flag for ready state.
|
||||
app.isReady = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Process various events as a response to UI interactions.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
bindUIActions() {
|
||||
app.$elements.$panel
|
||||
.on( 'connectionCreate', app.connection.create )
|
||||
.on( 'connectionDelete', app.connection.delete )
|
||||
.on( 'change', app.selectors.accountField, app.ui.accountField.change )
|
||||
.on( 'change', app.selectors.actionField, app.ui.actionField.change );
|
||||
},
|
||||
|
||||
/**
|
||||
* Fire certain events on certain actions, specific for related connections.
|
||||
* These are not directly caused by user manipulations.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
bindTriggers() {
|
||||
app.$elements.$connections.on( 'connectionsDataLoaded', function( event, data ) {
|
||||
if ( _.isEmpty( data.connections ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( const connectionId in data.connections ) {
|
||||
app.connection.generate( {
|
||||
connection: data.connections[ connectionId ],
|
||||
conditional: data.conditionals[ connectionId ],
|
||||
} );
|
||||
}
|
||||
} );
|
||||
|
||||
app.$elements.$connections.on( 'connectionGenerated', function( event, data ) {
|
||||
const $connection = app.connection.getById( data.connection.id );
|
||||
|
||||
if ( _.has( data.connection, 'isNew' ) && data.connection.isNew ) {
|
||||
// Run replacing temporary connection ID if it's a new connection.
|
||||
app.connection.replaceIds( data.connection.id, $connection );
|
||||
return;
|
||||
}
|
||||
|
||||
$( app.selectors.actionField, $connection ).trigger( 'change' );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Compile template with data if any and display them on a page.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
processInitial() {
|
||||
app.connection.dataLoad();
|
||||
},
|
||||
|
||||
/**
|
||||
* Connection property.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
connection: {
|
||||
/**
|
||||
* Sometimes we might need to a get a connection DOM element by its ID.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {string} connectionId Connection ID to search for a DOM element by.
|
||||
*
|
||||
* @return {jQuery} jQuery object for connection.
|
||||
*/
|
||||
getById( connectionId ) {
|
||||
return app.$elements.$connections.find( '.wpforms-builder-provider-connection[data-connection_id="' + connectionId + '"]' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Sometimes in DOM we might have placeholders or temporary connection IDs.
|
||||
* We need to replace them with actual values.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {string} connectionId New connection ID to replace to.
|
||||
* @param {Object} $connection jQuery DOM connection element.
|
||||
*/
|
||||
replaceIds( connectionId, $connection ) {
|
||||
// Replace old temporary %connection_id% from PHP code with the new one.
|
||||
$connection.find( 'input, select, label' ).each( function() {
|
||||
const $this = $( this );
|
||||
|
||||
if ( $this.attr( 'name' ) ) {
|
||||
$this.attr( 'name', $this.attr( 'name' ).replace( /%connection_id%/gi, connectionId ) );
|
||||
}
|
||||
|
||||
if ( $this.attr( 'id' ) ) {
|
||||
$this.attr( 'id', $this.attr( 'id' ).replace( /%connection_id%/gi, connectionId ) );
|
||||
}
|
||||
|
||||
if ( $this.attr( 'for' ) ) {
|
||||
$this.attr( 'for', $this.attr( 'for' ).replace( /%connection_id%/gi, connectionId ) );
|
||||
}
|
||||
|
||||
if ( $this.attr( 'data-name' ) ) {
|
||||
$this.attr( 'data-name', $this.attr( 'data-name' ).replace( /%connection_id%/gi, connectionId ) );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a connection using the user entered name.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
* @param {string} name Connection name.
|
||||
*/
|
||||
create( event, name ) {
|
||||
const connectionId = new Date().getTime().toString( 16 ),
|
||||
connection = {
|
||||
id: connectionId,
|
||||
name,
|
||||
isNew: true,
|
||||
};
|
||||
|
||||
app.Cache.addTo( app.provider, 'connections', connectionId, connection );
|
||||
|
||||
app.connection.generate( {
|
||||
connection,
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Connection is deleted - delete a cache as well.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {Object} event Event object.
|
||||
* @param {Object} $connection jQuery DOM element for a connection.
|
||||
*/
|
||||
delete( event, $connection ) {
|
||||
const $holder = app.Providers.getProviderHolder( app.provider );
|
||||
|
||||
if ( ! $connection.closest( $holder ).length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const connectionId = $connection.data( 'connection_id' );
|
||||
|
||||
if ( _.isString( connectionId ) ) {
|
||||
app.Cache.deleteFrom( app.provider, 'connections', connectionId );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the template and data for a connection and process it.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {Object} data Connection data.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
generate( data ) {
|
||||
const accounts = app.Cache.get( app.provider, 'accounts' );
|
||||
|
||||
if ( _.isEmpty( accounts ) || ! app.account.isAccountExists( data.connection.account_id, accounts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const actions = app.Cache.get( app.provider, 'actions' ),
|
||||
lists = app.Cache.get( app.provider, 'lists' );
|
||||
|
||||
return app.connection.renderConnections( accounts, lists, actions, data );
|
||||
},
|
||||
|
||||
/**
|
||||
* Render connections.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {Object} accounts List of accounts.
|
||||
* @param {Object} lists List of lists.
|
||||
* @param {Object} actions List of actions.
|
||||
* @param {Object} data Connection data.
|
||||
*/
|
||||
renderConnections( accounts, lists, actions, data ) {
|
||||
if ( ! app.account.isAccountExists( data.connection.account_id, accounts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tmplConnection = app.Templates.get( 'wpforms-' + app.provider + '-builder-content-connection' ),
|
||||
tmplConditional = app.Templates.get( 'wpforms-constant-contact-v3-builder-content-connection-conditionals' ),
|
||||
conditional = _.has( data.connection, 'isNew' ) && data.connection.isNew ? tmplConditional() : data.conditional;
|
||||
|
||||
app.$elements.$connections.prepend(
|
||||
tmplConnection( {
|
||||
accounts,
|
||||
lists,
|
||||
actions,
|
||||
connection: data.connection,
|
||||
conditional,
|
||||
provider: app.provider,
|
||||
} )
|
||||
);
|
||||
|
||||
app.$elements.$connections.trigger( 'connectionGenerated', [ data ] );
|
||||
},
|
||||
|
||||
/**
|
||||
* Fire AJAX-request to retrieve the list of all saved connections.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
dataLoad() {
|
||||
app
|
||||
.Providers.ajax
|
||||
.request( app.provider, {
|
||||
data: {
|
||||
task: 'connections_get',
|
||||
},
|
||||
} )
|
||||
.done( function( response ) {
|
||||
if (
|
||||
! response.success ||
|
||||
! _.has( response.data, 'connections' )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
[
|
||||
'accounts',
|
||||
'actions',
|
||||
'actions_fields',
|
||||
'conditionals',
|
||||
'connections',
|
||||
'custom_fields',
|
||||
'lists',
|
||||
].forEach( ( dataType ) => {
|
||||
app.Cache.set( app.provider, dataType, jQuery.extend( {}, response.data[ dataType ] ) );
|
||||
} );
|
||||
|
||||
app.$elements.$connections.trigger( 'connectionsDataLoaded', [ response.data ] );
|
||||
} );
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Account property.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
account: {
|
||||
/**
|
||||
* Check if a provided account is listed inside an account list.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {string} accountId Connection account ID to check.
|
||||
* @param {Object} accounts Array of objects, usually received from API.
|
||||
*
|
||||
* @return {boolean} True if an account exists.
|
||||
*/
|
||||
isAccountExists( accountId, accounts ) {
|
||||
if ( _.isEmpty( accounts ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// New connections that have not been saved don't have the account ID yet.
|
||||
if ( _.isEmpty( accountId ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return _.has( accounts, accountId );
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* All methods that modify the UI of a page.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
ui: {
|
||||
/**
|
||||
* Account field methods.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
accountField: {
|
||||
/**
|
||||
* Callback-function on change event.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
change() {
|
||||
const $this = $( this ),
|
||||
$connection = $this.closest( app.selectors.connection ),
|
||||
$actionName = $( app.selectors.actionField, $connection );
|
||||
|
||||
$actionName.prop( 'selectedIndex', 0 ).trigger( 'change' );
|
||||
|
||||
// If an account is empty.
|
||||
if ( _.isEmpty( $this.val() ) ) {
|
||||
$actionName.prop( 'disabled', true );
|
||||
$( app.selectors.actionData, $connection ).html( '' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$actionName.prop( 'disabled', false );
|
||||
$this.removeClass( 'wpforms-error' );
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Action methods.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
actionField: {
|
||||
/**
|
||||
* Callback-function on change event.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
change() {
|
||||
const $this = $( this ),
|
||||
$connection = $this.closest( app.selectors.connection ),
|
||||
$account = $( app.selectors.accountField, $connection ),
|
||||
$action = $( app.selectors.actionField, $connection );
|
||||
|
||||
app.ui.actionField.render( {
|
||||
action: 'action',
|
||||
target: $this,
|
||||
/* eslint-disable camelcase */
|
||||
account_id: $account.val(),
|
||||
action_name: $action.val(),
|
||||
connection_id: $connection.data( 'connection_id' ),
|
||||
/* eslint-enable camelcase */
|
||||
} );
|
||||
|
||||
$this.removeClass( 'wpforms-error' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Render HTML.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {Object} args Arguments.
|
||||
*/
|
||||
render( args ) {
|
||||
const fields = app.tmpl.renderActionFields( args ),
|
||||
$connection = app.connection.getById( args.connection_id ),
|
||||
$connectionData = $( app.selectors.actionData, $connection );
|
||||
|
||||
$connectionData.html( fields );
|
||||
|
||||
app.$elements.$holder.trigger( 'connectionRendered', [ app.provider, args.connection_id ] );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a list of constant-contact lists.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {string} accountId Account ID.
|
||||
*
|
||||
* @return {Array} List of constant-contact lists.
|
||||
*/
|
||||
getList( accountId ) {
|
||||
const listsCache = app.Cache.get( app.provider, 'lists' );
|
||||
|
||||
return ! _.isEmpty( listsCache ) && ! _.isEmpty( listsCache[ accountId ] ) ? listsCache[ accountId ] : [];
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* All methods for JavaScript templates.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*/
|
||||
tmpl: {
|
||||
/**
|
||||
* Compile and retrieve an HTML for common elements.
|
||||
*
|
||||
* @since 1.9.3
|
||||
* @deprecated 1.9.5
|
||||
*
|
||||
* @return {string} Compiled HTML.
|
||||
*/
|
||||
commonsHTML() {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn( 'WARNING! Function "WPForms.Admin.Builder.Providers.ConstantContactV3.tmpl.commonsHTML()" has been deprecated!' );
|
||||
|
||||
const tmplError = app.Templates.get( 'wpforms-' + app.provider + '-builder-content-connection-error' );
|
||||
|
||||
return tmplError();
|
||||
},
|
||||
|
||||
/**
|
||||
* Compile and retrieve an HTML for "Custom Fields Table".
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param {Object} args Arguments
|
||||
*
|
||||
* @return {string} Compiled HTML.
|
||||
*/
|
||||
renderActionFields( args ) {
|
||||
const fields = wpf.getFields(),
|
||||
actionsFields = app.Cache.get( app.provider, 'actions_fields' ),
|
||||
customFields = app.Cache.get( app.provider, 'custom_fields' ),
|
||||
connection = app.Cache.getById( app.provider, 'connections', args.connection_id );
|
||||
|
||||
let fieldHTML = '';
|
||||
|
||||
$.each( actionsFields[ args.target.val() ], function( key, field ) {
|
||||
if ( key === 'custom_fields' ) {
|
||||
const tmplFields = app.Templates.get( 'wpforms-providers-builder-content-connection-fields' );
|
||||
|
||||
fieldHTML += tmplFields( {
|
||||
connection,
|
||||
fields,
|
||||
provider: {
|
||||
slug: app.provider,
|
||||
fields: customFields[ args.account_id ],
|
||||
},
|
||||
isSupportSubfields: true,
|
||||
} );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const options = key === 'list' ? app.ui.actionField.getList( args.account_id ) : Object.values( fields );
|
||||
const templateName = 'wpforms-' + app.provider + '-builder-content-connection-' + field.type + '-field';
|
||||
const tmplField = app.Templates.get( templateName );
|
||||
|
||||
fieldHTML += tmplField( {
|
||||
connection,
|
||||
name: key,
|
||||
field,
|
||||
provider: {
|
||||
slug: app.provider,
|
||||
fields: actionsFields[ args.target.val() ],
|
||||
},
|
||||
options,
|
||||
} );
|
||||
} );
|
||||
|
||||
return fieldHTML;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
// Initialize.
|
||||
WPForms.Admin.Builder.Providers.ConstantContactV3.init();
|
||||
Vendored
Executable
+1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user