Resolves critical Safari hanging issues through multi-layered protection: Core Safari Resource Loading Bypass: - Added Safari-specific minimal asset loading in HVAC_Scripts_Styles - Prevents 35+ CSS file cascade that overwhelmed Safari rendering - Implements intelligent browser detection with fallback systems - Loads only essential CSS/JS files for Safari browsers - Dequeues non-critical assets to prevent resource overload Browser Detection Infrastructure: - Created HVAC_Browser_Detection class with accurate Safari identification - Added User-Agent parsing with version detection - Implements fallback detection methods for edge cases - Provides centralized browser compatibility services Find Trainer Assets Management: - Added HVAC_Find_Trainer_Assets class for proper WordPress hook timing - Ensures Safari-compatible script loading order - Prevents asset loading conflicts with theme integration Safari Debugging System: - Implemented HVAC_Safari_Request_Debugger for server-side monitoring - Added comprehensive Safari debugging with error tracking - Created detailed investigation documentation - Provides real-time Safari compatibility insights Performance Optimizations: - Optimized database queries in find-trainer template to prevent hanging - Implemented lazy component loading in HVAC_Plugin initialization - Reduced Astra theme override hook priorities from 999 to 50 - Removed CSS @import statements causing Safari render blocking MapGeo Integration Fixes: - Fixed JavaScript syntax error (dangling }) in MapGeo integration - Removed problematic console.log override causing Safari conflicts - Maintained full MapGeo functionality while preventing browser hangs Testing Results: - Verified with Playwright WebKit engine (Safari emulation) - Page loads successfully with complete functionality - Interactive map, trainer cards, and navigation all functional - Reduced CSS files from 35+ to 3 core files for optimal performance - No hanging or blank page issues detected 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			186 lines
		
	
	
		
			No EOL
		
	
	
		
			5.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
		
			No EOL
		
	
	
		
			5.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * HVAC Browser Detection Service
 | |
|  * 
 | |
|  * Centralized browser detection and compatibility handling
 | |
|  *
 | |
|  * @package HVAC_Community_Events
 | |
|  * @since 1.0.0
 | |
|  */
 | |
| 
 | |
| // Exit if accessed directly
 | |
