Implements /find-training page with Google Maps JavaScript API: - Interactive map showing trainers (teal) and venues (orange) markers - MarkerClusterer for dense areas - Filter by State, Certification, Training Format - Search by name/location - "Near Me" geolocation with proximity filtering - Trainer profile modal with contact form - Venue info modal with upcoming events - 301 redirect from /find-a-trainer to /find-training - Auto-geocoding for new TEC venues via Google API Multi-model code review fixes (GPT-5, Gemini 3, Zen MCP): - Added missing contact form AJAX handler with rate limiting - Fixed XSS risk in InfoWindow (DOM creation vs inline onclick) - Added caching for filter dropdown queries (1-hour TTL) - Added AJAX abort handling to prevent race conditions - Replaced alert() with inline error notifications New files: - includes/find-training/class-hvac-find-training-page.php - includes/find-training/class-hvac-training-map-data.php - includes/find-training/class-hvac-venue-geocoding.php - templates/page-find-training.php - assets/js/find-training-map.js - assets/js/find-training-filters.js - assets/css/find-training-map.css - assets/images/marker-trainer.svg - assets/images/marker-venue.svg Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
200 lines
8.4 KiB
PHP
200 lines
8.4 KiB
PHP
<?php
|
|
/**
|
|
* Template Name: Find Training
|
|
*
|
|
* Template for displaying the Find Training page with Google Maps
|
|
* showing trainers and venues on an interactive map.
|
|
*
|
|
* @package HVAC_Community_Events
|
|
* @since 2.2.0
|
|
*/
|
|
|
|
defined('ABSPATH') || exit;
|
|
define('HVAC_IN_PAGE_TEMPLATE', true);
|
|
|
|
get_header();
|
|
|
|
// Get page handler instance
|
|
$find_training = HVAC_Find_Training_Page::get_instance();
|
|
$filter_options = $find_training->get_filter_options();
|
|
?>
|
|
|
|
<div class="hvac-find-training-page">
|
|
<div class="ast-container">
|
|
|
|
<!-- Page Title -->
|
|
<h1 class="hvac-page-title">Find Training</h1>
|
|
|
|
<!-- Intro Section -->
|
|
<div class="hvac-find-training-intro">
|
|
<p>Upskill HVAC is proud to be the only training body offering Certified measureQuick training.</p>
|
|
<p><strong>Certified measureQuick Trainers</strong> have demonstrated their skills and mastery of HVAC science and the measureQuick app, and are authorized to provide measureQuick training to the industry.</p>
|
|
<p>Use the interactive map and filters below to discover trainers and training venues near you. Click on any marker to view details.</p>
|
|
</div>
|
|
|
|
<!-- Map and Filters Container -->
|
|
<div class="hvac-map-filters-wrapper">
|
|
|
|
<!-- Map Section -->
|
|
<div class="hvac-map-section">
|
|
<div id="hvac-training-map" class="hvac-google-map">
|
|
<div class="hvac-map-loading">
|
|
<span class="dashicons dashicons-location"></span>
|
|
<p>Loading map...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Map Legend -->
|
|
<div class="hvac-map-legend">
|
|
<div class="hvac-legend-item">
|
|
<span class="hvac-legend-marker hvac-legend-trainer"></span>
|
|
<span>Trainer</span>
|
|
</div>
|
|
<div class="hvac-legend-item">
|
|
<span class="hvac-legend-marker hvac-legend-venue"></span>
|
|
<span>Training Venue</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filters Section -->
|
|
<div class="hvac-filters-section">
|
|
<!-- Search Box -->
|
|
<div class="hvac-search-box">
|
|
<input type="text" id="hvac-training-search" class="hvac-search-input" placeholder="Search trainers or venues..." aria-label="Search">
|
|
<span class="dashicons dashicons-search"></span>
|
|
</div>
|
|
|
|
<!-- Near Me Button -->
|
|
<button type="button" id="hvac-near-me-btn" class="hvac-near-me-btn">
|
|
<span class="dashicons dashicons-location-alt"></span>
|
|
Near Me
|
|
</button>
|
|
|
|
<!-- Filters Header -->
|
|
<div class="hvac-filters-header">
|
|
<span class="hvac-filters-label">Filters:</span>
|
|
<button type="button" class="hvac-clear-filters" style="display: none;">
|
|
Clear All
|
|
</button>
|
|
</div>
|
|
|
|
<!-- State Filter -->
|
|
<div class="hvac-filter-group">
|
|
<label for="hvac-filter-state">State / Province</label>
|
|
<select id="hvac-filter-state" class="hvac-filter-select">
|
|
<option value="">All States</option>
|
|
<?php foreach ($filter_options['states'] as $state): ?>
|
|
<option value="<?php echo esc_attr($state); ?>"><?php echo esc_html($state); ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Certification Filter -->
|
|
<div class="hvac-filter-group">
|
|
<label for="hvac-filter-certification">Certification</label>
|
|
<select id="hvac-filter-certification" class="hvac-filter-select">
|
|
<option value="">All Certifications</option>
|
|
<?php foreach ($filter_options['certifications'] as $cert): ?>
|
|
<option value="<?php echo esc_attr($cert); ?>"><?php echo esc_html($cert); ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Training Format Filter -->
|
|
<div class="hvac-filter-group">
|
|
<label for="hvac-filter-format">Training Format</label>
|
|
<select id="hvac-filter-format" class="hvac-filter-select">
|
|
<option value="">All Formats</option>
|
|
<?php foreach ($filter_options['training_formats'] as $format): ?>
|
|
<option value="<?php echo esc_attr($format); ?>"><?php echo esc_html($format); ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Marker Type Toggles -->
|
|
<div class="hvac-marker-toggles">
|
|
<label class="hvac-toggle">
|
|
<input type="checkbox" id="hvac-show-trainers" checked>
|
|
<span class="hvac-toggle-slider"></span>
|
|
<span class="hvac-toggle-label">Show Trainers</span>
|
|
</label>
|
|
<label class="hvac-toggle">
|
|
<input type="checkbox" id="hvac-show-venues" checked>
|
|
<span class="hvac-toggle-slider"></span>
|
|
<span class="hvac-toggle-label">Show Venues</span>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Active Filters -->
|
|
<div class="hvac-active-filters"></div>
|
|
|
|
<!-- Results Count -->
|
|
<div class="hvac-results-count">
|
|
<span id="hvac-trainer-count">0</span> trainers, <span id="hvac-venue-count">0</span> venues
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Trainer Directory Grid -->
|
|
<div class="hvac-trainer-directory-section">
|
|
<h2>Trainers Directory</h2>
|
|
<div id="hvac-trainer-grid" class="hvac-trainer-grid">
|
|
<div class="hvac-grid-loading">
|
|
<span class="dashicons dashicons-update-alt hvac-spin"></span>
|
|
Loading trainers...
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Load More Button -->
|
|
<div class="hvac-load-more-wrapper" style="display: none;">
|
|
<button type="button" id="hvac-load-more" class="hvac-btn-secondary">
|
|
Load More
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- CTA Section -->
|
|
<div class="hvac-cta-section">
|
|
<p>Are you an HVAC Trainer that wants to be listed in our directory?</p>
|
|
<a href="<?php echo esc_url(site_url('/trainer/registration/')); ?>" class="hvac-btn-primary">Become A Trainer</a>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Trainer Profile Modal -->
|
|
<div id="hvac-trainer-modal" class="hvac-training-modal" style="display: none;" role="dialog" aria-modal="true" aria-labelledby="trainer-modal-title">
|
|
<div class="hvac-modal-overlay"></div>
|
|
<div class="hvac-modal-content">
|
|
<div class="hvac-modal-loading">
|
|
<span class="dashicons dashicons-update-alt hvac-spin"></span>
|
|
Loading...
|
|
</div>
|
|
<div class="hvac-modal-body"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Venue Info Modal -->
|
|
<div id="hvac-venue-modal" class="hvac-training-modal" style="display: none;" role="dialog" aria-modal="true" aria-labelledby="venue-modal-title">
|
|
<div class="hvac-modal-overlay"></div>
|
|
<div class="hvac-modal-content">
|
|
<div class="hvac-venue-modal-header">
|
|
<h2 id="venue-modal-title"></h2>
|
|
<button class="hvac-modal-close" aria-label="Close modal">×</button>
|
|
</div>
|
|
<div class="hvac-venue-modal-body">
|
|
<p class="hvac-venue-address"></p>
|
|
<div class="hvac-venue-events">
|
|
<h4>Upcoming Events at this Venue</h4>
|
|
<ul class="hvac-venue-events-list"></ul>
|
|
</div>
|
|
<a href="#" class="hvac-venue-directions hvac-btn-secondary" target="_blank">
|
|
<span class="dashicons dashicons-location"></span>
|
|
Get Directions
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php get_footer(); ?>
|