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