| if (!defined('ABSPATH')) {
 | |
|     exit;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * HVAC Browser Detection Service
 | |
|  */
 | |
| class HVAC_Browser_Detection {
 | |
|     
 | |
|     /**
 | |
|      * Instance
 | |
|      *
 | |
|      * @var HVAC_Browser_Detection
 | |
|      */
 | |
|     private static $instance = null;
 | |
|     
 | |
|     /**
 | |
|      * Cached user agent
 | |
|      *
 | |
|      * @var string
 | |
|      */
 | |
|     private $user_agent = '';
 | |
|     
 | |
|     /**
 | |
|      * Browser detection cache
 | |
|      *
 | |
|      * @var array
 | |
|      */
 | |
|     private $browser_cache = [];
 | |
|     
 | |
|     /**
 | |
|      * Get instance
 | |
|      */
 | |
|     public static function instance() {
 | |
|         if (null === self::$instance) {
 | |
|             self::$instance = new self();
 | |
|         }
 | |
|         return self::$instance;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Constructor
 | |
|      */
 | |
|     private function __construct() {
 | |
|         $this->user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Detect if user is using Safari browser
 | |
|      * Enhanced version with better detection accuracy
 | |
|      * 
 | |
|      * @return bool
 | |
|      */
 | |
|     public function is_safari_browser() {
 | |
|         if (isset($this->browser_cache['is_safari'])) {
 | |
|             return $this->browser_cache['is_safari'];
 | |
|         }
 | |
|         
 | |
|         if (empty($this->user_agent)) {
 | |
|             $this->browser_cache['is_safari'] = false;
 | |
|             return false;
 | |
|         }
 | |
|         
 | |
|         // Check for Safari but not Chrome/Chromium (Chrome contains Safari in UA)
 | |
|         // Also exclude Edge and other WebKit-based browsers
 | |
|         $is_safari = (strpos($this->user_agent, 'Safari') !== false && 
 | |
|                      strpos($this->user_agent, 'Chrome') === false &&
 | |
|                      strpos($this->user_agent, 'Chromium') === false &&
 | |
|                      strpos($this->user_agent, 'Edge') === false &&
 | |
|                      strpos($this->user_agent, 'Edg') === false);
 | |
|         
 | |
|         // Additional Safari-specific checks
 | |
|         if ($is_safari) {
 | |
|             // Verify it's actually Safari by checking for Version string (Safari-specific)
 | |
|             $is_safari = strpos($this->user_agent, 'Version/') !== false || 
 | |
|                         strpos($this->user_agent, 'Safari/') !== false;
 | |
|         }
 | |
|         
 | |
|         $this->browser_cache['is_safari'] = $is_safari;
 | |
|         
 | |
|         // Debug logging
 | |
|         if (defined('WP_DEBUG') && WP_DEBUG) {
 | |
|             error_log('[HVAC Browser Detection] Safari check: ' . ($is_safari ? 'true' : 'false') . ' | UA: ' . substr($this->user_agent, 0, 100));
 | |
|         }
 | |
|         
 | |
|         return $is_safari;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Detect if user is using Mobile Safari (iPhone/iPad)
 | |
|      * 
 | |
|      * @return bool
 | |
|      */
 | |
|     public function is_mobile_safari() {
 | |
|         if (isset($this->browser_cache['is_mobile_safari'])) {
 | |
|             return $this->browser_cache['is_mobile_safari'];
 | |
|         }
 | |
|         
 | |
|         $is_mobile_safari = $this->is_safari_browser() && 
 | |
|                            (strpos($this->user_agent, 'iPhone') !== false || 
 | |
|                             strpos($this->user_agent, 'iPad') !== false ||
 | |
|                             strpos($this->user_agent, 'iPod') !== false);
 | |
|         
 | |
|         $this->browser_cache['is_mobile_safari'] = $is_mobile_safari;
 | |
|         return $is_mobile_safari;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Get Safari version if available
 | |
|      * 
 | |
|      * @return string|null Safari version or null if not Safari
 | |
|      */
 | |
|     public function get_safari_version() {
 | |
|         if (!$this->is_safari_browser()) {
 | |
|             return null;
 | |
|         }
 | |
|         
 | |
|         if (isset($this->browser_cache['safari_version'])) {
 | |
|             return $this->browser_cache['safari_version'];
 | |
|         }
 | |
|         
 | |
|         $version = null;
 | |
|         
 | |
|         // Extract version from user agent
 | |
|         if (preg_match('/Version\/([0-9]+(?:\.[0-9]+)*)/', $this->user_agent, $matches)) {
 | |
|             $version = $matches[1];
 | |
|         }
 | |
|         
 | |
|         $this->browser_cache['safari_version'] = $version;
 | |
|         return $version;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Check if Safari version supports ES6+ features
 | |
|      * Safari 10+ has good ES6 support
 | |
|      * 
 | |
|      * @return bool
 | |
|      */
 | |
|     public function safari_supports_es6() {
 | |
|         if (!$this->is_safari_browser()) {
 | |
|             return true; // Not Safari, assume other browsers support ES6
 | |
|         }
 | |
|         
 | |
|         $version = $this->get_safari_version();
 | |
|         if (!$version) {
 | |
|             return false; // Unknown version, assume no ES6 support
 | |
|         }
 | |
|         
 | |
|         // Safari 10+ has good ES6 support
 | |
|         return version_compare($version, '10.0', '>=');
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Get browser info for debugging
 | |
|      * 
 | |
|      * @return array
 | |
|      */
 | |
|     public function get_browser_info() {
 | |
|         return [
 | |
|             'user_agent' => $this->user_agent,
 | |
|             'is_safari' => $this->is_safari_browser(),
 | |
|             'is_mobile_safari' => $this->is_mobile_safari(),
 | |
|             'safari_version' => $this->get_safari_version(),
 | |
|             'supports_es6' => $this->safari_supports_es6(),
 | |
|         ];
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Clear browser detection cache
 | |
|      * Useful for testing or if user agent changes
 | |
|      */
 | |
|     public function clear_cache() {
 | |
|         $this->browser_cache = [];
 | |
|     }
 | |
| } |