'array', 'sanitize_callback' => array($this, 'sanitize_debug_settings'), )); // Debug settings section add_settings_section( 'aipa_debug_section', __('Debug Settings', 'ai-product-assistant'), array($this, 'debug_section_callback'), 'ai-product-assistant-debug' ); // Debug enable/disable add_settings_field( 'debug_enabled', __('Enable Debug Logging', 'ai-product-assistant'), array($this, 'debug_enabled_callback'), 'ai-product-assistant-debug', 'aipa_debug_section' ); // Debug level add_settings_field( 'debug_level', __('Debug Level', 'ai-product-assistant'), array($this, 'debug_level_callback'), 'ai-product-assistant-debug', 'aipa_debug_section' ); // Advanced options add_settings_field( 'debug_advanced', __('Advanced Options', 'ai-product-assistant'), array($this, 'debug_advanced_callback'), 'ai-product-assistant-debug', 'aipa_debug_section' ); // Log files management add_settings_field( 'debug_log_files', __('Log Files', 'ai-product-assistant'), array($this, 'debug_log_files_callback'), 'ai-product-assistant-debug', 'aipa_debug_section' ); // Recent logs viewer add_settings_field( 'debug_recent_logs', __('Recent Logs', 'ai-product-assistant'), array($this, 'debug_recent_logs_callback'), 'ai-product-assistant-debug', 'aipa_debug_section' ); } /** * Debug section description */ public function debug_section_callback() { echo '

' . esc_html(__('Configure debug logging to help troubleshoot issues. Debug logs are stored securely and do not contain personal data.', 'ai-product-assistant')) . '

'; // Show current status $settings = AIPA_Debug::get_settings(); $status_class = $settings['enabled'] ? 'notice-success' : 'notice-warning'; $status_text = $settings['enabled'] ? esc_html(__('Debug logging is ENABLED', 'ai-product-assistant')) : esc_html(__('Debug logging is DISABLED', 'ai-product-assistant')); echo '

' . esc_html($status_text) . '

'; } /** * Debug enabled field */ public function debug_enabled_callback() { $settings = AIPA_Debug::get_settings(); $enabled = $settings['enabled']; echo ''; echo '

' . esc_html(__('When enabled, the plugin will log detailed information to help diagnose issues.', 'ai-product-assistant')) . '

'; } /** * Debug level field */ public function debug_level_callback() { $settings = AIPA_Debug::get_settings(); $current_level = $settings['level']; $levels = array( AIPA_Debug::LEVEL_ERROR => __('Error Only', 'ai-product-assistant'), AIPA_Debug::LEVEL_WARNING => __('Warning & Error', 'ai-product-assistant'), AIPA_Debug::LEVEL_INFO => __('Info, Warning & Error', 'ai-product-assistant'), AIPA_Debug::LEVEL_DEBUG => __('All (Debug, Info, Warning & Error)', 'ai-product-assistant') ); echo ''; echo '

'; echo esc_html(__('Higher levels include more details but create larger log files.', 'ai-product-assistant')); echo '
' . esc_html(__('Recommended:', 'ai-product-assistant')) . ' '; echo esc_html(__('Info for general troubleshooting, Debug for detailed analysis.', 'ai-product-assistant')); echo '

'; } /** * Advanced debug options */ public function debug_advanced_callback() { $settings = AIPA_Debug::get_settings(); echo ''; // Log API requests echo ''; echo ''; echo ''; echo ''; // Max log days echo ''; echo ''; echo ''; echo ''; // Auto cleanup echo ''; echo ''; echo ''; echo ''; echo '
' . esc_html(__('Log API Requests', 'ai-product-assistant')) . ''; echo ''; echo '
' . esc_html(__('Keep Logs For', 'ai-product-assistant')) . ''; echo ' '; echo esc_html(__('days', 'ai-product-assistant')); echo '

' . esc_html(__('Older log files will be automatically deleted.', 'ai-product-assistant')) . '

'; echo '
' . esc_html(__('Auto Cleanup', 'ai-product-assistant')) . ''; echo ''; echo '
'; // Test debug button echo '

'; echo ''; echo ' '; echo '

'; } /** * Log files management */ public function debug_log_files_callback() { $settings = AIPA_Debug::get_settings(); if (!$settings['enabled']) { echo '
'; echo '

' . esc_html(__('Debug logging is currently disabled. Enable it above to start collecting logs.', 'ai-product-assistant')) . '

