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:
+4195
File diff suppressed because one or more lines are too long
Vendored
Executable
+1
File diff suppressed because one or more lines are too long
+202
@@ -0,0 +1,202 @@
|
||||
/* global wpforms_divi_builder, WPFormsRepeaterField, ETBuilderBackendDynamic */
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
|
||||
/**
|
||||
* WPFormsSelector component.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
class WPFormsSelector extends Component {
|
||||
|
||||
/**
|
||||
* Module slug.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
static slug = 'wpforms_selector';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {string} props List of properties.
|
||||
*/
|
||||
constructor( props ) {
|
||||
|
||||
super( props );
|
||||
|
||||
this.state = {
|
||||
error: null,
|
||||
isLoading: true,
|
||||
form: null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set types for properties.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @returns {object} Properties type.
|
||||
*/
|
||||
static get propTypes() {
|
||||
|
||||
return {
|
||||
form_id: PropTypes.number, // eslint-disable-line camelcase
|
||||
show_title: PropTypes.string, // eslint-disable-line camelcase
|
||||
show_desc: PropTypes.string, // eslint-disable-line camelcase
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if form settings was updated.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @param {object} prevProps List of previous properties.
|
||||
*/
|
||||
componentDidUpdate( prevProps ) {
|
||||
|
||||
if ( prevProps.form_id !== this.props.form_id || prevProps.show_title !== this.props.show_title || prevProps.show_desc !== this.props.show_desc ) {
|
||||
this.componentDidMount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax request for form HTML.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*/
|
||||
componentDidMount() {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append( 'nonce', wpforms_divi_builder.nonce );
|
||||
formData.append( 'action', 'wpforms_divi_preview' );
|
||||
formData.append( 'form_id', this.props.form_id );
|
||||
formData.append( 'show_title', this.props.show_title );
|
||||
formData.append( 'show_desc', this.props.show_desc );
|
||||
|
||||
fetch(
|
||||
wpforms_divi_builder.ajax_url,
|
||||
{
|
||||
method: 'POST',
|
||||
cache: 'no-cache',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Cache-Control': 'no-cache',
|
||||
},
|
||||
body: new URLSearchParams( formData ),
|
||||
},
|
||||
)
|
||||
.then( ( res ) => res.json() )
|
||||
.then(
|
||||
( result ) => {
|
||||
this.setState( {
|
||||
isLoading: false,
|
||||
form: result.data,
|
||||
} );
|
||||
},
|
||||
( error ) => {
|
||||
this.setState( {
|
||||
isLoading: false,
|
||||
error,
|
||||
} );
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render module view.
|
||||
*
|
||||
* @since 1.6.3
|
||||
*
|
||||
* @returns {JSX.Element} View for module.
|
||||
*/
|
||||
render() {
|
||||
const { error, isLoaded, form } = this.state,
|
||||
wrapperClasses = isLoaded ? 'wpforms-divi-form-preview loading' : 'wpforms-divi-form-preview';
|
||||
|
||||
if ( typeof this.props.form_id === 'undefined' || this.props.form_id === '' ) {
|
||||
return (
|
||||
<div className="wpforms-divi-empty-block">
|
||||
<img src={ wpforms_divi_builder.block_empty_url } alt="" />
|
||||
|
||||
{ <p dangerouslySetInnerHTML={ { __html: wpforms_divi_builder.block_empty_text } } /> }
|
||||
|
||||
<button type="button" onClick={
|
||||
() => {
|
||||
window.open( wpforms_divi_builder.get_started_url, '_blank' );
|
||||
}
|
||||
}
|
||||
>
|
||||
{ wpforms_divi_builder.get_started_text }
|
||||
</button>
|
||||
|
||||
<p className="wpforms-admin-no-forms-footer">
|
||||
{ wpforms_divi_builder.help_text }
|
||||
<a href={ wpforms_divi_builder.guide_url } onClick={
|
||||
() => {
|
||||
window.open( wpforms_divi_builder.guide_url, '_blank' );
|
||||
}
|
||||
}
|
||||
>
|
||||
{ wpforms_divi_builder.guide_text }.
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if ( error || ! form ) {
|
||||
return (
|
||||
<div className="wpforms-divi-form-placeholder">
|
||||
<img src={ wpforms_divi_builder.placeholder } alt="" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ wrapperClasses }>
|
||||
{ <div dangerouslySetInnerHTML={ { __html: form } } /> }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
jQuery( window )
|
||||
|
||||
// Register custom modules.
|
||||
.on( 'et_builder_api_ready', ( event, API ) => {
|
||||
API.registerModules( [ WPFormsSelector ] );
|
||||
} )
|
||||
|
||||
// Re-initialize WPForms frontend.
|
||||
.on( 'wpformsDiviModuleDisplay', () => {
|
||||
window.wpforms.init();
|
||||
} );
|
||||
|
||||
jQuery( document )
|
||||
.on( 'wpformsReady', function() {
|
||||
const $ = jQuery;
|
||||
|
||||
// Make all the modern dropdowns disabled.
|
||||
$( '.choicesjs-select' ).each( function() {
|
||||
const $instance = $( this ).data( 'choicesjs' );
|
||||
|
||||
if ( $instance && typeof $instance.disable === 'function' ) {
|
||||
$instance.disable();
|
||||
}
|
||||
} );
|
||||
|
||||
// Init Repeater fields.
|
||||
if ( 'undefined' !== typeof WPFormsRepeaterField ) {
|
||||
WPFormsRepeaterField.ready();
|
||||
}
|
||||
} );
|
||||
Reference in New Issue
Block a user