/** * Caching & CDN Settings - Unified Design with TypeScript */ import { useState, useEffect, useCallback } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import { TextControl, TextareaControl, SelectControl, Notice, Spinner, RangeControl, Modal, Button, } from '@wordpress/components'; import apiFetch from '@wordpress/api-fetch'; import ProrankToggleSlider from '../../../components/ProrankToggleSlider'; import ProrankButton from '../../../components/ProrankButton'; import { useNotification } from '../../../contexts/NotificationContext'; import * as React from 'react'; // TypeScript Interfaces - Keys match settings manager (cache group) interface CachingSettings { // Page Cache (settings manager uses short names without cache_ prefix) enabled: boolean; lifetime: number; exclude_urls: string; cache_exclude_categories: string[]; cache_exclude_tags: string[]; cache_exclude_post_types: string[]; // CDN cdn_provider: 'none' | 'cloudflare' | 'bunnycdn' | 'fastly' | 'cloudfront' | 'keycdn' | 'webhook'; cloudflare_zone_id: string; cloudflare_api_token: string; bunny_pullzone_id: string; bunny_api_key: string; fastly_service_id: string; fastly_api_token: string; cdn_webhook_url: string; cdn_webhook_secret: string; keycdn_zone_id: string; keycdn_api_key: string; cloudfront_distribution_id: string; cloudfront_access_key: string; cloudfront_secret_key: string; cdn_clear_on_purge_all: boolean; // Cache Warming + adaptive throttle preload_enabled: boolean; preload_load_throttle_enabled: boolean; preload_max_load_average: number; preload_batch_delay: number; // WooCommerce cache safety woocommerce_safe_cache_enabled: boolean; // Read-only runtime flags (from API; never persisted) preload_throttle_supported?: boolean; preload_current_load?: number | null; woocommerce_active?: boolean; // Link Preloading link_preload_enabled: boolean; link_preload_delay: number; // DNS Prefetch dns_prefetch_enabled: boolean; dns_prefetch_hosts: string; dynamic_resource_hints_enabled: boolean; // Font Preloading font_preload_enabled: boolean; font_preload_urls: string; // Browser Cache browser_cache_enabled: boolean; browser_cache_images: string; browser_cache_css: string; browser_cache_js: string; browser_cache_fonts: string; browser_cache_html: string; // JS Optimization js_defer: boolean; js_delay: boolean; tracker_delay_enabled: boolean; js_delay_jquery: boolean; js_delay_elementor_modules: boolean; js_exclude: string; // CSS Optimization css_minify: boolean; css_combine: boolean; css_async: boolean; inline_css_minify_enabled: boolean; inline_css_relocate_enabled: boolean; css_exclude: string; performance_conflict_safe_mode: boolean; } interface CachingDeliverySettingsProps { onClose?: () => void; embedded?: boolean; betaEnabled?: boolean; } interface ApiSettingsResponse { settings: Partial; performance_conflicts?: { count?: number; plugins?: string[]; safe_mode_enabled?: boolean; }; } interface ApiClearResponse { cleared: number; } interface ApiNginxConfigResponse { success?: boolean; config?: string; cache_path?: string; } interface CacheStats { hit_rate?: number; miss_rate?: number; hits?: number; misses?: number; total_cached?: number; cached_files?: number; cache_size?: string; bytes_saved?: number; bandwidth_saved?: string; avg_response_time?: string | number; edge_locations?: number; compression_ratio?: string | number; cache_efficiency?: string | number; real_time_status?: string; } interface SafeModeApplyResponse { safe_mode?: { enabled?: boolean; conflicts?: string[]; applied?: boolean; message?: string; }; } interface JsDeferInlineDependencyViolation { label?: string; reason?: string; snippet?: string; src?: string; href?: string; } interface JsDeferPreflightSample { label?: string; url?: string; passed?: boolean; blocking_findings?: string[]; warnings?: string[]; inline_jquery_examples?: string[]; inline_dependency_violations?: JsDeferInlineDependencyViolation[]; critical_styles_stripped?: JsDeferInlineDependencyViolation[]; } interface JsDeferPreflightBlock { message?: string; title?: string; ackKey?: string; preflight?: { flag?: string; label?: string; blocking_findings?: string[]; warnings?: string[]; inline_jquery_examples?: string[]; inline_dependency_violations?: JsDeferInlineDependencyViolation[]; critical_styles_stripped?: JsDeferInlineDependencyViolation[]; samples?: JsDeferPreflightSample[]; sample_urls?: Array<{ label?: string; url?: string }>; url?: string; }; pendingSettings: Record; } const CachingDeliverySettings: React.FC = ({ onClose, embedded = false, betaEnabled = false }) => { const { showNotification } = useNotification(); const nginxInfo = (window as any)?.prorankSeoAdmin?.server?.nginx ?? {}; const litespeedInfo = (window as any)?.prorankSeoAdmin?.server?.litespeed ?? {}; const litespeedMessage = litespeedInfo.cache_plugin ? __('LiteSpeed Cache detected. ProRank will purge LSCache automatically on content updates.', 'prorank-seo') : litespeedInfo.server ? __('LiteSpeed server detected. ProRank is compatible and can purge LSCache when active.', 'prorank-seo') : __('LiteSpeed compatible. If you use LiteSpeed Cache, ProRank can purge it on content updates.', 'prorank-seo'); const litespeedTone = litespeedInfo.cache_plugin || litespeedInfo.server ? 'prorank-notice prorank-notice-success' : 'prorank-notice prorank-notice-info'; const [settings, setSettings] = useState({ // Page Cache (short keys match settings manager) enabled: false, lifetime: 604800, exclude_urls: '', cache_exclude_categories: [], cache_exclude_tags: [], cache_exclude_post_types: [], // CDN cdn_provider: 'none', cloudflare_zone_id: '', cloudflare_api_token: '', bunny_pullzone_id: '', bunny_api_key: '', fastly_service_id: '', fastly_api_token: '', cdn_webhook_url: '', cdn_webhook_secret: '', cloudfront_distribution_id: '', cloudfront_access_key: '', cloudfront_secret_key: '', cdn_clear_on_purge_all: false, keycdn_zone_id: '', keycdn_api_key: '', // Cache Warming + adaptive throttle preload_enabled: false, preload_load_throttle_enabled: false, preload_max_load_average: 4, preload_batch_delay: 45, // WooCommerce cache safety woocommerce_safe_cache_enabled: true, // Link Preloading link_preload_enabled: false, link_preload_delay: 50, // DNS Prefetch dns_prefetch_enabled: false, dns_prefetch_hosts: '', dynamic_resource_hints_enabled: true, // Font Preloading font_preload_enabled: false, font_preload_urls: '', // Browser Cache browser_cache_enabled: false, browser_cache_images: '31536000', browser_cache_css: '31536000', browser_cache_js: '31536000', browser_cache_fonts: '31536000', browser_cache_html: '3600', // JS Optimization js_defer: false, js_delay: false, tracker_delay_enabled: true, js_delay_jquery: false, js_delay_elementor_modules: false, js_exclude: '', // CSS Optimization css_minify: false, css_combine: false, css_async: false, inline_css_minify_enabled: true, inline_css_relocate_enabled: true, css_exclude: '', performance_conflict_safe_mode: true, }); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [clearing, setClearing] = useState(false); const [cdnTesting, setCdnTesting] = useState(false); const [cdnChecking, setCdnChecking] = useState(false); const [cdnPurging, setCdnPurging] = useState(false); const [cdnStatus, setCdnStatus] = useState(null); const [cdnSetup, setCdnSetup] = useState(null); const [cfZoneDetecting, setCfZoneDetecting] = useState(false); const [cfDevMode, setCfDevMode] = useState<{ enabled: boolean; time_remaining: number } | null>(null); const [cfDevModeBusy, setCfDevModeBusy] = useState(false); const [applyingPreset, setApplyingPreset] = useState(null); const [cacheStats, setCacheStats] = useState(null); const [statsLoading, setStatsLoading] = useState(false); const [statsError, setStatsError] = useState(null); const [performanceConflicts, setPerformanceConflicts] = useState([]); const [applyingSafeMode, setApplyingSafeMode] = useState(false); const [nginxConfig, setNginxConfig] = useState(''); const [nginxCachePath, setNginxCachePath] = useState(''); const [nginxConfigLoading, setNginxConfigLoading] = useState(false); const [nginxConfigError, setNginxConfigError] = useState(null); const [jsDeferPreflightBlock, setJsDeferPreflightBlock] = useState(null); const loadNginxConfig = useCallback(async (notify = false) => { if (!nginxInfo.server) { setNginxConfig(''); setNginxCachePath(''); setNginxConfigError(null); return; } setNginxConfigLoading(true); setNginxConfigError(null); try { const response = await apiFetch({ path: '/prorank-seo/v1/performance/nginx-config', }); setNginxConfig(response?.config || ''); setNginxCachePath(response?.cache_path || ''); if (notify) { showNotification(__('Nginx snippet refreshed', 'prorank-seo'), 'success'); } } catch (error: any) { const message = error?.message || __('Failed to load Nginx snippet', 'prorank-seo'); setNginxConfig(''); setNginxCachePath(''); setNginxConfigError(message); if (notify) { showNotification(message, 'error'); } } finally { setNginxConfigLoading(false); } }, [nginxInfo.server, showNotification]); const loadSettings = useCallback(async () => { setLoading(true); try { const response = await apiFetch({ path: '/prorank-seo/v1/performance/cache-settings', }); if (response?.settings) { // Map backend keys (cache_enabled) to frontend keys (enabled) const apiSettings = response.settings as any; const mappedSettings: Partial = { ...response.settings, // Map cache-prefixed keys to short keys enabled: apiSettings.cache_enabled ?? apiSettings.enabled ?? false, lifetime: apiSettings.cache_lifetime ?? apiSettings.lifetime ?? 604800, exclude_urls: apiSettings.cache_exclude_urls ?? apiSettings.exclude_urls ?? '', performance_conflict_safe_mode: apiSettings.performance_conflict_safe_mode ?? response.performance_conflicts?.safe_mode_enabled ?? true, }; setSettings(prev => { const newSettings = { ...prev, ...mappedSettings }; return newSettings; }); } setPerformanceConflicts(response?.performance_conflicts?.plugins || []); } catch (error) { console.error('[CachingDelivery] Failed to load cache settings:', error); } finally { setLoading(false); } }, []); const loadCacheStats = useCallback(async () => { setStatsLoading(true); setStatsError(null); try { const response = await apiFetch({ path: '/prorank-seo/v1/cache/stats', }); const hits = Number((response as any)?.hits ?? 0); const misses = Number((response as any)?.misses ?? 0); const derivedHitRate = (hits + misses) > 0 ? Math.round((hits / (hits + misses)) * 10000) / 100 : undefined; const normalized: CacheStats = { ...response, hit_rate: derivedHitRate ?? response?.hit_rate, miss_rate: derivedHitRate !== undefined ? Math.round((100 - derivedHitRate) * 100) / 100 : response?.miss_rate, total_cached: typeof response?.total_cached === 'number' ? response.total_cached : Number((response as any)?.cached_files ?? 0), bandwidth_saved: response?.bandwidth_saved || (typeof (response as any)?.bytes_saved === 'number' ? `${(response as any).bytes_saved} B` : undefined), }; setCacheStats(normalized); } catch (error: any) { setStatsError(error?.message || __('Failed to load cache stats', 'prorank-seo')); } finally { setStatsLoading(false); } }, []); useEffect(() => { loadSettings(); loadCacheStats(); loadNginxConfig(); }, [loadSettings, loadCacheStats, loadNginxConfig]); const buildBackendSettings = (ackJsDeferPreflight = false): Record => ({ ...settings, cache_enabled: settings.enabled, cache_lifetime: settings.lifetime, cache_exclude_urls: settings.exclude_urls, ...(ackJsDeferPreflight ? { js_defer_preflight_ack: true } : {}), }); const handleSaveSuccess = async (response: SafeModeApplyResponse) => { if (response?.safe_mode?.conflicts) { setPerformanceConflicts(response.safe_mode.conflicts); } if (response?.safe_mode?.applied) { showNotification(response?.safe_mode?.message || __('Settings saved and conflict safe mode applied', 'prorank-seo'), 'warning'); } else { showNotification(__('Settings saved successfully', 'prorank-seo'), 'success'); } await loadNginxConfig(); }; const getPreflightErrorCode = (error: any): string => { const code = String(error?.error || error?.code || ''); return ['js_defer_preflight_failed', 'js_delay_preflight_failed', 'unused_css_preflight_failed'].includes(code) ? code : ''; }; const getPreflightAckKey = (code: string): string => { if (code === 'js_delay_preflight_failed') { return 'js_delay_preflight_ack'; } if (code === 'unused_css_preflight_failed') { return 'unused_css_preflight_ack'; } return 'js_defer_preflight_ack'; }; const saveSettings = async () => { setSaving(true); // Validate CDN settings if (settings.cdn_provider === 'cloudflare' && (!settings.cloudflare_zone_id || !settings.cloudflare_api_token)) { showNotification(__('Please provide Cloudflare credentials', 'prorank-seo'), 'warning'); setSaving(false); return; } if (settings.cdn_provider === 'bunnycdn' && (!settings.bunny_pullzone_id || !settings.bunny_api_key)) { showNotification(__('Please provide BunnyCDN credentials', 'prorank-seo'), 'warning'); setSaving(false); return; } if (settings.cdn_provider === 'fastly' && (!settings.fastly_service_id || !settings.fastly_api_token)) { showNotification(__('Please provide Fastly Service ID and API token', 'prorank-seo'), 'warning'); setSaving(false); return; } if (settings.cdn_provider === 'webhook' && !settings.cdn_webhook_url) { showNotification(__('Please provide a webhook URL', 'prorank-seo'), 'warning'); setSaving(false); return; } if (settings.cdn_provider === 'cloudfront' && (!settings.cloudfront_distribution_id || !settings.cloudfront_access_key || !settings.cloudfront_secret_key)) { showNotification(__('Please provide CloudFront distribution ID and access keys', 'prorank-seo'), 'warning'); setSaving(false); return; } if (settings.cdn_provider === 'keycdn' && (!settings.keycdn_zone_id || !settings.keycdn_api_key)) { showNotification(__('Please provide KeyCDN Zone ID and API key', 'prorank-seo'), 'warning'); setSaving(false); return; } try { const backendSettings = buildBackendSettings(false); const response = await apiFetch({ path: '/prorank-seo/v1/performance/cache-settings', method: 'POST', data: { settings: backendSettings }, }); await handleSaveSuccess(response); } catch (error: any) { const preflightCode = getPreflightErrorCode(error); if (preflightCode) { const preflightLabel = error?.preflight?.label || __('Performance setting', 'prorank-seo'); setJsDeferPreflightBlock({ message: error?.message, title: sprintf( /* translators: %s: performance feature label */ __('%s preflight failed', 'prorank-seo'), preflightLabel ), ackKey: getPreflightAckKey(preflightCode), preflight: error?.preflight, pendingSettings: buildBackendSettings(false), }); showNotification(sprintf( /* translators: %s: performance feature label */ __('%s was not enabled. Review the preflight warning.', 'prorank-seo'), preflightLabel ), 'warning'); return; } showNotification(error.message || __('Failed to save settings', 'prorank-seo'), 'error'); } finally { setSaving(false); } }; const enableJsDeferAnyway = async () => { if (!jsDeferPreflightBlock) { return; } setSaving(true); try { const response = await apiFetch({ path: '/prorank-seo/v1/performance/cache-settings', method: 'POST', data: { settings: { ...jsDeferPreflightBlock.pendingSettings, [jsDeferPreflightBlock.ackKey || 'js_defer_preflight_ack']: true, }, }, }); setJsDeferPreflightBlock(null); await handleSaveSuccess(response); } catch (error: any) { showNotification(error?.message || __('Failed to enable JS defer', 'prorank-seo'), 'error'); } finally { setSaving(false); } }; const testCdn = async () => { if (settings.cdn_provider === 'none') { showNotification(__('Select a CDN provider to test credentials', 'prorank-seo'), 'warning'); return; } setCdnTesting(true); try { const response = await apiFetch({ path: '/prorank-seo/v1/cdn/test', method: 'POST', data: { settings: { cdn_provider: settings.cdn_provider, cloudflare_zone_id: settings.cloudflare_zone_id, cloudflare_api_token: settings.cloudflare_api_token, bunny_pullzone_id: settings.bunny_pullzone_id, bunny_api_key: settings.bunny_api_key, fastly_service_id: settings.fastly_service_id, fastly_api_token: settings.fastly_api_token, cloudfront_distribution_id: settings.cloudfront_distribution_id, cloudfront_access_key: settings.cloudfront_access_key, cloudfront_secret_key: settings.cloudfront_secret_key, keycdn_zone_id: settings.keycdn_zone_id, keycdn_api_key: settings.keycdn_api_key, cdn_webhook_url: settings.cdn_webhook_url, cdn_webhook_secret: settings.cdn_webhook_secret, }, }, }); setCdnStatus(response); showNotification(__('CDN credentials verified', 'prorank-seo'), 'success'); } catch (error: any) { setCdnStatus({ error: error?.message || __('CDN test failed', 'prorank-seo') }); showNotification(error?.message || __('CDN test failed', 'prorank-seo'), 'error'); } finally { setCdnTesting(false); } }; const checkCdnSetup = async () => { setCdnChecking(true); try { const response = await apiFetch({ path: '/prorank-seo/v1/cdn-setup/check', }); setCdnSetup(response?.summary || response); showNotification(__('Edge/CDN header check completed', 'prorank-seo'), 'success'); } catch (error: any) { setCdnSetup({ error: error?.message || __('Edge/CDN header check failed', 'prorank-seo') }); showNotification(error?.message || __('Edge/CDN header check failed', 'prorank-seo'), 'error'); } finally { setCdnChecking(false); } }; const purgeCdnCache = async () => { if (settings.cdn_provider === 'none') { showNotification(__('Select a CDN provider before purging', 'prorank-seo'), 'warning'); return; } setCdnPurging(true); try { await apiFetch({ path: '/prorank-seo/v1/cdn/purge', method: 'POST', }); showNotification(__('CDN cache purged', 'prorank-seo'), 'success'); } catch (error: any) { showNotification(error?.message || __('Failed to purge CDN cache', 'prorank-seo'), 'error'); } finally { setCdnPurging(false); } }; const detectCloudflareZone = async () => { if (!settings.cloudflare_api_token) { showNotification(__('Enter your Cloudflare API token first', 'prorank-seo'), 'warning'); return; } setCfZoneDetecting(true); try { const response = await apiFetch<{ success: boolean; result?: { zone_id: string; name: string } }>({ path: '/prorank-seo/v1/cdn/cloudflare/detect-zone', method: 'POST', data: { api_token: settings.cloudflare_api_token }, }); const zone = response?.result; if (zone?.zone_id) { updateSetting('cloudflare_zone_id', zone.zone_id); showNotification( __('Cloudflare zone detected: ', 'prorank-seo') + (zone.name || zone.zone_id), 'success' ); } else { showNotification(__('No Cloudflare zone matched this domain', 'prorank-seo'), 'warning'); } } catch (error: any) { showNotification(error?.message || __('Cloudflare zone detection failed', 'prorank-seo'), 'error'); } finally { setCfZoneDetecting(false); } }; const refreshCloudflareDevMode = useCallback(async () => { if (settings.cdn_provider !== 'cloudflare' || !settings.cloudflare_zone_id || !settings.cloudflare_api_token) { setCfDevMode(null); return; } try { const response = await apiFetch<{ success: boolean; result?: { enabled: boolean; time_remaining: number } }>({ path: '/prorank-seo/v1/cdn/cloudflare/dev-mode', }); if (response?.result) { setCfDevMode(response.result); } } catch { setCfDevMode(null); } }, [settings.cdn_provider, settings.cloudflare_zone_id, settings.cloudflare_api_token]); useEffect(() => { refreshCloudflareDevMode(); }, [refreshCloudflareDevMode]); const toggleCloudflareDevMode = async (enabled: boolean) => { setCfDevModeBusy(true); try { await apiFetch({ path: '/prorank-seo/v1/cdn/cloudflare/dev-mode', method: 'POST', data: { enabled }, }); showNotification( enabled ? __('Cloudflare development mode enabled (3 hours)', 'prorank-seo') : __('Cloudflare development mode disabled', 'prorank-seo'), 'success' ); await refreshCloudflareDevMode(); } catch (error: any) { showNotification(error?.message || __('Failed to toggle Cloudflare dev mode', 'prorank-seo'), 'error'); } finally { setCfDevModeBusy(false); } }; const clearCache = async () => { if (!window.confirm(__('Clear all cached pages?', 'prorank-seo'))) { return; } setClearing(true); try { const response = await apiFetch({ path: '/prorank-seo/v1/cache/clear', method: 'POST', }); showNotification( (response as any)?.message || __('All cache cleared successfully', 'prorank-seo'), 'success' ); } catch (error: any) { showNotification(error.message || __('Failed to clear cache', 'prorank-seo'), 'error'); } finally { setClearing(false); } }; const listToTextarea = (value?: string[]): string => Array.isArray(value) ? value.join('\n') : ''; const textareaToList = (value: string): string[] => value .split(/[\r\n,]+/) .map((item) => item.trim()) .filter(Boolean); const applyPerformancePreset = async (name: string, label: string) => { if (!window.confirm(sprintf(__('Apply the %s preset? This updates cache, asset, and image optimisation settings.', 'prorank-seo'), label))) { return; } setApplyingPreset(name); try { const response = await apiFetch<{ message?: string }>({ path: '/prorank-seo/v1/performance/presets/apply', method: 'POST', data: { name }, }); showNotification(response?.message || sprintf(__('%s preset applied', 'prorank-seo'), label), 'success'); await loadSettings(); await loadCacheStats(); await loadNginxConfig(); } catch (error: any) { showNotification(error?.message || __('Failed to apply performance preset', 'prorank-seo'), 'error'); } finally { setApplyingPreset(null); } }; const applyConflictSafeModeNow = async () => { setApplyingSafeMode(true); try { const response = await apiFetch({ path: '/prorank-seo/v1/performance/conflict-safe-mode/apply', method: 'POST', data: { enabled: settings.performance_conflict_safe_mode }, }); if (response?.safe_mode?.conflicts) { setPerformanceConflicts(response.safe_mode.conflicts); } showNotification( response?.safe_mode?.message || __('Conflict safe mode processed', 'prorank-seo'), response?.safe_mode?.applied ? 'warning' : 'success' ); await loadSettings(); } catch (error: any) { showNotification(error?.message || __('Failed to apply conflict safe mode', 'prorank-seo'), 'error'); } finally { setApplyingSafeMode(false); } }; const copyNginxConfig = async () => { if (!nginxConfig) { return; } try { if (!window?.navigator?.clipboard) { throw new Error(__('Clipboard access is not available in this browser', 'prorank-seo')); } await window.navigator.clipboard.writeText(nginxConfig); showNotification(__('Nginx snippet copied', 'prorank-seo'), 'success'); } catch (error: any) { showNotification(error?.message || __('Failed to copy Nginx snippet', 'prorank-seo'), 'error'); } }; // Helper function to update settings const updateSetting = (key: K, value: CachingSettings[K]) => { setSettings(prev => { return { ...prev, [key]: value }; }); }; const formatPercent = (value?: number) => { if (value === 0) { return '0%'; } if (typeof value !== 'number') { return '—'; } return `${Math.round(value)}%`; }; const formatValue = (value?: number | string, suffix?: string) => { if (value === 0) { return suffix ? `0${suffix}` : '0'; } if (!value) { return '—'; } return suffix ? `${value}${suffix}` : String(value); }; if (loading) { return (

