Integrate MLS listings with property map and add smart sync

Property Map:
- Replace ACF-based property display with MLS database queries
- Use real lat/lng coordinates from MLS (100% coverage)
- Create property-card-mls.php template for MLS property cards
- Update AJAX handler to filter MLS properties

MLS Plugin Enhancements:
- Add 'wp mls run' smart sync command (auto-detects full/incremental/resume)
- Add database index migrations for lat/lng and composite search indexes
- Add comprehensive README.md documentation

Documentation:
- Update site README.md with sysadmin quick reference
- Add FEATURES_PENDING_12_15.md tracking client feature requests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Hanson.xyz Dev
2025-12-15 22:32:41 -06:00
parent b9cddd2f64
commit fc018ca604
13 changed files with 2346 additions and 308 deletions
@@ -34,6 +34,7 @@ class MLS_CLI {
WP_CLI::add_command('mls test', array($instance, 'test'));
WP_CLI::add_command('mls status', array($instance, 'status'));
WP_CLI::add_command('mls sync', array($instance, 'sync'));
WP_CLI::add_command('mls run', array($instance, 'run'));
WP_CLI::add_command('mls stats', array($instance, 'stats'));
WP_CLI::add_command('mls cache', array($instance, 'cache'));
WP_CLI::add_command('mls recovery', array($instance, 'recovery'));
@@ -369,6 +370,149 @@ class MLS_CLI {
}
}
/**
* Run smart sync - autonomous self-healing sync.
*
* This is the recommended command for automated/cron usage. It automatically
* determines the best action based on current state:
*
* - If a sync is running: abort (prevents duplicate syncs)
* - If a previous sync failed/interrupted: resume it
* - If no data exists: run full sync
* - Otherwise: run incremental sync
*
* Failed syncs are automatically recoverable on the next run.
*
* ## OPTIONS
*
* [--quiet]
* : Suppress progress output (still shows status messages)
*
* [--verbose]
* : Show detailed output including API requests
*
* [--silent]
* : Suppress all output except errors (for cron)
*
* ## EXAMPLES
*
* wp mls run # Smart sync with progress
* wp mls run --quiet # Smart sync, status only
* wp mls run --verbose # Smart sync with full details
* wp mls run --silent # For cron jobs
*
* @subcommand run
*/
public function run($args, $assoc_args) {
$quiet = isset($assoc_args['quiet']);
$verbose = isset($assoc_args['verbose']);
$silent = isset($assoc_args['silent']);
$sync_engine = $this->plugin->get_sync_engine();
// Status callback for high-level messages
$status_callback = null;
if (!$silent) {
$status_callback = function($message, $level = 'info') {
$timestamp = date('H:i:s');
switch ($level) {
case 'warning':
WP_CLI::warning("[{$timestamp}] {$message}");
break;
case 'error':
WP_CLI::warning("[{$timestamp}] {$message}");
break;
default:
WP_CLI::line("[{$timestamp}] {$message}");
}
};
}
// Progress callback for record-level progress
$progress_callback = null;
if (!$quiet && !$silent) {
$progress_callback = function($event, $data = array()) use ($verbose) {
if ($verbose) {
$this->output_verbose_event($event, $data);
} else {
switch ($event) {
case 'property_created':
echo '.';
break;
case 'property_updated':
echo '#';
break;
case 'property_deleted':
echo 'x';
break;
case 'property_error':
echo '!';
break;
case 'page_complete':
echo '|';
break;
}
}
};
}
if (!$silent) {
WP_CLI::line('');
WP_CLI::line('=== MLS Smart Sync ===');
WP_CLI::line('');
}
// Run smart sync
$result = $sync_engine->smart_sync($progress_callback, $status_callback);
// Handle aborted case (sync already running)
if (isset($result['action']) && $result['action'] === 'aborted') {
if (!$silent) {
WP_CLI::warning('Sync aborted: ' . ($result['reason'] ?? 'Unknown reason'));
}
return;
}
// Output newline after progress dots
if (!$quiet && !$silent && !$verbose) {
echo "\n";
}
// Output results
if (!$silent) {
$action_labels = array(
'full' => 'Full sync',
'incremental' => 'Incremental sync',
'resumed' => 'Resumed sync',
);
$action_label = $action_labels[$result['action']] ?? 'Sync';
if ($result['success']) {
WP_CLI::success("{$action_label} completed successfully!");
} else {
WP_CLI::warning("{$action_label} failed: " . ($result['error'] ?? 'Unknown error'));
WP_CLI::line('The sync can be resumed on the next run.');
}
if (isset($result['stats'])) {
$stats = $result['stats'];
WP_CLI::line(sprintf(
'Processed: %d | Created: %d | Updated: %d | Deleted: %d | Errors: %d',
$stats['processed'],
$stats['created'],
$stats['updated'],
$stats['deleted'],
$stats['errors']
));
}
}
// Exit with error code if failed (for cron monitoring)
if (!$result['success']) {
WP_CLI::halt(1);
}
}
/**
* Print progress legend
*