upskill-event-manager/docs/TRAINER-TROUBLESHOOTING.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

36 KiB

HVAC Trainer System Troubleshooting Guide

This guide provides solutions for common issues with the HVAC Trainer custom post type and Find A Trainer page functionality.

Table of Contents

  1. Trainer Profile Issues
  2. Find A Trainer Page Issues
  3. MapGeo Integration Issues
  4. Performance Issues
  5. Database Issues
  6. API & AJAX Issues
  7. Geocoding Issues
  8. Permission Issues
  9. Debug Tools
  10. Known Issues

Trainer Profile Issues

Trainer Profiles Not Appearing

Symptoms: Trainer profiles exist but don't show in directory or admin list

Common Causes:

  1. Profile not set to public
  2. User account not approved
  3. Missing required meta fields
  4. Wrong post status

Solutions:

// Check profile visibility
$profile_id = 5840;
$is_public = get_post_meta($profile_id, 'is_public_profile', true);
if ($is_public !== '1') {
    update_post_meta($profile_id, 'is_public_profile', '1');
    echo "Profile set to public";
}

// Check user approval status
$user_id = get_post_meta($profile_id, 'user_id', true);
$user_status = get_user_meta($user_id, 'account_status', true);
if (!in_array($user_status, ['approved', 'active', 'inactive'])) {
    update_user_meta($user_id, 'account_status', 'approved');
    echo "User approved";
}

// Check post status
$post = get_post($profile_id);
if ($post->post_status !== 'publish') {
    wp_update_post([
        'ID' => $profile_id,
        'post_status' => 'publish'
    ]);
    echo "Profile published";
}

Profile Data Not Saving

Symptoms: Changes to trainer profiles don't persist

Common Causes:

  1. Permission issues
  2. Nonce verification failures
  3. Invalid data validation
  4. Database errors

Solutions:

// Debug profile save operation
add_action('hvac_trainer_profile_updated', function($profile_id, $old_data, $new_data) {
    error_log("Profile {$profile_id} updated");
    error_log("Old data: " . print_r($old_data, true));
    error_log("New data: " . print_r($new_data, true));
}, 10, 3);

// Check user permissions
if (!current_user_can('edit_hvac_profile')) {
    echo "User lacks edit_hvac_profile capability";
    // Grant capability temporarily for testing
    $user = wp_get_current_user();
    $user->add_cap('edit_hvac_profile');
}

// Test direct meta update
$result = update_post_meta($profile_id, 'trainer_city', 'Test City');
if ($result === false) {
    echo "Failed to update meta field";
} else {
    echo "Meta field updated successfully";
}

Profile Images Not Displaying

Symptoms: Profile images appear broken or don't load

Common Causes:

  1. Invalid image URLs
  2. Missing image files
  3. Permission issues on uploads
  4. SSL/HTTPS conflicts

Solutions:

// Validate image URLs
$profile_id = 5840;
$image_url = get_post_meta($profile_id, 'profile_image_url', true);

if (!empty($image_url)) {
    // Check if URL is accessible
    $response = wp_remote_head($image_url);
    if (is_wp_error($response)) {
        echo "Image URL not accessible: " . $response->get_error_message();
    } else {
        $response_code = wp_remote_retrieve_response_code($response);
        if ($response_code !== 200) {
            echo "Image URL returns HTTP {$response_code}";
        } else {
            echo "Image URL is valid and accessible";
        }
    }
    
    // Fix HTTP/HTTPS issues
    if (is_ssl() && strpos($image_url, 'http://') === 0) {
        $fixed_url = str_replace('http://', 'https://', $image_url);
        update_post_meta($profile_id, 'profile_image_url', $fixed_url);
        echo "Fixed HTTPS issue in image URL";
    }
} else {
    echo "No profile image URL set";
}

Find A Trainer Page Issues

Search Not Working

Symptoms: Search functionality returns no results or doesn't respond

Common Causes:

  1. AJAX endpoints not registered
  2. JavaScript errors
  3. Nonce verification issues
  4. Database query problems

Solutions:

// Check AJAX endpoint registration
add_action('wp_ajax_hvac_search_trainers', function() {
    echo "AJAX endpoint registered for logged-in users";
    wp_die();
});

add_action('wp_ajax_nopriv_hvac_search_trainers', function() {
    echo "AJAX endpoint registered for non-logged-in users";
    wp_die();
});