{__('Loading caching settings...', 'prorank-seo')}

); } const hitRate = typeof cacheStats?.hit_rate === 'number' ? cacheStats?.hit_rate : undefined; const avgResponse = typeof cacheStats?.avg_response_time === 'number' ? `${cacheStats?.avg_response_time}ms` : (cacheStats?.avg_response_time || '—'); const totalCached = typeof cacheStats?.total_cached === 'number' ? cacheStats.total_cached : 0; const showCacheStatsHelp = !statsLoading && !statsError && totalCached === 0; const preflightSamples = jsDeferPreflightBlock?.preflight?.samples || []; const performancePresets = [ { name: 'standard', label: __('Standard', 'prorank-seo'), description: __('Safe default for most sites: page cache, DNS prefetch, lazy loading, and WebP.', 'prorank-seo'), }, { name: 'aggressive', label: __('Aggressive', 'prorank-seo'), description: __('Maximum optimisation: defer/delay JavaScript, CSS minify/combine, HTML minify, and AVIF.', 'prorank-seo'), }, { name: 'ecommerce', label: __('E-commerce', 'prorank-seo'), description: __('WooCommerce-safe profile with cache variants on and risky JavaScript delays off.', 'prorank-seo'), }, ]; return (
{jsDeferPreflightBlock && ( setJsDeferPreflightBlock(null)} className="prorank-js-defer-preflight-modal" >

{jsDeferPreflightBlock.message || __('ProRank did not enable this setting because frontend checks found a possible menu, runtime, or layout break.', 'prorank-seo')}

{preflightSamples.length > 0 && ( <> {__('Checked URLs', 'prorank-seo')}
{preflightSamples.map((sample, index) => { const findings = sample.blocking_findings || []; return (

{sample.label || sample.url || __('Frontend URL', 'prorank-seo')} {sample.url ? <>
{sample.url} : null}

{findings.length > 0 ? (
    {findings.map((finding, findingIndex) => (
  • {finding}
  • ))}
) : (

{__('Passed', 'prorank-seo')}

)}
); })}
)} {preflightSamples.length === 0 && (jsDeferPreflightBlock.preflight?.blocking_findings || []).length > 0 && ( <> {__('Blocking findings', 'prorank-seo')}
    {(jsDeferPreflightBlock.preflight?.blocking_findings || []).map((finding, index) => (
  • {finding}
  • ))}
)} {(jsDeferPreflightBlock.preflight?.inline_jquery_examples || []).length > 0 && ( <> {__('Example inline scripts', 'prorank-seo')}
    {(jsDeferPreflightBlock.preflight?.inline_jquery_examples || []).map((snippet, index) => (
  • {snippet}
  • ))}
)} {(jsDeferPreflightBlock.preflight?.inline_dependency_violations || []).length > 0 && ( <> {__('Runtime dependency examples', 'prorank-seo')}
    {(jsDeferPreflightBlock.preflight?.inline_dependency_violations || []).map((violation, index) => (
  • {violation.label || __('Runtime provider', 'prorank-seo')} {violation.reason ? ` (${violation.reason})` : ''} {violation.snippet ? <>
    {violation.snippet} : null}
  • ))}
)} {(jsDeferPreflightBlock.preflight?.critical_styles_stripped || []).length > 0 && ( <> {__('Protected stylesheet examples', 'prorank-seo')}
    {(jsDeferPreflightBlock.preflight?.critical_styles_stripped || []).map((style, index) => (
  • {style.label || __('Stylesheet', 'prorank-seo')} {style.reason ? ` (${style.reason})` : ''} {style.href || style.src ? <>
    {style.href || style.src} : null}
  • ))}
)} {__('Recommended: fix the listed dependency issue, then try again. Only enable anyway if you have manually tested the menu, checkout, booking, and key interactions.', 'prorank-seo')}
)} {/* Performance Conflict Safe Mode */}

