PluginProbe
Adminify – White Label, Admin Menu Editor, Login Customizer / 4.1.3
Adminify – White Label, Admin Menu Editor, Login Customizer v4.1.3
4.3.1 4.3.0 4.2.26 4.2.25 4.2.24 4.2.23 4.2.22 4.2.21 4.2.20 4.2.19 4.2.18 4.2.17 4.2.16 4.2.15 4.2.14 4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 4.1.17 All 164 releases
adminify / Inc / Classes / GoogleFontsLocal.php

GoogleFontsLocal.php in Adminify – White Label, Admin Menu Editor, Login Customizer 4.1.3, at Inc/Classes/GoogleFontsLocal.php

369 lines 9.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPAdminify\Inc\Classes;
4
5 // no direct access allowed
6 if (!defined('ABSPATH')) {
7 exit;
8 }
9
10 /**
11 * Google Fonts Local
12 *
13 * Downloads Google Fonts locally and serves them from wp-content/uploads/adminify-google-fonts/
14 *
15 * @since 4.0.0
16 */
17 class GoogleFontsLocal
18 {
19 /**
20 * Singleton instance
21 */
22 private static $instance = null;
23
24 /**
25 * User agent for fetching woff2 fonts
26 */
27 private $user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36';
28
29 /**
30 * Base folder name for storing fonts
31 */
32 private $folder_name = 'adminify-google-fonts';
33
34 /**
35 * Get singleton instance
36 */
37 public static function get_instance()
38 {
39 if (self::$instance === null) {
40 self::$instance = new self();
41 }
42 return self::$instance;
43 }
44
45 /**
46 * Constructor
47 */
48 private function __construct()
49 {
50 // Hook into framework's save filter (most reliable)
51 add_filter('adminify__wpadminify_saved_before', [$this, 'on_settings_save'], 10, 1);
52
53 // Enqueue local fonts
54 add_action('admin_enqueue_scripts', [$this, 'enqueue_local_fonts'], 99);
55 }
56
57 /**
58 * Handle settings save via framework filter
59 */
60 public function on_settings_save($data)
61 {
62 $this->process_fonts($data);
63 return $data;
64 }
65
66 /**
67 * Process fonts from settings data
68 */
69 public function process_fonts($data)
70 {
71 if (!is_array($data)) {
72 return;
73 }
74
75 // Process Body Font
76 if (!empty($data['admin_general_google_font']['font-family'])) {
77 $font_family = $data['admin_general_google_font']['font-family'];
78 $font_weights = !empty($data['admin_general_google_font']['font-weight']) ? $data['admin_general_google_font']['font-weight'] : '400';
79 $result = $this->download_font($font_family, $font_weights);
80 }
81
82 // Process Light Mode Logo Typography
83 if (!empty($data['light_dark_mode']['admin_ui_light_mode']['admin_ui_light_logo_text_typo']['font-family'])) {
84 $typo = $data['light_dark_mode']['admin_ui_light_mode']['admin_ui_light_logo_text_typo'];
85 $font_family = $typo['font-family'];
86 $font_weights = !empty($typo['font-weight']) ? $typo['font-weight'] : '400';
87 $this->download_font($font_family, $font_weights);
88 }
89
90 // Process Dark Mode Logo Typography
91 if (!empty($data['light_dark_mode']['admin_ui_dark_mode']['admin_ui_dark_logo_text_typo']['font-family'])) {
92 $typo = $data['light_dark_mode']['admin_ui_dark_mode']['admin_ui_dark_logo_text_typo'];
93 $font_family = $typo['font-family'];
94 $font_weights = !empty($typo['font-weight']) ? $typo['font-weight'] : '400';
95 $this->download_font($font_family, $font_weights);
96 }
97 }
98
99 /**
100 * Get the local fonts folder path
101 */
102 public function get_folder()
103 {
104 $upload_dir = wp_get_upload_dir();
105 return $upload_dir['basedir'] . '/' . $this->folder_name;
106 }
107
108 /**
109 * Get the local fonts folder URL
110 */
111 public function get_folder_url()
112 {
113 $upload_dir = wp_get_upload_dir();
114 $folder_url = $upload_dir['baseurl'] . '/' . $this->folder_name;
115
116 if (is_ssl()) {
117 $folder_url = set_url_scheme($folder_url, 'https');
118 }
119
120 return $folder_url;
121 }
122
123 /**
124 * Download a Google Font locally
125 */
126 public function download_font($font_family, $font_weights = '400')
127 {
128 if (empty($font_family)) {
129 return false;
130 }
131
132 // Sanitize font family for folder name
133 $font_slug = sanitize_title($font_family);
134 $folder = $this->get_folder() . '/' . $font_slug;
135
136 // Create base folder
137 if (!file_exists($this->get_folder())) {
138 wp_mkdir_p($this->get_folder());
139 }
140
141 // Create font folder
142 if (!file_exists($folder)) {
143 wp_mkdir_p($folder);
144 }
145
146 // Normalize font weights - convert 'normal' to '400', 'bold' to '700'
147 $weight_map = [
148 'normal' => '400',
149 'bold' => '700',
150 'lighter' => '300',
151 'bolder' => '700',
152 ];
153
154 if (is_array($font_weights)) {
155 $font_weights = array_map(function($w) use ($weight_map) {
156 return isset($weight_map[$w]) ? $weight_map[$w] : $w;
157 }, $font_weights);
158 $weights_string = implode(',', $font_weights);
159 $weights_array = $font_weights;
160 } else {
161 $font_weights = isset($weight_map[$font_weights]) ? $weight_map[$font_weights] : $font_weights;
162 $weights_string = $font_weights;
163 $weights_array = [$font_weights];
164 }
165
166 // Try the newer css2 API first
167 $font_string = urlencode($font_family);
168 $wght_string = implode(';', $weights_array);
169 $google_url = 'https://fonts.googleapis.com/css2?family=' . $font_string . ':wght@' . $wght_string . '&display=swap';
170
171 // Fetch CSS from Google
172 $response = wp_remote_get($google_url, [
173 'user-agent' => $this->user_agent,
174 'timeout' => 30,
175 ]);
176
177 $css_content = '';
178 if (!is_wp_error($response)) {
179 $css_content = wp_remote_retrieve_body($response);
180 }
181
182 // Fallback: Use the older Google Fonts API (css) which is more forgiving
183 if (empty($css_content) || strpos($css_content, '@font-face') === false) {
184 $font_string = urlencode($font_family);
185 if (!empty($weights_string)) {
186 $font_string .= ':' . $weights_string;
187 }
188 $google_url = 'https://fonts.googleapis.com/css?family=' . $font_string . '&display=swap';
189
190 // Fetch CSS from Google using older API
191 $response = wp_remote_get($google_url, [
192 'user-agent' => $this->user_agent,
193 'timeout' => 30,
194 ]);
195
196 if (!is_wp_error($response)) {
197 $css_content = wp_remote_retrieve_body($response);
198 }
199 }
200
201 // Final fallback: Generate system font fallback CSS if Google Font not found
202 if (empty($css_content) || strpos($css_content, '@font-face') === false) {
203 $css_content = $this->generate_system_font_fallback($font_family, $weights_array);
204 }
205
206 // Find all font file URLs
207 preg_match_all('/url\(([^)]+)\)/i', $css_content, $matches);
208
209 if (!empty($matches[1])) {
210 foreach ($matches[1] as $font_url) {
211 $font_url = trim($font_url, '"\'');
212
213 // Only process Google font URLs
214 if (strpos($font_url, 'fonts.gstatic.com') === false) {
215 continue;
216 }
217
218 // Generate local filename
219 $url_hash = substr(md5($font_url), 0, 8);
220 $extension = pathinfo(parse_url($font_url, PHP_URL_PATH), PATHINFO_EXTENSION);
221 if (empty($extension)) {
222 $extension = 'woff2';
223 }
224 $local_filename = $font_slug . '-' . $url_hash . '.' . $extension;
225 $local_path = $folder . '/' . $local_filename;
226 $local_url = $this->get_folder_url() . '/' . $font_slug . '/' . $local_filename;
227
228 // Download font file if not exists
229 if (!file_exists($local_path)) {
230 $font_response = wp_remote_get($font_url, [
231 'user-agent' => $this->user_agent,
232 'timeout' => 30,
233 ]);
234
235 if (!is_wp_error($font_response)) {
236 $font_data = wp_remote_retrieve_body($font_response);
237 if (!empty($font_data)) {
238 file_put_contents($local_path, $font_data);
239 }
240 }
241 }
242
243 // Replace URL in CSS
244 $css_content = str_replace($font_url, $local_url, $css_content);
245 }
246 }
247
248 // Save local CSS file
249 $css_file = $folder . '/' . $font_slug . '.css';
250 $header = "/* Local Google Font: {$font_family} */\n";
251 $header .= "/* Generated by WP Adminify - " . date('Y-m-d H:i:s') . " */\n\n";
252 file_put_contents($css_file, $header . $css_content);
253
254 return true;
255 }
256
257 /**
258 * Get local font CSS URL
259 */
260 public function get_local_font_url($font_family)
261 {
262 if (empty($font_family)) {
263 return false;
264 }
265
266 $font_slug = sanitize_title($font_family);
267 $css_file = $this->get_folder() . '/' . $font_slug . '/' . $font_slug . '.css';
268
269 if (file_exists($css_file)) {
270 return $this->get_folder_url() . '/' . $font_slug . '/' . $font_slug . '.css?ver=' . filemtime($css_file);
271 }
272
273 return false;
274 }
275
276 /**
277 * Check if font exists locally
278 */
279 public function is_font_local($font_family)
280 {
281 if (empty($font_family)) {
282 return false;
283 }
284
285 $font_slug = sanitize_title($font_family);
286 $css_file = $this->get_folder() . '/' . $font_slug . '/' . $font_slug . '.css';
287
288 return file_exists($css_file);
289 }
290
291 /**
292 * Enqueue local fonts for admin
293 */
294 public function enqueue_local_fonts()
295 {
296 $options = get_option('_wpadminify');
297
298 if (empty($options) || !is_array($options)) {
299 return;
300 }
301
302 // Body Font
303 if (!empty($options['admin_general_google_font']['font-family'])) {
304 $font_family = $options['admin_general_google_font']['font-family'];
305 $local_url = $this->get_local_font_url($font_family);
306
307 if ($local_url) {
308 wp_enqueue_style('adminify-local-body-font', $local_url, [], null);
309 }
310 }
311
312 // Light Mode Logo Typography
313 if (!empty($options['light_dark_mode']['admin_ui_light_mode']['admin_ui_light_logo_text_typo']['font-family'])) {
314 $font_family = $options['light_dark_mode']['admin_ui_light_mode']['admin_ui_light_logo_text_typo']['font-family'];
315 $local_url = $this->get_local_font_url($font_family);
316
317 if ($local_url) {
318 wp_enqueue_style('adminify-local-logo-light-font', $local_url, [], null);
319 }
320 }
321
322 // Dark Mode Logo Typography
323 if (!empty($options['light_dark_mode']['admin_ui_dark_mode']['admin_ui_dark_logo_text_typo']['font-family'])) {
324 $font_family = $options['light_dark_mode']['admin_ui_dark_mode']['admin_ui_dark_logo_text_typo']['font-family'];
325 $local_url = $this->get_local_font_url($font_family);
326
327 if ($local_url) {
328 wp_enqueue_style('adminify-local-logo-dark-font', $local_url, [], null);
329 }
330 }
331 }
332
333 /**
334 * Generate system font fallback CSS when Google Font is not found
335 */
336 private function generate_system_font_fallback($font_family, $weights_array)
337 {
338 // System fonts to try as local fallbacks
339 $system_fonts = [
340 'BlinkMacSystemFont',
341 'Segoe UI',
342 'Roboto',
343 'Helvetica Neue',
344 'Arial',
345 'sans-serif',
346 ];
347
348 $css = "/* Fallback: Google Font '{$font_family}' not found */\n";
349 $css .= "/* Using system font stack as fallback */\n\n";
350
351 foreach ($weights_array as $weight) {
352 $local_src = [];
353 foreach ($system_fonts as $font) {
354 $local_src[] = "local('{$font}')";
355 }
356
357 $css .= "@font-face {\n";
358 $css .= " font-family: '{$font_family}';\n";
359 $css .= " font-style: normal;\n";
360 $css .= " font-weight: {$weight};\n";
361 $css .= " font-display: swap;\n";
362 $css .= " src: " . implode(",\n ", $local_src) . ";\n";
363 $css .= "}\n\n";
364 }
365
366 return $css;
367 }
368 }
369