// Debug search query
add_action('wp_ajax_hvac_search_trainers', function() {
    error_log('Search AJAX called with data: ' . print_r($_POST, true));
    
    // Test basic query
    $args = [
        'post_type' => 'trainer_profile',
        'post_status' => 'publish',
        'posts_per_page' => 5
    ];
    
    $query = new WP_Query($args);
    error_log("Basic query found {$query->found_posts} profiles");
    
    wp_send_json_success([
        'found_posts' => $query->found_posts,
        'debug' => true
    ]);
});

JavaScript Debug:

// Test AJAX endpoint
jQuery.ajax({
    url: hvac_find_trainer.ajax_url,
    method: 'POST',
    data: {
        action: 'hvac_search_trainers',
        search: 'test',
        nonce: hvac_find_trainer.nonce
    },
    success: function(response) {
        console.log('Search test successful:', response);
    },
    error: function(jqXHR, textStatus, errorThrown) {
        console.error('Search test failed:', textStatus, errorThrown);
        console.error('Response text:', jqXHR.responseText);
    }
});

Filters Not Working

Symptoms: Filter dropdowns don't affect results

Common Causes:

  1. Taxonomy terms not assigned
  2. Filter value mismatches
  3. Query argument issues
  4. Cache problems

Solutions:

// Check taxonomy assignments
$profile_id = 5840;
$business_types = wp_get_post_terms($profile_id, 'business_type', ['fields' => 'names']);

if (empty($business_types)) {
    echo "No business type assigned to profile {$profile_id}";
    
    // Assign a business type for testing
    wp_set_post_terms($profile_id, ['Contractor'], 'business_type');
    echo "Assigned 'Contractor' business type";
} else {
    echo "Business types: " . implode(', ', $business_types);
}

// Debug filter query
function debug_trainer_filter_query($args, $filters) {
    error_log("Filter args: " . print_r($args, true));
    error_log("Applied filters: " . print_r($filters, true));
    
    // Test the query
    $query = new WP_Query($args);
    error_log("Filter query found {$query->found_posts} results");
    
    return $args;
}

add_filter('hvac_trainer_query_args', 'debug_trainer_filter_query', 10, 2);

Pagination Not Working

Symptoms: Pagination links don't work or show incorrect page counts

Common Causes:

  1. Incorrect pagination calculations
  2. JavaScript event handling issues
  3. AJAX parameter problems

Solutions:

// Debug pagination calculations
function debug_pagination($query) {
    if ($query->get('post_type') === 'trainer_profile') {
        error_log("Pagination debug:");
        error_log("Found posts: " . $query->found_posts);
        error_log("Posts per page: " . $query->get('posts_per_page'));
        error_log("Max pages: " . $query->max_num_pages);
        error_log("Current page: " . $query->get('paged'));
    }
}

add_action('pre_get_posts', 'debug_pagination');

JavaScript Debug:

// Test pagination AJAX
jQuery(document).on('click', '.hvac-page-link', function(e) {
    e.preventDefault();
    var page = jQuery(this).data('page');
    
    console.log('Pagination clicked, page:', page);
    
    // Test the AJAX call
    jQuery.ajax({
        url: hvac_find_trainer.ajax_url,
        method: 'POST',
        data: {
            action: 'hvac_filter_trainers',
            filters: HVAC_FindTrainer.config.filters,
            page: page,
            per_page: 12,
            nonce: hvac_find_trainer.nonce
        },
        success: function(response) {
            console.log('Pagination AJAX success:', response);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.error('Pagination AJAX failed:', textStatus, errorThrown);
        }
    });
});

MapGeo Integration Issues

Markers Not Appearing on Map

Symptoms: Map loads but no trainer markers are visible

Common Causes:

  1. Missing geocoding data (latitude/longitude)
  2. MapGeo configuration issues
  3. Profile visibility settings
  4. Map ID mismatch

Solutions:

// Check geocoding status for all trainers
function check_geocoding_status() {
    $args = [
        'post_type' => 'trainer_profile',
        'post_status' => 'publish',
        'posts_per_page' => -1
    ];
    
    $query = new WP_Query($args);
    $total = $query->found_posts;
    $geocoded = 0;
    $missing_coords = [];
    
    while ($query->have_posts()) {
        $query->the_post();
        $profile_id = get_the_ID();
        
        $lat = get_post_meta($profile_id, 'geocoded_lat', true);
        $lng = get_post_meta($profile_id, 'geocoded_lng', true);
        
        if (!empty($lat) && !empty($lng)) {
            $geocoded++;
        } else {
            $missing_coords[] = [
                'id' => $profile_id,
                'title' => get_the_title(),
                'city' => get_post_meta($profile_id, 'trainer_city', true),
                'state' => get_post_meta($profile_id, 'trainer_state', true)
            ];
        }
    }
    
    wp_reset_postdata();
    
    echo "Geocoding Status Report:\n";
    echo "Total profiles: {$total}\n";
    echo "Geocoded profiles: {$geocoded}\n";
    echo "Missing coordinates: " . count($missing_coords) . "\n";
    
    if (!empty($missing_coords)) {
        echo "\nProfiles missing coordinates:\n";
        foreach ($missing_coords as $profile) {
            echo "- {$profile['title']} (ID: {$profile['id']}) - {$profile['city']}, {$profile['state']}\n";
        }
    }
}