{__('Performance Conflict Safe Mode', 'prorank-seo')}

{settings.performance_conflict_safe_mode ? __('Enabled', 'prorank-seo') : __('Disabled', 'prorank-seo')}
{__('Auto-disable overlapping optimizations', 'prorank-seo')} {__('Automatically turns off overlapping ProRank runtime features when other performance plugins are active.', 'prorank-seo')}
updateSetting('performance_conflict_safe_mode', value)} label="" />
{performanceConflicts.length > 0 ? ( <> {sprintf( /* translators: %d: number of active plugin conflicts */ __('Detected %d active optimization plugins that may conflict with ProRank.', 'prorank-seo'), performanceConflicts.length )}
{performanceConflicts.join(', ')}
{__('Keep only one tool responsible for page cache, CSS delivery, JavaScript delay, lazy loading, and HTML minification. After changing performance stacks, retest builder/template pages before leaving the setup in production.', 'prorank-seo')} ) : ( {__('No active performance plugin conflicts detected.', 'prorank-seo')} )} {settings.performance_conflict_safe_mode && performanceConflicts.length > 0 && (
{applyingSafeMode ? __('Applying...', 'prorank-seo') : __('Apply Safe Mode Now', 'prorank-seo')}
)}
{/* Performance Presets */}

{__('Performance Presets', 'prorank-seo')}

