Refactor MLS sync to Active/Pending only with on-demand media

Major changes to sync strategy following MLS Grid best practices:

- Initial sync now fetches only Active/Pending properties (~30K vs 1.3M)
- Replication (incremental) fetches all changes, deletes non-Active/Pending
- On-demand media fetching replaces background queue (avoids rate limits)
- Media downloaded and cached when first viewed, not during sync
- Updated CLI commands: wp mls media status/fetch/clear
- Comprehensive documentation with troubleshooting guide

This fixes the "Value out of range" API error caused by high $skip values.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Hanson.xyz Dev
2025-12-15 08:25:37 -06:00
parent 6eadf3d266
commit b9cddd2f64
6 changed files with 538 additions and 874 deletions
@@ -318,26 +318,53 @@ class MLS_API_Client {
}
/**
* Get properties including those marked for deletion (for sync)
* Get properties for initial sync (Active/Pending only)
*
* @param string|null $timestamp Optional modification timestamp filter
* @param string|null $expand Expand parameter
* @param int|null $top Number of records
* @return array|WP_Error Response data or error
*/
public function get_properties_for_sync($timestamp = null, $expand = null, $top = null) {
// Don't filter by MlgCanView for sync - we need to see deleted records
public function get_properties_for_initial_sync($expand = null, $top = null) {
$params = array();
$system = $this->options->get_originating_system();
if ($timestamp) {
$params['$filter'] = "OriginatingSystemName eq '{$system}' and ModificationTimestamp gt {$timestamp}";
} else {
// Initial sync - only get viewable records
$params['$filter'] = "OriginatingSystemName eq '{$system}' and MlgCanView eq true";
// Initial sync: only Active/Pending with MlgCanView=true
$params['$filter'] = "OriginatingSystemName eq '{$system}' and MlgCanView eq true and (StandardStatus eq 'Active' or StandardStatus eq 'Pending')";
if ($expand) {
$params['$expand'] = $expand;
}
if ($top) {
$params['$top'] = min($top, $expand ? self::MAX_TOP_WITH_EXPAND : self::MAX_TOP_NO_EXPAND);
} else {
$params['$top'] = $expand ? self::MAX_TOP_WITH_EXPAND : self::DEFAULT_TOP;
}
return $this->request('Property', $params);
}
/**
* Get properties modified since timestamp (for replication)
*
* Does NOT filter by MlgCanView or StandardStatus so we can detect:
* - Records that became unavailable (MlgCanView=false)
* - Records that changed status (Active -> Sold)
*
* @param string $timestamp ISO 8601 modification timestamp
* @param string|null $expand Expand parameter
* @param int|null $top Number of records
* @return array|WP_Error Response data or error
*/
public function get_properties_for_replication($timestamp, $expand = null, $top = null) {
$params = array();
$system = $this->options->get_originating_system();
// Replication: get ALL changes since timestamp (no MlgCanView or Status filter)
$params['$filter'] = "OriginatingSystemName eq '{$system}' and ModificationTimestamp gt {$timestamp}";
if ($expand) {
$params['$expand'] = $expand;
}