Implement launch blockers and MLS state filter
- Add MLS state filter for MN/IA only queries - Add property inquiry form auto-population with read-only display - Update broker info and office hours in footer - Remove Bridge Realty text from about page - Update service area to Minnesota and Iowa - Add HomeProz listing identification (is_homeproz column) - Add dynamic featured listings on front page - Add gallery thumbnail preloading and loading spinners - Update FEATURES_PENDING with completion status 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -11,9 +11,9 @@ class MLS_DB {
|
||||
|
||||
/**
|
||||
* Schema version for index migrations
|
||||
* Increment this when adding new indexes
|
||||
* Increment this when adding new indexes or columns
|
||||
*/
|
||||
const SCHEMA_VERSION = 2;
|
||||
const SCHEMA_VERSION = 3;
|
||||
|
||||
/**
|
||||
* Get table name with prefix
|
||||
@@ -126,6 +126,7 @@ class MLS_DB {
|
||||
list_office_key VARCHAR(50) DEFAULT NULL,
|
||||
list_office_mls_id VARCHAR(50) DEFAULT NULL,
|
||||
list_office_name VARCHAR(150) DEFAULT NULL,
|
||||
is_homeproz TINYINT(1) NOT NULL DEFAULT 0,
|
||||
|
||||
photos_count INT(5) DEFAULT 0,
|
||||
modification_timestamp DATETIME NOT NULL,
|
||||
@@ -332,8 +333,41 @@ class MLS_DB {
|
||||
update_option('mls_schema_version', 2);
|
||||
}
|
||||
|
||||
// Migration to schema version 3: Add is_homeproz column and index
|
||||
if ($current_schema < 3) {
|
||||
$table_properties = $wpdb->prefix . MLS_TABLE_PROPERTIES;
|
||||
|
||||
// Check if column exists
|
||||
$column_exists = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s AND COLUMN_NAME = 'is_homeproz'",
|
||||
DB_NAME,
|
||||
$table_properties
|
||||
));
|
||||
|
||||
if (!$column_exists) {
|
||||
$wpdb->query("ALTER TABLE {$table_properties} ADD COLUMN is_homeproz TINYINT(1) NOT NULL DEFAULT 0 AFTER list_office_name");
|
||||
}
|
||||
|
||||
// Add index if not exists
|
||||
$existing_indexes = self::get_existing_indexes($table_properties);
|
||||
if (!isset($existing_indexes['idx_is_homeproz'])) {
|
||||
$wpdb->query("ALTER TABLE {$table_properties} ADD INDEX idx_is_homeproz (is_homeproz)");
|
||||
}
|
||||
|
||||
// Update existing HomeProz listings
|
||||
if (defined('MLS_HOMEPROZ_OFFICE_ID')) {
|
||||
$wpdb->query($wpdb->prepare(
|
||||
"UPDATE {$table_properties} SET is_homeproz = 1 WHERE list_office_mls_id = %s",
|
||||
MLS_HOMEPROZ_OFFICE_ID
|
||||
));
|
||||
}
|
||||
|
||||
update_option('mls_schema_version', 3);
|
||||
}
|
||||
|
||||
// Future migrations go here:
|
||||
// if ($current_schema < 3) { ... }
|
||||
// if ($current_schema < 4) { ... }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,6 +23,23 @@ class MLS_Query {
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state filter SQL clause
|
||||
* Restricts results to MN and IA only
|
||||
*
|
||||
* @return string SQL clause
|
||||
*/
|
||||
private function get_state_filter() {
|
||||
if (!defined('MLS_ALLOWED_STATES') || empty(MLS_ALLOWED_STATES)) {
|
||||
return '';
|
||||
}
|
||||
$states = array_map(function($s) {
|
||||
global $wpdb;
|
||||
return $wpdb->prepare('%s', $s);
|
||||
}, MLS_ALLOWED_STATES);
|
||||
return 'state_or_province IN (' . implode(',', $states) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properties matching criteria
|
||||
*
|
||||
@@ -79,6 +96,12 @@ class MLS_Query {
|
||||
$where = array('mlg_can_view = 1');
|
||||
$values = array();
|
||||
|
||||
// Add state filter (MN and IA only)
|
||||
$state_filter = $this->get_state_filter();
|
||||
if ($state_filter) {
|
||||
$where[] = $state_filter;
|
||||
}
|
||||
|
||||
if ($args['status']) {
|
||||
$where[] = 'standard_status = %s';
|
||||
$values[] = $args['status'];
|
||||
@@ -305,18 +328,20 @@ class MLS_Query {
|
||||
global $wpdb;
|
||||
|
||||
$table = $this->db->properties_table();
|
||||
$state_filter = $this->get_state_filter();
|
||||
$state_clause = $state_filter ? " AND {$state_filter}" : '';
|
||||
|
||||
if ($status) {
|
||||
$cities = $wpdb->get_col($wpdb->prepare(
|
||||
"SELECT DISTINCT city FROM {$table}
|
||||
WHERE mlg_can_view = 1 AND standard_status = %s AND city IS NOT NULL
|
||||
WHERE mlg_can_view = 1 AND standard_status = %s AND city IS NOT NULL{$state_clause}
|
||||
ORDER BY city ASC",
|
||||
$status
|
||||
));
|
||||
} else {
|
||||
$cities = $wpdb->get_col(
|
||||
"SELECT DISTINCT city FROM {$table}
|
||||
WHERE mlg_can_view = 1 AND city IS NOT NULL
|
||||
WHERE mlg_can_view = 1 AND city IS NOT NULL{$state_clause}
|
||||
ORDER BY city ASC"
|
||||
);
|
||||
}
|
||||
@@ -334,18 +359,20 @@ class MLS_Query {
|
||||
global $wpdb;
|
||||
|
||||
$table = $this->db->properties_table();
|
||||
$state_filter = $this->get_state_filter();
|
||||
$state_clause = $state_filter ? " AND {$state_filter}" : '';
|
||||
|
||||
if ($status) {
|
||||
$counties = $wpdb->get_col($wpdb->prepare(
|
||||
"SELECT DISTINCT county FROM {$table}
|
||||
WHERE mlg_can_view = 1 AND standard_status = %s AND county IS NOT NULL
|
||||
WHERE mlg_can_view = 1 AND standard_status = %s AND county IS NOT NULL{$state_clause}
|
||||
ORDER BY county ASC",
|
||||
$status
|
||||
));
|
||||
} else {
|
||||
$counties = $wpdb->get_col(
|
||||
"SELECT DISTINCT county FROM {$table}
|
||||
WHERE mlg_can_view = 1 AND county IS NOT NULL
|
||||
WHERE mlg_can_view = 1 AND county IS NOT NULL{$state_clause}
|
||||
ORDER BY county ASC"
|
||||
);
|
||||
}
|
||||
@@ -367,6 +394,12 @@ class MLS_Query {
|
||||
$where = array('mlg_can_view = 1');
|
||||
$values = array();
|
||||
|
||||
// Add state filter (MN and IA only)
|
||||
$state_filter = $this->get_state_filter();
|
||||
if ($state_filter) {
|
||||
$where[] = $state_filter;
|
||||
}
|
||||
|
||||
if (!empty($args['status'])) {
|
||||
$where[] = 'standard_status = %s';
|
||||
$values[] = $args['status'];
|
||||
@@ -437,8 +470,11 @@ class MLS_Query {
|
||||
public function has_data() {
|
||||
global $wpdb;
|
||||
|
||||
$state_filter = $this->get_state_filter();
|
||||
$state_clause = $state_filter ? " AND {$state_filter}" : '';
|
||||
|
||||
$count = $wpdb->get_var(
|
||||
"SELECT COUNT(*) FROM {$this->db->properties_table()} WHERE mlg_can_view = 1"
|
||||
"SELECT COUNT(*) FROM {$this->db->properties_table()} WHERE mlg_can_view = 1{$state_clause}"
|
||||
);
|
||||
|
||||
return (int) $count > 0;
|
||||
@@ -454,12 +490,14 @@ class MLS_Query {
|
||||
global $wpdb;
|
||||
|
||||
$table = $this->db->properties_table();
|
||||
$state_filter = $this->get_state_filter();
|
||||
$state_clause = $state_filter ? " AND {$state_filter}" : '';
|
||||
|
||||
if ($status) {
|
||||
return $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT property_type, COUNT(*) as count
|
||||
FROM {$table}
|
||||
WHERE mlg_can_view = 1 AND standard_status = %s AND property_type IS NOT NULL
|
||||
WHERE mlg_can_view = 1 AND standard_status = %s AND property_type IS NOT NULL{$state_clause}
|
||||
GROUP BY property_type
|
||||
ORDER BY count DESC",
|
||||
$status
|
||||
@@ -469,7 +507,7 @@ class MLS_Query {
|
||||
return $wpdb->get_results(
|
||||
"SELECT property_type, COUNT(*) as count
|
||||
FROM {$table}
|
||||
WHERE mlg_can_view = 1 AND property_type IS NOT NULL
|
||||
WHERE mlg_can_view = 1 AND property_type IS NOT NULL{$state_clause}
|
||||
GROUP BY property_type
|
||||
ORDER BY count DESC"
|
||||
);
|
||||
@@ -485,12 +523,14 @@ class MLS_Query {
|
||||
global $wpdb;
|
||||
|
||||
$table = $this->db->properties_table();
|
||||
$state_filter = $this->get_state_filter();
|
||||
$state_clause = $state_filter ? " AND {$state_filter}" : '';
|
||||
|
||||
if ($status) {
|
||||
return $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT MIN(list_price) as min_price, MAX(list_price) as max_price
|
||||
FROM {$table}
|
||||
WHERE mlg_can_view = 1 AND standard_status = %s AND list_price > 0",
|
||||
WHERE mlg_can_view = 1 AND standard_status = %s AND list_price > 0{$state_clause}",
|
||||
$status
|
||||
));
|
||||
}
|
||||
@@ -498,7 +538,7 @@ class MLS_Query {
|
||||
return $wpdb->get_row(
|
||||
"SELECT MIN(list_price) as min_price, MAX(list_price) as max_price
|
||||
FROM {$table}
|
||||
WHERE mlg_can_view = 1 AND list_price > 0"
|
||||
WHERE mlg_can_view = 1 AND list_price > 0{$state_clause}"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -694,6 +694,7 @@ class MLS_Sync_Engine {
|
||||
'list_office_key' => $property['ListOfficeKey'] ?? null,
|
||||
'list_office_mls_id' => $property['ListOfficeMlsId'] ?? null,
|
||||
'list_office_name' => $property['ListOfficeName'] ?? null,
|
||||
'is_homeproz' => (($property['ListOfficeMlsId'] ?? '') === MLS_HOMEPROZ_OFFICE_ID) ? 1 : 0,
|
||||
|
||||
'photos_count' => $property['PhotosCount'] ?? 0,
|
||||
'modification_timestamp' => $this->format_timestamp($property['ModificationTimestamp'] ?? null),
|
||||
|
||||
@@ -32,6 +32,12 @@ define('MLS_TABLE_RATE_LIMITS', 'mls_rate_limits');
|
||||
define('MLS_TABLE_SYNC_LOG', 'mls_sync_log');
|
||||
define('MLS_TABLE_MEDIA_LOG', 'mls_media_log');
|
||||
|
||||
// HomeProz office MLS ID for identifying our listings
|
||||
define('MLS_HOMEPROZ_OFFICE_ID', 'NST253235');
|
||||
|
||||
// Allowed states for MLS queries (MN and IA only)
|
||||
define('MLS_ALLOWED_STATES', array('MN', 'IA'));
|
||||
|
||||
/**
|
||||
* Main plugin class
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user