Sync property list with map viewport
Major changes: - Property list now updates when map pans/zooms - Properties sorted by distance from map center (closest first) - Shows "X properties in view" when viewport filtering active - Min 30 properties required before grouping kicks in - Added rule to CLAUDE.md: no commits unless asked Backend: - MLS_Query: Added bounds filtering and distance-based sorting - AJAX handler: Accepts bounds/center, sorts by distance when provided Frontend: - Map move triggers property list refresh with same viewport - Loop prevention flag to avoid map->filter->map recursion - Resets to page 1 when viewport changes Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+1
-1
File diff suppressed because one or more lines are too long
@@ -34,6 +34,19 @@ function homeproz_ajax_filter_properties() {
|
||||
$sort = isset($_POST['sort']) ? sanitize_text_field($_POST['sort']) : 'newest';
|
||||
$paged = isset($_POST['paged']) ? intval($_POST['paged']) : 1;
|
||||
|
||||
// Map bounds and center (for map-synced list view)
|
||||
$bounds = null;
|
||||
$center = null;
|
||||
$has_map_bounds = false;
|
||||
|
||||
if (isset($_POST['bounds']) && is_array($_POST['bounds']) && count($_POST['bounds']) === 4) {
|
||||
$bounds = array_map('floatval', $_POST['bounds']);
|
||||
$has_map_bounds = true;
|
||||
}
|
||||
if (isset($_POST['center']) && is_array($_POST['center']) && count($_POST['center']) === 2) {
|
||||
$center = array_map('floatval', $_POST['center']);
|
||||
}
|
||||
|
||||
// Build filter args for count and properties
|
||||
$per_page = 12;
|
||||
$filter_args = array(
|
||||
@@ -55,6 +68,9 @@ function homeproz_ajax_filter_properties() {
|
||||
if ($beds) {
|
||||
$filter_args['min_beds'] = $beds;
|
||||
}
|
||||
if ($bounds) {
|
||||
$filter_args['bounds'] = $bounds;
|
||||
}
|
||||
|
||||
// Get total count efficiently from database
|
||||
$total = mls_get_property_count($filter_args);
|
||||
@@ -64,10 +80,16 @@ function homeproz_ajax_filter_properties() {
|
||||
$mls_args = array_merge($filter_args, array(
|
||||
'limit' => $per_page,
|
||||
'offset' => ($paged - 1) * $per_page,
|
||||
'orderby' => 'modification_timestamp',
|
||||
'order' => 'DESC',
|
||||
));
|
||||
|
||||
// If we have map center, sort by distance; otherwise by date
|
||||
if ($center) {
|
||||
$mls_args['center'] = $center;
|
||||
} else {
|
||||
$mls_args['orderby'] = 'modification_timestamp';
|
||||
$mls_args['order'] = 'DESC';
|
||||
}
|
||||
|
||||
// Fetch only the properties we need for this page
|
||||
$paged_properties = mls_get_properties($mls_args);
|
||||
|
||||
@@ -80,8 +102,11 @@ function homeproz_ajax_filter_properties() {
|
||||
<?php if ($total > 0) : ?>
|
||||
Showing <strong><?php echo esc_html($total); ?></strong>
|
||||
<?php echo $total === 1 ? 'property' : 'properties'; ?>
|
||||
<?php if ($has_map_bounds) : ?>
|
||||
in view
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
No properties found
|
||||
No properties in view
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -113,19 +113,24 @@
|
||||
|
||||
var self = this;
|
||||
var bounds = this.map.getBounds();
|
||||
var center = this.map.getCenter();
|
||||
var zoom = this.map.getZoom();
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
// Bounds array for both map clusters and property list
|
||||
var boundsArray = [
|
||||
bounds.getSouthWest().lat,
|
||||
bounds.getSouthWest().lng,
|
||||
bounds.getNorthEast().lat,
|
||||
bounds.getNorthEast().lng
|
||||
];
|
||||
var centerArray = [center.lat, center.lng];
|
||||
|
||||
var requestData = {
|
||||
action: 'mls_get_clusters',
|
||||
zoom: zoom,
|
||||
bounds: [
|
||||
bounds.getSouthWest().lat,
|
||||
bounds.getSouthWest().lng,
|
||||
bounds.getNorthEast().lat,
|
||||
bounds.getNorthEast().lng
|
||||
],
|
||||
bounds: boundsArray,
|
||||
status: this.currentFilters.status || 'Active',
|
||||
property_type: this.currentFilters.property_type || '',
|
||||
city: this.currentFilters.city || '',
|
||||
@@ -134,6 +139,9 @@
|
||||
min_beds: this.currentFilters.min_beds || ''
|
||||
};
|
||||
|
||||
// Also update the property list with the same viewport
|
||||
PropertyFilters.updateFromMap(boundsArray, centerArray);
|
||||
|
||||
$.ajax({
|
||||
url: homeprozMapData.clusterEndpoint,
|
||||
type: 'GET',
|
||||
@@ -518,6 +526,9 @@
|
||||
// State
|
||||
isFirstLoad: true,
|
||||
isLoading: false,
|
||||
mapBounds: null, // Current map viewport bounds
|
||||
mapCenter: null, // Current map center for distance sorting
|
||||
isMapUpdate: false, // Flag to prevent map->filter->map loop
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
@@ -597,6 +608,18 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update property list based on map viewport
|
||||
* Called by PropertyMap when map moves/zooms
|
||||
*/
|
||||
updateFromMap: function(bounds, center) {
|
||||
this.mapBounds = bounds;
|
||||
this.mapCenter = center;
|
||||
this.isMapUpdate = true;
|
||||
// Reset to page 1 when map viewport changes
|
||||
this.filterProperties(1, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get page number from URL hash
|
||||
*/
|
||||
@@ -629,35 +652,47 @@
|
||||
this.$results.html('<div class="property-results-loading"><div class="spinner"></div></div>');
|
||||
}
|
||||
|
||||
// Build request data
|
||||
var requestData = {
|
||||
action: 'homeproz_filter_properties',
|
||||
nonce: homeprozAjax.nonce,
|
||||
property_type: formData.property_type,
|
||||
property_location: formData.property_location,
|
||||
min_price: formData.min_price,
|
||||
max_price: formData.max_price,
|
||||
beds: formData.beds,
|
||||
paged: page
|
||||
};
|
||||
|
||||
// Add map bounds and center if available
|
||||
if (this.mapBounds) {
|
||||
requestData.bounds = this.mapBounds;
|
||||
}
|
||||
if (this.mapCenter) {
|
||||
requestData.center = this.mapCenter;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: homeprozAjax.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'homeproz_filter_properties',
|
||||
nonce: homeprozAjax.nonce,
|
||||
property_type: formData.property_type,
|
||||
property_location: formData.property_location,
|
||||
min_price: formData.min_price,
|
||||
max_price: formData.max_price,
|
||||
beds: formData.beds,
|
||||
paged: page
|
||||
},
|
||||
data: requestData,
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
self.$results.html(response.data.html);
|
||||
self.isFirstLoad = false;
|
||||
|
||||
// Update map with new filter params
|
||||
if (response.data.filters) {
|
||||
// Update map with new filter params (but not if this was triggered by map move)
|
||||
if (response.data.filters && !self.isMapUpdate) {
|
||||
PropertyMap.updateFilters(response.data.filters);
|
||||
}
|
||||
self.isMapUpdate = false;
|
||||
|
||||
// Recalculate layout after content update
|
||||
if (typeof LayoutCalculator !== 'undefined') {
|
||||
LayoutCalculator.calculate();
|
||||
}
|
||||
|
||||
// Update URL
|
||||
// Update URL (skip when map-triggered)
|
||||
if (updateHistory) {
|
||||
self.updateUrl(formData, page);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user