# HVAC Trainer System Documentation This document provides comprehensive documentation for all functionality related to the HVAC Trainer custom post type and Find A Trainer page in the HVAC Community Events plugin. ## Table of Contents 1. [System Overview](#system-overview) 2. [Trainer Profile Custom Post Type](#trainer-profile-custom-post-type) 3. [Find A Trainer Page](#find-a-trainer-page) 4. [MapGeo Integration](#mapgeo-integration) 5. [User Roles & Permissions](#user-roles--permissions) 6. [API Reference](#api-reference) 7. [Frontend Components](#frontend-components) 8. [Database Schema](#database-schema) 9. [Performance Optimizations](#performance-optimizations) 10. [Troubleshooting](#troubleshooting) ## System Overview The HVAC Trainer System is a comprehensive solution for managing trainer profiles and providing a public directory with interactive map functionality. The system consists of: - **Custom Post Type**: `trainer_profile` for storing trainer information - **Find A Trainer Page**: Public-facing directory with search and filtering - **MapGeo Integration**: Interactive map with trainer markers and modals - **Profile Management**: Complete CRUD operations for trainer profiles - **Taxonomy System**: Categorization for business types, training formats, etc. ### Architecture Diagram ``` WordPress Users (hvac_trainer/hvac_master_trainer) ↓ Trainer Profile Custom Post Type (trainer_profile) ↓ Find A Trainer Page ← MapGeo Integration → Interactive Map ↓ Search/Filter System → AJAX Handlers → Database Queries ``` ## Trainer Profile Custom Post Type ### Overview The `trainer_profile` custom post type stores comprehensive information about HVAC trainers, including personal details, certifications, business information, and location data. ### Core Files - **Main Handler**: `includes/class-hvac-trainer-profile-manager.php` - **Settings**: `includes/class-hvac-trainer-profile-settings.php` - **Status Management**: `includes/class-hvac-trainer-status.php` ### Custom Fields Reference #### Personal Information | Field Name | Type | Description | Example | |------------|------|-------------|---------| | `trainer_first_name` | string | First name | "John" | | `trainer_last_name` | string | Last name | "Smith" | | `trainer_display_name` | string | Public display name | "John Smith" | | `trainer_city` | string | City location | "Chicago" | | `trainer_state` | string | State/Province | "Illinois" | | `trainer_country` | string | Country | "USA" | | `profile_image_url` | string | Profile photo URL | "https://..." | | `linkedin_profile_url` | string | LinkedIn profile | "https://linkedin..." | #### Certification Details | Field Name | Type | Description | Values | |------------|------|-------------|--------| | `certification_type` | string | Certification level | "Certified measureQuick Trainer", "Certified measureQuick Champion" | | `certification_status` | string | Current status | "Active", "Expired", "Pending", "Disabled" | | `certification_color` | string | Hex color for MapGeo | "#5077bb", "#f19a42", "#f0f7e8" | | `date_certified` | string | Certification date | "2024-01-15" | | `personal_accreditation` | string | Additional certifications | Free text | #### Business Information | Field Name | Type | Description | |------------|------|-------------| | `annual_revenue_target` | string | Revenue goals | | `application_details` | string | Registration application details | #### System Fields | Field Name | Type | Description | |------------|------|-------------| | `user_id` | integer | WordPress user ID | | `is_public_profile` | string | Visibility flag ("1" or "0") | | `_last_geocode_attempt` | string | Last geocoding timestamp | | `geocoded_lat` | string | Latitude coordinate | | `geocoded_lng` | string | Longitude coordinate | ### Taxonomies #### Business Type (`business_type`) - Manufacturer - Distributor - Contractor - Consultant - Educator - Government - Other #### Training Audience (`training_audience`) - Anyone (open to the public) - Industry professionals - Internal staff in my company - Registered students/members of my org/institution #### Training Formats (`training_formats`) - In-person - Virtual - Hybrid - On-demand #### Training Locations (`training_locations`) - Online - Local - Regional Travel - National Travel - International Travel #### Training Resources (`training_resources`) - Classroom - Training Lab - Ducted Furnace(s) - Ducted Air Handler(s) - Ducted Air Conditioner(s) - Ducted Heat Pump(s) - Ductless Heat Pump(s) - Training Manuals - Presentation Slides - LMS Platform / SCORM Files - Custom Curriculum - Other ### Profile Creation Workflow 1. **User Registration**: User completes registration form 2. **Role Assignment**: User assigned `hvac_trainer` or `hvac_master_trainer` role 3. **Profile Creation**: System automatically creates `trainer_profile` post 4. **Data Population**: Registration data mapped to profile fields 5. **Geocoding**: System attempts to geocode trainer location 6. **Approval Process**: Admin reviews and approves profile for public display ### Profile Management #### Creating Profiles Programmatically ```php $profile_manager = HVAC_Trainer_Profile_Manager::get_instance(); $profile_data = [ 'trainer_first_name' => 'John', 'trainer_last_name' => 'Smith', 'trainer_city' => 'Chicago', 'trainer_state' => 'Illinois', 'certification_type' => 'Certified measureQuick Trainer', 'user_id' => 123, 'is_public_profile' => '1' ]; $profile_id = $profile_manager->create_profile($profile_data); ``` #### Updating Profiles ```php $profile_manager->update_profile($profile_id, $updated_data); ``` #### Retrieving Profiles ```php // Get single profile $profile = $profile_manager->get_profile($profile_id); // Get all public profiles $public_profiles = $profile_manager->get_public_profiles(); // Get profiles by criteria $filtered_profiles = $profile_manager->get_profiles_by_criteria([ 'state' => 'Illinois', 'certification_type' => 'Certified measureQuick Trainer' ]); ``` ## Find A Trainer Page ### Overview The Find A Trainer page (`/find-a-trainer/`) provides a public directory of approved trainer profiles with interactive search, filtering, and map functionality. ### Core Files - **Page Handler**: `includes/find-trainer/class-hvac-find-trainer-page.php` - **Directory Query**: `includes/find-trainer/class-hvac-trainer-directory-query.php` - **Contact Handler**: `includes/find-trainer/class-hvac-contact-form-handler.php` - **Template**: `templates/page-find-trainer.php` ### Features #### Search Functionality - **Text Search**: Search by trainer name, city, or state - **Real-time Results**: AJAX-powered instant search results - **Autocomplete**: Suggestions as user types #### Filtering System - **State/Province Filter**: Location-based filtering - **Business Type Filter**: Filter by trainer business type - **Training Format Filter**: Filter by available training formats - **Training Resources Filter**: Filter by available resources - **Multiple Filters**: Combine multiple filter criteria #### Directory Display - **Card Layout**: Clean trainer cards with essential information - **Pagination**: Performance-optimized pagination system - **Sorting**: Certified Trainers first, then Champions, then alphabetical - **Champion Distinction**: Special styling for measureQuick Champions #### Contact Integration - **Contact Forms**: Direct contact forms for each trainer - **Email Integration**: Automated email delivery to trainers - **Lead Tracking**: Track contact form submissions ### AJAX Endpoints | Endpoint | Purpose | Parameters | |----------|---------|------------| | `hvac_filter_trainers` | Filter trainers | `filters`, `page`, `per_page` | | `hvac_search_trainers` | Search trainers | `search`, `page`, `per_page` | | `hvac_get_filter_options` | Get filter options | None | | `hvac_submit_contact_form` | Submit contact form | `trainer_id`, `name`, `email`, `message` | ### Frontend Implementation #### JavaScript Integration ```javascript // Initialize Find A Trainer functionality jQuery(document).ready(function($) { HVAC_FindTrainer.init({ ajax_url: hvac_find_trainer.ajax_url, nonce: hvac_find_trainer.nonce, filters: { state: [], business_type: [], training_format: [] } }); }); ``` #### CSS Classes | Class | Purpose | |-------|---------| | `.hvac-trainer-card` | Individual trainer card container | | `.hvac-trainer-card-certified` | Certified trainer styling | | `.hvac-champion-card` | Champion trainer styling | | `.hvac-trainer-filters` | Filter panel container | | `.hvac-search-box` | Search input container | | `.hvac-trainer-modal` | Trainer profile modal | ## MapGeo Integration ### Overview The MapGeo integration provides an interactive map showing trainer locations with clickable markers that open detailed trainer modals. ### Core Files - **Integration Handler**: `includes/find-trainer/class-hvac-mapgeo-integration.php` - **Map Configuration**: Integrated in Find A Trainer page template ### Features #### Interactive Map - **Map ID**: 5872 (configured in MapGeo plugin) - **Marker Display**: Trainers with geocoded coordinates appear as markers - **Color Coding**: Different colors based on certification type - **Click Handlers**: Custom click actions for trainer markers #### Performance Optimizations - **Request Deduplication**: Prevents duplicate AJAX calls - **Caching System**: Caches trainer data for instant subsequent access - **Click Throttling**: Prevents rapid-fire clicking issues - **Fallback Handling**: Graceful degradation when data unavailable #### Modal System - **Trainer Profiles**: Complete trainer information in popup modals - **Champion Filtering**: Champions don't show modals (directory-only display) - **Contact Integration**: Direct contact forms within modals - **Responsive Design**: Mobile-optimized modal display ### Technical Implementation #### MapGeo Marker Configuration ```php public function modify_map_layout($meta, $map_id = null) { // Only process for our specific map (5872) if ($map_id && $map_id != $this->map_id) { return $meta; } // Configure markers with trainer profile data foreach ($meta['markers'] as &$marker) { $trainer_profile_id = $this->find_trainer_profile_by_name($marker['title']); if ($trainer_profile_id) { $marker['action'] = 'hvac_show_trainer_modal'; $marker['hvac_profile_id'] = $trainer_profile_id; $marker['id'] = 'trainer_' . $trainer_profile_id; } } return $meta; } ``` #### JavaScript Modal Handler ```javascript window.hvac_show_trainer_modal = function(markerData) { var profileId = markerData.hvac_profile_id; // Check cache first for immediate response if (window.hvacTrainerDataCache[profileId]) { var cachedData = window.hvacTrainerDataCache[profileId]; if (typeof window.showTrainerModal === 'function') { window.showTrainerModal(cachedData); } return; } // Fetch profile data via AJAX if not cached // Implementation handles caching, error handling, and modal display }; ``` ### Certification Color Coding | Certification Type | Color | Usage | |--------------------|-------|-------| | Certified measureQuick Trainer | `#5077bb` | Primary trainer markers | | Certified measureQuick Champion | `#f19a42` | Champion markers (no modals) | | Default/Other | `#f0f7e8` | Fallback color | ## User Roles & Permissions ### HVAC Trainer (`hvac_trainer`) #### Core Capabilities - `read` - Basic WordPress read access - `upload_files` - File upload capability - `edit_hvac_profile` - Edit own trainer profile - `view_hvac_dashboard` - Access trainer dashboard - `manage_hvac_events` - Manage own events - `manage_attendees` - Manage event attendees - `email_attendees` - Send emails to attendees #### Events Calendar Integration - `publish_tribe_events` - Create and publish events - `edit_tribe_events` - Edit events - `delete_tribe_events` - Delete events - `edit_published_tribe_events` - Edit published events - `delete_published_tribe_events` - Delete published events - `read_private_tribe_events` - View private events ### HVAC Master Trainer (`hvac_master_trainer`) #### Extended Capabilities - All trainer capabilities - Access to master dashboard with analytics - View aggregate trainer statistics - Enhanced reporting capabilities ### Permission Checks ```php // Check if user can edit trainer profiles if (current_user_can('edit_hvac_profile')) { // Allow profile editing } // Check for master trainer capabilities if (current_user_can('hvac_master_trainer')) { // Show master trainer features } ``` ## API Reference ### AJAX Handlers #### Get Trainer Profile **Endpoint**: `hvac_get_trainer_profile` **Method**: POST **Parameters**: - `profile_id` (integer) - Trainer profile ID - `nonce` (string) - Security nonce **Response**: ```json { "success": true, "data": { "profile_id": 5840, "user_id": "31", "name": "Jeremy Begley", "city": "Knoxville", "state": "Tennessee", "certification_type": "Certified measureQuick Trainer", "profile_image": "https://...", "business_type": "Independent Contractor", "event_count": 5, "training_formats": "In-Person, Virtual", "training_locations": "On-site, Remote", "upcoming_events": [] } } ``` #### Filter Trainers **Endpoint**: `hvac_filter_trainers` **Method**: POST **Parameters**: - `filters` (array) - Filter criteria - `page` (integer) - Page number - `per_page` (integer) - Results per page - `nonce` (string) - Security nonce **Response**: ```json { "success": true, "data": { "html": "
...
", "pagination": "
...
", "count": 25, "page": 1, "max_pages": 3 } } ``` #### Search Trainers **Endpoint**: `hvac_search_trainers` **Method**: POST **Parameters**: - `search` (string) - Search query - `page` (integer) - Page number - `per_page` (integer) - Results per page - `nonce` (string) - Security nonce **Response**: Same format as filter trainers ### PHP API Methods #### HVAC_Trainer_Profile_Manager Methods ```php // Get instance $manager = HVAC_Trainer_Profile_Manager::get_instance(); // Create profile $profile_id = $manager->create_profile($data); // Update profile $manager->update_profile($profile_id, $data); // Get profile $profile = $manager->get_profile($profile_id); // Get public profiles $profiles = $manager->get_public_profiles(); // Delete profile $manager->delete_profile($profile_id); ``` #### HVAC_Find_Trainer_Page Methods ```php // Get instance $page = HVAC_Find_Trainer_Page::get_instance(); // Render trainer cards $page->render_trainer_cards($trainers); // Get filter options $options = $page->get_filter_options(); // Build query args $args = $page->build_query_args($filters); ``` ## Frontend Components ### CSS Architecture #### Find A Trainer Styles (`assets/css/find-trainer.css`) ```css /* Main container */ .hvac-find-trainer-container { max-width: 1200px; margin: 0 auto; padding: 20px; } /* Search and filters */ .hvac-search-filters { display: flex; gap: 20px; margin-bottom: 30px; flex-wrap: wrap; } /* Trainer cards */ .hvac-trainer-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; margin-bottom: 30px; } .hvac-trainer-card { border: 1px solid #ddd; border-radius: 8px; padding: 20px; background: white; box-shadow: 0 2px 4px rgba(0,0,0,0.1); transition: transform 0.2s, box-shadow 0.2s; } .hvac-trainer-card:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.15); } /* Certified trainer styling */ .hvac-trainer-card-certified { border-color: #5077bb; } .hvac-trainer-card-certified::before { content: "✓ Certified Trainer"; background: #5077bb; color: white; padding: 4px 8px; border-radius: 4px; font-size: 12px; position: absolute; top: -8px; right: 10px; } /* Champion styling */ .hvac-champion-card { border-color: #f19a42; background: linear-gradient(135deg, #fff 0%, #fef9f5 100%); } .hvac-champion-card .hvac-trainer-name { color: #f19a42; font-weight: bold; } ``` #### MapGeo Integration Styles ```css /* MapGeo modal styling */ .hvac-trainer-modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; border-radius: 8px; box-shadow: 0 10px 30px rgba(0,0,0,0.3); max-width: 500px; width: 90%; max-height: 80vh; overflow-y: auto; z-index: 10000; } .hvac-modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.5); z-index: 9999; } /* Map markers */ .hvac-trainer-marker { cursor: pointer; transition: all 0.2s; } .hvac-trainer-marker:hover { transform: scale(1.1); } ``` ### JavaScript Components #### Find A Trainer JavaScript (`assets/js/find-trainer.js`) ```javascript var HVAC_FindTrainer = { // Configuration config: { ajax_url: '', nonce: '', filters: {}, current_page: 1, per_page: 12 }, // Initialize init: function(options) { this.config = Object.assign(this.config, options); this.bindEvents(); this.loadInitialResults(); }, // Event bindings bindEvents: function() { // Search functionality jQuery('#hvac-trainer-search').on('input', this.handleSearch.bind(this)); // Filter changes jQuery('.hvac-filter-select').on('change', this.handleFilterChange.bind(this)); // Pagination jQuery(document).on('click', '.hvac-page-link', this.handlePagination.bind(this)); // Trainer card clicks jQuery(document).on('click', '.hvac-open-profile', this.openTrainerModal.bind(this)); }, // Handle search input handleSearch: function(e) { var query = jQuery(e.target).val(); this.performSearch(query); }, // Handle filter changes handleFilterChange: function(e) { var $filter = jQuery(e.target); var filterType = $filter.data('filter'); var value = $filter.val(); this.config.filters[filterType] = value; this.applyFilters(); }, // Perform AJAX search performSearch: function(query) { jQuery.ajax({ url: this.config.ajax_url, method: 'POST', data: { action: 'hvac_search_trainers', search: query, page: 1, per_page: this.config.per_page, nonce: this.config.nonce }, success: this.updateResults.bind(this) }); }, // Apply filters applyFilters: function() { jQuery.ajax({ url: this.config.ajax_url, method: 'POST', data: { action: 'hvac_filter_trainers', filters: this.config.filters, page: 1, per_page: this.config.per_page, nonce: this.config.nonce }, success: this.updateResults.bind(this) }); }, // Update results display updateResults: function(response) { if (response.success) { jQuery('.hvac-trainer-cards').html(response.data.html); jQuery('.hvac-pagination').html(response.data.pagination); this.updateResultsCount(response.data.count); } }, // Open trainer modal openTrainerModal: function(e) { e.preventDefault(); var profileId = jQuery(e.target).data('profile-id'); this.showTrainerProfile(profileId); } }; ``` ## Database Schema ### Trainer Profile Posts Table ```sql -- wp_posts table entries for trainer_profile post type SELECT ID, post_title, post_status, post_type, post_date FROM wp_posts WHERE post_type = 'trainer_profile'; ``` ### Trainer Profile Meta Data ```sql -- wp_postmeta table entries for trainer profiles SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN ( SELECT ID FROM wp_posts WHERE post_type = 'trainer_profile' ) ORDER BY post_id, meta_key; ``` ### Taxonomy Relationships ```sql -- Get trainer profiles with business type taxonomy SELECT p.ID, p.post_title, t.name as business_type FROM wp_posts p LEFT JOIN wp_term_relationships tr ON p.ID = tr.object_id LEFT JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id LEFT JOIN wp_terms t ON tt.term_id = t.term_id WHERE p.post_type = 'trainer_profile' AND tt.taxonomy = 'business_type'; ``` ### Key Database Queries #### Get Public Trainer Profiles ```php $args = [ 'post_type' => 'trainer_profile', 'post_status' => 'publish', 'posts_per_page' => -1, 'meta_query' => [ 'relation' => 'AND', [ 'key' => 'is_public_profile', 'value' => '1', 'compare' => '=' ], [ 'key' => 'user_id', 'value' => $approved_user_ids, 'compare' => 'IN' ] ] ]; $query = new WP_Query($args); ``` #### Get Geocoded Trainers for Map ```php $args = [ 'post_type' => 'trainer_profile', 'post_status' => 'publish', 'posts_per_page' => -1, 'meta_query' => [ 'relation' => 'AND', [ 'key' => 'is_public_profile', 'value' => '1', 'compare' => '=' ], [ 'key' => 'geocoded_lat', 'compare' => 'EXISTS' ], [ 'key' => 'geocoded_lng', 'compare' => 'EXISTS' ] ] ]; ``` ## Performance Optimizations ### MapGeo Integration Optimizations #### Request Deduplication ```javascript // Prevent duplicate AJAX requests window.hvacTrainerDataCache = {}; window.hvacPendingRequests = {}; function getTrainerProfile(profileId) { // Check cache first if (window.hvacTrainerDataCache[profileId]) { return Promise.resolve(window.hvacTrainerDataCache[profileId]); } // Check if request already pending if (window.hvacPendingRequests[profileId]) { return window.hvacPendingRequests[profileId]; } // Make new request and cache promise window.hvacPendingRequests[profileId] = makeAjaxRequest(profileId) .then(function(data) { window.hvacTrainerDataCache[profileId] = data; delete window.hvacPendingRequests[profileId]; return data; }); return window.hvacPendingRequests[profileId]; } ``` #### Click Throttling ```javascript // Prevent rapid-fire clicking var lastClickTime = 0; function handleMarkerClick(e) { var now = Date.now(); if (now - lastClickTime < 500) { return; // Throttle clicks to 500ms intervals } lastClickTime = now; // Process click processMarkerClick(e); } ``` ### Database Query Optimization #### Efficient Trainer Queries ```php // Use meta_query for better performance with indexes $args = [ 'post_type' => 'trainer_profile', 'posts_per_page' => 12, 'paged' => $page, 'meta_query' => [ 'relation' => 'AND', [ 'key' => 'is_public_profile', 'value' => '1', 'compare' => '=' ] ], 'fields' => 'ids' // Only get IDs when possible ]; // Add user status filter efficiently $user_query = new WP_User_Query([ 'meta_query' => [ [ 'key' => 'account_status', 'value' => ['approved', 'active', 'inactive'], 'compare' => 'IN' ] ], 'fields' => 'ID' ]); $approved_user_ids = $user_query->get_results(); if (!empty($approved_user_ids)) { $args['meta_query'][] = [ 'key' => 'user_id', 'value' => $approved_user_ids, 'compare' => 'IN' ]; } ``` #### Caching Strategies ```php // Cache expensive queries $cache_key = 'hvac_public_trainers_' . md5(serialize($args)); $trainers = wp_cache_get($cache_key, 'hvac_trainers'); if (false === $trainers) { $query = new WP_Query($args); $trainers = $query->posts; wp_cache_set($cache_key, $trainers, 'hvac_trainers', HOUR_IN_SECONDS); } ``` ## Troubleshooting ### Common Issues #### Trainers Not Appearing on Map **Symptoms**: Trainers visible in directory but not on MapGeo map **Causes**: 1. Missing geocoding data (latitude/longitude) 2. MapGeo configuration issues 3. Profile not public **Solutions**: ```php // Check geocoding status $lat = get_post_meta($profile_id, 'geocoded_lat', true); $lng = get_post_meta($profile_id, 'geocoded_lng', true); if (empty($lat) || empty($lng)) { // Trigger geocoding $geocoding_service = HVAC_Geocoding_Service::get_instance(); $geocoding_service->geocode_trainer($profile_id); } // Check public status $is_public = get_post_meta($profile_id, 'is_public_profile', true); if ($is_public !== '1') { update_post_meta($profile_id, 'is_public_profile', '1'); } ``` #### Modal Not Opening **Symptoms**: Clicking map markers doesn't open trainer modal **Causes**: 1. JavaScript errors preventing modal system 2. Missing trainer data 3. Champion profiles (intentionally no modal) **Solutions**: ```javascript // Debug modal system console.log('MapGeo integration loaded:', typeof window.hvac_show_trainer_modal); console.log('Modal function available:', typeof window.showTrainerModal); // Check if trainer is Champion (no modal should show) if (trainerData.certification_type === 'Certified measureQuick Champion') { console.log('Champion detected - no modal shown'); return; } ``` #### Search/Filter Not Working **Symptoms**: Search and filters not returning results **Causes**: 1. AJAX endpoint errors 2. Nonce verification failures 3. Database query issues **Solutions**: ```php // Debug AJAX handlers add_action('wp_ajax_hvac_filter_trainers', function() { error_log('Filter trainers AJAX called'); error_log('POST data: ' . print_r($_POST, true)); // Verify nonce if (!wp_verify_nonce($_POST['nonce'], 'hvac_find_trainer')) { error_log('Nonce verification failed'); wp_send_json_error('Invalid nonce'); return; } // Continue with handler... }); ``` #### Performance Issues **Symptoms**: Slow loading times, multiple AJAX requests **Causes**: 1. Duplicate requests not prevented 2. Missing caching 3. Inefficient database queries **Solutions**: 1. Implement request deduplication 2. Add caching layers 3. Optimize database queries with proper indexes 4. Use pagination for large datasets ### Debug Mode Enable debug logging for troubleshooting: ```php // Add to wp-config.php define('HVAC_DEBUG', true); // In plugin code if (defined('HVAC_DEBUG') && HVAC_DEBUG) { error_log('HVAC Debug: ' . $message); } ``` ### Performance Monitoring Monitor system performance: ```javascript // Track AJAX request timing var startTime = performance.now(); jQuery.ajax({ // ... ajax config success: function(response) { var endTime = performance.now(); console.log('AJAX request took:', (endTime - startTime), 'milliseconds'); } }); ``` ## Conclusion The HVAC Trainer System provides a comprehensive solution for managing trainer profiles and presenting them through an interactive Find A Trainer directory. The system is designed for performance, scalability, and user experience, with extensive customization options and robust error handling. For additional support or feature requests, refer to the main plugin documentation or contact the development team.