{performancePresets.map((preset) => (

{preset.label}

{preset.description}

applyPerformancePreset(preset.name, preset.label)} disabled={!!applyingPreset} > {applyingPreset === preset.name ? __('Applying...', 'prorank-seo') : __('Apply Preset', 'prorank-seo')}
))}
{/* Cache Insights Card */}

{__('Cache Insights', 'prorank-seo')}

{statsLoading ? __('Refreshing...', 'prorank-seo') : __('Refresh Stats', 'prorank-seo')}
{statsError && ( {statsError} )} {!statsError && ( <> {statsLoading ? (

{__('Loading cache stats...', 'prorank-seo')}

) : ( <> {showCacheStatsHelp && (
{__( 'Cache stats appear after logged-out visits. Open your site in an incognito window, browse a few pages, then refresh stats.', 'prorank-seo' )}
)}
{formatPercent(hitRate)}
{__('Hit Rate', 'prorank-seo')}
{formatValue(cacheStats?.total_cached)}
{__('Cached Pages', 'prorank-seo')}
{formatValue(cacheStats?.cache_size)}
{__('Cache Size', 'prorank-seo')}
{formatValue(cacheStats?.bandwidth_saved)}
{__('Bandwidth Saved', 'prorank-seo')}
{avgResponse}
{__('Avg Response', 'prorank-seo')}
{formatValue(cacheStats?.edge_locations)}
{__('Edge Locations', 'prorank-seo')}
)} )}
{/* Page Cache Card */}

