# 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](#trainer-profile-issues) 2. [Find A Trainer Page Issues](#find-a-trainer-page-issues) 3. [MapGeo Integration Issues](#mapgeo-integration-issues) 4. [Performance Issues](#performance-issues) 5. [Database Issues](#database-issues) 6. [API & AJAX Issues](#api--ajax-issues) 7. [Geocoding Issues](#geocoding-issues) 8. [Permission Issues](#permission-issues) 9. [Debug Tools](#debug-tools) 10. [Known Issues](#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**: ```php // 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**: ```php // 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**: ```php // 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**: ```php // 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**: ```javascript // 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**: ```php // 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**: ```php // 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**: ```javascript // 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**: ```php // 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**: ```javascript // 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**: ```php // 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**: ```javascript // 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**: ```php // 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**: ```php // 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**: ```php // 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**: ```php // 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**: ```php // 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**: ```php // 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"; ?> '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**: ```php // 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**: ```php // 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 ```php // 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 ```php // Add debug info to admin function hvac_add_debug_panel() { if (current_user_can('manage_options') && isset($_GET['hvac_debug'])) { echo '
'; echo '

HVAC Trainer System Debug Info

'; // Plugin version echo '

Plugin Version: ' . (defined('HVAC_PLUGIN_VERSION') ? HVAC_PLUGIN_VERSION : 'Unknown') . '

'; // Active trainers $trainer_count = wp_count_posts('trainer_profile'); echo '

Total Trainer Profiles: ' . $trainer_count->publish . '

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

Geocoded Trainers: ' . count($geocoded) . '

'; // MapGeo integration echo '

MapGeo Active: ' . (class_exists('HVAC_MapGeo_Integration') ? 'Yes' : 'No') . '

'; // Google Maps API $api_key = get_option('hvac_google_maps_api_key'); echo '

Google Maps API: ' . (!empty($api_key) ? 'Configured' : 'Not Configured') . '

'; echo '
'; } } 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.