PluginProbe
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant / 1.1.4
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant v1.1.4
2.0.4 2.0.3 2.0.2 2.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2 1.3 2.0.0
easyfonts / easyfonts.php

easyfonts.php in EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant 1.1.4, at easyfonts.php

332 lines 12.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: EasyFonts
4 Plugin URI:
5 Description: Automatically Host existing google fonts locally on your server
6 Version: 1.1.4
7 Author: Uzair
8 Author URI: https://easywpstuff.com
9 License: GPL2
10 */
11
12 // If this file is called directly, abort.
13 if (!defined("WPINC")){
14 die;
15 }
16
17 require_once dirname(__FILE__) . '/lib/simple_html_dom.php';
18
19 include_once dirname(__FILE__) . '/inc/options.php';
20
21 include_once dirname(__FILE__) . '/inc/notices.php';
22
23 function get_base_url() {
24 return is_ssl() ? set_url_scheme(wp_upload_dir()['baseurl'], 'https') : wp_upload_dir()['baseurl'];
25 }
26
27 function wp_get_remote_file($url) {
28 $backtrace = debug_backtrace();
29 $function_name = isset($backtrace[1]['function']) ? $backtrace[1]['function'] : '';
30
31
32 $response = wp_remote_get($url, array('user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',));
33
34
35 if (is_wp_error($response)) {
36 add_settings_error($function_name, 'http_error', $response->get_error_message(), 'error');
37 return false;
38 }
39
40
41 return wp_remote_retrieve_body($response);
42 }
43
44 function easyfont_process_html_with_dom($content, $callback) {
45 // using simple html dom
46 $html = hgfl_str_get_html($content, false, true, 'UTF-8', false, PHP_EOL, ' ');
47
48 if (empty($html)) {
49 return $content;
50 }
51
52 $callback($html);
53
54 $content = $html->save();
55 return $content;
56 }
57
58 function easyfonts_process_font_face_declarations($css, $easyfonts_dir) {
59 if (preg_match_all('/@font-face\s*\{([^}]+)\}/', $css, $matches)) {
60 foreach ($matches[1] as $match) {
61 if (preg_match_all('/src\s*:\s*([^;]+);/', $match, $srcs)) {
62 foreach ($srcs[1] as $src) {
63 if (preg_match('/url\(([^)]+)\)/', $src, $url_match)) {
64 $font_url = trim($url_match[1], "'\"");
65 $font_filename = hash('sha256', $font_url, false);
66 $font_filename = substr($font_filename, 0, 10) . '.' . pathinfo($font_url, PATHINFO_EXTENSION);
67 if (!file_exists($easyfonts_dir . '/' . $font_filename)) {
68 $font_data = wp_get_remote_file($font_url);
69 // Save the font file to the 'wp-content/uploads/easyfonts' directory
70 file_put_contents($easyfonts_dir . '/' . $font_filename, $font_data);
71 }
72 // Replace the src property with a local reference to the downloaded font file
73 $finalbase = get_base_url();
74 $css = str_replace($src, "url('" . $finalbase . "/easyfonts/" . $font_filename . "')", $css);
75 }
76 }
77 }
78 }
79 }
80 return $css;
81 }
82
83
84 function easyfont_process_content_link_tag($content) {
85 return easyfont_process_html_with_dom($content, function($html) use ($content) {
86
87 $upload_dir = wp_upload_dir();
88 $easyfonts_dir = $upload_dir['basedir'] . '/easyfonts';
89
90 if (!wp_mkdir_p($easyfonts_dir)) {
91 return $content;
92 }
93
94 // Filter-based support toggle for Bunny Fonts
95 $apply_bunnyfonts_filter = apply_filters('easyfonts_bunnyfonts', true);
96
97 // List of supported font providers
98 $font_providers = [
99 'fonts.googleapis.com',
100 ];
101
102 if ($apply_bunnyfonts_filter) {
103 $font_providers[] = 'fonts.bunny.net';
104 }
105
106 foreach ($html->find('link[rel=stylesheet]') as $link) {
107 $href = $link->href;
108 $matched = false;
109
110 foreach ($font_providers as $provider) {
111 if (strpos($href, $provider) !== false) {
112 $matched = true;
113 break;
114 }
115 }
116
117 if (!$matched) continue;
118
119 // Normalize URL
120 if (strpos($href, '//') === 0) {
121 $href = 'https:' . $href;
122 }
123
124 $decoded_url = rawurldecode(htmlspecialchars_decode($href));
125 $filename = substr(hash('sha256', $decoded_url), 0, 10) . '.css';
126 $local_css_path = $easyfonts_dir . '/' . $filename;
127
128 if (!file_exists($local_css_path)) {
129 $css = wp_get_remote_file($decoded_url);
130 if (!preg_match_all('/@font-face\s*\{([^}]+)\}/', $css, $matches)) continue;
131
132 $css = easyfonts_process_font_face_declarations($css, $easyfonts_dir);
133 file_put_contents($local_css_path, $css);
134 }
135
136 $finalbasecss = get_base_url();
137 $link->href = $finalbasecss . '/easyfonts/' . $filename;
138 }
139
140 return $html;
141 });
142 }
143
144 function easyfont_process_content_import($content) {
145 // using simple html dom
146 return easyfont_process_html_with_dom($content, function($html) {
147 // Check if the 'easyfonts' directory exists and is writable
148 $easyfonts_dir = wp_upload_dir() ['basedir'] . '/easyfonts';
149 if (!wp_mkdir_p($easyfonts_dir)) {
150 return $content;
151 }
152 // Find all <style> tags with @import statements that import a Google Fonts stylesheet
153 foreach ($html->find('style') as $style) {
154 if (preg_match_all('/@import\s+(url\()?\s*([^\)]+)\s*(\))?/', $style->innertext, $matches)) {
155 foreach ($matches[2] as $match) {
156 if (strpos($match, 'fonts.googleapis.com') !== false) {
157 $url = trim($match, "'\"");
158 if (strpos($url, '//') === 0) {
159 $url = 'https:' . $url;
160 }
161 $decoded_url = rawurldecode(htmlspecialchars_decode($url));
162 $filename = hash('sha256', $decoded_url, false);
163 $filename = substr($filename, 0, 10) . '.css';
164 // Check if the stylesheet file already exists
165 if (!file_exists($easyfonts_dir . '/' . $filename)) {
166 $css = wp_get_remote_file($decoded_url);
167 $css = easyfonts_process_font_face_declarations($css, $easyfonts_dir);
168 // Save the modified stylesheet to the 'wp-content/uploads/easyfonts' directory
169 file_put_contents($easyfonts_dir . '/' . $filename, $css);
170 }
171 $finalbasecss = get_base_url();
172 // Replace the @import statement with a local reference to the downloaded stylesheet
173 $style->innertext = str_replace($match, "" . $finalbasecss . '/easyfonts/' . $filename . "", $style->innertext);
174 }
175 }
176 }
177 }
178 // Return the modified content
179 });
180 }
181 function easyfonts_remove_resource_hints($content) {
182 // Load the HTML into the Simple HTML DOM library
183 return easyfont_process_html_with_dom($content, function($html) {
184
185 // Find all <link> elements with the preload, preconnect, or prefetch attributes
186 $links = $html->find('link[rel=preload],link[rel=preconnect],link[rel=dns-prefetch]');
187
188 // Loop through the <link> elements
189 foreach($links as $link) {
190 // Check if the <link> element has a href attribute with the fonts.googleapis.com or fonts.gstatic.com domain
191 if (preg_match('/(https:\/\/|\/\/)(fonts\.googleapis\.com|fonts\.gstatic\.com)/', $link->href)) {
192 // Remove the <link> element
193 $link->outertext = '';
194 }
195 }
196
197 // Find all <style> elements
198 $styles = $html->find('style');
199
200 // Loop through the <style> elements
201 foreach($styles as $style) {
202 // Remove comments that contain the fonts.googleapis.com or fonts.gstatic.com domain
203 if (strpos($style->innertext, 'fonts.googleapis.com') !== false || strpos($style->innertext, 'fonts.gstatic.com') !== false) {
204 $style->innertext = preg_replace('#/\*(?:[^*]*(?:\*(?!/))*)*\*/#','',$style->innertext);
205 }
206 }
207 // Return the modified HTML
208 });
209 }
210
211
212 function easyfont_remove_font_scripts($content) {
213 // Load the HTML string into a Simple HTML DOM object
214 return easyfont_process_html_with_dom($content, function($html) {
215
216 // Find all `script` elements
217 $scripts = $html->find('script');
218 foreach($scripts as $script) {
219 // Check if the `script` element contains the `WebFontConfig` or `webfont.js` strings
220 if(strpos($script->innertext, 'WebFontConfig') !== false || strpos($script->innertext, 'webfont.js') !== false) {
221 // Remove the `script` element
222 $script->outertext = '';
223 }
224 }
225
226 // Return the modified HTML as a string
227 });
228 }
229
230 function easyfont_download_gstatic_fonts($content) {
231 // Create the "easyfonts" directory if it doesn't exist
232 $easyfonts_dir = wp_upload_dir()['basedir'] . '/easyfonts';
233 if (!wp_mkdir_p($easyfonts_dir)) {
234 return $content;
235 }
236 $content = preg_replace('/(url\s?\(["\']?)\/\/(fonts\.gstatic\.com[^"\']+)/', '$1https://$2', $content);
237 $html = hgfl_str_get_html($content, false, true, 'UTF-8', false, PHP_EOL, ' ');
238 if (empty($html)) {
239 return $content;
240 }
241 foreach ($html->find('style') as $style) {
242 if (preg_match_all('/url\(([^)]+)\)/', $style->innertext, $matches)) {
243 foreach ($matches[1] as $match) {
244 $url = trim($match, "'\"");
245 if(strpos($url,'//') === 0){
246 $url = 'https:'.$url;
247 }
248 if (strpos($url, 'fonts.gstatic.com') !== false) {
249 $path_parts = pathinfo($url);
250 $extension = isset($path_parts['extension'])?$path_parts['extension']:'';
251 if (empty($extension)) {
252 if(strpos($url,'/l/font') !== false){
253 $extension = 'svg';
254 }else{
255 $extension = 'woff2';
256 }
257 }
258 $filename = hash('sha256', $url, false);
259 $filename = substr($filename, 0, 10) . '.' . $extension;
260 // Check if the font file already exists
261 if (!file_exists($easyfonts_dir . '/' . $filename)) {
262 $font_data = wp_get_remote_file($url);
263 $file = fopen($easyfonts_dir . '/' . $filename, 'w');
264 fwrite($file, $font_data);
265 fclose($file);
266 }
267 $finalbase = get_base_url();
268 $local_url = $finalbase . '/easyfonts/' . $filename;
269 $content = str_replace($url, $local_url, $content);
270 }
271 }
272 }
273 }
274 return $content;
275 }
276
277
278 function easy_fonts_combined_callback($buffer) {
279 if (get_option('easyfonts_host_google_fonts_locally_link', false)) {
280 $buffer = easyfont_process_content_link_tag($buffer);
281 }
282
283 if (get_option('easyfonts_host_google_fonts_locally_import', false)) {
284 $buffer = easyfont_process_content_import($buffer);
285 }
286
287 if (get_option('easyfonts_remove_inline_css_fontface', false)) {
288 $buffer = easyfont_download_gstatic_fonts($buffer);
289 }
290
291 if (get_option('easyfonts_remove_resource_hints', false)) {
292 $buffer = easyfonts_remove_resource_hints($buffer);
293 }
294
295 if (get_option('easyfonts_remove_inline_script_font', false)) {
296 $buffer = easyfont_remove_font_scripts($buffer);
297 }
298
299 return $buffer;
300 }
301
302 function easy_fonts_run_template_redirect() {
303
304 ob_start('easy_fonts_combined_callback', 0, PHP_OUTPUT_HANDLER_REMOVABLE);
305 add_filter( 'wordpress_prepare_output', 'easyfont_run_after_smart_slider', 11 );
306 add_filter('groovy_menu_final_output', 'easyfont_run_after_smart_slider', 11);
307
308
309 }
310 add_action( 'template_redirect', 'easy_fonts_run_template_redirect', 999 );
311
312
313 function easyfont_run_after_smart_slider( $buffer ) {
314 if (get_option('easyfonts_host_google_fonts_locally_link', false)) {
315 $buffer = easyfont_process_content_link_tag( $buffer );
316 }
317 return $buffer;
318 }
319
320 function easyfonts_enqueue_options_styles() {
321 if ( 'settings_page_easyfonts' == get_current_screen()->id ) {
322 wp_enqueue_style( 'easyfonts-options-styles', plugin_dir_url( __FILE__ ) . 'assets/style.css', array(), '1.0.0' );
323 }
324 }
325 add_action( 'admin_enqueue_scripts', 'easyfonts_enqueue_options_styles' );
326
327 function easyfonts_settings_link($links) {
328 $settings_link = '<a href="options-general.php?page=easyfonts">Settings</a>';
329 array_push($links, $settings_link);
330 return $links;
331 }
332 add_filter("plugin_action_links_easyfonts/easyfonts.php", "easyfonts_settings_link");