fix: Improve Zoho CRM integration debug and error handling

- Enhanced error messages for Zoho CRM connection test failures
- Added detailed error information display in admin UI
- Created diagnostics.php script for advanced troubleshooting
- Improved logging with file, line, and stack trace information
- Added client ID, secret, and refresh token validation checks
- Enhanced CSS styling for error messages and debugging info
- Added configuration status checks to help identify issues

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
bengizmo 2025-05-21 11:09:23 -03:00
parent 8d44245ec9
commit 005bbf537e
5 changed files with 596 additions and 10 deletions

View file

@ -2,6 +2,7 @@
* Zoho CRM Admin Styles * Zoho CRM Admin Styles
*/ */
/* Main Sections */
.hvac-zoho-status, .hvac-zoho-status,
.hvac-zoho-sync, .hvac-zoho-sync,
.hvac-zoho-settings { .hvac-zoho-settings {
@ -54,3 +55,74 @@ code {
border-radius: 3px; border-radius: 3px;
font-family: 'Courier New', Courier, monospace; font-family: 'Courier New', Courier, monospace;
} }
/* Debug Information Styling */
.hvac-zoho-debug-info {
margin-top: 15px;
padding: 15px;
background: #f9f9f9;
border: 1px solid #ddd;
border-left: 4px solid #dc3232;
}
.hvac-zoho-debug-info p {
margin: 5px 0;
}
.hvac-zoho-debug-info strong {
color: #23282d;
}
.hvac-zoho-debug-info details {
margin-top: 10px;
}
.hvac-zoho-debug-info details summary {
cursor: pointer;
font-weight: bold;
color: #0073aa;
padding: 5px;
background: #f0f0f0;
border: 1px solid #ddd;
border-radius: 3px;
margin-bottom: 5px;
}
.hvac-zoho-debug-info details summary:hover {
background: #e9e9e9;
}
.hvac-zoho-debug-info pre {
white-space: pre-wrap;
word-wrap: break-word;
font-family: monospace;
background: #f0f0f0;
padding: 15px;
max-height: 300px;
overflow: auto;
border: 1px solid #ddd;
border-radius: 3px;
font-size: 12px;
line-height: 1.4;
color: #333;
}
/* Error Notice Improvements */
.notice-error {
padding: 15px;
}
.notice-error p {
margin: 0.5em 0;
}
.notice-error p:first-child {
font-weight: 500;
}
/* Staging Mode Banner */
.notice-info h3 {
margin-top: 0.5em;
margin-bottom: 0.5em;
color: #0073aa;
}

View file

@ -21,11 +21,65 @@ jQuery(document).ready(function($) {
if (response.success) { if (response.success) {
$status.html('<div class="notice notice-success"><p>' + response.data.message + ' (' + response.data.modules + ')</p></div>'); $status.html('<div class="notice notice-success"><p>' + response.data.message + ' (' + response.data.modules + ')</p></div>');
} else { } else {
$status.html('<div class="notice notice-error"><p>' + response.data.message + ': ' + response.data.error + '</p></div>'); // Create detailed error display
var errorHtml = '<div class="notice notice-error">';
errorHtml += '<p><strong>' + response.data.message + ':</strong> ' + response.data.error + '</p>';
// Add error code if available
if (response.data.code) {
errorHtml += '<p><strong>Error Code:</strong> ' + response.data.code + '</p>';
}
// Add details if available
if (response.data.details) {
errorHtml += '<p><strong>Details:</strong> ' + response.data.details + '</p>';
}
// Add debugging info
errorHtml += '<div class="hvac-zoho-debug-info">';
errorHtml += '<p><strong>Debug Information:</strong></p>';
errorHtml += '<p>Check the PHP error log for more details.</p>';
errorHtml += '<p>Log location: wp-content/plugins/hvac-community-events/logs/zoho-debug.log</p>';
// Add raw response data if available
if (response.data.raw) {
errorHtml += '<details>';
errorHtml += '<summary>Raw Response Data (click to expand)</summary>';
errorHtml += '<pre style="background: #f0f0f0; padding: 10px; max-height: 300px; overflow: auto;">' +
JSON.stringify(JSON.parse(response.data.raw), null, 2) +
'</pre>';
errorHtml += '</details>';
}
// Add file/line info if available (for exceptions)
if (response.data.file) {
errorHtml += '<p><strong>File:</strong> ' + response.data.file + '</p>';
}
// Add trace if available
if (response.data.trace) {
errorHtml += '<details>';
errorHtml += '<summary>Stack Trace (click to expand)</summary>';
errorHtml += '<pre style="background: #f0f0f0; padding: 10px; max-height: 300px; overflow: auto;">' +
response.data.trace +
'</pre>';
errorHtml += '</details>';
}
errorHtml += '</div>'; // Close debug info
errorHtml += '</div>'; // Close notice
$status.html(errorHtml);
} }
}, },
error: function() { error: function(xhr, status, error) {
$status.html('<div class="notice notice-error"><p>Connection test failed</p></div>'); var errorHtml = '<div class="notice notice-error">';
errorHtml += '<p><strong>AJAX Error:</strong> Connection test failed</p>';
errorHtml += '<p><strong>Status:</strong> ' + status + '</p>';
errorHtml += '<p><strong>Error:</strong> ' + error + '</p>';
errorHtml += '</div>';
$status.html(errorHtml);
}, },
complete: function() { complete: function() {
$button.prop('disabled', false).text('Test Connection'); $button.prop('disabled', false).text('Test Connection');

View file

@ -162,26 +162,105 @@ class HVAC_Zoho_Admin {
try { try {
require_once HVAC_CE_PLUGIN_DIR . 'includes/zoho/class-zoho-crm-auth.php'; require_once HVAC_CE_PLUGIN_DIR . 'includes/zoho/class-zoho-crm-auth.php';
// Enable debug logging
if (!defined('ZOHO_DEBUG_MODE')) {
define('ZOHO_DEBUG_MODE', true);
}
// Create a temporary log file if needed
if (!defined('ZOHO_LOG_FILE')) {
$log_dir = HVAC_CE_PLUGIN_DIR . 'logs';
if (!file_exists($log_dir)) {
mkdir($log_dir, 0755, true);
}
define('ZOHO_LOG_FILE', $log_dir . '/zoho-debug.log');
}
// Load the general logger for additional context
require_once HVAC_CE_PLUGIN_DIR . 'includes/class-hvac-logger.php';
HVAC_Logger::set_enabled(true);
HVAC_Logger::info('Starting Zoho connection test', 'ZOHO_TEST');
$auth = new HVAC_Zoho_CRM_Auth(); $auth = new HVAC_Zoho_CRM_Auth();
// Debug connection parameters
HVAC_Logger::info('Checking Zoho configuration', 'ZOHO_TEST', array(
'client_id_exists' => !empty($auth->get_client_id()),
'client_secret_exists' => !empty($auth->get_client_secret()),
'refresh_token_exists' => !empty($auth->get_refresh_token())
));
// Test API call // Test API call
$response = $auth->make_api_request('/settings/modules', 'GET'); $response = $auth->make_api_request('/settings/modules', 'GET');
// Detailed logging of the response
if (is_wp_error($response)) {
HVAC_Logger::error('WP Error in API request', 'ZOHO_TEST', array(
'error_message' => $response->get_error_message(),
'error_code' => $response->get_error_code()
));
wp_send_json_error(array(
'message' => 'Connection failed - WordPress Error',
'error' => $response->get_error_message(),
'details' => 'Error Code: ' . $response->get_error_code()
));
return;
}
if ($response && !isset($response['error'])) { if ($response && !isset($response['error'])) {
HVAC_Logger::info('Connection successful', 'ZOHO_TEST', array(
'modules_count' => isset($response['modules']) ? count($response['modules']) : 0
));
wp_send_json_success(array( wp_send_json_success(array(
'message' => 'Connection successful!', 'message' => 'Connection successful!',
'modules' => count($response['modules']) . ' modules available' 'modules' => isset($response['modules']) ? count($response['modules']) . ' modules available' : 'No modules found'
)); ));
} else { } else {
$error_message = isset($response['error']) ? $response['error'] : 'Unknown error';
$error_code = isset($response['code']) ? $response['code'] : '';
$error_details = isset($response['details']) ? $response['details'] : '';
// Extract more detailed error information if available
if (isset($response['data']) && is_array($response['data']) && !empty($response['data'])) {
$first_error = $response['data'][0];
$error_code = isset($first_error['code']) ? $first_error['code'] : $error_code;
$error_message = isset($first_error['message']) ? $first_error['message'] : $error_message;
if (isset($first_error['details']) && is_array($first_error['details'])) {
$error_details = json_encode($first_error['details']);
}
}
HVAC_Logger::error('Connection failed', 'ZOHO_TEST', array(
'error' => $error_message,
'code' => $error_code,
'details' => $error_details,
'full_response' => $response
));
wp_send_json_error(array( wp_send_json_error(array(
'message' => 'Connection failed', 'message' => 'Connection failed',
'error' => isset($response['error']) ? $response['error'] : 'Unknown error' 'error' => $error_message,
'code' => $error_code,
'details' => $error_details,
'raw' => json_encode($response)
)); ));
} }
} catch (Exception $e) { } catch (Exception $e) {
HVAC_Logger::error('Exception in Zoho connection test', 'ZOHO_TEST', array(
'exception' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString()
));
wp_send_json_error(array( wp_send_json_error(array(
'message' => 'Connection failed', 'message' => 'Connection failed due to exception',
'error' => $e->getMessage() 'error' => $e->getMessage(),
'file' => $e->getFile() . ':' . $e->getLine(),
'trace' => $e->getTraceAsString()
)); ));
} }
} }

View file

@ -20,6 +20,7 @@ class HVAC_Zoho_CRM_Auth {
private $redirect_uri; private $redirect_uri;
private $access_token; private $access_token;
private $token_expiry; private $token_expiry;
private $last_error = null;
public function __construct() { public function __construct() {
// Load configuration if available // Load configuration if available
@ -178,42 +179,134 @@ class HVAC_Zoho_CRM_Auth {
); );
} }
// Debug logging of config status
if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE) {
$config_status = $this->get_configuration_status();
$this->log_debug('Configuration status: ' . json_encode($config_status));
if (!$config_status['client_id_exists']) {
$this->log_error('Client ID is missing or empty');
}
if (!$config_status['client_secret_exists']) {
$this->log_error('Client Secret is missing or empty');
}
if (!$config_status['refresh_token_exists']) {
$this->log_error('Refresh Token is missing or empty');
}
if ($config_status['token_expired']) {
$this->log_debug('Access token is expired, will attempt to refresh');
}
}
$access_token = $this->get_access_token(); $access_token = $this->get_access_token();
if (!$access_token) { if (!$access_token) {
return new WP_Error('no_token', 'No valid access token available'); $error_message = 'No valid access token available';
$this->log_error($error_message);
return new WP_Error('no_token', $error_message);
} }
$api_base_url = defined('ZOHO_API_BASE_URL') ? ZOHO_API_BASE_URL : 'https://www.zohoapis.com/crm/v2'; $api_base_url = defined('ZOHO_API_BASE_URL') ? ZOHO_API_BASE_URL : 'https://www.zohoapis.com/crm/v2';
$url = $api_base_url . $endpoint; $url = $api_base_url . $endpoint;
// Log the request details
$this->log_debug('Making ' . $method . ' request to: ' . $url);
$args = array( $args = array(
'method' => $method, 'method' => $method,
'headers' => array( 'headers' => array(
'Authorization' => 'Zoho-oauthtoken ' . $access_token, 'Authorization' => 'Zoho-oauthtoken ' . $access_token,
'Content-Type' => 'application/json' 'Content-Type' => 'application/json'
) ),
'timeout' => 30 // Increase timeout to 30 seconds for potentially slow responses
); );
if ($data && in_array($method, array('POST', 'PUT', 'PATCH'))) { if ($data && in_array($method, array('POST', 'PUT', 'PATCH'))) {
$args['body'] = json_encode($data); $args['body'] = json_encode($data);
$this->log_debug('Request payload: ' . json_encode($data));
} }
// Execute the request
$this->log_debug('Executing request to Zoho API');
$response = wp_remote_request($url, $args); $response = wp_remote_request($url, $args);
// Handle WordPress errors
if (is_wp_error($response)) { if (is_wp_error($response)) {
$this->log_error('API request failed: ' . $response->get_error_message()); $error_message = 'API request failed: ' . $response->get_error_message();
$error_data = $response->get_error_data();
$this->log_error($error_message);
$this->log_debug('Error details: ' . json_encode($error_data));
return $response; return $response;
} }
// Get response code and body
$status_code = wp_remote_retrieve_response_code($response);
$headers = wp_remote_retrieve_headers($response);
$body = wp_remote_retrieve_body($response); $body = wp_remote_retrieve_body($response);
$this->log_debug('Response code: ' . $status_code);
// Log headers for debugging
if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE) {
$this->log_debug('Response headers: ' . json_encode($headers->getAll()));
}
// Handle empty responses
if (empty($body)) {
$error_message = 'Empty response received from Zoho API';
$this->log_error($error_message);
return array(
'error' => $error_message,
'code' => $status_code,
'details' => 'No response body received'
);
}
// Parse the JSON response
$data = json_decode($body, true); $data = json_decode($body, true);
// Check for JSON parsing errors
if ($data === null && json_last_error() !== JSON_ERROR_NONE) {
$error_message = 'Invalid JSON response: ' . json_last_error_msg();
$this->log_error($error_message);
$this->log_debug('Raw response: ' . $body);
return array(
'error' => $error_message,
'code' => 'JSON_PARSE_ERROR',
'details' => 'Raw response: ' . substr($body, 0, 255) . (strlen($body) > 255 ? '...' : '')
);
}
// Log response for debugging // Log response for debugging
if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE) { if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE) {
$this->log_debug('API Response: ' . $body); $this->log_debug('API Response: ' . $body);
} }
// Check for API errors
if ($status_code >= 400) {
$error_message = isset($data['message']) ? $data['message'] : 'API error with status code ' . $status_code;
$this->log_error($error_message);
// Add HTTP error information to the response
$data['http_status'] = $status_code;
$data['error'] = $error_message;
// Extract more detailed error information if available
if (isset($data['code'])) {
$this->log_debug('Error code: ' . $data['code']);
}
if (isset($data['details'])) {
$this->log_debug('Error details: ' . json_encode($data['details']));
}
}
return $data; return $data;
} }
@ -250,9 +343,16 @@ class HVAC_Zoho_CRM_Auth {
* Log error messages * Log error messages
*/ */
private function log_error($message) { private function log_error($message) {
$this->last_error = $message;
if (defined('ZOHO_LOG_FILE')) { if (defined('ZOHO_LOG_FILE')) {
error_log('[' . date('Y-m-d H:i:s') . '] ERROR: ' . $message . PHP_EOL, 3, ZOHO_LOG_FILE); error_log('[' . date('Y-m-d H:i:s') . '] ERROR: ' . $message . PHP_EOL, 3, ZOHO_LOG_FILE);
} }
// Also log to WordPress debug log if available
if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
error_log('[ZOHO CRM] ' . $message);
}
} }
/** /**
@ -262,5 +362,62 @@ class HVAC_Zoho_CRM_Auth {
if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE && defined('ZOHO_LOG_FILE')) { if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE && defined('ZOHO_LOG_FILE')) {
error_log('[' . date('Y-m-d H:i:s') . '] DEBUG: ' . $message . PHP_EOL, 3, ZOHO_LOG_FILE); error_log('[' . date('Y-m-d H:i:s') . '] DEBUG: ' . $message . PHP_EOL, 3, ZOHO_LOG_FILE);
} }
// Also log to WordPress debug log if available
if (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE && defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
error_log('[ZOHO CRM DEBUG] ' . $message);
}
}
/**
* Get the last error message
*
* @return string|null
*/
public function get_last_error() {
return $this->last_error;
}
/**
* Get client ID (for debugging only)
*
* @return string
*/
public function get_client_id() {
return $this->client_id;
}
/**
* Check if client secret exists (for debugging only)
*
* @return bool
*/
public function get_client_secret() {
return !empty($this->client_secret);
}
/**
* Check if refresh token exists (for debugging only)
*
* @return bool
*/
public function get_refresh_token() {
return !empty($this->refresh_token);
}
/**
* Get configuration status (for debugging)
*
* @return array
*/
public function get_configuration_status() {
return array(
'client_id_exists' => !empty($this->client_id),
'client_secret_exists' => !empty($this->client_secret),
'refresh_token_exists' => !empty($this->refresh_token),
'access_token_exists' => !empty($this->access_token),
'token_expired' => $this->token_expiry < time(),
'config_loaded' => file_exists(plugin_dir_path(__FILE__) . 'zoho-config.php')
);
} }
} }

