upskill-event-manager/docs/TRAINER-SYSTEM-DOCUMENTATION.md
bengizmo 705e6b563c feat: Implement Training Leads system and restructure navigation menu
- Add comprehensive Training Leads system for HVAC trainers
  * New /trainer/training-leads/ page with tabular contact submission display
  * HVAC_Training_Leads class with AJAX status updates and filtering
  * Empty state messaging and profile sharing CTA
  * Database integration with existing contact forms system

- Restructure trainer navigation menu for better UX
  * Rename "Customize" to "Profile" with logical groupings
  * Move "Logout" under "Profile" submenu
  * Change "Personal Profile" to "Trainer Profile"
  * Add "Training Leads" under Profile section
  * Update help menu to show only question mark icon positioned far right

- Enhance documentation system
  * Fix /trainer/documentation/ page styling and navigation integration
  * Update content to reflect current platform features
  * Add Training Leads documentation and navigation guide
  * Implement proper WordPress template structure

- Update user management
  * Change joe@upskillhvac.com display name to "Joe Medosch"
  * Assign Joe as author of measureQuick headquarters venue
  * Assign Joe as author of measureQuick and Upskill HVAC organizers

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-05 16:02:57 -03:00

27 KiB

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
  2. Trainer Profile Custom Post Type
  3. Find A Trainer Page
  4. MapGeo Integration
  5. User Roles & Permissions
  6. API Reference
  7. Frontend Components
  8. Database Schema
  9. Performance Optimizations
  10. 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

$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

$profile_manager->update_profile($profile_id, $updated_data);

Retrieving Profiles

// 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

// 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

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

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

// 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:

{
    "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:

{
    "success": true,
    "data": {
        "html": "<div class='hvac-trainer-card'>...</div>",
        "pagination": "<div class='hvac-pagination'>...</div>",
        "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

// 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

// 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)

/* 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

/* 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)

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

-- 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

-- 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

-- 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

$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

$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

// 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

// 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

// 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

// 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:

// 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:

// 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:

// 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:

// 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:

// 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.