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:
root
2026-04-29 15:32:23 +00:00
parent 57b752f54e
commit b6df4dbb92
5385 changed files with 838580 additions and 2416 deletions
+57 -2
View File
@@ -5,12 +5,18 @@
* Cleans up old MLS image directories when disk space is low.
* Runs after sync to prevent disk from filling up.
*
* IMPORTANT: Only cleans the standard cache directory (mls-listings).
* The persistent cache directory (mls-listings-persistent) is NEVER touched.
* HomeProz listing images are stored in persistent cache and preserved
* even after listings are sold or removed from MLS.
*
* Configuration (wp-config.php):
* - MLS_GC_DISK_THRESHOLD: Minimum free disk space in bytes before cleanup triggers
* Example: define('MLS_GC_DISK_THRESHOLD', 5 * 1024 * 1024 * 1024); // 5GB
*
* Behavior:
* - Only runs if MLS_GC_DISK_THRESHOLD is defined
* - Only cleans standard cache (mls-listings), never persistent cache
* - Skips directories modified within the last 24 hours
* - Deletes oldest directories first
* - Stops when free space >= 5GB or 2GB deleted per run
@@ -42,13 +48,20 @@ class MLS_Garbage_Collector {
*/
private $logger;
/**
* Database instance
*/
private $db;
/**
* Constructor
*
* @param MLS_Logger $logger Logger instance
* @param MLS_DB|null $db Database instance (optional for backwards compatibility)
*/
public function __construct(MLS_Logger $logger) {
public function __construct(MLS_Logger $logger, MLS_DB $db = null) {
$this->logger = $logger;
$this->db = $db;
}
/**
@@ -70,7 +83,11 @@ class MLS_Garbage_Collector {
}
/**
* Get the MLS images upload directory
* Get the MLS images upload directory (standard cache only)
*
* Returns the standard cache directory that is subject to garbage collection.
* The persistent cache (mls-listings-persistent) is intentionally excluded
* to preserve HomeProz listing images indefinitely.
*
* @return string Absolute path to MLS images directory
*/
@@ -324,6 +341,10 @@ class MLS_Garbage_Collector {
$deleted_bytes += $size;
$deleted_count++;
// Reset download_status to 'pending' for this listing's media
// so images can be re-downloaded on demand later
$this->reset_media_download_status($listing_key);
$this->logger->info('Garbage collection deleted directory', array(
'listing_key' => $listing_key,
'size' => $size,
@@ -366,6 +387,40 @@ class MLS_Garbage_Collector {
return $result;
}
/**
* Reset download_status to 'pending' for a listing's media records
*
* Called after deleting cached files so images can be re-downloaded on demand.
*
* @param string $listing_key Listing key
*/
private function reset_media_download_status($listing_key) {
global $wpdb;
// Get the media table name
$media_table = $this->db ? $this->db->media_table() : $wpdb->prefix . 'mls_media';
$updated = $wpdb->update(
$media_table,
array(
'download_status' => 'pending',
'local_path' => null,
'local_url' => null,
'downloaded_at' => null,
),
array('listing_key' => $listing_key),
array('%s', null, null, null),
array('%s')
);
if ($updated > 0) {
$this->logger->debug('Reset media download status for garbage collected listing', array(
'listing_key' => $listing_key,
'records_updated' => $updated,
));
}
}
/**
* Clean up empty prefix directories
*/