PluginProbe ʕ •ᴥ•ʔ
10Web Booster – Website speed optimization, Cache & Page Speed optimizer / trunk
10Web Booster – Website speed optimization, Cache & Page Speed optimizer vtrunk
2.33.0 2.30.5 2.30.7 2.30.9 2.31.10 2.31.8 2.32.11 2.32.21 2.32.3 2.32.4 2.32.7 2.6.31 2.6.40 2.6.42 2.6.7 2.7.37 2.7.44 2.7.47 2.8.18 2.8.19 2.8.32 2.8.34 2.8.35 2.9.23 2.9.24 2.9.25 2.9.27 v2.27.4 trunk 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.17 2.0.18 2.0.21 2.0.22 2.0.25 2.0.26 2.0.27 2.0.3 2.0.7 2.0.9 2.10.46 2.10.65 2.10.66 2.10.68 2.11.41 2.11.42 2.11.43 2.12.15 2.12.21 2.12.22 2.12.23 2.12.26 2.13.37 2.13.40 2.13.41 2.13.42 2.13.44 2.13.45 2.13.47 2.14.49 2.14.50 2.15.18 2.17.21 2.17.23 2.18.17 2.19.44 2.19.45 2.19.46 2.19.49 2.2.12 2.2.15 2.2.16 2.2.18 2.2.8 2.20.31 2.20.32 2.20.33 2.21.11 2.21.12 2.21.16 2.21.25 2.22.32 2.23.13 2.23.15 2.23.16 2.23.18 2.24.12 2.24.14 2.24.18 2.25.14 2.26.6 2.28.10 2.28.13 2.28.14 2.28.7 2.29.1 2.29.2 2.29.3 2.3.0 2.3.1 2.3.2 2.3.3 2.30.18
tenweb-speed-optimizer / includes / OptimizerFonts.php
tenweb-speed-optimizer / includes Last commit date
WebPageCache 7 months ago external 2 months ago ExcludeJsFromDelay.php 2 years ago OptimizerBanner.php 11 months ago OptimizerBase.php 2 years ago OptimizerCSSMin.php 2 years ago OptimizerCache.php 1 year ago OptimizerCacheStructure.php 2 years ago OptimizerCriticalCss.php 1 year ago OptimizerElementor.php 2 years ago OptimizerFonts.php 2 years ago OptimizerImages.php 1 year ago OptimizerLogger.php 1 year ago OptimizerMain.php 2 months ago OptimizerOnInit.php 11 months ago OptimizerScripts.php 2 years ago OptimizerSettings.php 2 months ago OptimizerStyles.php 2 years ago OptimizerUrl.php 1 year ago OptimizerUtils.php 2 months ago OptimizerWhiteLabel.php 2 years ago
OptimizerFonts.php
300 lines
1 <?php
2
3 namespace TenWebOptimizer;
4
5 /*
6 * Thin wrapper around css minifiers to avoid rewriting a bunch of existing code.
7 */
8 if (!defined('ABSPATH')) {
9 exit;
10 }
11
12 class OptimizerFonts extends OptimizerBase
13 {
14 const TWO_PRELOAD_LINK_TYPES = [
15 'preload',
16 'preconnect'
17 ];
18
19 /**
20 * @var bool|mixed|void
21 */
22 private $linksToPreload;
23
24 private $font_swap;
25
26 private $two_load_fonts_via_webfont;
27
28 private $webFont_list;
29
30 private $google_subsets;
31
32 private $google_fonts;
33
34 private $fontsExtensions = [
35 'eot' => 'font/eot',
36 'ttf' => 'font/ttf',
37 'woff' => 'font/woff',
38 'woff2' => 'font/woff2',
39 ];
40
41 private $styleExtensions = [
42 'css' => 'text/css',
43 ];
44
45 private $scriptExtensions = [
46 'js' => 'application/javascript',
47 ];
48
49 private $videoExtensions = [
50 'avi' => 'video/x-msvideo',
51 'mpeg' => 'video/mpeg',
52 'ogv' => 'video/ogg',
53 'ts' => 'video/mp2t',
54 'webm' => 'video/webm',
55 '3gp' => 'video/3gpp',
56 '3g2' => 'video/3gpp2',
57 ];
58
59 /**
60 * @var false|mixed|void
61 */
62 private $linksToPreconnect;
63
64 public function addPreload($option, $type)
65 {
66 if (empty($option)) {
67 return true;
68 }
69
70 $links = $this->convertOptionToArray($option);
71 $this->injectLinks($type, $links);
72
73 return true;
74 }
75
76 /**
77 * @param string $preloadType
78 * @param array $links
79 */
80 private function injectLinks($preloadType, $links)
81 {
82 if (in_array($preloadType, self::TWO_PRELOAD_LINK_TYPES, false)) { // phpcs:ignore
83 if (!empty($links)) {
84 $preloadString = '';
85
86 foreach ($links as $link) {
87 $linkWithoutQueryArgs = strpos($link, '?') !== false ? substr($link, 0, strpos($link, '?')) : $link;
88 $linkPath = pathinfo($linkWithoutQueryArgs);
89
90 if (isset($linkPath['extension'])) {
91 $type = $this->getLinkType($linkPath['extension']);
92
93 if ($type !== false) {
94 $preloadString .= '<link rel="' . $preloadType . '" as="' . $type[0] . '" href="' . $link . '" type="' . $type[1] . '" crossorigin="anonymous">';
95 } else {
96 $preloadString .= '<link rel="' . $preloadType . '" href="' . $link . '" crossorigin="anonymous">';
97 }
98 }
99 }
100 }
101
102 if (!empty($preloadString)) {
103 $this->content = OptimizerUtils::inject_in_html($this->content, $preloadString, [ '<head', 'after_tag' ]);
104 }
105 }
106 }
107
108 /**
109 * Get all google fonts from html combine them add preconnect and remove old ones
110 *
111 * @return bool
112 */
113 public function combineGoogleFonts()
114 {
115 if (!$this->font_swap) {
116 return true;
117 }
118
119 //check if google fonts are in HTML
120 $google_fonts_pattern = '/<link(?:\s+(?:(?!href\s*=\s*)[^>])+)?(?:\s+href\s*=\s*([\'"])(?<url>(?:https?:)?\/\/fonts\.googleapis\.com\/css(?:(?!\1).)+)\1)(?:\s+[^>]*)?>/Umsi';
121 $result = preg_match_all($google_fonts_pattern, $this->content, $fonts, PREG_SET_ORDER);
122
123 if (empty($result)) {
124 return true;
125 }
126
127 //add preconnect for google fonts
128 $this->addPreconnect();
129
130 //if more than 1 font is found parse and combine them into 1 <link> tag
131 if (count($fonts) > 1) {
132 $this->parse_google_fonts($fonts);
133 $google_font_tag = $this->get_combined_font_tag();
134 $this->content = OptimizerUtils::inject_in_html($this->content, $google_font_tag, [ '<head', 'after_tag' ]);
135
136 foreach ($fonts as $font) {
137 $this->remove_from_html($font[0]);
138 }
139 }
140 }
141
142 /**
143 * Add preconnect for google fonts
144 *
145 * @return bool
146 */
147 public function addPreconnect()
148 {
149 // check if preconnect already exists
150 $preconnect_pattern = "/((<link[^>]*rel=(['\"])preconnect(['\"])[^>]*href=(['\"])(?:https?:)\/\/fonts.gstatic.com[^>]*)|(<link[^>]*href=(['\"])(?:https?:)\/\/fonts.gstatic.com[^>]*rel=(['\"])preconnect(['\"])[^>]*))/Umsi";
151 $result = preg_match_all($preconnect_pattern, $this->content, $preconnect, PREG_SET_ORDER);
152
153 if (!empty($result)) {
154 return true;
155 }
156
157 //if everything is fine add precoonect to final html
158 $preconnect_string = '<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>';
159 $this->content = OptimizerUtils::inject_in_html($this->content, $preconnect_string, [ '<head', 'after_tag' ]);
160 }
161
162 /**
163 * Get Combined tag for all found google fonts
164 *
165 * @return string
166 */
167 protected function get_combined_font_tag()
168 {
169 return '<link rel="preload" as="style" href="https://fonts.googleapis.com/css?family=' . $this->google_fonts . $this->google_subsets . '&display=swap">
170 <link rel="stylesheet" media="none" onload="this.onload=null;this.removeAttribute(\'media\');" href="https://fonts.googleapis.com/css?family=' . $this->google_fonts . $this->google_subsets . '&display=swap">
171 <noscript>
172 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=' . $this->google_fonts . $this->google_subsets . '&display=swap">
173 </noscript>';
174 }
175
176 /**
177 * Parse all found google fonts
178 */
179 protected function parse_google_fonts($fonts)
180 {
181 $fonts_array = [];
182 $subsets_array = [];
183
184 foreach ($fonts as $font) {
185 $url = html_entity_decode($font[2]);
186 $query = wp_parse_url($url, PHP_URL_QUERY);
187
188 if (empty($query)) {
189 return;
190 }
191
192 $font = wp_parse_args($query);
193
194 if (isset($font['family'])) {
195 $font_family = $font['family'];
196 $font_family = rtrim($font_family, '%7C');
197 $font_family = rtrim($font_family, '|');
198 // Add font to the collection.
199 $fonts_array[] = rawurlencode(htmlentities($font_family));
200 }
201
202 // Add subset to collection.
203 if (isset($font['subset'])) {
204 $subsets_array[] = rawurlencode(htmlentities($font['subset']));
205 }
206 }
207
208 // Concatenate fonts tag.
209 $this->google_subsets = ! empty($subsets_array) ? '&subset=' . implode(',', array_filter(array_unique($subsets_array))) : '';
210 $this->google_fonts = ! empty($fonts_array) ? implode('%7C', array_filter(array_unique($fonts_array))) : '';
211 }
212
213 /**
214 * Returns array of as and type
215 *
216 * @return array|bool
217 */
218 private function getLinkType($extension)
219 {
220 if (isset($this->fontsExtensions[$extension])) {
221 return ['font', $this->fontsExtensions[$extension]];
222 }
223
224 if (isset($this->styleExtensions[$extension])) {
225 return ['style', $this->styleExtensions[$extension]];
226 }
227
228 if (isset($this->scriptExtensions[$extension])) {
229 return ['script', $this->scriptExtensions[$extension]];
230 }
231
232 if (isset($this->videoExtensions[$extension])) {
233 return ['video', $this->videoExtensions[$extension]];
234 }
235
236 return false;
237 }
238
239 public function getcontent()
240 {
241 return $this->content;
242 }
243
244 public function read($options)
245 {
246 global $TwoSettings;
247 $this->linksToPreload = $TwoSettings->get_settings('two_fonts_to_preload', '');
248 $this->linksToPreconnect = $TwoSettings->get_settings('two_fonts_to_preconnect', '');
249 $this->font_swap = empty($TwoSettings->get_settings('two_async_font', false)) ? false : true;
250 $this->two_load_fonts_via_webfont = empty($TwoSettings->get_settings('two_load_fonts_via_webfont', false)) ? false : true;
251
252 if (isset($options['webFont_list'])) {
253 $this->webFont_list = $options['webFont_list'];
254 }
255 }
256
257 public function optimize()
258 {
259 $this->addPreload($this->linksToPreload, 'preload');
260 $this->addPreload($this->linksToPreconnect, 'preconnect');
261 $this->combineGoogleFonts();
262
263 if ($this->two_load_fonts_via_webfont && is_array($this->webFont_list) && !empty($this->webFont_list)) {
264 $this->add_WebFont();
265 }
266 }
267
268 public function add_WebFont()
269 {
270 $webFont_js = '
271 <script ' . esc_attr(OptimizerScripts::TWO_DISABLE_PAGESPEED_DEFER_ATTRIBUTE) . ' ' . OptimizerScripts::TWO_NO_DELAYED_JS_ATTRIBUTE . '>
272 WebFontConfig = {
273 google: {families: ' .
274 json_encode($this->webFont_list) // phpcs:ignore
275 . "}
276 };
277 (function () {
278 var wf = document.createElement('script');
279 wf.src = 'https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
280 wf.type = 'text/javascript';
281 wf.async = 'true';
282 var s = document.getElementsByTagName('script')[0];
283 s.parentNode.insertBefore(wf, s);
284 })();
285 </script>
286 ";
287 $this->content = OptimizerUtils::inject_in_html($this->content, $webFont_js, [ '<head', 'after_tag' ]);
288 }
289
290 public function cache()
291 {
292 // TODO: Implement cache() method.
293 }
294
295 private function convertOptionToArray($option)
296 {
297 return array_filter(array_map('trim', explode(',', $option)));
298 }
299 }
300