init_compression(); } /** * Initialize compression hooks and filters */ public function init_compression() { // Admin hooks (always register to handle form submissions) if (is_admin()) { add_action('admin_post_update_compression_settings', array($this, 'handle_form_submission')); add_action('wp_ajax_tigerstyle_analyze_cache', array($this, 'ajax_analyze_cache')); } if (!get_option('tigerstyle_dash_compression_enabled', false)) { return; } // Hook into output buffering for automatic compression add_action('template_redirect', array($this, 'start_compression_buffer'), 1); // Hook into post updates to clear relevant cache add_action('save_post', array($this, 'clear_post_compression_cache')); add_action('wp_update_nav_menu', array($this, 'clear_compression_cache')); add_action('switch_theme', array($this, 'clear_compression_cache')); } /** * Start output buffering for compression */ public function start_compression_buffer() { // Only compress HTML pages, not admin or AJAX requests if (is_admin() || wp_doing_ajax() || wp_doing_cron()) { return; } // Check if content type should be compressed $content_type = $_SERVER['CONTENT_TYPE'] ?? ''; if (!empty($content_type) && strpos($content_type, 'text/html') === false) { return; } ob_start(array($this, 'compress_output_buffer')); } /** * Compress output buffer callback */ public function compress_output_buffer($content) { // Only compress if content is substantial and HTML if (strlen($content) < 1000 || strpos($content, 'compress_and_cache($content, $_SERVER['REQUEST_URI'] ?? ''); } /** * Main compression function with Brotli + Gzip fallbacks */ public function compress_and_cache($content, $url = '') { if (!get_option('tigerstyle_dash_compression_enabled', false)) { return $content; } $method = get_option('tigerstyle_dash_compression_method', 'auto'); $level = get_option('tigerstyle_dash_compression_level', 6); $cache_enabled = get_option('tigerstyle_dash_cache_enabled', true); $accept_encoding = $_SERVER['HTTP_ACCEPT_ENCODING'] ?? ''; $compressed_content = $content; $compression_used = 'none'; $original_size = strlen($content); // Determine best compression method if ($method === 'auto') { if (strpos($accept_encoding, 'br') !== false && function_exists('brotli_compress')) { $compressed_content = brotli_compress($content, $level); $compression_used = 'brotli'; header('Content-Encoding: br'); } elseif (strpos($accept_encoding, 'gzip') !== false) { $compressed_content = gzencode($content, $level); $compression_used = 'gzip'; header('Content-Encoding: gzip'); } } elseif ($method === 'brotli' && function_exists('brotli_compress')) { if (strpos($accept_encoding, 'br') !== false) { $compressed_content = brotli_compress($content, $level); $compression_used = 'brotli'; header('Content-Encoding: br'); } } elseif ($method === 'gzip') { if (strpos($accept_encoding, 'gzip') !== false) { $compressed_content = gzencode($content, $level); $compression_used = 'gzip'; header('Content-Encoding: gzip'); } } // Cache compressed content if enabled if ($cache_enabled && !empty($url) && $compression_used !== 'none') { $this->cache_compressed_content($url, $compressed_content, $compression_used); } // Update compression statistics $this->update_compression_stats($original_size, strlen($compressed_content), $compression_used); // Set additional performance headers header('Vary: Accept-Encoding'); header('Cache-Control: public, max-age=31536000'); return $compressed_content; } /** * Cache compressed content to filesystem */ private function cache_compressed_content($url, $content, $compression_type) { $upload_dir = wp_upload_dir(); $cache_dir = $upload_dir['basedir'] . '/tigerstyle-dash-cache/'; if (!is_dir($cache_dir)) { wp_mkdir_p($cache_dir); } $cache_key = md5($url); $cache_file = $cache_dir . $cache_key . '.' . $compression_type; file_put_contents($cache_file, $content); // Store metadata $metadata = array( 'url' => $url, 'compression' => $compression_type, 'size' => strlen($content), 'created' => time() ); file_put_contents($cache_file . '.meta', json_encode($metadata)); } /** * Update compression statistics */ private function update_compression_stats($original_size, $compressed_size, $compression_used) { $stats = get_option('tigerstyle_compression_stats', array( 'total_files' => 0, 'total_original_size' => 0, 'total_compressed_size' => 0, 'compression_methods' => array() )); $stats['total_files']++; $stats['total_original_size'] += $original_size; $stats['total_compressed_size'] += $compressed_size; if (!isset($stats['compression_methods'][$compression_used])) { $stats['compression_methods'][$compression_used] = 0; } $stats['compression_methods'][$compression_used]++; // Calculate derived stats $bandwidth_saved = $stats['total_original_size'] - $stats['total_compressed_size']; $avg_ratio = $stats['total_original_size'] > 0 ? round((1 - $stats['total_compressed_size'] / $stats['total_original_size']) * 100, 1) : 0; $stats['bandwidth_saved'] = $this->format_bytes($bandwidth_saved); $stats['avg_ratio'] = $avg_ratio . '%'; $stats['files_compressed'] = number_format($stats['total_files']); update_option('tigerstyle_compression_stats', $stats); } /** * Format bytes into human readable format */ private function format_bytes($bytes, $precision = 2) { $units = array('B', 'KB', 'MB', 'GB', 'TB'); for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) { $bytes /= 1024; } return round($bytes, $precision) . ' ' . $units[$i]; } /** * Clear compression cache */ public function clear_compression_cache() { $upload_dir = wp_upload_dir(); $cache_dir = $upload_dir['basedir'] . '/tigerstyle-dash-cache/'; if (is_dir($cache_dir)) { $this->delete_directory_contents($cache_dir); } } /** * Warm compression cache for popular pages */ public function warm_compression_cache() { // Get popular posts and pages $popular_posts = get_posts(array( 'numberposts' => 10, 'meta_key' => 'views', 'orderby' => 'meta_value_num', 'order' => 'DESC' )); $home_url = home_url('/'); $urls_to_warm = array($home_url); foreach ($popular_posts as $post) { $urls_to_warm[] = get_permalink($post->ID); } // Pre-compress popular URLs foreach ($urls_to_warm as $url) { $this->precompress_url($url); } } /** * Pre-compress a specific URL */ private function precompress_url($url) { $response = wp_remote_get($url, array( 'timeout' => 10, 'headers' => array( 'Accept-Encoding' => 'gzip, br' ) )); if (!is_wp_error($response)) { $content = wp_remote_retrieve_body($response); $this->compress_and_cache($content, $url); } } /** * Clear compression cache for a specific post */ public function clear_post_compression_cache($post_id) { $post_url = get_permalink($post_id); $cache_key = md5($post_url); $upload_dir = wp_upload_dir(); $cache_dir = $upload_dir['basedir'] . '/tigerstyle-dash-cache/'; // Remove all cached versions of this post $files = glob($cache_dir . $cache_key . '.*'); foreach ($files as $file) { if (is_file($file)) { unlink($file); } } // Also clear home page cache as it might include this post $home_cache_key = md5(home_url('/')); $home_files = glob($cache_dir . $home_cache_key . '.*'); foreach ($home_files as $file) { if (is_file($file)) { unlink($file); } } } /** * Delete directory contents recursively */ private function delete_directory_contents($dir) { if (!is_dir($dir)) { return; } $files = array_diff(scandir($dir), array('.', '..')); foreach ($files as $file) { $path = $dir . '/' . $file; if (is_dir($path)) { $this->delete_directory_contents($path); rmdir($path); } else { unlink($path); } } } /** * AJAX handler for cache analysis */ public function ajax_analyze_cache() { check_ajax_referer('tigerstyle_cache_analysis', 'nonce'); if (!current_user_can('manage_options')) { wp_die('Unauthorized access'); } $analysis = $this->analyze_cacheable_content(); wp_send_json_success($analysis); } /** * Analyze cacheable content and calculate potential savings */ public function analyze_cacheable_content() { $analysis = array( 'pages' => array(), 'assets' => array(), 'total_size' => 0, 'potential_savings' => 0, 'compression_estimates' => array() ); // Analyze main pages $pages_analysis = $this->analyze_pages(); $analysis['pages'] = $pages_analysis['pages']; $analysis['total_size'] += $pages_analysis['total_size']; $analysis['potential_savings'] += $pages_analysis['potential_savings']; // Analyze static assets $assets_analysis = $this->analyze_static_assets(); $analysis['assets'] = $assets_analysis['assets']; $analysis['total_size'] += $assets_analysis['total_size']; $analysis['potential_savings'] += $assets_analysis['potential_savings']; // Calculate compression estimates $analysis['compression_estimates'] = $this->calculate_compression_estimates($analysis['total_size']); // Format results $analysis['total_size_formatted'] = $this->format_bytes($analysis['total_size']); $analysis['potential_savings_formatted'] = $this->format_bytes($analysis['potential_savings']); $analysis['savings_percentage'] = $analysis['total_size'] > 0 ? round(($analysis['potential_savings'] / $analysis['total_size']) * 100, 1) : 0; return $analysis; } /** * Analyze main pages for caching potential */ private function analyze_pages() { $pages = array(); $total_size = 0; $potential_savings = 0; // Get homepage $home_url = home_url('/'); $home_analysis = $this->analyze_single_page($home_url, 'Homepage'); if ($home_analysis) { $pages[] = $home_analysis; $total_size += $home_analysis['size']; $potential_savings += $home_analysis['potential_savings']; } // Get recent posts $recent_posts = get_posts(array( 'numberposts' => 5, 'post_status' => 'publish' )); foreach ($recent_posts as $post) { $post_url = get_permalink($post->ID); $post_analysis = $this->analyze_single_page($post_url, $post->post_title); if ($post_analysis) { $pages[] = $post_analysis; $total_size += $post_analysis['size']; $potential_savings += $post_analysis['potential_savings']; } } // Get recent pages $recent_pages = get_posts(array( 'numberposts' => 3, 'post_type' => 'page', 'post_status' => 'publish' )); foreach ($recent_pages as $page) { $page_url = get_permalink($page->ID); $page_analysis = $this->analyze_single_page($page_url, $page->post_title); if ($page_analysis) { $pages[] = $page_analysis; $total_size += $page_analysis['size']; $potential_savings += $page_analysis['potential_savings']; } } return array( 'pages' => $pages, 'total_size' => $total_size, 'potential_savings' => $potential_savings ); } /** * Analyze a single page for compression potential */ private function analyze_single_page($url, $title) { // Use WordPress HTTP API to fetch the page $response = wp_remote_get($url, array( 'timeout' => 15, 'user-agent' => 'TigerStyle-SEO-Cache-Analyzer/1.0' )); if (is_wp_error($response)) { return null; } $content = wp_remote_retrieve_body($response); $original_size = strlen($content); // Skip if too small or not HTML if ($original_size < 500 || strpos($content, ' $title, 'url' => $url, 'size' => $original_size, 'gzip_size' => $gzip_size, 'brotli_size' => $brotli_size, 'potential_savings' => $potential_savings, 'compression_ratio' => round((1 - $best_compressed_size / $original_size) * 100, 1), 'size_formatted' => $this->format_bytes($original_size), 'savings_formatted' => $this->format_bytes($potential_savings) ); } /** * Analyze static assets for compression potential */ private function analyze_static_assets() { $assets = array(); $total_size = 0; $potential_savings = 0; // Analyze CSS files $css_files = $this->find_theme_files('*.css'); foreach ($css_files as $file) { $asset_analysis = $this->analyze_static_file($file, 'CSS'); if ($asset_analysis) { $assets[] = $asset_analysis; $total_size += $asset_analysis['size']; $potential_savings += $asset_analysis['potential_savings']; } } // Analyze JS files $js_files = $this->find_theme_files('*.js'); foreach ($js_files as $file) { $asset_analysis = $this->analyze_static_file($file, 'JavaScript'); if ($asset_analysis) { $assets[] = $asset_analysis; $total_size += $asset_analysis['size']; $potential_savings += $asset_analysis['potential_savings']; } } return array( 'assets' => $assets, 'total_size' => $total_size, 'potential_savings' => $potential_savings ); } /** * Find theme files by pattern */ private function find_theme_files($pattern) { $theme_dir = get_stylesheet_directory(); $files = glob($theme_dir . '/' . $pattern); // Also check parent theme if using child theme if (is_child_theme()) { $parent_theme_dir = get_template_directory(); $parent_files = glob($parent_theme_dir . '/' . $pattern); $files = array_merge($files, $parent_files); } // Limit to reasonable number of files return array_slice($files, 0, 10); } /** * Analyze a static file for compression potential */ private function analyze_static_file($file_path, $type) { if (!file_exists($file_path) || !is_readable($file_path)) { return null; } $content = file_get_contents($file_path); $original_size = strlen($content); // Skip small files if ($original_size < 1000) { return null; } // Estimate compression savings $gzip_size = strlen(gzcompress($content, 6)); $brotli_size = function_exists('brotli_compress') ? strlen(brotli_compress($content, 6)) : $gzip_size * 0.85; $best_compressed_size = min($gzip_size, $brotli_size); $potential_savings = $original_size - $best_compressed_size; $filename = basename($file_path); return array( 'filename' => $filename, 'type' => $type, 'path' => $file_path, 'size' => $original_size, 'gzip_size' => $gzip_size, 'brotli_size' => $brotli_size, 'potential_savings' => $potential_savings, 'compression_ratio' => round((1 - $best_compressed_size / $original_size) * 100, 1), 'size_formatted' => $this->format_bytes($original_size), 'savings_formatted' => $this->format_bytes($potential_savings) ); } /** * Calculate compression estimates for different scenarios */ private function calculate_compression_estimates($total_size) { return array( 'gzip_only' => array( 'method' => 'Gzip only', 'ratio' => 70, // Conservative estimate 'savings' => round($total_size * 0.30), 'savings_formatted' => $this->format_bytes(round($total_size * 0.30)) ), 'brotli_only' => array( 'method' => 'Brotli only', 'ratio' => 78, // Better compression 'savings' => round($total_size * 0.22), 'savings_formatted' => $this->format_bytes(round($total_size * 0.22)) ), 'auto_best' => array( 'method' => 'Auto (Brotli + Gzip fallback)', 'ratio' => 75, // Average between both 'savings' => round($total_size * 0.25), 'savings_formatted' => $this->format_bytes(round($total_size * 0.25)) ) ); } public function render_admin_page() { // Get current settings $compression_enabled = get_option('tigerstyle_dash_compression_enabled', false); $compression_method = get_option('tigerstyle_dash_compression_method', 'auto'); $compression_level = get_option('tigerstyle_dash_compression_level', 6); $compression_cache_enabled = get_option('tigerstyle_dash_cache_enabled', true); $compression_stats = get_option('tigerstyle_compression_stats', array()); ?>
__('Auto (Brotli + Gzip fallback)', 'tigerstyle-dash'), 'brotli' => __('Brotli only', 'tigerstyle-dash'), 'gzip' => __('Gzip only', 'tigerstyle-dash') ); ?> -