| 1 |
<?php |
| 2 |
|
| 3 |
if (!defined('ABSPATH')) { |
| 4 |
exit; |
| 5 |
} |
| 6 |
|
| 7 |
/** |
| 8 |
* Admin theme detection and critical CSS output. |
| 9 |
* |
| 10 |
* Detects dark mode from WordPress color schemes, dark mode plugins, |
| 11 |
* and browser preferences. Outputs critical theme CSS inline in the |
| 12 |
* <head> to prevent flash of unstyled content. |
| 13 |
*/ |
| 14 |
class ABJ_404_Solution_AdminThemeManager { |
| 15 |
|
| 16 |
/** Detect if dark mode is enabled from various sources. |
| 17 |
* |
| 18 |
* @return bool True if dark mode is detected |
| 19 |
*/ |
| 20 |
static function isDarkModeDetected() { |
| 21 |
$current_user_id = get_current_user_id(); |
| 22 |
if ($current_user_id) { |
| 23 |
$admin_color = get_user_meta($current_user_id, 'admin_color', true); |
| 24 |
$dark_schemes = array('midnight', 'ectoplasm', 'coffee'); |
| 25 |
if (in_array($admin_color, $dark_schemes)) { |
| 26 |
return true; |
| 27 |
} |
| 28 |
} |
| 29 |
|
| 30 |
if (get_option('wp_dark_mode_enabled')) { |
| 31 |
return true; |
| 32 |
} |
| 33 |
|
| 34 |
if (get_option('dark_mode_for_wp_dashboard_enabled')) { |
| 35 |
return true; |
| 36 |
} |
| 37 |
|
| 38 |
if (class_exists('WP_Dark_Mode') || class_exists('Dark_Mode_For_WP_Dashboard')) { |
| 39 |
return true; |
| 40 |
} |
| 41 |
|
| 42 |
return false; |
| 43 |
} |
| 44 |
|
| 45 |
/** |
| 46 |
* @return string The theme to use ('obsidian' for dark mode, 'default' otherwise) |
| 47 |
*/ |
| 48 |
static function getAutoSelectedTheme() { |
| 49 |
if (self::isDarkModeDetected()) { |
| 50 |
return 'obsidian'; |
| 51 |
} |
| 52 |
return 'default'; |
| 53 |
} |
| 54 |
|
| 55 |
/** |
| 56 |
* Output critical theme CSS inline to prevent FOUC. |
| 57 |
* |
| 58 |
* @return void |
| 59 |
*/ |
| 60 |
static function outputCriticalThemeCSS() { |
| 61 |
try { |
| 62 |
if (!array_key_exists('abj404_settingsPageName', $GLOBALS) || |
| 63 |
!array_key_exists('page', $_GET) || |
| 64 |
$_GET['page'] != ABJ404_PP) { |
| 65 |
return; |
| 66 |
} |
| 67 |
|
| 68 |
$logic = abj_service('plugin_logic'); |
| 69 |
$options = abj_service('options_repository')->getOptions(); |
| 70 |
$theme = (isset($options['admin_theme']) && is_string($options['admin_theme'])) ? $options['admin_theme'] : 'default'; |
| 71 |
|
| 72 |
$auto_dark_mode = !isset($options['disable_auto_dark_mode']) || $options['disable_auto_dark_mode'] != '1'; |
| 73 |
|
| 74 |
if ($theme === 'default' && $auto_dark_mode) { |
| 75 |
$theme = self::getAutoSelectedTheme(); |
| 76 |
} |
| 77 |
|
| 78 |
$allowed_themes = array('default', 'calm', 'mono', 'neon', 'obsidian'); |
| 79 |
if (!in_array($theme, $allowed_themes)) { |
| 80 |
$theme = 'default'; |
| 81 |
} |
| 82 |
|
| 83 |
if ($theme === 'default') { |
| 84 |
$html = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/themeRemoverScript.html"); |
| 85 |
echo $html; |
| 86 |
return; |
| 87 |
} |
| 88 |
|
| 89 |
$html = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/themeSetterScript.html"); |
| 90 |
$f = abj_service('functions'); |
| 91 |
$html = $f->str_replace('{theme}', esc_js($theme), $html); |
| 92 |
echo $html; |
| 93 |
|
| 94 |
$themeVariables = array( |
| 95 |
'mono' => array( |
| 96 |
'--abj404-bg' => '#F8FAFC', |
| 97 |
'--abj404-bg-muted' => '#F5F7FA', |
| 98 |
'--abj404-surface' => '#ffffff', |
| 99 |
'--abj404-surface-muted' => '#F1F5F9', |
| 100 |
'--abj404-text' => '#111827', |
| 101 |
'--abj404-text-muted' => '#6B7280', |
| 102 |
'--abj404-border' => '#E5E7EB', |
| 103 |
'--abj404-primary' => '#374151', |
| 104 |
'--abj404-accent' => '#2563EB', |
| 105 |
'--abj404-info' => '#3B82F6', |
| 106 |
'--abj404-success' => '#10B981', |
| 107 |
'--abj404-warning' => '#F59E0B', |
| 108 |
'--abj404-danger' => '#EF4444', |
| 109 |
'--abj404-focus' => '#93C5FD', |
| 110 |
'--abj404-table-header' => '#F1F5F9', |
| 111 |
'--abj404-row-hover' => '#F5F7FA', |
| 112 |
'--abj404-row-selected' => '#DBEAFE', |
| 113 |
'--abj404-badge-bg' => '#EFF1F5', |
| 114 |
'--abj404-badge-text' => '#374151', |
| 115 |
), |
| 116 |
'calm' => array( |
| 117 |
'--abj404-bg' => '#F7FAFD', |
| 118 |
'--abj404-bg-muted' => '#F1F6FE', |
| 119 |
'--abj404-surface' => '#ffffff', |
| 120 |
'--abj404-surface-muted' => '#E9F0FB', |
| 121 |
'--abj404-text' => '#17223B', |
| 122 |
'--abj404-text-muted' => '#5A6B86', |
| 123 |
'--abj404-border' => '#E1E8F5', |
| 124 |
'--abj404-primary' => '#1E6BD6', |
| 125 |
'--abj404-accent' => '#00A27A', |
| 126 |
'--abj404-info' => '#2B8AE2', |
| 127 |
'--abj404-success' => '#20B67A', |
| 128 |
'--abj404-warning' => '#F6A700', |
| 129 |
'--abj404-danger' => '#D53F3F', |
| 130 |
'--abj404-focus' => '#5AA2FF', |
| 131 |
'--abj404-table-header' => '#E9F0FB', |
| 132 |
'--abj404-row-hover' => '#F1F6FE', |
| 133 |
'--abj404-row-selected' => '#D7E8FF', |
| 134 |
'--abj404-badge-bg' => '#EEF2F8', |
| 135 |
'--abj404-badge-text' => '#3E546E', |
| 136 |
), |
| 137 |
'neon' => array( |
| 138 |
'--abj404-bg' => '#0C0F13', |
| 139 |
'--abj404-bg-muted' => '#11151A', |
| 140 |
'--abj404-surface' => '#151A21', |
| 141 |
'--abj404-surface-muted' => '#1B222B', |
| 142 |
'--abj404-text' => '#E5EAF2', |
| 143 |
'--abj404-text-muted' => '#A6B0C3', |
| 144 |
'--abj404-border' => '#273141', |
| 145 |
'--abj404-primary' => '#7C3AED', |
| 146 |
'--abj404-accent' => '#22D3EE', |
| 147 |
'--abj404-info' => '#60A5FA', |
| 148 |
'--abj404-success' => '#34D399', |
| 149 |
'--abj404-warning' => '#F59E0B', |
| 150 |
'--abj404-danger' => '#F87171', |
| 151 |
'--abj404-focus' => '#38BDF8', |
| 152 |
'--abj404-table-header' => '#1F2732', |
| 153 |
'--abj404-row-hover' => '#192028', |
| 154 |
'--abj404-row-selected' => '#0E2936', |
| 155 |
'--abj404-badge-bg' => '#202734', |
| 156 |
'--abj404-badge-text' => '#CFD8E6', |
| 157 |
), |
| 158 |
'obsidian' => array( |
| 159 |
'--abj404-bg' => '#0A0F1A', |
| 160 |
'--abj404-bg-muted' => '#0E1522', |
| 161 |
'--abj404-surface' => '#121826', |
| 162 |
'--abj404-surface-muted' => '#172032', |
| 163 |
'--abj404-text' => '#E6ECF7', |
| 164 |
'--abj404-text-muted' => '#A9B7CC', |
| 165 |
'--abj404-border' => '#223149', |
| 166 |
'--abj404-primary' => '#1D4ED8', |
| 167 |
'--abj404-accent' => '#A78BFA', |
| 168 |
'--abj404-info' => '#60A5FA', |
| 169 |
'--abj404-success' => '#22C55E', |
| 170 |
'--abj404-warning' => '#F59E0B', |
| 171 |
'--abj404-danger' => '#EF4444', |
| 172 |
'--abj404-focus' => '#93C5FD', |
| 173 |
'--abj404-table-header' => '#1B253A', |
| 174 |
'--abj404-row-hover' => '#141C2C', |
| 175 |
'--abj404-row-selected' => '#1A2A46', |
| 176 |
'--abj404-badge-bg' => '#1A2438', |
| 177 |
'--abj404-badge-text' => '#DCE6F7', |
| 178 |
), |
| 179 |
); |
| 180 |
|
| 181 |
/** @var string $themeKey */ |
| 182 |
$themeKey = $theme; |
| 183 |
if (isset($themeVariables[$themeKey])) { |
| 184 |
$cssVars = ''; |
| 185 |
foreach ($themeVariables[$themeKey] as $var => $value) { |
| 186 |
$cssVars .= esc_html($var) . ':' . esc_html($value) . ';'; |
| 187 |
} |
| 188 |
|
| 189 |
$html = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/criticalThemeCSS.html"); |
| 190 |
$f = abj_service('functions'); |
| 191 |
$html = $f->str_replace('{css_variables}', $cssVars, $html); |
| 192 |
echo $html; |
| 193 |
} |
| 194 |
} catch (Throwable $e) { |
| 195 |
ABJ_404_Solution_AdminRuntimeErrorNotice::reportAdminRuntimeError('admin_head', $e); |
| 196 |
} |
| 197 |
} |
| 198 |
} |
| 199 |
|