'; echo '
'; return; } $log_files = AIPA_Debug::get_log_files(); if (empty($log_files)) { echo '

' . esc_html(__('No log files found yet. Logs will appear here once the plugin starts logging events.', 'ai-product-assistant')) . '

'; echo '

' . esc_html(__('Try performing some actions like searching for products or analyzing your cart to generate logs.', 'ai-product-assistant')) . '

'; return; } echo '
'; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; foreach ($log_files as $file) { echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; } echo ''; echo '
' . esc_html(__('File Name', 'ai-product-assistant')) . '' . esc_html(__('Size', 'ai-product-assistant')) . '' . esc_html(__('Modified', 'ai-product-assistant')) . '' . esc_html(__('Actions', 'ai-product-assistant')) . '
' . esc_html($file['filename']) . '' . esc_html($file['readable_size']) . '' . esc_html($file['readable_date']) . ''; echo ' '; echo '' . esc_html(__('Download', 'ai-product-assistant')) . ' '; echo ''; echo '
'; // Clear all logs button echo '

'; echo ''; echo '

'; echo '
'; } /** * Recent logs viewer */ public function debug_recent_logs_callback() { $settings = AIPA_Debug::get_settings(); if (!$settings['enabled']) { echo '
'; echo '

' . esc_html(__('Enable debug logging to view recent log entries.', 'ai-product-assistant')) . '

'; echo '
'; return; } $log_files = AIPA_Debug::get_log_files(); if (empty($log_files)) { echo '

' . esc_html(__('No recent logs available yet.', 'ai-product-assistant')) . '

'; return; } // Get the most recent log file $recent_log = $log_files[0]; $content = AIPA_Debug::read_log_file($recent_log['filename'], 50); // Last 50 lines echo '
'; echo '

' . esc_html(sprintf( /* translators: %s: log filename */ __('Last 50 lines from %s', 'ai-product-assistant'), $recent_log['filename'] )) . '

'; if ($content) { echo ''; } else { echo '

' . esc_html(__('No content available.', 'ai-product-assistant')) . '

'; } echo '

'; echo ''; echo '

