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:
@@ -0,0 +1,789 @@
|
||||
/* global wpforms_education, WPFormsBuilder, wpf */
|
||||
|
||||
/**
|
||||
* WPForms Education Core.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*/
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* @param wpforms_education.activate_confirm
|
||||
* @param wpforms_education.activate_prompt
|
||||
* @param wpforms_education.activating
|
||||
* @param wpforms_education.addon_activated
|
||||
* @param wpforms_education.addon_error
|
||||
* @param wpforms_education.addon_incompatible.title
|
||||
* @param wpforms_education.addon_incompatible.button_text
|
||||
* @param wpforms_education.addon_incompatible.button_url
|
||||
* @param wpforms_education.ajax_url
|
||||
* @param wpforms_education.can_activate_addons
|
||||
* @param wpforms_education.can_install_addons
|
||||
* @param wpforms_education.cancel
|
||||
* @param wpforms_education.close
|
||||
* @param wpforms_education.install_confirm
|
||||
* @param wpforms_education.install_prompt
|
||||
* @param wpforms_education.installing
|
||||
* @param wpforms_education.nonce
|
||||
* @param wpforms_education.ok
|
||||
* @param wpforms_education.plugin_activated
|
||||
* @param wpforms_education.save_confirm
|
||||
* @param wpforms_education.save_prompt
|
||||
* @param wpforms_education.saving
|
||||
* @param wpforms_education.thanks_for_interest
|
||||
* @param wpforms_education.upgrade
|
||||
* @param wpforms_education.upgrade.modal
|
||||
* @param wpforms_education.upgrade.url
|
||||
* @param wpforms_education.upgrade.url_template
|
||||
*/
|
||||
|
||||
var WPFormsEducation = window.WPFormsEducation || {}; // eslint-disable-line no-var
|
||||
|
||||
WPFormsEducation.core = window.WPFormsEducation.core || ( function( document, window, $ ) {
|
||||
/**
|
||||
* Spinner markup.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
const spinner = '<i class="wpforms-loading-spinner wpforms-loading-white wpforms-loading-inline"></i>';
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*/
|
||||
ready() {
|
||||
app.events();
|
||||
},
|
||||
|
||||
/**
|
||||
* Register JS events.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*/
|
||||
events() {
|
||||
app.dismissEvents();
|
||||
app.openModalButtonClick();
|
||||
app.setDykColspan();
|
||||
app.gotoAdvancedTabClick();
|
||||
app.proFieldDelete();
|
||||
},
|
||||
|
||||
/**
|
||||
* Open education modal.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*/
|
||||
openModalButtonClick() {
|
||||
$( document )
|
||||
.on( 'click', '.education-modal:not(.wpforms-add-fields-button)', app.openModalButtonHandler )
|
||||
.on( 'mousedown', '.education-modal.wpforms-add-fields-button', app.openModalButtonHandler )
|
||||
.on( 'click', '.education-action-button', app.actionButtonHandler );
|
||||
},
|
||||
|
||||
/**
|
||||
* Action button click handler.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @param {Event} event Event.
|
||||
*/
|
||||
actionButtonHandler( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
const $this = $( this );
|
||||
const action = $this.data( 'action' );
|
||||
|
||||
// Currently, only the upgrade action is supported.
|
||||
if ( action !== 'upgrade' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const utmContent = $this.data( 'utm-content' );
|
||||
const type = $this.data( 'license' );
|
||||
|
||||
window.open( WPFormsEducation.core.getUpgradeURL( utmContent, type ), '_blank' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Open education modal handler.
|
||||
*
|
||||
* @since 1.8.0
|
||||
* @since 1.9.6.1 Added `$element` parameter.
|
||||
*
|
||||
* @param {Event} event Event.
|
||||
* @param {jQuery} $element jQuery element.
|
||||
*/
|
||||
openModalButtonHandler( event, $element = null ) {
|
||||
event.preventDefault();
|
||||
|
||||
const $this = $element || $( this );
|
||||
|
||||
switch ( $this.data( 'action' ) ) {
|
||||
case 'activate':
|
||||
app.activateModal( $this );
|
||||
break;
|
||||
case 'install':
|
||||
app.installModal( $this );
|
||||
break;
|
||||
case 'incompatible':
|
||||
app.incompatibleModal( $this );
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide Pro fields notice when all disabled fields deleted.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*/
|
||||
proFieldDelete() {
|
||||
$( '#wpforms-builder' ).on(
|
||||
'wpformsFieldDelete',
|
||||
function() {
|
||||
if ( ! $( '.wpforms-field-wrap .wpforms-field-is-pro' ).length ) {
|
||||
$( '.wpforms-preview .wpforms-pro-fields-notice' ).addClass( 'wpforms-hidden' );
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Dismiss button events.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*/
|
||||
dismissEvents() {
|
||||
$( document ).on( 'click', '.wpforms-dismiss-container .wpforms-dismiss-button', function() {
|
||||
const $this = $( this ),
|
||||
$cont = $this.closest( '.wpforms-dismiss-container' ),
|
||||
data = {
|
||||
action: 'wpforms_education_dismiss',
|
||||
nonce: wpforms_education.nonce,
|
||||
section: $this.data( 'section' ),
|
||||
page: typeof window.pagenow === 'string' ? window.pagenow : '',
|
||||
};
|
||||
let $out = $cont.find( '.wpforms-dismiss-out' );
|
||||
|
||||
if ( $cont.hasClass( 'wpforms-dismiss-out' ) ) {
|
||||
$out = $cont;
|
||||
}
|
||||
|
||||
if ( $out.length > 0 ) {
|
||||
$out.addClass( 'out' );
|
||||
setTimeout(
|
||||
function() {
|
||||
$cont.remove();
|
||||
},
|
||||
300
|
||||
);
|
||||
} else {
|
||||
$cont.remove();
|
||||
}
|
||||
|
||||
$.post( wpforms_education.ajax_url, data );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate and dynamically set the DYK block cell colspan attribute.
|
||||
*
|
||||
* @since 1.7.3
|
||||
*/
|
||||
setDykColspan() {
|
||||
$( '#adv-settings' ).on(
|
||||
'change',
|
||||
'input.hide-column-tog',
|
||||
function() {
|
||||
const $dykCell = $( '.wpforms-dyk td' ),
|
||||
colCount = $( '.wp-list-table thead .manage-column' ).not( '.hidden' ).length;
|
||||
|
||||
$dykCell.attr( 'colspan', colCount );
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Go to Advanced tab when click on the link in Calculations educational notice.
|
||||
*
|
||||
* @since 1.8.4.1
|
||||
*/
|
||||
gotoAdvancedTabClick() {
|
||||
$( document )
|
||||
.on( 'click', '.wpforms-educational-alert.wpforms-calculations a', function( e ) {
|
||||
const $a = $( this );
|
||||
|
||||
if ( $a.attr( 'href' ) !== '#advanced-tab' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$a.closest( '.wpforms-field-option' )
|
||||
.find( '.wpforms-field-option-group-advanced .wpforms-field-option-group-toggle' )
|
||||
.trigger( 'click' );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get UTM content for different elements.
|
||||
*
|
||||
* @since 1.6.9
|
||||
*
|
||||
* @param {jQuery} $el Element.
|
||||
*
|
||||
* @return {string} UTM content string.
|
||||
*/
|
||||
getUTMContentValue( $el ) {
|
||||
// UTM content for Fields.
|
||||
if ( $el.hasClass( 'wpforms-add-fields-button' ) ) {
|
||||
return $el.data( 'utm-content' ) + ' Field';
|
||||
}
|
||||
|
||||
// UTM content for Templates.
|
||||
if ( $el.hasClass( 'wpforms-template-select' ) ) {
|
||||
return app.slugToUTMContent( $el.data( 'slug' ) );
|
||||
}
|
||||
|
||||
// UTM content for Addons (sidebar).
|
||||
if ( $el.hasClass( 'wpforms-panel-sidebar-section' ) ) {
|
||||
return app.slugToUTMContent( $el.data( 'slug' ) ) + ' Addon';
|
||||
}
|
||||
|
||||
// UTM content by default with fallback `data-name`.
|
||||
return $el.data( 'utm-content' ) || $el.data( 'name' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert slug to UTM content.
|
||||
*
|
||||
* @since 1.6.9
|
||||
*
|
||||
* @param {string} slug Slug.
|
||||
*
|
||||
* @return {string} UTM content string.
|
||||
*/
|
||||
slugToUTMContent( slug ) {
|
||||
if ( ! slug ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return slug.toString()
|
||||
|
||||
// Replace all non-alphanumeric characters with space.
|
||||
.replace( /[^a-z\d ]/gi, ' ' )
|
||||
|
||||
// Uppercase each word.
|
||||
.replace( /\b[a-z]/g, function( char ) {
|
||||
return char.toUpperCase();
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get upgrade URL according to the UTM content and license type.
|
||||
*
|
||||
* @since 1.6.9
|
||||
*
|
||||
* @param {string} utmContent UTM content.
|
||||
* @param {string} type Feature license type: pro or elite.
|
||||
*
|
||||
* @return {string} Upgrade URL.
|
||||
*/
|
||||
getUpgradeURL( utmContent, type ) {
|
||||
let baseURL = wpforms_education.upgrade[ type ].url;
|
||||
|
||||
if ( utmContent.toLowerCase().indexOf( 'template' ) > -1 ) {
|
||||
baseURL = wpforms_education.upgrade[ type ].url_template;
|
||||
}
|
||||
|
||||
if ( utmContent.toLowerCase().indexOf( 'themes' ) > -1 ) {
|
||||
baseURL = wpforms_education.upgrade[ type ].url_themes;
|
||||
}
|
||||
|
||||
// Test if the base URL already contains `?`.
|
||||
let appendChar = /(\?)/.test( baseURL ) ? '&' : '?';
|
||||
|
||||
// If the upgrade link is changed by partners, appendChar has to be encoded.
|
||||
if ( baseURL.indexOf( 'https://wpforms.com' ) === -1 ) {
|
||||
appendChar = encodeURIComponent( appendChar );
|
||||
}
|
||||
|
||||
return baseURL + appendChar + 'utm_content=' + encodeURIComponent( utmContent.trim() );
|
||||
},
|
||||
|
||||
/**
|
||||
* Upgrade modal second state.
|
||||
*
|
||||
* @since 1.6.6
|
||||
*
|
||||
* @param {string} type Feature license type: pro or elite.
|
||||
*/
|
||||
upgradeModalThankYou: ( type ) => {
|
||||
$.alert( {
|
||||
title: wpforms_education.thanks_for_interest,
|
||||
content: wpforms_education.upgrade[ type ].modal,
|
||||
icon: 'fa fa-info-circle',
|
||||
type: 'blue',
|
||||
boxWidth: '565px',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.ok,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get spinner markup.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @return {string} Spinner markup.
|
||||
*/
|
||||
getSpinner: () => {
|
||||
return spinner;
|
||||
},
|
||||
|
||||
/**
|
||||
* Addon activate modal.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param {jQuery} $button jQuery button element.
|
||||
*/
|
||||
activateModal( $button ) {
|
||||
const feature = $button.data( 'name' ),
|
||||
message = $button.data( 'message' );
|
||||
|
||||
const canActivateAddons = wpforms_education.can_activate_addons;
|
||||
|
||||
$.alert( {
|
||||
title: false,
|
||||
content: message ? message : wpforms_education.activate_prompt.replace( /%name%/g, feature ),
|
||||
icon: 'fa fa-info-circle',
|
||||
type: 'blue',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.activate_confirm,
|
||||
btnClass: 'btn-confirm' + ( ! canActivateAddons ? ' hidden' : '' ),
|
||||
keys: [ 'enter' ],
|
||||
isHidden: ! canActivateAddons,
|
||||
action() {
|
||||
this.$$confirm
|
||||
.prop( 'disabled', true )
|
||||
.html( spinner + wpforms_education.activating );
|
||||
|
||||
this.$$cancel
|
||||
.prop( 'disabled', true );
|
||||
|
||||
app.activateAddon( $button, this );
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_education.cancel,
|
||||
action() {
|
||||
/**
|
||||
* Trigger event when modal is closed.
|
||||
* This event is used to handle any custom logic when the modal is closed.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*
|
||||
* @param {jQuery} $button jQuery button element.
|
||||
*/
|
||||
$( document ).trigger( 'wpformsEducationModalClose', $button );
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Activate addon via AJAX.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param {jQuery} $button jQuery button element.
|
||||
* @param {Object} previousModal Previous modal instance.
|
||||
*/
|
||||
activateAddon( $button, previousModal ) {
|
||||
const path = $button.data( 'path' ),
|
||||
pluginType = $button.data( 'type' ),
|
||||
nonce = $button.data( 'nonce' ),
|
||||
hideOnSuccess = $button.data( 'hide-on-success' );
|
||||
|
||||
$.post(
|
||||
wpforms_education.ajax_url,
|
||||
{
|
||||
action: 'wpforms_activate_addon',
|
||||
nonce,
|
||||
plugin: path,
|
||||
type: pluginType,
|
||||
},
|
||||
function( res ) {
|
||||
previousModal.close();
|
||||
|
||||
if ( res.success ) {
|
||||
if ( hideOnSuccess ) {
|
||||
$button.hide();
|
||||
}
|
||||
|
||||
app.saveModal( pluginType === 'plugin' ? wpforms_education.plugin_activated : wpforms_education.addon_activated );
|
||||
} else {
|
||||
$.alert( {
|
||||
title: false,
|
||||
content: res.data,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.close,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Ask user if they would like to save form and refresh form builder.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param {string} title Modal title.
|
||||
* @param {string|boolean} content Modal content.
|
||||
* @param {Object} args Additional arguments.
|
||||
*/
|
||||
saveModal( title, content = false, args = undefined ) {
|
||||
title = title || wpforms_education.addon_activated;
|
||||
content = content || wpforms_education.save_prompt;
|
||||
|
||||
$.alert( {
|
||||
title: title.replace( /\.$/, '' ), // Remove a dot in the title end.
|
||||
content,
|
||||
icon: 'fa fa-check-circle',
|
||||
type: 'green',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: args?.saveConfirm || wpforms_education.save_confirm,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
if ( typeof WPFormsBuilder === 'undefined' ) {
|
||||
location.reload();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.$$confirm
|
||||
.prop( 'disabled', true )
|
||||
.html( spinner + wpforms_education.saving );
|
||||
|
||||
this.$$cancel
|
||||
.prop( 'disabled', true );
|
||||
|
||||
if ( WPFormsBuilder.formIsSaved() ) {
|
||||
app.redirect( args?.redirectUrl );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const saveForm = WPFormsBuilder.formSave( false );
|
||||
|
||||
if ( ! saveForm ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
saveForm.done( function() {
|
||||
app.redirect( args?.redirectUrl );
|
||||
} );
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_education.close,
|
||||
action() {
|
||||
/**
|
||||
* Triggers an event to notify that the education save modal has been closed.
|
||||
*
|
||||
* @since 1.9.6.1
|
||||
*/
|
||||
$( document ).trigger( 'wpformsEducationSaveModalClose' );
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Redirect to URL or reload the page.
|
||||
*
|
||||
* @since 1.9.2
|
||||
*
|
||||
* @param {string} url Redirect URL.
|
||||
*/
|
||||
redirect( url ) {
|
||||
if ( url ) {
|
||||
location.href = url;
|
||||
} else {
|
||||
location.reload();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Addon install modal.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param {jQuery} $button jQuery button element.
|
||||
*/
|
||||
installModal( $button ) {
|
||||
const feature = $button.data( 'name' ),
|
||||
url = $button.data( 'url' );
|
||||
|
||||
if ( ! url || '' === url ) {
|
||||
wpf.debug( `Couldn't install the ${ feature } addon: Empty install URL.` );
|
||||
return;
|
||||
}
|
||||
|
||||
const canInstallAddons = wpforms_education.can_install_addons,
|
||||
message = $button.data( 'message' );
|
||||
|
||||
$.alert( {
|
||||
title: false,
|
||||
content: message ? message : wpforms_education.install_prompt.replace( /%name%/g, feature ),
|
||||
icon: 'fa fa-info-circle',
|
||||
type: 'blue',
|
||||
boxWidth: '425px',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.install_confirm,
|
||||
btnClass: 'btn-confirm' + ( ! canInstallAddons ? ' hidden' : '' ),
|
||||
keys: [ 'enter' ],
|
||||
isHidden: ! canInstallAddons,
|
||||
action() {
|
||||
this.$$confirm.prop( 'disabled', true )
|
||||
.html( spinner + wpforms_education.installing );
|
||||
|
||||
this.$$cancel
|
||||
.prop( 'disabled', true );
|
||||
|
||||
app.installAddon( $button, this );
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_education.cancel,
|
||||
action() {
|
||||
$( document ).trigger( 'wpformsEducationModalClose', $button );
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Inform customer about incompatible addon modal.
|
||||
*
|
||||
* @since 1.9.4
|
||||
*
|
||||
* @param {jQuery} $button jQuery button element.
|
||||
*/
|
||||
incompatibleModal( $button ) {
|
||||
const title = wpforms_education.addon_incompatible.title;
|
||||
const content = $button.data( 'message' ) || wpforms_education.addon_error;
|
||||
|
||||
$.alert( {
|
||||
title,
|
||||
content,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.addon_incompatible.button_text,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
action() {
|
||||
if ( typeof WPFormsBuilder === 'undefined' ) {
|
||||
app.redirect( wpforms_education.addon_incompatible.button_url );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
this.$$confirm
|
||||
.prop( 'disabled', true )
|
||||
.html( spinner + this.$$confirm.text() );
|
||||
|
||||
this.$$cancel
|
||||
.prop( 'disabled', true );
|
||||
|
||||
if ( WPFormsBuilder.formIsSaved() ) {
|
||||
app.redirect( wpforms_education.addon_incompatible.button_url );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const saveForm = WPFormsBuilder.formSave( false );
|
||||
|
||||
if ( ! saveForm ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
saveForm.done( function() {
|
||||
app.redirect( wpforms_education.addon_incompatible.button_url );
|
||||
} );
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
text: wpforms_education.cancel,
|
||||
action() {
|
||||
$( document ).trigger( 'wpformsEducationModalClose', $button );
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Install addon via AJAX.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param {jQuery} $button Button object.
|
||||
* @param {Object} previousModal Previous modal instance.
|
||||
*/
|
||||
installAddon( $button, previousModal ) {
|
||||
const url = $button.data( 'url' ),
|
||||
pluginType = $button.data( 'type' ),
|
||||
nonce = $button.data( 'nonce' ),
|
||||
hideOnSuccess = $button.data( 'hide-on-success' );
|
||||
|
||||
$.post(
|
||||
wpforms_education.ajax_url,
|
||||
{
|
||||
action: 'wpforms_install_addon',
|
||||
nonce,
|
||||
plugin: url,
|
||||
type: pluginType,
|
||||
},
|
||||
function( res ) {
|
||||
previousModal.close();
|
||||
|
||||
if ( res.success ) {
|
||||
if ( hideOnSuccess ) {
|
||||
$button.hide();
|
||||
}
|
||||
|
||||
app.saveModal( res.data.msg );
|
||||
} else {
|
||||
let message = res.data;
|
||||
|
||||
if ( 'object' === typeof res.data ) {
|
||||
message = wpforms_education.addon_error;
|
||||
}
|
||||
|
||||
$.alert( {
|
||||
title: false,
|
||||
content: message,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.close,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get upgrade modal width.
|
||||
*
|
||||
* @since 1.7.3
|
||||
*
|
||||
* @param {boolean} isVideoModal Upgrade a modal type (with video or not).
|
||||
*
|
||||
* @return {string} Modal width in pixels.
|
||||
*/
|
||||
getUpgradeModalWidth( isVideoModal ) {
|
||||
const windowWidth = $( window ).width();
|
||||
|
||||
if ( windowWidth <= 300 ) {
|
||||
return '250px';
|
||||
}
|
||||
|
||||
if ( windowWidth <= 750 ) {
|
||||
return '350px';
|
||||
}
|
||||
|
||||
if ( ! isVideoModal || windowWidth <= 1024 ) {
|
||||
return '550px';
|
||||
}
|
||||
|
||||
return windowWidth > 1070 ? '1040px' : '994px';
|
||||
},
|
||||
|
||||
/**
|
||||
* Error modal.
|
||||
*
|
||||
* @since 1.7.6
|
||||
*
|
||||
* @param {string} title Modal title.
|
||||
* @param {string} content Modal content.
|
||||
*/
|
||||
errorModal( title, content ) {
|
||||
$.alert( {
|
||||
title: title || false,
|
||||
content,
|
||||
icon: 'fa fa-exclamation-circle',
|
||||
type: 'orange',
|
||||
buttons: {
|
||||
confirm: {
|
||||
text: wpforms_education.close,
|
||||
btnClass: 'btn-confirm',
|
||||
keys: [ 'enter' ],
|
||||
},
|
||||
},
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
WPFormsEducation.core.init();
|
||||
+1
File diff suppressed because one or more lines are too long
+436
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,476 @@
|
||||
/* global wpforms_edit_post_education */
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* WPForms Edit Post Education function.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line no-var, no-unused-vars
|
||||
var WPFormsEditPostEducation = window.WPFormsEditPostEducation || ( function( document, window, $ ) {
|
||||
// The identifiers for the Redux stores.
|
||||
const coreEditSite = 'core/edit-site',
|
||||
coreEditor = 'core/editor',
|
||||
coreBlockEditor = 'core/block-editor',
|
||||
coreNotices = 'core/notices',
|
||||
|
||||
// Heading block name.
|
||||
coreHeading = 'core/heading';
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Determine if the notice was shown before.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
isNoticeVisible: false,
|
||||
|
||||
/**
|
||||
* Identifier for the plugin and notice.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
pluginId: 'wpforms-edit-post-product-education-guide',
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
init() {
|
||||
$( window ).on( 'load', function() {
|
||||
// In the case of jQuery 3.+, we need to wait for a ready event first.
|
||||
if ( typeof $.ready.then === 'function' ) {
|
||||
$.ready.then( app.load );
|
||||
} else {
|
||||
app.load();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Page load.
|
||||
*
|
||||
* @since 1.8.1
|
||||
* @since 1.9.5 Added compatibility for the Site Editor.
|
||||
*/
|
||||
load() {
|
||||
if ( ! app.isGutenbergEditor() ) {
|
||||
app.maybeShowClassicNotice();
|
||||
app.bindClassicEvents();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.maybeShowGutenbergNotice();
|
||||
|
||||
// "core/edit-site" store available only in the Site Editor.
|
||||
if ( !! wp.data.select( coreEditSite ) ) {
|
||||
app.subscribeForSiteEditor();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.subscribeForBlockEditor();
|
||||
},
|
||||
|
||||
/**
|
||||
* This method listens for changes in the WordPress data store and performs the following actions:
|
||||
* - Monitors the editor title and focus mode to detect changes.
|
||||
* - Dismisses a custom notice if the focus mode is disabled and the notice is visible.
|
||||
* - Shows a custom Gutenberg notice if the title or focus mode changes.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
subscribeForSiteEditor() {
|
||||
// Store the initial editor title and focus mode state.
|
||||
let prevTitle = app.getEditorTitle();
|
||||
let prevFocusMode = null;
|
||||
const { subscribe, select, dispatch } = wp.data;
|
||||
|
||||
// Listen for changes in the WordPress data store.
|
||||
subscribe( () => {
|
||||
// Fetch the current editor mode setting.
|
||||
// If true - Site Editor canvas is opened, and you can edit something.
|
||||
// If false - you should see the sidebar with navigation and preview
|
||||
// with selected template or page.
|
||||
const { focusMode } = select( coreEditor ).getEditorSettings();
|
||||
|
||||
// If focus mode is disabled and a notice is visible, remove the notice.
|
||||
// This is essential because user can switch pages / templates
|
||||
// without a page-reload.
|
||||
if ( ! focusMode && app.isNoticeVisible ) {
|
||||
app.isNoticeVisible = false;
|
||||
prevFocusMode = focusMode;
|
||||
|
||||
dispatch( coreNotices ).removeNotice( app.pluginId );
|
||||
}
|
||||
|
||||
const title = app.getEditorTitle();
|
||||
|
||||
// If neither the title nor the focus mode has changed, do nothing.
|
||||
if ( prevTitle === title && prevFocusMode === focusMode ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the previous title and focus mode values for the next subscription cycle.
|
||||
prevTitle = title;
|
||||
prevFocusMode = focusMode;
|
||||
|
||||
// Show a custom Gutenberg notice if conditions are met.
|
||||
app.maybeShowGutenbergNotice();
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Subscribes to changes in the WordPress block editor and monitors the editor's title.
|
||||
* When the title changes, it triggers a process to potentially display a Gutenberg notice.
|
||||
* The subscription is automatically stopped if the notice becomes visible.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*/
|
||||
subscribeForBlockEditor() {
|
||||
let prevTitle = app.getEditorTitle();
|
||||
const { subscribe } = wp.data;
|
||||
|
||||
// Subscribe to WordPress data changes.
|
||||
const unsubscribe = subscribe( () => {
|
||||
const title = app.getEditorTitle();
|
||||
|
||||
// Check if the title has changed since the previous value.
|
||||
if ( prevTitle === title ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the previous title to the current title.
|
||||
prevTitle = title;
|
||||
|
||||
app.maybeShowGutenbergNotice();
|
||||
|
||||
// If the notice is visible, stop the WordPress data subscription.
|
||||
if ( app.isNoticeVisible ) {
|
||||
unsubscribe();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the title of the post currently being edited. If in the Site Editor,
|
||||
* it attempts to fetch the title from the topmost heading block. Otherwise, it
|
||||
* retrieves the title attribute of the edited post.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @return {string} The post title or an empty string if no title is found.
|
||||
*/
|
||||
getEditorTitle() {
|
||||
const { select } = wp.data;
|
||||
|
||||
// Retrieve the title for Post Editor.
|
||||
if ( ! select( coreEditSite ) ) {
|
||||
return select( coreEditor ).getEditedPostAttribute( 'title' );
|
||||
}
|
||||
|
||||
if ( app.isEditPostFSE() ) {
|
||||
return app.getPostTitle();
|
||||
}
|
||||
|
||||
return app.getTopmostHeadingTitle();
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the content of the first heading block.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @return {string} The topmost heading content or null if not found.
|
||||
*/
|
||||
getTopmostHeadingTitle() {
|
||||
const { select } = wp.data;
|
||||
|
||||
const headings = select( coreBlockEditor ).getBlocksByName( coreHeading );
|
||||
|
||||
if ( ! headings.length ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const headingBlock = select( coreBlockEditor ).getBlock( headings[ 0 ] );
|
||||
|
||||
return headingBlock?.attributes?.content?.text ?? '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if the current editing context is for a post type in the Full Site Editor (FSE).
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @return {boolean} True if the current context represents a post type in the FSE, otherwise false.
|
||||
*/
|
||||
isEditPostFSE() {
|
||||
const { select } = wp.data;
|
||||
const { context } = select( coreEditSite ).getPage();
|
||||
|
||||
return !! context?.postType;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the title of a post based on its type and ID from the current editing context.
|
||||
*
|
||||
* @since 1.9.5
|
||||
*
|
||||
* @return {string} The title of the post.
|
||||
*/
|
||||
getPostTitle() {
|
||||
const { select } = wp.data;
|
||||
const { context } = select( coreEditSite ).getPage();
|
||||
|
||||
// Use `getEditedEntityRecord` instead of `getEntityRecord`
|
||||
// to fetch the live, updated data for the post being edited.
|
||||
const { title = '' } = select( 'core' ).getEditedEntityRecord(
|
||||
'postType',
|
||||
context.postType,
|
||||
context.postId
|
||||
) || {};
|
||||
|
||||
return title;
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events for Classic Editor.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
bindClassicEvents() {
|
||||
const $document = $( document );
|
||||
|
||||
if ( ! app.isNoticeVisible ) {
|
||||
$document.on( 'input', '#title', _.debounce( app.maybeShowClassicNotice, 1000 ) );
|
||||
}
|
||||
|
||||
$document.on( 'click', '.wpforms-edit-post-education-notice-close', app.closeNotice );
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine if the editor is Gutenberg.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @return {boolean} True if the editor is Gutenberg.
|
||||
*/
|
||||
isGutenbergEditor() {
|
||||
return typeof wp !== 'undefined' && typeof wp.blocks !== 'undefined';
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a notice for Gutenberg.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
showGutenbergNotice() {
|
||||
wp.data.dispatch( coreNotices ).createInfoNotice(
|
||||
wpforms_edit_post_education.gutenberg_notice.template,
|
||||
app.getGutenbergNoticeSettings()
|
||||
);
|
||||
|
||||
// The notice component doesn't have a way to add HTML id or class to the notice.
|
||||
// Also, the notice became visible with a delay on old Gutenberg versions.
|
||||
const hasNotice = setInterval( function() {
|
||||
const noticeBody = $( '.wpforms-edit-post-education-notice-body' );
|
||||
if ( ! noticeBody.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $notice = noticeBody.closest( '.components-notice' );
|
||||
$notice.addClass( 'wpforms-edit-post-education-notice' );
|
||||
$notice.find( '.is-secondary, .is-link' ).removeClass( 'is-secondary' ).removeClass( 'is-link' ).addClass( 'is-primary' );
|
||||
|
||||
// We can't use onDismiss callback as it was introduced in WordPress 6.0 only.
|
||||
const dismissButton = $notice.find( '.components-notice__dismiss' );
|
||||
if ( dismissButton ) {
|
||||
dismissButton.on( 'click', function() {
|
||||
app.updateUserMeta();
|
||||
} );
|
||||
}
|
||||
|
||||
clearInterval( hasNotice );
|
||||
}, 100 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get settings for the Gutenberg notice.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @return {Object} Notice settings.
|
||||
*/
|
||||
getGutenbergNoticeSettings() {
|
||||
const noticeSettings = {
|
||||
id: app.pluginId,
|
||||
isDismissible: true,
|
||||
HTML: true,
|
||||
__unstableHTML: true,
|
||||
actions: [
|
||||
{
|
||||
className: 'wpforms-edit-post-education-notice-guide-button',
|
||||
variant: 'primary',
|
||||
label: wpforms_edit_post_education.gutenberg_notice.button,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if ( ! wpforms_edit_post_education.gutenberg_guide ) {
|
||||
noticeSettings.actions[ 0 ].url = wpforms_edit_post_education.gutenberg_notice.url;
|
||||
|
||||
return noticeSettings;
|
||||
}
|
||||
|
||||
const { Guide } = wp.components,
|
||||
{ useState } = wp.element,
|
||||
{ registerPlugin, unregisterPlugin } = wp.plugins;
|
||||
|
||||
const GutenbergTutorial = function() {
|
||||
const [ isOpen, setIsOpen ] = useState( true );
|
||||
|
||||
if ( ! isOpen ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line react/react-in-jsx-scope
|
||||
<Guide
|
||||
className="edit-post-welcome-guide"
|
||||
onFinish={ () => {
|
||||
unregisterPlugin( app.pluginId );
|
||||
setIsOpen( false );
|
||||
} }
|
||||
pages={ app.getGuidePages() }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
noticeSettings.actions[ 0 ].onClick = () => registerPlugin( app.pluginId, { render: GutenbergTutorial } );
|
||||
|
||||
return noticeSettings;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get Guide pages in proper format.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @return {Array} Guide Pages.
|
||||
*/
|
||||
getGuidePages() {
|
||||
const pages = [];
|
||||
|
||||
wpforms_edit_post_education.gutenberg_guide.forEach( function( page ) {
|
||||
pages.push(
|
||||
{
|
||||
/* eslint-disable react/react-in-jsx-scope */
|
||||
content: (
|
||||
<>
|
||||
<h1 className="edit-post-welcome-guide__heading">{ page.title }</h1>
|
||||
<p className="edit-post-welcome-guide__text">{ page.content }</p>
|
||||
</>
|
||||
),
|
||||
image: <img className="edit-post-welcome-guide__image" src={ page.image } alt={ page.title } />,
|
||||
/* eslint-enable react/react-in-jsx-scope */
|
||||
}
|
||||
);
|
||||
} );
|
||||
|
||||
return pages;
|
||||
},
|
||||
|
||||
/**
|
||||
* Show notice if the page title matches some keywords for Classic Editor.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
maybeShowClassicNotice() {
|
||||
if ( app.isNoticeVisible ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( app.isTitleMatchKeywords( $( '#title' ).val() ) ) {
|
||||
app.isNoticeVisible = true;
|
||||
|
||||
$( '.wpforms-edit-post-education-notice' ).removeClass( 'wpforms-hidden' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Show notice if the page title matches some keywords for Gutenberg Editor.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
maybeShowGutenbergNotice() {
|
||||
if ( app.isNoticeVisible ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const title = app.getEditorTitle();
|
||||
|
||||
if ( app.isTitleMatchKeywords( title ) ) {
|
||||
app.isNoticeVisible = true;
|
||||
|
||||
app.showGutenbergNotice();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine if the title matches keywords.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*
|
||||
* @param {string} titleValue Page title value.
|
||||
*
|
||||
* @return {boolean} True if the title matches some keywords.
|
||||
*/
|
||||
isTitleMatchKeywords( titleValue ) {
|
||||
const expectedTitleRegex = new RegExp( /\b(contact|form)\b/i );
|
||||
|
||||
return expectedTitleRegex.test( titleValue );
|
||||
},
|
||||
|
||||
/**
|
||||
* Close a notice.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
closeNotice() {
|
||||
$( this ).closest( '.wpforms-edit-post-education-notice' ).remove();
|
||||
|
||||
app.updateUserMeta();
|
||||
},
|
||||
|
||||
/**
|
||||
* Update user meta and don't show the notice next time.
|
||||
*
|
||||
* @since 1.8.1
|
||||
*/
|
||||
updateUserMeta() {
|
||||
$.post(
|
||||
wpforms_edit_post_education.ajax_url,
|
||||
{
|
||||
action: 'wpforms_education_dismiss',
|
||||
nonce: wpforms_edit_post_education.education_nonce,
|
||||
section: 'edit-post-notice',
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
return app;
|
||||
}( document, window, jQuery ) );
|
||||
|
||||
WPFormsEditPostEducation.init();
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* PDF Education.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @param {Window} window The global window object.
|
||||
* @param {jQuery} $ The jQuery object.
|
||||
*/
|
||||
( function( window, $ ) {
|
||||
const app = {
|
||||
/**
|
||||
* The whole popup element.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$popup: null,
|
||||
|
||||
/**
|
||||
* The builder element.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$builder: null,
|
||||
|
||||
/**
|
||||
* The close button element inside the popup. Closes popup.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$close: null,
|
||||
|
||||
/**
|
||||
* The button element inside the popup. Triggers the PDF panel.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$switchButton: null,
|
||||
|
||||
/**
|
||||
* The notification section element.
|
||||
* This is what a user sees when clicking on Builder > Settings > Notifications.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$notifications: null,
|
||||
|
||||
/**
|
||||
* The PDF panel element.
|
||||
* This is what a user sees when clicking on Builder > Settings > PDF.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$pdfPanel: null,
|
||||
|
||||
/**
|
||||
* Initializes the app.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*/
|
||||
ready() {
|
||||
app.$popup = $( '#wpforms-pdf-popup' );
|
||||
app.$close = app.$popup.find( '.close-popup' );
|
||||
app.$switchButton = app.$popup.find( 'button.education-modal[data-target="wpforms-pdf"]' );
|
||||
app.$notifications = $( '.wpforms-panel-content-section.wpforms-panel-content-section-notifications' );
|
||||
app.$builder = $( '#wpforms-builder' );
|
||||
app.$pdfPanel = $( '.wpforms-panel-sidebar-section.wpforms-panel-sidebar-section-pdf' );
|
||||
|
||||
app.run();
|
||||
},
|
||||
/**
|
||||
* Runs the app.
|
||||
*
|
||||
* @since 1.9.7.3
|
||||
*/
|
||||
run() {
|
||||
/*
|
||||
* User clicked on one of the subsections in Builder > Settings.
|
||||
*/
|
||||
app.$builder.on( 'wpformsPanelSectionSwitch', function( e, section ) {
|
||||
if ( section === 'default' || ! section ) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.$popup.toggle( section === 'notifications' );
|
||||
} );
|
||||
|
||||
/*
|
||||
* User clicked on the left dark sidebar in Builder.
|
||||
*/
|
||||
app.$builder.on( 'wpformsPanelSwitched', () => {
|
||||
app.$popup.toggle( app.$notifications.is( ':visible' ) );
|
||||
} );
|
||||
|
||||
/*
|
||||
* User clicked on the 'Try it Out' button.
|
||||
*/
|
||||
app.$switchButton.on( 'click', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
app.$pdfPanel.click();
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
app.init();
|
||||
}( window, jQuery ) );
|
||||
+1
@@ -0,0 +1 @@
|
||||
(n=>{let i={$popup:null,$builder:null,$close:null,$switchButton:null,$notifications:null,$pdfPanel:null,init(){n(i.ready)},ready(){i.$popup=n("#wpforms-pdf-popup"),i.$close=i.$popup.find(".close-popup"),i.$switchButton=i.$popup.find('button.education-modal[data-target="wpforms-pdf"]'),i.$notifications=n(".wpforms-panel-content-section.wpforms-panel-content-section-notifications"),i.$builder=n("#wpforms-builder"),i.$pdfPanel=n(".wpforms-panel-sidebar-section.wpforms-panel-sidebar-section-pdf"),i.run()},run(){i.$builder.on("wpformsPanelSectionSwitch",function(n,o){"default"!==o&&o&&i.$popup.toggle("notifications"===o)}),i.$builder.on("wpformsPanelSwitched",()=>{i.$popup.toggle(i.$notifications.is(":visible"))}),i.$switchButton.on("click",function(n){n.preventDefault(),i.$pdfPanel.click()})}};i.init()})((window,jQuery));
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/* eslint-disable camelcase */
|
||||
/* global ajaxurl, wpforms_education_pointers_payment */
|
||||
|
||||
// noinspection ES6ConvertVarToLetConst
|
||||
/**
|
||||
* Module for handling education pointers related to payments in WPForms.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var WPFormsPointersPayment = window.WPFormsPointersPayment || ( function( document, window, $, l10n ) {
|
||||
/**
|
||||
* Elements holder.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const el = {};
|
||||
|
||||
/**
|
||||
* Runtime variables.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const vars = {
|
||||
/**
|
||||
* Unique ID for the pointer.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
pointerId: l10n.pointer,
|
||||
|
||||
/**
|
||||
* Cryptographic token for validating authorized Ajax data exchange.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
nonce: l10n.nonce,
|
||||
};
|
||||
|
||||
/**
|
||||
* Public functions and properties.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
const app = {
|
||||
|
||||
/**
|
||||
* Start the engine.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
init() {
|
||||
$( app.ready );
|
||||
},
|
||||
|
||||
/**
|
||||
* Document ready.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
ready() {
|
||||
app.setup();
|
||||
app.bindEvents();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup. Prepare some variables.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
setup() {
|
||||
// Cache DOM elements.
|
||||
el.$document = $( document );
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*/
|
||||
bindEvents() {
|
||||
el.$document.on( 'click', '#toplevel_page_wpforms-overview [href$="-payments"], #wpforms-education-pointers-payments', app.handleOnClick );
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for clicking on the action link.
|
||||
*
|
||||
* @since 1.8.8
|
||||
*
|
||||
* @param {Object} event An event which takes place in the DOM.
|
||||
*/
|
||||
handleOnClick( event ) {
|
||||
// Prevent the default action.
|
||||
event.preventDefault();
|
||||
|
||||
const $this = $( this );
|
||||
|
||||
// Get the href attribute.
|
||||
const href = $this.attr( 'href' );
|
||||
|
||||
// Return early if href is missing.
|
||||
if ( ! href ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide the pointer before redirecting.
|
||||
$this.closest( '.wp-pointer-content' ).parent().hide();
|
||||
|
||||
// Send AJAX request.
|
||||
$.post(
|
||||
ajaxurl,
|
||||
{
|
||||
pointer_id: vars.pointerId,
|
||||
_ajax_nonce: vars.nonce,
|
||||
action: 'wpforms_education_pointers_engagement',
|
||||
}
|
||||
).done( function() {
|
||||
window.location.href = href;
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
// Provide access to public functions/properties.
|
||||
return app;
|
||||
}( document, window, jQuery, wpforms_education_pointers_payment ) );
|
||||
|
||||
// Initialize.
|
||||
WPFormsPointersPayment.init();
|
||||
Vendored
Executable
+1
@@ -0,0 +1 @@
|
||||
var WPFormsPointersPayment=window.WPFormsPointersPayment||((e,t,o,n)=>{let i={},r={pointerId:n.pointer,nonce:n.nonce},a={init(){o(a.ready)},ready(){a.setup(),a.bindEvents()},setup(){i.$document=o(e)},bindEvents(){i.$document.on("click",'#toplevel_page_wpforms-overview [href$="-payments"], #wpforms-education-pointers-payments',a.handleOnClick)},handleOnClick(e){e.preventDefault();e=o(this);let n=e.attr("href");n&&(e.closest(".wp-pointer-content").parent().hide(),o.post(ajaxurl,{pointer_id:r.pointerId,_ajax_nonce:r.nonce,action:"wpforms_education_pointers_engagement"}).done(function(){t.location.href=n}))}};return a})(document,window,jQuery,wpforms_education_pointers_payment);WPFormsPointersPayment.init();
|
||||
Reference in New Issue
Block a user