Files
homeproz/wp-content/themes/homeproz/template-parts/property/property-card-agent.php
T
root b6df4dbb92 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>
2026-04-29 15:32:23 +00:00

136 lines
5.2 KiB
PHP
Executable File

<?php
/**
* Property Card for Agent Pages
*
* MLS property card using the same markup as the original property-card.php
* for consistent styling on agent profile pages.
*
* Expects MLS property object via set_query_var('agent_listing', $property)
*
* @package HomeProz
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
$property = get_query_var('agent_listing');
if (!$property) {
return;
}
// Extract property data from MLS object
$listing_key = $property->listing_key;
$listing_id = $property->listing_id;
$status = $property->standard_status;
// Use close_price for Closed properties if available
$price = ($status === 'Closed' && !empty($property->close_price)) ? $property->close_price : $property->list_price;
$bedrooms = $property->bedrooms_total;
$bathrooms = $property->bathrooms_total;
$square_feet = $property->living_area;
// Build address
$street_address = trim(implode(' ', array_filter([
$property->street_number,
$property->street_name,
$property->street_suffix,
])));
$city = $property->city;
$state = $property->state_or_province;
$full_address = $street_address;
if ($city) {
$full_address .= ', ' . $city;
}
if ($state) {
$full_address .= ', ' . $state;
}
// Status class
$status_class = 'badge-success';
if (strtolower($status) === 'pending') {
$status_class = 'badge-warning';
} elseif (strtolower($status) === 'sold' || strtolower($status) === 'closed') {
$status_class = 'badge-muted';
}
// Property URL
$property_url = home_url('/properties/?listing=' . urlencode($listing_key));
// Get primary photo from MLS
$primary_photo = function_exists('mls_get_property_image') ? mls_get_property_image($listing_key, true) : '';
?>
<article class="property-card card">
<a href="<?php echo esc_url($property_url); ?>" class="property-card-link-overlay" aria-hidden="true" tabindex="-1"></a>
<div class="property-card-image">
<?php if ($primary_photo) : ?>
<img src="<?php echo esc_url($primary_photo); ?>" alt="<?php echo esc_attr($full_address); ?>" loading="lazy">
<?php else : ?>
<div class="property-card-placeholder">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
<polyline points="9 22 9 12 15 12 15 22"/>
</svg>
</div>
<?php endif; ?>
<?php if ($status) : ?>
<span class="property-card-badge badge <?php echo esc_attr($status_class); ?>">
<?php echo esc_html($status); ?>
</span>
<?php endif; ?>
</div>
<div class="property-card-content">
<div class="property-card-price">
<?php echo esc_html(homeproz_format_price($price)); ?>
</div>
<h3 class="property-card-title">
<?php echo esc_html($full_address); ?>
</h3>
<?php if ($bedrooms || $bathrooms || $square_feet) : ?>
<ul class="property-card-specs">
<?php if ($bedrooms) : ?>
<li class="spec-item">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M3 7v11h18V7M3 7V4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v3M3 7h18M7 11h4v4H7zM14 11h3"/>
</svg>
<span><?php echo esc_html($bedrooms); ?> <?php echo $bedrooms == 1 ? 'Bed' : 'Beds'; ?></span>
</li>
<?php endif; ?>
<?php if ($bathrooms) : ?>
<li class="spec-item">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M4 12h16M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7M4 12V6a2 2 0 0 1 2-2h3v2a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V4"/>
</svg>
<span><?php echo esc_html($bathrooms); ?> <?php echo $bathrooms == 1 ? 'Bath' : 'Baths'; ?></span>
</li>
<?php endif; ?>
<?php if ($square_feet) : ?>
<li class="spec-item">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<path d="M3 9h18M9 3v18"/>
</svg>
<span><?php echo esc_html(number_format($square_feet)); ?> sqft</span>
</li>
<?php endif; ?>
</ul>
<?php endif; ?>
<span class="property-card-link">
View Details
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="M5 12h14M12 5l7 7-7 7"/>
</svg>
</span>
</div>
</article>