{__('Page Cache', 'prorank-seo')}

{settings.enabled ? __('Enabled', 'prorank-seo') : __('Disabled', 'prorank-seo')}
{__('Enable Page Cache', 'prorank-seo')} {__('Cache static HTML files for faster loading', 'prorank-seo')}
updateSetting('enabled', value)} label="" />
{settings.woocommerce_active ? ( <>
{__('WooCommerce Safe Cache', 'prorank-seo')} {__('Never cache cart, checkout, my-account or order pages, and bypass the cache while a customer has an active cart/session. Recommended for all stores.', 'prorank-seo')}
updateSetting('woocommerce_safe_cache_enabled', value)} label="" />
{settings.woocommerce_safe_cache_enabled !== false && (
{__('Active WooCommerce protections:', 'prorank-seo')}
  • {__('Cart, checkout, my-account & order pages bypass the cache', 'prorank-seo')}
  • {__('Cache bypassed while a cart / session cookie is present', 'prorank-seo')}
  • {__('Cart, checkout, wc-ajax & Store API URLs excluded from preloading', 'prorank-seo')}
  • {__('Cart fragments, checkout & payment-gateway scripts excluded from JS delay/defer/minify', 'prorank-seo')}
)} ) : (
{__('WooCommerce Safe Cache', 'prorank-seo')} {__('Activate WooCommerce to protect cart, checkout, and account pages from caching.', 'prorank-seo')}
{__('WooCommerce not active', 'prorank-seo')}
)} {settings.enabled && ( <>
updateSetting('lifetime', value)} min={60} max={2592000} step={60} help={`${settings.lifetime} ${__('seconds', 'prorank-seo')}`} />
updateSetting('exclude_urls', value)} rows={4} placeholder="/checkout/* /cart/* /my-account/*" />
updateSetting('cache_exclude_categories', textareaToList(value))} rows={3} placeholder="news 123" />
updateSetting('cache_exclude_tags', textareaToList(value))} rows={3} placeholder="uncached 456" />
updateSetting('cache_exclude_post_types', textareaToList(value))} rows={3} placeholder="tribe_events product" />
{clearing ? __('Clearing...', 'prorank-seo') : __('Clear Cache', 'prorank-seo')}
{__('Cache Warming', 'prorank-seo')} {__('Keep core pages warm by re-priming the cache every 15 minutes after it is cleared.', 'prorank-seo')}
updateSetting('preload_enabled', value)} label="" />
{settings.preload_enabled && ( <>
{__('Adaptive Load Throttle', 'prorank-seo')} {__('Skip cache warming while the server is under heavy load, then resume on the next cycle.', 'prorank-seo')}
updateSetting('preload_load_throttle_enabled', value)} label="" />
{settings.preload_load_throttle_enabled && ( <>
updateSetting('preload_max_load_average', value ?? 4)} min={0.5} max={32} step={0.5} help={__('Skip warming when the 1-minute load average exceeds this value.', 'prorank-seo')} />
updateSetting('preload_batch_delay', value ?? 45)} min={5} max={600} step={5} help={__('Minimum wait before throttled warming is retried.', 'prorank-seo')} />
{settings.preload_throttle_supported === false ? __('Server load monitoring is unavailable on this host, so throttling will not engage.', 'prorank-seo') : (typeof settings.preload_current_load === 'number' ? `${__('Active — current server load:', 'prorank-seo')} ${settings.preload_current_load.toFixed(2)}` : __('Active — server load monitoring is available.', 'prorank-seo'))}
)} )} )}
{/* CDN Configuration Card */}

