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:
@@ -17,7 +17,7 @@ if (!defined('ABSPATH')) {
|
||||
}
|
||||
|
||||
// Plugin constants
|
||||
define('MLS_PLUGIN_VERSION', '1.0.0');
|
||||
define('MLS_PLUGIN_VERSION', '1.0.1');
|
||||
define('MLS_PLUGIN_FILE', __FILE__);
|
||||
define('MLS_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||||
define('MLS_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||||
@@ -33,10 +33,16 @@ define('MLS_TABLE_SYNC_LOG', 'mls_sync_log');
|
||||
define('MLS_TABLE_MEDIA_LOG', 'mls_media_log');
|
||||
define('MLS_TABLE_GEO_CITIES', 'mls_geo_cities');
|
||||
define('MLS_TABLE_GEO_ZIPCODES', 'mls_geo_zipcodes');
|
||||
define('MLS_TABLE_MANUAL_PROPERTIES', 'mls_properties_manual');
|
||||
|
||||
// HomeProz office MLS ID for identifying our listings
|
||||
define('MLS_HOMEPROZ_OFFICE_ID', 'NST253235');
|
||||
|
||||
// Specific MLS listing IDs to treat as HomeProz (for listings from other offices we want to showcase)
|
||||
define('MLS_HOMEPROZ_OVERRIDE_LISTINGS', array(
|
||||
'NST6769023', // 121 Main Street, Glenville, MN 56036 (LandProz)
|
||||
));
|
||||
|
||||
// Allowed states for MLS queries (MN and IA only)
|
||||
define('MLS_ALLOWED_STATES', array('MN', 'IA'));
|
||||
|
||||
@@ -64,6 +70,7 @@ final class MLS_Plugin {
|
||||
private $query;
|
||||
private $cluster;
|
||||
private $garbage_collector;
|
||||
private $manual_property;
|
||||
|
||||
/**
|
||||
* Get single instance
|
||||
@@ -100,6 +107,8 @@ final class MLS_Plugin {
|
||||
require_once MLS_PLUGIN_DIR . 'includes/class-mls-cluster.php';
|
||||
require_once MLS_PLUGIN_DIR . 'includes/class-mls-geo-validator.php';
|
||||
require_once MLS_PLUGIN_DIR . 'includes/class-mls-garbage-collector.php';
|
||||
require_once MLS_PLUGIN_DIR . 'includes/class-mls-geocoder.php';
|
||||
require_once MLS_PLUGIN_DIR . 'includes/class-mls-manual-property.php';
|
||||
|
||||
// Activation/Deactivation
|
||||
require_once MLS_PLUGIN_DIR . 'includes/class-mls-activator.php';
|
||||
@@ -151,7 +160,8 @@ final class MLS_Plugin {
|
||||
);
|
||||
$this->query = new MLS_Query($this->db);
|
||||
$this->cluster = new MLS_Cluster($this->db);
|
||||
$this->garbage_collector = new MLS_Garbage_Collector($this->logger);
|
||||
$this->garbage_collector = new MLS_Garbage_Collector($this->logger, $this->db);
|
||||
$this->manual_property = new MLS_Manual_Property($this->db);
|
||||
|
||||
// Register AJAX handlers
|
||||
add_action('wp_ajax_mls_get_clusters', array($this, 'ajax_get_clusters'));
|
||||
@@ -257,6 +267,13 @@ final class MLS_Plugin {
|
||||
return $this->garbage_collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Manual Property instance
|
||||
*/
|
||||
public function get_manual_property() {
|
||||
return $this->manual_property;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler for getting map clusters
|
||||
*/
|
||||
@@ -326,12 +343,12 @@ function mls_get_properties($args = array()) {
|
||||
* @param string $identifier Listing key or MLS ID
|
||||
* @return object|null Property object or null
|
||||
*/
|
||||
function mls_get_property($identifier) {
|
||||
function mls_get_property($identifier, $skip_manual_override = false) {
|
||||
$plugin = mls_plugin();
|
||||
if (!$plugin->get_query()) {
|
||||
return null;
|
||||
}
|
||||
return $plugin->get_query()->get_property($identifier);
|
||||
return $plugin->get_query()->get_property($identifier, $skip_manual_override);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,17 +370,31 @@ function mls_get_property_media($listing_key) {
|
||||
*
|
||||
* Images are fetched from MLS Grid and cached locally on first request.
|
||||
* Per MLS Grid rules, images must be served from our own server.
|
||||
* For manual properties (MANUAL-xxx), returns the first gallery image.
|
||||
*
|
||||
* @param string $listing_key The listing key
|
||||
* @param bool $fetch_if_missing Whether to fetch from MLS Grid if not cached (default: true)
|
||||
* @return string|null Image URL or null
|
||||
*/
|
||||
function mls_get_property_image($listing_key, $fetch_if_missing = true) {
|
||||
// Handle manual properties - images are in WordPress media library
|
||||
if (strpos($listing_key, 'MANUAL-') === 0) {
|
||||
$images = MLS_Manual_Property::get_manual_property_images($listing_key);
|
||||
if (!empty($images) && isset($images[0]->local_url)) {
|
||||
return $images[0]->local_url;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
$plugin = mls_plugin();
|
||||
if (!$plugin->get_media_handler()) {
|
||||
return null;
|
||||
}
|
||||
return $plugin->get_media_handler()->get_primary_image($listing_key, $fetch_if_missing);
|
||||
$result = $plugin->get_media_handler()->get_primary_image($listing_key, $fetch_if_missing);
|
||||
if (is_wp_error($result) || !is_string($result)) {
|
||||
return null;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user