PluginProbe
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant / 1.1.3
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant v1.1.3
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.3, at easyfonts.php

305 lines 11.9 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.3
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) {
86 // Check if the 'easyfonts' directory exists and is writable
87 $easyfonts_dir = wp_upload_dir() ['basedir'] . '/easyfonts';
88 if (!wp_mkdir_p($easyfonts_dir)) {
89 return $content;
90 }
91 // Find all <link> tags with a rel attribute of 'stylesheet' and a href attribute that points to a Google Fonts stylesheet
92 foreach ($html->find('link[rel=stylesheet][href*=fonts.googleapis.com]') as $link) {
93 $url = $link->href;
94 if(strpos($url,'//') === 0){
95 $url = 'https:'.$url;
96 }
97 $decoded_url = rawurldecode(htmlspecialchars_decode($url));
98 // Generate a local filename for the stylesheet
99 $filename = hash('sha256', $decoded_url, false);
100 $filename = substr($filename, 0, 10) . '.css';
101 if (!file_exists($easyfonts_dir . '/' . $filename)) {
102 $css = wp_get_remote_file($decoded_url);
103 if (!preg_match_all('/@font-face\s*\{([^}]+)\}/', $css, $matches)) continue;
104
105 $css = easyfonts_process_font_face_declarations($css, $easyfonts_dir);
106 // Save the modified stylesheet to the 'wp-content/uploads/easyfonts' directory
107 file_put_contents($easyfonts_dir . '/' . $filename, $css);
108 }
109 $finalbasecss = get_base_url();
110 // Replace the href attribute with a local reference to the downloaded stylesheet
111 $link->href = $finalbasecss . '/easyfonts/' . $filename;
112 }
113 // Return the modified content
114 });
115 }
116
117 function easyfont_process_content_import($content) {
118 // using simple html dom
119 return easyfont_process_html_with_dom($content, function($html) {
120 // Check if the 'easyfonts' directory exists and is writable
121 $easyfonts_dir = wp_upload_dir() ['basedir'] . '/easyfonts';
122 if (!wp_mkdir_p($easyfonts_dir)) {
123 return $content;
124 }
125 // Find all <style> tags with @import statements that import a Google Fonts stylesheet
126 foreach ($html->find('style') as $style) {
127 if (preg_match_all('/@import\s+(url\()?\s*([^\)]+)\s*(\))?/', $style->innertext, $matches)) {
128 foreach ($matches[2] as $match) {
129 if (strpos($match, 'fonts.googleapis.com') !== false) {
130 $url = trim($match, "'\"");
131 if (strpos($url, '//') === 0) {
132 $url = 'https:' . $url;
133 }
134 $decoded_url = rawurldecode(htmlspecialchars_decode($url));
135 $filename = hash('sha256', $decoded_url, false);
136 $filename = substr($filename, 0, 10) . '.css';
137 // Check if the stylesheet file already exists
138 if (!file_exists($easyfonts_dir . '/' . $filename)) {
139 $css = wp_get_remote_file($decoded_url);
140 $css = easyfonts_process_font_face_declarations($css, $easyfonts_dir);
141 // Save the modified stylesheet to the 'wp-content/uploads/easyfonts' directory
142 file_put_contents($easyfonts_dir . '/' . $filename, $css);
143 }
144 $finalbasecss = get_base_url();
145 // Replace the @import statement with a local reference to the downloaded stylesheet
146 $style->innertext = str_replace($match, "" . $finalbasecss . '/easyfonts/' . $filename . "", $style->innertext);
147 }
148 }
149 }
150 }
151 // Return the modified content
152 });
153 }
154 function easyfonts_remove_resource_hints($content) {
155 // Load the HTML into the Simple HTML DOM library
156 return easyfont_process_html_with_dom($content, function($html) {
157
158 // Find all <link> elements with the preload, preconnect, or prefetch attributes
159 $links = $html->find('link[rel=preload],link[rel=preconnect],link[rel=dns-prefetch]');
160
161 // Loop through the <link> elements
162 foreach($links as $link) {
163 // Check if the <link> element has a href attribute with the fonts.googleapis.com or fonts.gstatic.com domain
164 if (preg_match('/(https:\/\/|\/\/)(fonts\.googleapis\.com|fonts\.gstatic\.com)/', $link->href)) {
165 // Remove the <link> element
166 $link->outertext = '';
167 }
168 }
169
170 // Find all <style> elements
171 $styles = $html->find('style');
172
173 // Loop through the <style> elements
174 foreach($styles as $style) {
175 // Remove comments that contain the fonts.googleapis.com or fonts.gstatic.com domain
176 if (strpos($style->innertext, 'fonts.googleapis.com') !== false || strpos($style->innertext, 'fonts.gstatic.com') !== false) {
177 $style->innertext = preg_replace('#/\*(?:[^*]*(?:\*(?!/))*)*\*/#','',$style->innertext);
178 }
179 }
180 // Return the modified HTML
181 });
182 }
183
184
185 function easyfont_remove_font_scripts($content) {
186 // Load the HTML string into a Simple HTML DOM object
187 return easyfont_process_html_with_dom($content, function($html) {
188
189 // Find all `script` elements
190 $scripts = $html->find('script');
191 foreach($scripts as $script) {
192 // Check if the `script` element contains the `WebFontConfig` or `webfont.js` strings
193 if(strpos($script->innertext, 'WebFontConfig') !== false || strpos($script->innertext, 'webfont.js') !== false) {
194 // Remove the `script` element
195 $script->outertext = '';
196 }
197 }
198
199 // Return the modified HTML as a string
200 });
201 }
202
203 function easyfont_download_gstatic_fonts($content) {
204 // Create the "easyfonts" directory if it doesn't exist
205 $easyfonts_dir = wp_upload_dir()['basedir'] . '/easyfonts';
206 if (!wp_mkdir_p($easyfonts_dir)) {
207 return $content;
208 }
209 $content = preg_replace('/(url\s?\(["\']?)\/\/(fonts\.gstatic\.com[^"\']+)/', '$1https://$2', $content);
210 $html = hgfl_str_get_html($content, false, true, 'UTF-8', false, PHP_EOL, ' ');
211 if (empty($html)) {
212 return $content;
213 }
214 foreach ($html->find('style') as $style) {
215 if (preg_match_all('/url\(([^)]+)\)/', $style->innertext, $matches)) {
216 foreach ($matches[1] as $match) {
217 $url = trim($match, "'\"");
218 if(strpos($url,'//') === 0){
219 $url = 'https:'.$url;
220 }
221 if (strpos($url, 'fonts.gstatic.com') !== false) {
222 $path_parts = pathinfo($url);
223 $extension = isset($path_parts['extension'])?$path_parts['extension']:'';
224 if (empty($extension)) {
225 if(strpos($url,'/l/font') !== false){
226 $extension = 'svg';
227 }else{
228 $extension = 'woff2';
229 }
230 }
231 $filename = hash('sha256', $url, false);
232 $filename = substr($filename, 0, 10) . '.' . $extension;
233 // Check if the font file already exists
234 if (!file_exists($easyfonts_dir . '/' . $filename)) {
235 $font_data = wp_get_remote_file($url);
236 $file = fopen($easyfonts_dir . '/' . $filename, 'w');
237 fwrite($file, $font_data);
238 fclose($file);
239 }
240 $finalbase = get_base_url();
241 $local_url = $finalbase . '/easyfonts/' . $filename;
242 $content = str_replace($url, $local_url, $content);
243 }
244 }
245 }
246 }
247 return $content;
248 }
249
250
251 function easy_fonts_combined_callback($buffer) {
252 if (get_option('easyfonts_host_google_fonts_locally_link', false)) {
253 $buffer = easyfont_process_content_link_tag($buffer);
254 }
255
256 if (get_option('easyfonts_host_google_fonts_locally_import', false)) {
257 $buffer = easyfont_process_content_import($buffer);
258 }
259
260 if (get_option('easyfonts_remove_inline_css_fontface', false)) {
261 $buffer = easyfont_download_gstatic_fonts($buffer);
262 }
263
264 if (get_option('easyfonts_remove_resource_hints', false)) {
265 $buffer = easyfonts_remove_resource_hints($buffer);
266 }
267
268 if (get_option('easyfonts_remove_inline_script_font', false)) {
269 $buffer = easyfont_remove_font_scripts($buffer);
270 }
271
272 return $buffer;
273 }
274
275 function easy_fonts_run_template_redirect() {
276
277 ob_start('easy_fonts_combined_callback', 0, PHP_OUTPUT_HANDLER_REMOVABLE);
278 add_filter( 'wordpress_prepare_output', 'easyfont_run_after_smart_slider', 11 );
279 add_filter('groovy_menu_final_output', 'easyfont_run_after_smart_slider', 11);
280
281
282 }
283 add_action( 'template_redirect', 'easy_fonts_run_template_redirect', 999 );
284
285
286 function easyfont_run_after_smart_slider( $buffer ) {
287 if (get_option('easyfonts_host_google_fonts_locally_link', false)) {
288 $buffer = easyfont_process_content_link_tag( $buffer );
289 }
290 return $buffer;
291 }
292
293 function easyfonts_enqueue_options_styles() {
294 if ( 'settings_page_easyfonts' == get_current_screen()->id ) {
295 wp_enqueue_style( 'easyfonts-options-styles', plugin_dir_url( __FILE__ ) . 'assets/style.css', array(), '1.0.0' );
296 }
297 }
298 add_action( 'admin_enqueue_scripts', 'easyfonts_enqueue_options_styles' );
299
300 function easyfonts_settings_link($links) {
301 $settings_link = '<a href="options-general.php?page=easyfonts">Settings</a>';
302 array_push($links, $settings_link);
303 return $links;
304 }
305 add_filter("plugin_action_links_easyfonts/easyfonts.php", "easyfonts_settings_link");