{__('CDN Configuration', 'prorank-seo')}

updateSetting('cdn_provider', value)} />
{settings.cdn_provider === 'cloudflare' && ( <>
updateSetting('cloudflare_zone_id', value)} />
updateSetting('cloudflare_api_token', value)} />
{settings.cloudflare_zone_id && settings.cloudflare_api_token && (
{__('Cloudflare Development Mode', 'prorank-seo')} {cfDevMode?.enabled ? sprintf( // translators: %d is the number of seconds remaining. __('On — %d seconds remaining before automatic shutoff', 'prorank-seo'), cfDevMode.time_remaining ) : __('Bypass Cloudflare cache for 3 hours while you test changes', 'prorank-seo')}
toggleCloudflareDevMode(value)} disabled={cfDevModeBusy} label="" />
)}
{__('Clear Cloudflare when purging all', 'prorank-seo')} {__('Also purge the Cloudflare zone whenever ProRank clears all cached pages', 'prorank-seo')}
updateSetting('cdn_clear_on_purge_all', value)} label="" />
)} {settings.cdn_provider === 'cloudfront' && ( <>
updateSetting('cloudfront_distribution_id', value)} />
updateSetting('cloudfront_access_key', value)} />
updateSetting('cloudfront_secret_key', value)} />
)} {settings.cdn_provider === 'keycdn' && ( <>
updateSetting('keycdn_zone_id', value)} />
updateSetting('keycdn_api_key', value)} />
)} {settings.cdn_provider === 'bunnycdn' && ( <>
updateSetting('bunny_pullzone_id', value)} />
updateSetting('bunny_api_key', value)} />
)} {settings.cdn_provider === 'fastly' && ( <>
updateSetting('fastly_service_id', value)} />
updateSetting('fastly_api_token', value)} />
)} {settings.cdn_provider === 'webhook' && ( <>
updateSetting('cdn_webhook_url', value)} />
updateSetting('cdn_webhook_secret', value)} />
)}
{cdnTesting ? __('Testing…', 'prorank-seo') : __('Test Credentials', 'prorank-seo')} {cdnChecking ? __('Checking…', 'prorank-seo') : __('Check Edge/CDN Headers', 'prorank-seo')} {cdnPurging ? __('Purging…', 'prorank-seo') : __('Purge CDN Cache', 'prorank-seo')}
{cdnStatus && ( {cdnStatus?.success ? __('CDN connected: ', 'prorank-seo') + (cdnStatus?.result?.provider || settings.cdn_provider) : cdnStatus?.error || __('CDN test failed', 'prorank-seo')} )} {cdnSetup && !cdnSetup?.error && (

{__('Edge Cache Status', 'prorank-seo')}

{__('Status', 'prorank-seo')}
{cdnSetup.status || '—'}
{__('Cache', 'prorank-seo')}
{cdnSetup.cache_status || __('Unknown', 'prorank-seo')}
{__('Server', 'prorank-seo')}
{cdnSetup.server || '—'}
{__('Brotli', 'prorank-seo')}
{cdnSetup.brotli ? __('Yes', 'prorank-seo') : __('No', 'prorank-seo')}
{__('HTTP/3', 'prorank-seo')}
{cdnSetup.http3 ? __('Yes', 'prorank-seo') : __('No', 'prorank-seo')}
{__('Edge timing (ms)', 'prorank-seo')}
{cdnSetup.timing_ms ?? '—'}
{Array.isArray(cdnSetup.warnings) && cdnSetup.warnings.length > 0 && (
    {cdnSetup.warnings.map((w: string, idx: number) => (
  • {w}
  • ))}
)}
)} {cdnSetup?.error && ( {cdnSetup.error} )}
{/* Resource Preloading Card */}