// Run the check
check_geocoding_status();

// Trigger geocoding for profiles missing coordinates
function fix_missing_geocoding() {
    $args = [
        'post_type' => 'trainer_profile',
        'post_status' => 'publish',
        'posts_per_page' => -1,
        'meta_query' => [
            'relation' => 'OR',
            [
                'key' => 'geocoded_lat',
                'compare' => 'NOT EXISTS'
            ],
            [
                'key' => 'geocoded_lng',
                'compare' => 'NOT EXISTS'
            ]
        ]
    ];
    
    $query = new WP_Query($args);
    
    if (class_exists('HVAC_Geocoding_Service')) {
        $geocoding = HVAC_Geocoding_Service::get_instance();
        
        while ($query->have_posts()) {
            $query->the_post();
            $profile_id = get_the_ID();
            
            echo "Attempting to geocode profile {$profile_id}...";
            $result = $geocoding->geocode_trainer($profile_id);
            
            if ($result) {
                echo " SUCCESS\n";
            } else {
                echo " FAILED\n";
            }
            
            // Rate limiting
            sleep(1);
        }
    }
    
    wp_reset_postdata();
}

Map Modal Not Opening

Symptoms: Clicking map markers doesn't open trainer modals

Common Causes:

  1. JavaScript errors preventing modal system
  2. Missing trainer data in modal correlation
  3. Champions (intentionally don't show modals)
  4. MapGeo custom action configuration

Solutions:

// Debug modal system
console.log('MapGeo Integration Debug:');
console.log('hvac_show_trainer_modal function:', typeof window.hvac_show_trainer_modal);
console.log('showTrainerModal function:', typeof window.showTrainerModal);
console.log('Cache object exists:', typeof window.hvacTrainerDataCache);

// Test modal function directly
if (typeof window.hvac_show_trainer_modal === 'function') {
    // Test with sample data
    window.hvac_show_trainer_modal({
        hvac_profile_id: '5840',
        id: 'trainer_5840',
        title: 'Test Trainer'
    });
} else {
    console.error('hvac_show_trainer_modal function not found');
}

// Check for JavaScript errors
window.addEventListener('error', function(e) {
    if (e.filename && e.filename.includes('mapgeo')) {
        console.error('MapGeo JavaScript error:', e.message, e.filename, e.lineno);
    }
});

// Debug marker click events
jQuery(document).on('click', '.imapsSprite-group, .imapsMapObject-group, [class*="imaps"], circle', function(e) {
    console.log('Marker clicked:', this);
    console.log('Last MapGeo data:', window.lastMapGeoTrainerData);
});

PHP Debug:

// Check MapGeo map configuration
add_filter('igm_add_meta', function($meta, $map_id) {
    if ($map_id == '5872') { // Your map ID
        error_log("MapGeo meta data for map {$map_id}:");
        error_log(print_r($meta, true));
        
        // Check if markers have trainer data
        if (isset($meta['markers'])) {
            foreach ($meta['markers'] as $i => $marker) {
                if (isset($marker['hvac_profile_id'])) {
                    error_log("Marker {$i} has trainer profile ID: " . $marker['hvac_profile_id']);
                } else {
                    error_log("Marker {$i} missing trainer profile ID");
                }
            }
        }
    }
    return $meta;
}, 10, 2);

Modal Performance Issues

Symptoms: Modal takes >5 seconds to load or shows multiple AJAX requests

Common Causes:

  1. Duplicate AJAX requests
  2. Missing caching
  3. Complex fallback logic

Solutions:

// Check for duplicate requests
var requestTracker = {};

// Override jQuery.ajax to track requests
var originalAjax = jQuery.ajax;
jQuery.ajax = function(options) {
    if (options.data && options.data.action === 'hvac_get_trainer_profile') {
        var profileId = options.data.profile_id;
        var requestKey = 'profile_' + profileId;
        
        if (requestTracker[requestKey]) {
            console.warn('Duplicate AJAX request prevented for profile:', profileId);
            return requestTracker[requestKey];
        }
        
        console.log('New AJAX request for profile:', profileId);
        requestTracker[requestKey] = originalAjax.call(this, options);
        
        // Clean up after request completes
        requestTracker[requestKey].always(function() {
            delete requestTracker[requestKey];
        });
        
        return requestTracker[requestKey];
    }
    
    return originalAjax.call(this, options);
};

// Monitor cache usage
setInterval(function() {
    if (window.hvacTrainerDataCache) {
        var cacheSize = Object.keys(window.hvacTrainerDataCache).length;
        console.log('Trainer data cache size:', cacheSize);
    }
}, 5000);

Performance Issues

Slow Page Loading

Symptoms: Find A Trainer page loads slowly

Common Causes:

  1. Large number of trainer profiles
  2. Inefficient database queries
  3. Missing indexes
  4. Large images

Solutions:

// Add database indexes for better performance
function add_trainer_performance_indexes() {
    global $wpdb;
    
    // Index for trainer profile queries
    $wpdb->query("
        CREATE INDEX IF NOT EXISTS idx_postmeta_trainer_queries 
        ON {$wpdb->postmeta} (meta_key, meta_value(50), post_id)
    ");
    
    // Index for geocoded trainer queries
    $wpdb->query("
        CREATE INDEX IF NOT EXISTS idx_posts_trainer_type_status 
        ON {$wpdb->posts} (post_type, post_status, post_date)
    ");
    
    echo "Performance indexes added";
}

// Optimize trainer queries with caching
function get_cached_trainers($args) {
    $cache_key = 'hvac_trainers_' . md5(serialize($args));
    $trainers = wp_cache_get($cache_key, 'hvac_trainers');
    
    if (false === $trainers) {
        $query = new WP_Query($args);
        $trainers = [];
        
        while ($query->have_posts()) {
            $query->the_post();
            $trainers[] = [
                'id' => get_the_ID(),
                'title' => get_the_title(),
                'city' => get_post_meta(get_the_ID(), 'trainer_city', true),
                // ... other fields
            ];
        }
        wp_reset_postdata();
        
        wp_cache_set($cache_key, $trainers, 'hvac_trainers', HOUR_IN_SECONDS);
    }
    
    return $trainers;
}

// Profile query optimization
function optimize_trainer_profile_queries($args) {
    // Use 'fields' => 'ids' when only IDs are needed
    if (!isset($args['fields'])) {
        $args['fields'] = 'ids';
    }
    
    // Add specific meta_query structure for better index usage
    if (isset($args['meta_query'])) {
        // Ensure is_public_profile check is first for index efficiency
        usort($args['meta_query'], function($a, $b) {
            if (isset($a['key']) && $a['key'] === 'is_public_profile') {
                return -1;
            }
            if (isset($b['key']) && $b['key'] === 'is_public_profile') {
                return 1;
            }
            return 0;
        });
    }
    
    return $args;
}

add_filter('hvac_trainer_query_args', 'optimize_trainer_profile_queries');

Memory Issues

Symptoms: PHP memory limit exceeded or slow performance

Solutions:

// Monitor memory usage
function check_memory_usage($context = '') {
    $memory_used = memory_get_usage(true);
    $memory_peak = memory_get_peak_usage(true);
    $memory_limit = ini_get('memory_limit');
    
    error_log("Memory usage {$context}: " . 
        "Current: " . size_format($memory_used) . 
        ", Peak: " . size_format($memory_peak) . 
        ", Limit: {$memory_limit}");
}

// Optimize large trainer queries
function get_trainers_in_batches($total_needed = -1, $batch_size = 50) {
    $trainers = [];
    $page = 1;
    
    do {
        $args = [
            'post_type' => 'trainer_profile',
            'post_status' => 'publish',
            'posts_per_page' => $batch_size,
            'paged' => $page,
            'fields' => 'ids'
        ];
        
        $query = new WP_Query($args);
        
        foreach ($query->posts as $profile_id) {
            $trainers[] = $profile_id;
            
            if ($total_needed > 0 && count($trainers) >= $total_needed) {
                break 2;
            }
        }
        
        wp_reset_postdata();
        $page++;
        
        check_memory_usage("after batch {$page}");
        
    } while ($query->have_posts() && ($total_needed < 0 || count($trainers) < $total_needed));
    
    return $trainers;
}

Database Issues

Missing Meta Fields

Symptoms: Trainer data appears incomplete or missing

Solutions:

// Audit trainer profile meta fields
function audit_trainer_meta_fields() {
    $required_fields = [
        'user_id',
        'trainer_display_name',
        'trainer_city',
        'trainer_state',
        'is_public_profile',
        'certification_type'
    ];
    
    $args = [
        'post_type' => 'trainer_profile',
        'post_status' => 'publish',
        'posts_per_page' => -1,
        'fields' => 'ids'
    ];
    
    $profiles = get_posts($args);
    $issues = [];
    
    foreach ($profiles as $profile_id) {
        $profile_issues = [];
        
        foreach ($required_fields as $field) {
            $value = get_post_meta($profile_id, $field, true);
            if (empty($value)) {
                $profile_issues[] = $field;
            }
        }
        
        if (!empty($profile_issues)) {
            $issues[$profile_id] = [
                'title' => get_the_title($profile_id),
                'missing_fields' => $profile_issues
            ];
        }
    }
    
    if (!empty($issues)) {
        echo "Profiles with missing meta fields:\n";
        foreach ($issues as $profile_id => $issue) {
            echo "Profile {$profile_id} ({$issue['title']}): " . 
                implode(', ', $issue['missing_fields']) . "\n";
        }
    } else {
        echo "All profiles have required meta fields\n";
    }
    
    return $issues;
}

// Fix common meta field issues
function fix_trainer_meta_issues() {
    $profiles = get_posts([
        'post_type' => 'trainer_profile',
        'post_status' => 'publish',
        'posts_per_page' => -1,
        'fields' => 'ids'
    ]);
    
    foreach ($profiles as $profile_id) {
        $updated = false;
        
        // Fix missing display name
        $display_name = get_post_meta($profile_id, 'trainer_display_name', true);
        if (empty($display_name)) {
            $post_title = get_the_title($profile_id);
            if (!empty($post_title)) {
                update_post_meta($profile_id, 'trainer_display_name', $post_title);
                $updated = true;
            }
        }
        
        // Fix missing public profile flag
        $is_public = get_post_meta($profile_id, 'is_public_profile', true);
        if ($is_public === '') {
            update_post_meta($profile_id, 'is_public_profile', '1');
            $updated = true;
        }
        
        // Fix missing certification type
        $cert_type = get_post_meta($profile_id, 'certification_type', true);
        if (empty($cert_type)) {
            update_post_meta($profile_id, 'certification_type', 'HVAC Trainer');
            $updated = true;
        }
        
        if ($updated) {
            echo "Fixed meta fields for profile {$profile_id}\n";
        }
    }
}

Taxonomy Issues

Symptoms: Filters not working, missing taxonomy terms

Solutions:

// Check taxonomy registration
function check_trainer_taxonomies() {
    $taxonomies = ['business_type', 'training_formats', 'training_resources', 'training_audience'];
    
    foreach ($taxonomies as $taxonomy) {
        if (taxonomy_exists($taxonomy)) {
            $terms = get_terms([
                'taxonomy' => $taxonomy,
                'hide_empty' => false
            ]);
            
            echo "Taxonomy '{$taxonomy}': " . count($terms) . " terms\n";
            
            if (empty($terms)) {
                echo "  WARNING: No terms found for {$taxonomy}\n";
            }
        } else {
            echo "ERROR: Taxonomy '{$taxonomy}' not registered\n";
        }
    }
}

// Create missing taxonomy terms
function create_default_taxonomy_terms() {
    $taxonomies = [
        'business_type' => [
            'Manufacturer',
            'Distributor', 
            'Contractor',
            'Consultant',
            'Educator',
            'Government',
            'Other'
        ],
        'training_formats' => [
            'In-person',
            'Virtual',
            'Hybrid',
            'On-demand'
        ],
        'training_resources' => [
            'Classroom',
            'Training Lab',
            'Online Platform',
            'Custom Curriculum'
        ]
    ];
    
    foreach ($taxonomies as $taxonomy => $terms) {
        if (taxonomy_exists($taxonomy)) {
            foreach ($terms as $term) {
                if (!term_exists($term, $taxonomy)) {
                    $result = wp_insert_term($term, $taxonomy);
                    if (!is_wp_error($result)) {
                        echo "Created term '{$term}' in taxonomy '{$taxonomy}'\n";
                    }
                }
            }
        }
    }
}

API & AJAX Issues

AJAX Endpoints Not Working

Symptoms: AJAX requests return 404 or 400 errors

Solutions:

// Debug AJAX endpoint registration
function debug_ajax_endpoints() {
    global $wp_filter;
    
    $ajax_actions = [
        'hvac_get_trainer_profile',
        'hvac_filter_trainers', 
        'hvac_search_trainers',
        'hvac_get_trainer_certification'
    ];
    
    foreach ($ajax_actions as $action) {
        // Check logged-in user endpoints
        $logged_in_hook = "wp_ajax_{$action}";
        if (isset($wp_filter[$logged_in_hook])) {
            echo "✓ {$logged_in_hook} registered\n";
        } else {
            echo "✗ {$logged_in_hook} NOT registered\n";
        }
        
        // Check non-logged-in user endpoints
        $public_hook = "wp_ajax_nopriv_{$action}";
        if (isset($wp_filter[$public_hook])) {
            echo "✓ {$public_hook} registered\n";
        } else {
            echo "✗ {$public_hook} NOT registered\n";
        }
    }
}

// Test AJAX endpoint manually
function test_ajax_endpoint($action, $data = []) {
    // Simulate AJAX request
    $_POST = array_merge([
        'action' => $action,
        'nonce' => wp_create_nonce('hvac_find_trainer')
    ], $data);
    
    // Capture output
    ob_start();
    do_action("wp_ajax_{$action}");
    do_action("wp_ajax_nopriv_{$action}");
    $output = ob_get_clean();
    
    echo "AJAX Test for '{$action}':\n";
    echo "Output: {$output}\n";
    
    // Clean up
    $_POST = [];
}

// Usage
test_ajax_endpoint('hvac_get_trainer_profile', ['profile_id' => 5840]);

Nonce Verification Failures

Symptoms: AJAX requests fail with "Invalid nonce" errors

Solutions:

// Debug nonce issues
function debug_nonce_verification() {
    $action = 'hvac_find_trainer';
    $nonce = wp_create_nonce($action);
    
    echo "Generated nonce: {$nonce}\n";
    echo "Nonce action: {$action}\n";
    echo "Current user ID: " . get_current_user_id() . "\n";
    
    // Test verification
    $verify_result = wp_verify_nonce($nonce, $action);
    echo "Verification result: " . ($verify_result ? 'PASS' : 'FAIL') . "\n";
    
    // Check nonce in JavaScript context
    echo "JavaScript nonce check:\n";
    ?>
    <script>
    console.log('Frontend nonce:', hvac_find_trainer.nonce);
    console.log('Nonce matches:', hvac_find_trainer.nonce === '<?php echo $nonce; ?>');
    </script>
    <?php
}

// Fix nonce issues in AJAX
function fix_ajax_nonce_handling() {
    add_action('wp_ajax_hvac_get_trainer_profile', function() {
        $nonce = $_POST['nonce'] ?? '';
        $action = 'hvac_find_trainer';
        
        error_log("Nonce verification attempt:");
        error_log("Received nonce: {$nonce}");
        error_log("Expected action: {$action}");
        error_log("User ID: " . get_current_user_id());
        
        $verify_result = wp_verify_nonce($nonce, $action);
        error_log("Verification result: " . ($verify_result ? 'PASS' : 'FAIL'));
        
        if (!$verify_result) {
            wp_send_json_error([
                'message' => 'Nonce verification failed',
                'debug' => [
                    'received_nonce' => $nonce,
                    'expected_action' => $action,
                    'user_id' => get_current_user_id()
                ]
            ]);
            return;
        }
        
        // Continue with normal processing...
    });
}

Geocoding Issues

Trainers Not Being Geocoded

Symptoms: Trainer profiles missing latitude/longitude coordinates

Solutions:

// Check Google Maps API configuration
function check_geocoding_setup() {
    $api_key = get_option('hvac_google_maps_api_key');
    
    if (empty($api_key)) {
        echo "ERROR: Google Maps API key not configured\n";
        echo "Set it with: update_option('hvac_google_maps_api_key', 'your_key_here');\n";
        return false;
    }
    
    echo "Google Maps API key configured: " . substr($api_key, 0, 10) . "...\n";
    
    // Test API key with a simple request
    $test_address = 'Chicago, IL';
    $response = wp_remote_get('https://maps.googleapis.com/maps/api/geocode/json?' . http_build_query([
        'address' => $test_address,
        'key' => $api_key
    ]));
    
    if (is_wp_error($response)) {
        echo "ERROR: API request failed: " . $response->get_error_message() . "\n";
        return false;
    }
    
    $data = json_decode(wp_remote_retrieve_body($response), true);
    
    if (isset($data['status'])) {
        echo "API test result: {$data['status']}\n";
        
        if ($data['status'] === 'OK') {
            echo "✓ Geocoding API is working correctly\n";
            return true;
        } else {
            echo "✗ API Error: " . ($data['error_message'] ?? 'Unknown error') . "\n";
            return false;
        }
    }
    
    return false;
}

// Manual geocoding test
function test_geocoding_for_profile($profile_id) {
    echo "Testing geocoding for profile {$profile_id}...\n";
    
    $city = get_post_meta($profile_id, 'trainer_city', true);
    $state = get_post_meta($profile_id, 'trainer_state', true);
    
    if (empty($city) || empty($state)) {
        echo "ERROR: Missing city or state data\n";
        return false;
    }
    
    $address = "{$city}, {$state}";
    echo "Address to geocode: {$address}\n";
    
    $api_key = get_option('hvac_google_maps_api_key');
    if (empty($api_key)) {
        echo "ERROR: No API key configured\n";
        return false;
    }
    
    $response = wp_remote_get('https://maps.googleapis.com/maps/api/geocode/json?' . http_build_query([
        'address' => $address,
        'key' => $api_key
    ]));
    
    if (is_wp_error($response)) {
        echo "ERROR: " . $response->get_error_message() . "\n";
        return false;
    }
    
    $data = json_decode(wp_remote_retrieve_body($response), true);
    
    if ($data['status'] === 'OK' && !empty($data['results'][0])) {
        $location = $data['results'][0]['geometry']['location'];
        $lat = $location['lat'];
        $lng = $location['lng'];
        
        echo "✓ Geocoding successful: {$lat}, {$lng}\n";
        
        // Save coordinates
        update_post_meta($profile_id, 'geocoded_lat', $lat);
        update_post_meta($profile_id, 'geocoded_lng', $lng);
        update_post_meta($profile_id, '_last_geocode_attempt', time());
        
        echo "✓ Coordinates saved to profile\n";
        return true;
    } else {
        echo "✗ Geocoding failed: {$data['status']}\n";
        if (isset($data['error_message'])) {
            echo "Error: {$data['error_message']}\n";
        }
        return false;
    }
}

// Batch geocoding with rate limiting
function batch_geocode_missing_profiles($limit = 10) {
    $profiles = get_posts([
        'post_type' => 'trainer_profile',
        'post_status' => 'publish',
        'posts_per_page' => $limit,
        'meta_query' => [
            'relation' => 'OR',
            [
                'key' => 'geocoded_lat',
                'compare' => 'NOT EXISTS'
            ],
            [
                'key' => 'geocoded_lng', 
                'compare' => 'NOT EXISTS'
            ]
        ],
        'fields' => 'ids'
    ]);
    
    echo "Found " . count($profiles) . " profiles needing geocoding\n";
    
    foreach ($profiles as $profile_id) {
        $title = get_the_title($profile_id);
        echo "\nProcessing: {$title} (ID: {$profile_id})\n";
        
        test_geocoding_for_profile($profile_id);
        
        // Rate limiting - wait 1 second between requests
        sleep(1);
    }
    
    echo "\nBatch geocoding complete\n";
}

Permission Issues

Users Can't Edit Profiles

Symptoms: Trainers can't access or edit their profiles

Solutions:

// Check user capabilities
function check_trainer_capabilities($user_id = null) {
    if (!$user_id) {
        $user_id = get_current_user_id();
    }
    
    $user = get_user_by('id', $user_id);
    if (!$user) {
        echo "User not found\n";
        return;
    }
    
    echo "User: {$user->display_name} (ID: {$user_id})\n";
    echo "Roles: " . implode(', ', $user->roles) . "\n";
    
    $required_caps = [
        'read',
        'edit_hvac_profile',
        'view_hvac_dashboard',
        'manage_hvac_events'
    ];
    
    foreach ($required_caps as $cap) {
        $has_cap = user_can($user_id, $cap);
        echo "Capability '{$cap}': " . ($has_cap ? '✓' : '✗') . "\n";
        
        if (!$has_cap) {
            // Grant capability for testing
            $user->add_cap($cap);
            echo "  → Granted capability '{$cap}'\n";
        }
    }
}

// Fix role capabilities
function fix_trainer_role_capabilities() {
    $trainer_role = get_role('hvac_trainer');
    $master_role = get_role('hvac_master_trainer');
    
    if (!$trainer_role) {
        echo "Creating hvac_trainer role...\n";
        $trainer_role = add_role('hvac_trainer', 'HVAC Trainer', [
            'read' => true,
            'edit_hvac_profile' => true,
            'view_hvac_dashboard' => true,
            'manage_hvac_events' => true,
            'upload_files' => true
        ]);
    }
    
    if (!$master_role) {
        echo "Creating hvac_master_trainer role...\n";
        $master_role = add_role('hvac_master_trainer', 'HVAC Master Trainer', [
            'read' => true,
            'edit_hvac_profile' => true,
            'view_hvac_dashboard' => true,
            'manage_hvac_events' => true,
            'upload_files' => true,
            'hvac_master_trainer' => true
        ]);
    }
    
    // Add missing capabilities
    $trainer_caps = [
        'edit_hvac_profile',
        'view_hvac_dashboard',
        'manage_hvac_events',
        'manage_attendees',
        'email_attendees'
    ];
    
    foreach ($trainer_caps as $cap) {
        if ($trainer_role && !$trainer_role->has_cap($cap)) {
            $trainer_role->add_cap($cap);
            echo "Added '{$cap}' to hvac_trainer role\n";
        }
        
        if ($master_role && !$master_role->has_cap($cap)) {
            $master_role->add_cap($cap);
            echo "Added '{$cap}' to hvac_master_trainer role\n";
        }
    }
}

Debug Tools

Enable Debug Logging

// Add to wp-config.php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
define('HVAC_DEBUG', true);

// Custom debug logging
function hvac_debug_log($message, $context = '') {
    if (defined('HVAC_DEBUG') && HVAC_DEBUG) {
        $timestamp = date('Y-m-d H:i:s');
        $log_message = "[{$timestamp}] HVAC Debug";
        
        if (!empty($context)) {
            $log_message .= " ({$context})";
        }
        
        $log_message .= ": {$message}";
        
        error_log($log_message);
    }
}

// Usage
hvac_debug_log('Trainer profile created: ' . $profile_id, 'Profile Manager');

Debug Information Panel

// Add debug info to admin
function hvac_add_debug_panel() {
    if (current_user_can('manage_options') && isset($_GET['hvac_debug'])) {
        echo '<div style="background: #f1f1f1; padding: 20px; margin: 20px 0; border: 1px solid #ccc;">';
        echo '<h3>HVAC Trainer System Debug Info</h3>';
        
        // Plugin version
        echo '<p><strong>Plugin Version:</strong> ' . (defined('HVAC_PLUGIN_VERSION') ? HVAC_PLUGIN_VERSION : 'Unknown') . '</p>';
        
        // Active trainers
        $trainer_count = wp_count_posts('trainer_profile');
        echo '<p><strong>Total Trainer Profiles:</strong> ' . $trainer_count->publish . '</p>';
        
        // Geocoded trainers
        $geocoded = get_posts([
            'post_type' => 'trainer_profile',
            'posts_per_page' => -1,
            'meta_query' => [
                'relation' => 'AND',
                ['key' => 'geocoded_lat', 'compare' => 'EXISTS'],
                ['key' => 'geocoded_lng', 'compare' => 'EXISTS']
            ],
            'fields' => 'ids'
        ]);
        echo '<p><strong>Geocoded Trainers:</strong> ' . count($geocoded) . '</p>';
        
        // MapGeo integration
        echo '<p><strong>MapGeo Active:</strong> ' . (class_exists('HVAC_MapGeo_Integration') ? 'Yes' : 'No') . '</p>';
        
        // Google Maps API
        $api_key = get_option('hvac_google_maps_api_key');
        echo '<p><strong>Google Maps API:</strong> ' . (!empty($api_key) ? 'Configured' : 'Not Configured') . '</p>';
        
        echo '</div>';
    }
}

add_action('admin_notices', 'hvac_add_debug_panel');

Known Issues

MapGeo Certification Color Field Bug

Issue: When certification_color field is mapped to MapGeo "Fill Colour", markers disappear completely.

Workaround: Remove certification_color from MapGeo Fill Colour mapping. Colors are handled programmatically instead.

Status: Documented as known bug. MapGeo plugin has compatibility issues with custom color fields.

Champions Don't Show Modals

Issue: measureQuick Champions don't show modal popups when clicked on map.

Status: This is intentional behavior. Only Certified measureQuick Trainers show modals. Champions are directory-only display.

High Memory Usage with Large Datasets

Issue: Sites with 500+ trainer profiles may experience memory issues.

Workaround:

  • Implement pagination with smaller page sizes
  • Use query optimization techniques
  • Consider caching strategies
  • Use fields => 'ids' in queries when possible

This troubleshooting guide covers the most common issues encountered with the HVAC Trainer system. For additional support, enable debug logging and use the provided debug tools to gather more specific information about your particular issue.