PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.3
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.3
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 3.2.3, at minify/class-wp-optimize-minify-fonts.php

299 lines 8.9 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 wether 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 private static function parse_font_url($font) {
76 if (false !== strpos($font, 'css?')) {
77 self::parse_font_api1_url($font);
78 } else {
79 self::parse_font_api2_url($font);
80 }
81 }
82
83 /**
84 * Parses google font api version 1 url
85 */
86 private static function parse_font_api1_url($font) {
87 parse_str(parse_url(rtrim($font, '|'), PHP_URL_QUERY), $font_elements);
88 // Process each font family
89 foreach (explode('|', $font_elements['family']) as $font_family) {
90 // Separate font and sizes
91 $font_family = explode(':', $font_family);
92 // if the family wasn't added yet
93 if (!in_array($font_family[0], array_keys(self::$fonts))) {
94 self::$fonts[$font_family[0]]['specs'] = isset($font_family[1]) ? explode(',', rtrim($font_family[1], ',')) : array();
95 } else {
96 // if the family was already added, and this new one has weights, merge with previous
97 if (isset($font_family[1])) {
98 if (isset(self::$fonts[$font_family[0]]['version']) && 'V2' == self::$fonts[$font_family[0]]['version']) {
99 self::$fonts[$font_family[0]]['specs'] = explode(',', rtrim($font_family[1], ','));
100 } else {
101 self::$fonts[$font_family[0]]['specs'] = array_merge(self::$fonts[$font_family[0]]['specs'], explode(',', rtrim($font_family[1], ',')));
102 }
103 }
104 }
105 self::$fonts[$font_family[0]]['version'] = 'V1';
106 }
107
108 // Add subsets
109 if (isset($font_elements['subset'])) {
110 self::$subsets = array_merge(self::$subsets, explode(',', $font_elements['subset']));
111 }
112 }
113
114 /**
115 * Parses google font api version 2 url
116 */
117 private static function parse_font_api2_url($font) {
118 $parsed_url = parse_url($font, PHP_URL_QUERY);
119 $query_elements = explode('&', $parsed_url);
120 foreach ($query_elements as $element) {
121 $family_str = str_replace('family=', '', $element);
122 $family = explode(':', $family_str);
123 if (!empty($family)) {
124 $font_name = $family[0];
125 $font_elements = isset($family[1]) ? explode('@', $family[1]) : '';
126 if (!empty($font_elements) && !empty($font_elements[0]) && !empty($font_elements[1])) {
127 $font_styles = $font_elements[0];
128 $font_units = explode(',', $font_elements[1]);
129 }
130 } else {
131 $font_name = $family_str;
132 continue;
133 }
134
135 if (!isset(self::$fonts[$font_name])) {
136 self::$fonts[$font_name]['specs'] = array(
137 'wght' => array(),
138 'ital' => array(),
139 'ital,wght' => array(),
140 );
141 }
142
143 if (!isset(self::$fonts[$font_name]['version'])) {
144 self::$fonts[$font_name]['version'] = 'V2';
145 }
146 if (isset($font_styles) && isset($font_units) && isset($font_elements[1])) {
147 $font_units = explode(';', $font_elements[1]);
148 switch ($font_styles) {
149 case 'wght':
150 foreach ($font_units as $font_unit) {
151 if (!in_array($font_unit, self::$fonts[$font_name]['specs']['wght'])) {
152 array_push(self::$fonts[$font_name]['specs']['wght'], $font_unit);
153 }
154 }
155 break;
156 case 'ital':
157 foreach ($font_units as $font_unit) {
158 if (!in_array($font_unit, self::$fonts[$font_name]['specs']['ital'])) {
159 array_push(self::$fonts[$font_name]['specs']['ital'], $font_unit);
160 }
161 }
162 break;
163 case 'ital,wght':
164 foreach ($font_units as $font_unit) {
165 if (!in_array($font_unit, self::$fonts[$font_name]['specs']['ital,wght'])) {
166 array_push(self::$fonts[$font_name]['specs']['ital,wght'], $font_unit);
167 }
168 }
169 break;
170 }
171 }
172 }
173 }
174
175 /**
176 * Converts google font api version 1 font specification into API V2
177 */
178 private static function convert_v1_font_specs_to_v2() {
179 foreach (self::$fonts as $font_name => $font_details) {
180 if ('V2' == $font_details['version']) continue;
181 if (0 == count($font_details['specs'])) {
182 self::$fonts[$font_name]['specs'] = array(
183 'wght' => array(),
184 'ital' => array(),
185 'ital,wght' => array(),
186 );
187 } else {
188 foreach ($font_details['specs'] as $key => $detail) {
189 if (is_array($detail)) $detail = implode('', $detail);
190 switch ($detail) {
191 case 'i':
192 unset(self::$fonts[$font_name]['specs'][$key]);
193 self::$fonts[$font_name]['specs']['ital'] = array(1);
194 break;
195 case 'b':
196 unset(self::$fonts[$font_name]['specs'][$key]);
197 self::$fonts[$font_name]['specs']['wght'] = array();
198 break;
199 case 'bi':
200 unset(self::$fonts[$font_name]['specs'][$key]);
201 self::$fonts[$font_name]['specs']['ital'] = array('0;1');
202 break;
203 default:
204 unset(self::$fonts[$font_name]['specs'][$key]);
205 if (!isset(self::$fonts[$font_name]['specs']['ital,wght'])) {
206 self::$fonts[$font_name]['specs']['ital,wght'] = array();
207 }
208 if (false !== strpos($detail, 'i')) {
209 $detail = str_replace(array('italic', 'i'), '', $detail);
210 $detail = '' === $detail ? 400 : $detail;
211 array_push(self::$fonts[$font_name]['specs']['ital,wght'], '1,' . $detail);
212 } else {
213 $detail = 'regular' === $detail ? 400 : $detail;
214 array_push(self::$fonts[$font_name]['specs']['ital,wght'], '0,' . $detail);
215 }
216 break;
217 }
218 }
219 }
220 }
221 }
222
223 /**
224 * Build valid Google font api 2 url string
225 *
226 * @return string $result Url string
227 */
228 private static function build() {
229 $result = '';
230 foreach (self::$fonts as $font_name => $font_details) {
231 if ('display=swap' == $font_name) continue;
232 if ('' != $result) {
233 $result .= '&';
234 }
235 $result .= 'family=' . str_replace(' ', '+', $font_name);
236 $result .= self::specs_to_string($font_details['specs']);
237 }
238 return $result;
239 }
240
241 /**
242 * Converts font specifications into a valid google font api2 url string
243 *
244 * @param array $font_specs Font style and weight specifications
245 *
246 * @return string
247 */
248 private static function specs_to_string($font_specs) {
249 $result = array();
250 $weights = isset($font_specs['wght']) && count($font_specs['wght']);
251 $italic_weights = isset($font_specs['ital']) && count($font_specs['ital']);
252 $all_weights = isset($font_specs['ital,wght']) && count($font_specs['ital,wght']);
253
254 // Nothing is set, return
255 if (!$weights && !$italic_weights && !$all_weights) {
256 return '';
257 }
258
259 // Italic only
260 if ($italic_weights && !$weights && !$all_weights) {
261 if ('1' == $font_specs['ital'][0]) {
262 return ':ital@1';
263 } elseif ('0;1' == $font_specs['ital'][0]) {
264 return ':ital@0;1';
265 }
266 }
267
268 foreach ($font_specs as $style => $units) {
269 switch ($style) {
270 case 'wght':
271 foreach ($units as $unit) {
272 $multiple_units = explode(',', $unit);
273 if (count($multiple_units) > 0) {
274 foreach ($multiple_units as $single_unit) {
275 array_push($result, '0,' . $single_unit);
276 }
277 } else {
278 array_push($result, '0,' . $unit);
279 }
280 }
281 break;
282 case 'ital':
283 foreach ($units as $unit) {
284 array_push($result, 1 == $unit ? '1,400' : $unit);
285 }
286 break;
287 case 'ital,wght':
288 foreach ($units as $unit) {
289 array_push($result, $unit);
290 }
291 break;
292 }
293 }
294
295 sort($result);
296 return ':ital,wght@' . implode(';', array_unique($result));
297 }
298 }
299