{__('Resource Preloading', 'prorank-seo')}

{__('Link Preloading', 'prorank-seo')} {__('Prefetch links on hover for instant navigation', 'prorank-seo')}
updateSetting('link_preload_enabled', value)} label="" />
{settings.link_preload_enabled && (
updateSetting('link_preload_delay', value)} min={0} max={500} step={10} />
)}
{__('DNS Prefetch', 'prorank-seo')} {__('Resolve DNS for external domains early', 'prorank-seo')}
updateSetting('dns_prefetch_enabled', value)} label="" />
{settings.dns_prefetch_enabled && (
updateSetting('dns_prefetch_hosts', value)} rows={4} placeholder="fonts.googleapis.com fonts.gstatic.com www.example-cdn.com" />
)} {settings.dns_prefetch_enabled && (
{__('Auto-Discover Third-Party Origins', 'prorank-seo')} {__('Let ProRank inspect final HTML and add a small preconnect budget for external origins discovered on the page.', 'prorank-seo')}
updateSetting('dynamic_resource_hints_enabled', value)} label="" />
)}
{__('Font Preloading', 'prorank-seo')} {__('Load critical fonts early to prevent flash', 'prorank-seo')}
updateSetting('font_preload_enabled', value)} label="" />
{settings.font_preload_enabled && (
updateSetting('font_preload_urls', value)} rows={4} />
)}
{/* Browser Cache Card */}

