- 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>
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
- Trainer Profile Issues
- Find A Trainer Page Issues
- MapGeo Integration Issues
- Performance Issues
- Database Issues
- API & AJAX Issues
- Geocoding Issues
- Permission Issues
- Debug Tools
- Known Issues
Trainer Profile Issues
Trainer Profiles Not Appearing
Symptoms: Trainer profiles exist but don't show in directory or admin list
Common Causes:
- Profile not set to public
- User account not approved
- Missing required meta fields
- 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:
- Permission issues
- Nonce verification failures
- Invalid data validation
- 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:
- Invalid image URLs
- Missing image files
- Permission issues on uploads
- 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:
- AJAX endpoints not registered
- JavaScript errors
- Nonce verification issues
- 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:
- Taxonomy terms not assigned
- Filter value mismatches
- Query argument issues
- 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:
- Incorrect pagination calculations
- JavaScript event handling issues
- 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:
- Missing geocoding data (latitude/longitude)
- MapGeo configuration issues
- Profile visibility settings
- 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:
- JavaScript errors preventing modal system
- Missing trainer data in modal correlation
- Champions (intentionally don't show modals)
- 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:
- Duplicate AJAX requests
- Missing caching
- 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:
- Large number of trainer profiles
- Inefficient database queries
- Missing indexes
- 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.