'; echo '
'; // Add log viewer modal echo ''; } /** * AJAX: View log file */ public function ajax_view_log_file() { check_ajax_referer('aipa_admin_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_die(esc_html(__('Insufficient permissions.', 'ai-product-assistant'))); } $filename = isset($_POST['filename']) ? sanitize_file_name(wp_unslash($_POST['filename'])) : ''; $content = AIPA_Debug::read_log_file($filename, 100); // Last 100 lines if ($content !== false) { wp_send_json_success(array( 'content' => $content, 'filename' => $filename )); } else { wp_send_json_error(esc_html(__('Could not read log file.', 'ai-product-assistant'))); } } /** * AJAX: Delete log file */ public function ajax_delete_log_file() { check_ajax_referer('aipa_admin_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_die(esc_html(__('Insufficient permissions.', 'ai-product-assistant'))); } $filename = isset($_POST['filename']) ? sanitize_file_name(wp_unslash($_POST['filename'])) : ''; if (AIPA_Debug::delete_log_file($filename)) { wp_send_json_success(esc_html(__('Log file deleted.', 'ai-product-assistant'))); } else { wp_send_json_error(esc_html(__('Could not delete log file.', 'ai-product-assistant'))); } } /** * AJAX: Clear all logs */ public function ajax_clear_all_logs() { check_ajax_referer('aipa_admin_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_die(esc_html(__('Insufficient permissions.', 'ai-product-assistant'))); } $deleted = AIPA_Debug::clear_all_logs(); wp_send_json_success(esc_html(sprintf( /* translators: %d: number of deleted log files */ __('Deleted %d log files.', 'ai-product-assistant'), $deleted ))); } /** * AJAX: Test debug logging */ public function ajax_test_debug_log() { check_ajax_referer('aipa_admin_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_die(esc_html(__('Insufficient permissions.', 'ai-product-assistant'))); } // Test all log levels $test_data = array('test' => true, 'timestamp' => current_time('mysql')); AIPA_Debug::error('DEBUG_TEST', 'Test error message', $test_data); AIPA_Debug::warning('DEBUG_TEST', 'Test warning message'); AIPA_Debug::info('DEBUG_TEST', 'Test info message'); AIPA_Debug::debug('DEBUG_TEST', 'Test debug message', $test_data); wp_send_json_success(esc_html(__('Test messages logged successfully. Check the recent logs section.', 'ai-product-assistant'))); } /** * Sanitize debug settings */ public function sanitize_debug_settings($input) { $sanitized = array(); $sanitized['enabled'] = !empty($input['enabled']); $sanitized['level'] = absint($input['level']); $sanitized['log_api_requests'] = !empty($input['log_api_requests']); $sanitized['max_log_days'] = min(90, max(1, absint($input['max_log_days']))); $sanitized['auto_cleanup'] = !empty($input['auto_cleanup']); // Validate level if (!in_array($sanitized['level'], array(1, 2, 3, 4))) { $sanitized['level'] = AIPA_Debug::LEVEL_INFO; } return $sanitized; } /** * AJAX: Test debug logging */ public function ajax_test_debug_logging() { check_ajax_referer('aipa_admin_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(esc_html(__('Insufficient permissions.', 'ai-product-assistant'))); } try { // Test all log levels AIPA_Debug::log(AIPA_Debug::LEVEL_ERROR, 'Debug_Test', 'Test error message'); AIPA_Debug::log(AIPA_Debug::LEVEL_WARNING, 'Debug_Test', 'Test warning message'); AIPA_Debug::log(AIPA_Debug::LEVEL_INFO, 'Debug_Test', 'Test info message'); AIPA_Debug::log(AIPA_Debug::LEVEL_DEBUG, 'Debug_Test', 'Test debug message', array('test_data' => 'sample')); wp_send_json_success(esc_html(__('Debug logging test completed successfully!', 'ai-product-assistant'))); } catch (Exception $e) { wp_send_json_error($e->getMessage()); } } /** * AJAX: Download log file */ public function ajax_download_log() { check_ajax_referer('aipa_download_log', 'nonce'); if (!current_user_can('manage_options')) { wp_die(esc_html(__('Insufficient permissions.', 'ai-product-assistant'))); } $filename = isset($_GET['filename']) ? sanitize_file_name(wp_unslash($_GET['filename'])) : ''; $log_dir = AIPA_Debug::get_log_dir(); $filepath = $log_dir . '/' . $filename; // Security check - ensure file is within log directory if (!file_exists($filepath) || strpos(realpath($filepath), realpath($log_dir)) !== 0) { wp_die(esc_html(__('Invalid log file.', 'ai-product-assistant'))); } // Output file contents using WordPress filesystem global $wp_filesystem; if (WP_Filesystem()) { $content = $wp_filesystem->get_contents($filepath); if ($content !== false) { // Set headers for download header('Content-Type: text/plain'); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Content-Length: ' . strlen($content)); header('Cache-Control: no-cache, must-revalidate'); header('Expires: 0'); // For file downloads, we need to output raw content // This is safe because: // 1. We've verified the file path is within our log directory // 2. Content-Type is set to text/plain // 3. Content-Disposition forces download print( $content ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } else { wp_die(esc_html(__('Could not read log file.', 'ai-product-assistant'))); } } else { // Alternative fallback using file_get_contents for better WordPress compliance if (file_exists($filepath)) { $content = file_get_contents($filepath); if ($content !== false) { // Set headers for download header('Content-Type: text/plain'); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Content-Length: ' . strlen($content)); header('Cache-Control: no-cache, must-revalidate'); header('Expires: 0'); // For file downloads, we need to output raw content print( $content ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } else { wp_die(esc_html(__('Could not read log file.', 'ai-product-assistant'))); } } else { wp_die(esc_html(__('Log file not found.', 'ai-product-assistant'))); } } exit; } /** * AJAX: Get recent logs */ public function ajax_get_recent_logs() { check_ajax_referer('aipa_admin_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(esc_html(__('Insufficient permissions.', 'ai-product-assistant'))); } $log_files = AIPA_Debug::get_log_files(); if (empty($log_files)) { wp_send_json_error(esc_html(__('No log files available.', 'ai-product-assistant'))); } // Get the most recent log file $recent_log = $log_files[0]; $content = AIPA_Debug::read_log_file($recent_log['filename'], 50); // Last 50 lines if ($content !== false) { wp_send_json_success(array( 'content' => $content, 'filename' => $recent_log['filename'] )); } else { wp_send_json_error(esc_html(__('Could not read log file.', 'ai-product-assistant'))); } } }