{__('Browser Cache', 'prorank-seo')}

{__('Enable Browser Caching', 'prorank-seo')} {__('Store resources in visitor browsers', 'prorank-seo')}
updateSetting('browser_cache_enabled', value)} label="" />
{nginxInfo.server && (
{__( 'Nginx detected. Browser cache values from this screen do not apply through .htaccess. Use the generated Nginx snippet or your server config to enforce them.', 'prorank-seo' )}
)} {nginxInfo.server && (
{__('Generated Nginx Snippet', 'prorank-seo')}
{__('This snippet reflects your saved ProRank cache settings. Save changes first, then copy it into your Nginx server block to enforce static asset cache headers.', 'prorank-seo')}
{nginxCachePath && (
{sprintf(__('Page cache path: %s', 'prorank-seo'), nginxCachePath)}
)}
loadNginxConfig(true)} disabled={nginxConfigLoading} > {nginxConfigLoading ? __('Refreshing...', 'prorank-seo') : __('Refresh Snippet', 'prorank-seo')} {__('Copy Snippet', 'prorank-seo')}
{nginxConfigError && (
{nginxConfigError}
)} {!nginxConfigError && nginxConfig && (
                  {nginxConfig}
                
)}
)}
{litespeedMessage}
{settings.browser_cache_enabled && ( <>
updateSetting('browser_cache_images', value)} />
{ updateSetting('browser_cache_css', value); updateSetting('browser_cache_js', value); }} />
updateSetting('browser_cache_html', value)} />
)}
{/* JavaScript Optimization Card */}

{__('JavaScript Optimization', 'prorank-seo')}

{__('Defer JavaScript', 'prorank-seo')} {__('Load scripts after page content. Keep off if another plugin already rewrites script loading.', 'prorank-seo')}
updateSetting('js_defer', value)} label="" />
{__('Delay JavaScript', 'prorank-seo')} {__('Delay scripts until user interaction. Builder and booking-heavy pages need explicit testing before production use.', 'prorank-seo')}
updateSetting('js_delay', value)} label="" />
{__('Delay Third-Party Trackers', 'prorank-seo')} {__('Safely push known analytics and ad trackers behind interaction without enabling full-site JavaScript delay.', 'prorank-seo')}
updateSetting('tracker_delay_enabled', value)} label="" />
updateSetting('js_exclude', value)} rows={4} />
{__('Experimental JS Delay (Advanced)', 'prorank-seo')}
{__('Use only for benchmarking/tuning. Keep disabled for universal-safe defaults, especially on Elementor or conversion-critical pages.', 'prorank-seo')}
{__('Delay jQuery Core', 'prorank-seo')} {__('Can reduce unused JavaScript, but may affect legacy plugins.', 'prorank-seo')}
updateSetting('js_delay_jquery', value)} label="" disabled={!settings.js_delay} />
{__('Delay Elementor Frontend Modules', 'prorank-seo')} {__('Aggressive mode for lower unused JS. Test layout/interactions before using in production.', 'prorank-seo')}
updateSetting('js_delay_elementor_modules', value)} label="" disabled={!settings.js_delay} />
{/* CSS Optimization Card */}

{__('CSS Optimization', 'prorank-seo')}

{__('Minify CSS', 'prorank-seo')} {__('Remove whitespace and comments', 'prorank-seo')}
updateSetting('css_minify', value)} label="" />
{__('Combine CSS', 'prorank-seo')} {__('Merge multiple CSS files into one. Keep off if another optimizer already handles CSS aggregation.', 'prorank-seo')} {__('On HTTP/2, split delivery is often safer than combining on builder-heavy sites.', 'prorank-seo')}
updateSetting('css_combine', value)} label="" />
{__('Optimize CSS Delivery', 'prorank-seo')} {__('Builder-sensitive beta. Do not combine with another CSS optimizer, and retest Elementor/template pages before production use.', 'prorank-seo')}
updateSetting('css_async', value)} label="" />
{__('Minify Large Inline CSS Blocks', 'prorank-seo')} {__('Compress builder and plugin-generated inline style tags in the final HTML. Keep off if another optimizer already rewrites final HTML.', 'prorank-seo')}
updateSetting('inline_css_minify_enabled', value)} label="" />
{__('Move Body Styles Into Head', 'prorank-seo')} {__('Relocate late body-injected style tags into the document head so CSS arrives earlier. Avoid when another optimizer is already relocating or inlining styles.', 'prorank-seo')}
updateSetting('inline_css_relocate_enabled', value)} label="" />
updateSetting('css_exclude', value)} rows={4} />
{/* Save Button */}
{saving ? __('Saving...', 'prorank-seo') : __('Save Settings', 'prorank-seo')}
); }; export default CachingDeliverySettings;