PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.5.2
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.5.2
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / minify / class-wp-optimize-minify-fonts.php

class-wp-optimize-minify-fonts.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.5.2, at minify/class-wp-optimize-minify-fonts.php

312 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) die('No direct access allowed');
3
4 class WP_Optimize_Minify_Fonts {
5
6 private static $fonts = array();
7
8 private static $subsets = array();
9
10 /**
11 * Get a list of Google fonts
12 *
13 * @return array
14 */
15 public static function get_google_fonts() {
16 // https://www.googleapis.com/webfonts/v1/webfonts?sort=alpha
17 $google_fonts_file = WPO_PLUGIN_MAIN_PATH.'google-fonts.json';
18 if (is_file($google_fonts_file) && is_readable($google_fonts_file)) {
19 return json_decode(file_get_contents($google_fonts_file), true);
20 }
21 return array();
22 }
23
24 /**
25 * Check if the Google font exist or not
26 *
27 * @param string $font
28 * @return boolean
29 */
30 public static function concatenate_google_fonts_allowed($font) {
31 $gfonts_whitelist = self::get_google_fonts();
32
33 // normalize
34 $font = str_ireplace('+', ' ', strtolower($font));
35
36 return in_array($font, $gfonts_whitelist);
37 }
38
39 /**
40 * Concatenates Google Fonts tags (http://fonts.googleapis.com/css?...)
41 *
42 * @param array $gfonts_array
43 * @return string|boolean
44 */
45 public static function concatenate_google_fonts($gfonts_array) {
46 // Loop through fonts array
47 foreach ($gfonts_array as $font) {
48 self::parse_font_url($font);
49 }
50 self::convert_v1_font_specs_to_v2();
51 $merge = self::build();
52 $config = wp_optimize_minify_config();
53 /**
54 * Filters whether to add display=swap to Google fonts urls
55 *
56 * @param boolean $display - Default to true
57 */
58 if (apply_filters('wpo_minify_gfont_display_swap', $config->get('enable_display_swap'))) {
59 /**
60 * Filters the value of the display parameter.
61 *
62 * @param string $display_value - Default to 'swap'. https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display
63 */
64 $merge.= '&display='.apply_filters('wpo_minify_gfont_display_type', 'swap');
65 }
66
67 if (!empty($merge)) return 'https://fonts.googleapis.com/css2?' . $merge;
68
69 return false;
70 }
71
72 /**
73 * Parses font url based on whether it is API version 1 or 2
74 *
75 * @param string $font
76 */
77 private static function parse_font_url($font) {
78 if (false !== strpos($font, 'css?')) {
79 self::parse_font_api1_url($font);
80 } else {
81 self::parse_font_api2_url($font);
82 }
83 }
84
85 /**
86 * Parses google font api version 1 url
87 *
88 * @param string $font
89 */
90 private static function parse_font_api1_url($font) {
91 parse_str(wp_parse_url(rtrim($font, '|'), PHP_URL_QUERY), $font_elements);
92 // Process each font family
93 foreach (explode('|', $font_elements['family']) as $font_family) {
94 // Separate font and sizes
95 $font_family = explode(':', $font_family);
96 // if the family wasn't added yet
97 if (!in_array($font_family[0], array_keys(self::$fonts))) {
98 self::$fonts[$font_family[0]]['specs'] = isset($font_family[1]) ? explode(',', rtrim($font_family[1], ',')) : array();
99 } else {
100 // if the family was already added, and this new one has weights, merge with previous
101 if (isset($font_family[1])) {
102 if (isset(self::$fonts[$font_family[0]]['version']) && 'V2' === self::$fonts[$font_family[0]]['version']) {
103 self::$fonts[$font_family[0]]['specs'] = explode(',', rtrim($font_family[1], ','));
104 } else {
105 self::$fonts[$font_family[0]]['specs'] = array_merge(self::$fonts[$font_family[0]]['specs'], explode(',', rtrim($font_family[1], ',')));
106 }
107 }
108 }
109 self::$fonts[$font_family[0]]['version'] = 'V1';
110 }
111
112 // Add subsets
113 if (isset($font_elements['subset'])) {
114 self::$subsets = array_merge(self::$subsets, explode(',', $font_elements['subset']));
115 }
116 }
117
118 /**
119 * Parses google font api version 2 url
120 *
121 * @param string $font
122 */
123 private static function parse_font_api2_url($font) {
124 $parsed_url = wp_parse_url($font, PHP_URL_QUERY);
125 $query_elements = explode('&', $parsed_url);
126 foreach ($query_elements as $element) {
127 $family_str = str_replace('family=', '', $element);
128 $family = explode(':', $family_str);
129 if (!empty($family)) {
130 $font_name = $family[0];
131 $font_elements = isset($family[1]) ? explode('@', $family[1]) : '';
132 if (!empty($font_elements) && !empty($font_elements[0]) && !empty($font_elements[1])) {
133 $font_styles = $font_elements[0];
134 $font_units = explode(',', $font_elements[1]);
135 }
136 } else {
137 $font_name = $family_str;
138 continue;
139 }
140
141 if (!isset(self::$fonts[$font_name])) {
142 self::$fonts[$font_name]['specs'] = array(
143 'wght' => array(),
144 'ital' => array(),
145 'ital,wght' => array(),
146 );
147 }
148
149 if (!isset(self::$fonts[$font_name]['version'])) {
150 self::$fonts[$font_name]['version'] = 'V2';
151 }
152 if (isset($font_styles) && isset($font_units) && isset($font_elements[1])) {
153 $font_units = explode(';', $font_elements[1]);
154 switch ($font_styles) {
155 case 'wght':
156 foreach ($font_units as $font_unit) {
157 if (!in_array($font_unit, self::$fonts[$font_name]['specs']['wght'])) {
158 array_push(self::$fonts[$font_name]['specs']['wght'], $font_unit);
159 }
160 }
161 break;
162 case 'ital':
163 foreach ($font_units as $font_unit) {
164 if (!in_array($font_unit, self::$fonts[$font_name]['specs']['ital'])) {
165 array_push(self::$fonts[$font_name]['specs']['ital'], $font_unit);
166 }
167 }
168 break;
169 case 'ital,wght':
170 foreach ($font_units as $font_unit) {
171 if (!in_array($font_unit, self::$fonts[$font_name]['specs']['ital,wght'])) {
172 array_push(self::$fonts[$font_name]['specs']['ital,wght'], $font_unit);
173 }
174 }
175 break;
176 }
177 }
178 }
179 }
180
181 /**
182 * Converts google font api version 1 font specification into API V2
183 */
184 private static function convert_v1_font_specs_to_v2() {
185 foreach (self::$fonts as $font_name => $font_details) {
186 if ('V2' === $font_details['version']) continue;
187 if (0 === count($font_details['specs'])) {
188 self::$fonts[$font_name]['specs'] = array(
189 'wght' => array(),
190 'ital' => array(),
191 'ital,wght' => array(),
192 );
193 } else {
194 foreach ($font_details['specs'] as $key => $detail) {
195 if (is_array($detail)) $detail = implode('', $detail);
196 switch ($detail) {
197 case 'i':
198 unset(self::$fonts[$font_name]['specs'][$key]);
199 self::$fonts[$font_name]['specs']['ital'] = array(1);
200 break;
201 case 'b':
202 unset(self::$fonts[$font_name]['specs'][$key]);
203 self::$fonts[$font_name]['specs']['wght'] = array();
204 break;
205 case 'bi':
206 unset(self::$fonts[$font_name]['specs'][$key]);
207 self::$fonts[$font_name]['specs']['ital'] = array('0;1');
208 break;
209 default:
210 unset(self::$fonts[$font_name]['specs'][$key]);
211 if (!isset(self::$fonts[$font_name]['specs']['ital,wght'])) {
212 self::$fonts[$font_name]['specs']['ital,wght'] = array();
213 }
214 if ('inherit' === $detail) {
215 array_push(self::$fonts[$font_name]['specs']['ital,wght'], '0,400');
216 array_push(self::$fonts[$font_name]['specs']['ital,wght'], '1,400');
217 } elseif ('regular' === $detail) {
218 $detail = 'regular' === $detail ? 400 : $detail;
219 array_push(self::$fonts[$font_name]['specs']['ital,wght'], '0,' . $detail);
220 } elseif (false !== strpos($detail, 'i')) {
221 $detail = str_replace(array('italic', 'i'), '', $detail);
222 $detail = '' === $detail ? 400 : $detail;
223 array_push(self::$fonts[$font_name]['specs']['ital,wght'], '1,' . $detail);
224 } else {
225 $detail = str_replace(array('normal'), '', $detail);
226 $detail = '' === $detail ? 400 : $detail;
227 array_push(self::$fonts[$font_name]['specs']['ital,wght'], '0,' . $detail);
228 }
229 break;
230 }
231 }
232 }
233 }
234 }
235
236 /**
237 * Build valid Google font api 2 url string
238 *
239 * @return string $result Url string
240 */
241 private static function build() {
242 $result = '';
243 foreach (self::$fonts as $font_name => $font_details) {
244 if ('display=swap' === $font_name) continue;
245 if ('' !== $result) {
246 $result .= '&';
247 }
248 $result .= 'family=' . str_replace(' ', '+', $font_name);
249 $result .= self::specs_to_string($font_details['specs']);
250 }
251 return $result;
252 }
253
254 /**
255 * Converts font specifications into a valid Google font api2 url string
256 *
257 * @param array $font_specs Font style and weight specifications
258 *
259 * @return string
260 */
261 private static function specs_to_string($font_specs) {
262 $result = array();
263 $weights = isset($font_specs['wght']) && count($font_specs['wght']);
264 $italic_weights = isset($font_specs['ital']) && count($font_specs['ital']);
265 $all_weights = isset($font_specs['ital,wght']) && count($font_specs['ital,wght']);
266
267 // Nothing is set, return
268 if (!$weights && !$italic_weights && !$all_weights) {
269 return '';
270 }
271
272 // Italic only
273 if ($italic_weights && !$weights && !$all_weights) {
274 if ('1' === $font_specs['ital'][0]) {
275 return ':ital@1';
276 } elseif ('0;1' === $font_specs['ital'][0]) {
277 return ':ital@0;1';
278 }
279 }
280
281 foreach ($font_specs as $style => $units) {
282 switch ($style) {
283 case 'wght':
284 foreach ($units as $unit) {
285 $multiple_units = explode(',', $unit);
286 if (count($multiple_units) > 0) {
287 foreach ($multiple_units as $single_unit) {
288 array_push($result, '0,' . $single_unit);
289 }
290 } else {
291 array_push($result, '0,' . $unit);
292 }
293 }
294 break;
295 case 'ital':
296 foreach ($units as $unit) {
297 array_push($result, 1 === (int) $unit ? '1,400' : $unit);
298 }
299 break;
300 case 'ital,wght':
301 foreach ($units as $unit) {
302 array_push($result, $unit);
303 }
304 break;
305 }
306 }
307
308 sort($result);
309 return ':ital,wght@' . implode(';', array_unique($result));
310 }
311 }
312