View file

@ -0,0 +1,224 @@
<?php
/**
* Zoho CRM Diagnostics Tool
*
* A standalone script to diagnose Zoho CRM integration issues
*
* To use: Add the following line to wp-config.php:
* define('ZOHO_DIAGNOSTICS_ENABLED', true);
*
* Then access: /wp-content/plugins/hvac-community-events/includes/zoho/diagnostics.php
*
* @package HVACCommunityEvents
*/
// Security check to prevent direct access unless diagnostics are enabled
if (!defined('ABSPATH')) {
// Check if this is a direct access with the diagnostics parameter
if (!isset($_GET['run_diagnostics']) || $_GET['run_diagnostics'] !== 'true') {
die('Access denied.');
}
// Bootstrap WordPress
$wp_load_path = dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/wp-load.php';
if (file_exists($wp_load_path)) {
require_once $wp_load_path;
} else {
die('WordPress not found. Please run diagnostics from the WordPress installation directory.');
}
// Check if diagnostics are enabled
if (!defined('ZOHO_DIAGNOSTICS_ENABLED') || !ZOHO_DIAGNOSTICS_ENABLED) {
die('Zoho diagnostics are not enabled. Add define("ZOHO_DIAGNOSTICS_ENABLED", true); to wp-config.php');
}
// Check if user is logged in and has appropriate capabilities
if (!current_user_can('manage_options')) {
die('You do not have permission to run diagnostics.');
}
}
// Set up error reporting and logging
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Create a log directory if it doesn't exist
$log_dir = dirname(dirname(__FILE__)) . '/logs';
if (!file_exists($log_dir)) {
mkdir($log_dir, 0755, true);
}
// Define log file constants
if (!defined('ZOHO_LOG_FILE')) {
define('ZOHO_LOG_FILE', $log_dir . '/zoho-diagnostics.log');
}
if (!defined('ZOHO_DEBUG_MODE')) {
define('ZOHO_DEBUG_MODE', true);
}
// Function to log diagnostic messages
function diagnostics_log($message, $type = 'INFO') {
$log_message = '[' . date('Y-m-d H:i:s') . '] ' . $type . ': ' . $message . PHP_EOL;
error_log($log_message, 3, ZOHO_LOG_FILE);
// Also output to screen if this is a direct access
if (!defined('ABSPATH')) {
echo $log_message . "<br>\n";
}
}
// Start diagnostics
diagnostics_log('Starting Zoho CRM diagnostics');
// Check for required files
$required_files = array(
'class-zoho-crm-auth.php' => dirname(__FILE__) . '/class-zoho-crm-auth.php',
'zoho-config.php' => dirname(__FILE__) . '/zoho-config.php',
);
$missing_files = array();
foreach ($required_files as $name => $path) {
if (!file_exists($path)) {
$missing_files[] = $name;
diagnostics_log("Missing required file: $name", 'ERROR');
} else {
diagnostics_log("Found required file: $name");
}
}
if (!empty($missing_files)) {
diagnostics_log('Diagnostics failed due to missing files', 'ERROR');
die('Missing required files: ' . implode(', ', $missing_files));
}
// Check for config constants
require_once $required_files['zoho-config.php'];
$required_constants = array(
'ZOHO_CLIENT_ID',
'ZOHO_CLIENT_SECRET',
'ZOHO_REFRESH_TOKEN',
'ZOHO_ACCOUNTS_URL',
'ZOHO_API_BASE_URL',
);
$missing_constants = array();
$empty_constants = array();
foreach ($required_constants as $constant) {
if (!defined($constant)) {
$missing_constants[] = $constant;
diagnostics_log("Missing required constant: $constant", 'ERROR');
} else {
$value = constant($constant);
if (empty($value)) {
$empty_constants[] = $constant;
diagnostics_log("Constant is empty: $constant", 'WARNING');
} else {
// Mask the actual value for security
$masked_value = $constant === 'ZOHO_CLIENT_ID' ? substr($value, 0, 4) . '...' : '[MASKED]';
diagnostics_log("Found constant: $constant = $masked_value");
}
}
}
if (!empty($missing_constants)) {
diagnostics_log('Diagnostics found missing constants', 'ERROR');
echo 'Missing required constants: ' . implode(', ', $missing_constants) . "<br>\n";
}
if (!empty($empty_constants)) {
diagnostics_log('Diagnostics found empty constants', 'WARNING');
echo 'Empty constants: ' . implode(', ', $empty_constants) . "<br>\n";
}
// Initialize Zoho CRM Auth
require_once $required_files['class-zoho-crm-auth.php'];
$auth = new HVAC_Zoho_CRM_Auth();
// Check the configuration status
$config_status = $auth->get_configuration_status();
diagnostics_log('Configuration status: ' . json_encode($config_status));
foreach ($config_status as $key => $value) {
$status = $value ? 'OK' : 'FAIL';
$type = $value ? 'INFO' : 'ERROR';
diagnostics_log("$key: $status", $type);
echo "$key: " . ($value ? '✅' : '❌') . "<br>\n";
}
// Test getting an access token
try {
diagnostics_log('Testing access token retrieval');
$access_token = $auth->get_access_token();
if ($access_token) {
diagnostics_log('Successfully retrieved access token');
echo "Access token retrieval: ✅<br>\n";
} else {
diagnostics_log('Failed to retrieve access token', 'ERROR');
echo "Access token retrieval: ❌<br>\n";
}
} catch (Exception $e) {
diagnostics_log('Exception while retrieving access token: ' . $e->getMessage(), 'ERROR');
echo "Access token retrieval exception: " . $e->getMessage() . "<br>\n";
}
// Test API connection
try {
diagnostics_log('Testing API connection');
$response = $auth->make_api_request('/settings/modules', 'GET');
if (is_wp_error($response)) {
diagnostics_log('API connection failed: ' . $response->get_error_message(), 'ERROR');
echo "API connection: ❌ - " . $response->get_error_message() . "<br>\n";
} else if (isset($response['modules'])) {
$module_count = count($response['modules']);
diagnostics_log("API connection successful. Found $module_count modules.");
echo "API connection: ✅ - Found $module_count modules<br>\n";
// List first few modules
echo "<strong>Available Modules:</strong><br>\n";
echo "<ul>\n";
$count = 0;
foreach ($response['modules'] as $module) {
if ($count++ < 5) {
echo "<li>" . $module['api_name'] . " (" . $module['plural_label'] . ")</li>\n";
}
}
if ($module_count > 5) {
echo "<li>... and " . ($module_count - 5) . " more</li>\n";
}
echo "</ul>\n";
} else {
diagnostics_log('API connection failed: ' . json_encode($response), 'ERROR');
echo "API connection: ❌ - Error response<br>\n";
echo "<pre>" . json_encode($response, JSON_PRETTY_PRINT) . "</pre>\n";
}
} catch (Exception $e) {
diagnostics_log('Exception while testing API connection: ' . $e->getMessage(), 'ERROR');
echo "API connection exception: " . $e->getMessage() . "<br>\n";
}
// Environment information
echo "<h3>Environment Information</h3>\n";
echo "<ul>\n";
echo "<li>PHP Version: " . phpversion() . "</li>\n";
echo "<li>WordPress Version: " . get_bloginfo('version') . "</li>\n";
echo "<li>Site URL: " . get_site_url() . "</li>\n";
echo "<li>Staging Mode: " . (strpos(get_site_url(), 'upskillhvac.com') === false ? 'Yes' : 'No') . "</li>\n";
echo "<li>Zoho Debug Mode: " . (defined('ZOHO_DEBUG_MODE') && ZOHO_DEBUG_MODE ? 'Enabled' : 'Disabled') . "</li>\n";
echo "<li>Diagnostic Log: " . ZOHO_LOG_FILE . "</li>\n";
echo "</ul>\n";
// Final diagnostics message
diagnostics_log('Zoho CRM diagnostics completed');
echo "<p><strong>Diagnostics completed.</strong> Check the log file for more details: " . ZOHO_LOG_FILE . "</p>\n";
// Include a simple CSS for better presentation
echo "<style>
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; line-height: 1.4; padding: 20px; max-width: 800px; margin: 0 auto; }
h1, h2, h3 { color: #23282d; }
pre { background: #f0f0f0; padding: 15px; border-radius: 3px; overflow: auto; }
ul { margin-left: 20px; }
</style>\n";