OMGF | GDPR/DSVGO Compliant, Faster Google Fonts. Easy. - Version 5.2.1

Version Description

| June 25th, 2022 = * Fixed: shorthand syntax (r,i,b,bi) is now parsed correctly. * Added: Basic Variable Fonts support (full support coming in 5.3.0!) * Fixed: "preload" attributes added by 3rd party plugins would somehow be misunderstood as preload resource hints. * Deprecated: Force Subsets (Pro) and Include File Types (Pro) are marked as deprecated in preparation for the upcoming release which includes full Variable Fonts support, rendering these options useless.

Download this release

Release Info

Developer DaanvandenBergh
Plugin Icon 128x128 OMGF | GDPR/DSVGO Compliant, Faster Google Fonts. Easy.
Version 5.2.1
Comparing to
See all releases

Code changes from version 5.2.0 to 5.2.1

host-webfonts-local.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin Name: OMGF
5
  * Plugin URI: https://ffw.press/wordpress/omgf/
6
  * Description: Increase GDPR compliance, reduce DNS requests and leverage browser cache by automatically downloading Google Fonts to your server.
7
- * Version: 5.2.0
8
  * Author: Daan from FFW.Press
9
  * Author URI: https://ffw.press
10
  * License: GPL2v2 or later
4
  * Plugin Name: OMGF
5
  * Plugin URI: https://ffw.press/wordpress/omgf/
6
  * Description: Increase GDPR compliance, reduce DNS requests and leverage browser cache by automatically downloading Google Fonts to your server.
7
+ * Version: 5.2.1
8
  * Author: Daan from FFW.Press
9
  * Author URI: https://ffw.press
10
  * License: GPL2v2 or later
includes/admin/settings/class-optimize.php CHANGED
@@ -197,7 +197,7 @@ class OMGF_Admin_Settings_Optimize extends OMGF_Admin_Settings_Builder
197
  public function do_promo_include_file_types()
198
  {
199
  $this->do_select(
200
- __('Include File Types (Pro)', $this->plugin_text_domain),
201
  'omgf_pro_file_types',
202
  OMGF_Admin_Settings::OMGF_FILE_TYPES_OPTIONS,
203
  defined('OMGF_PRO_FILE_TYPES') ? OMGF_PRO_FILE_TYPES : [],
@@ -213,7 +213,7 @@ class OMGF_Admin_Settings_Optimize extends OMGF_Admin_Settings_Builder
213
  public function do_promo_force_subsets()
214
  {
215
  $this->do_select(
216
- __('Force Subsets (Pro)', $this->plugin_text_domain),
217
  'omgf_pro_force_subsets',
218
  OMGF_Admin_Settings::OMGF_FORCE_SUBSETS_OPTIONS,
219
  defined('OMGF_PRO_FORCE_SUBSETS') ? OMGF_PRO_FORCE_SUBSETS : [],
@@ -315,7 +315,20 @@ class OMGF_Admin_Settings_Optimize extends OMGF_Admin_Settings_Builder
315
  <input autocomplete="off" type="checkbox" class="replace" <?= $replace; ?> <?= $fallback ? '' : 'disabled'; ?> <?= apply_filters('omgf_pro_replace_font_setting_disabled', true) ? 'disabled' : ''; ?> name="omgf_pro_replace_font[<?= $handle; ?>][<?= $font->id; ?>]" />
316
  </td>
317
  </tr>
 
318
  <?php foreach ($font->variants as $variant) : ?>
 
 
 
 
 
 
 
 
 
 
 
 
319
  <tr>
320
  <td></td>
321
  <?php
197
  public function do_promo_include_file_types()
198
  {
199
  $this->do_select(
200
+ __('Include File Types (Pro) (Deprecated)', $this->plugin_text_domain),
201
  'omgf_pro_file_types',
202
  OMGF_Admin_Settings::OMGF_FILE_TYPES_OPTIONS,
203
  defined('OMGF_PRO_FILE_TYPES') ? OMGF_PRO_FILE_TYPES : [],
213
  public function do_promo_force_subsets()
214
  {
215
  $this->do_select(
216
+ __('Force Subsets (Pro) (Deprecated)', $this->plugin_text_domain),
217
  'omgf_pro_force_subsets',
218
  OMGF_Admin_Settings::OMGF_FORCE_SUBSETS_OPTIONS,
219
  defined('OMGF_PRO_FORCE_SUBSETS') ? OMGF_PRO_FORCE_SUBSETS : [],
315
  <input autocomplete="off" type="checkbox" class="replace" <?= $replace; ?> <?= $fallback ? '' : 'disabled'; ?> <?= apply_filters('omgf_pro_replace_font_setting_disabled', true) ? 'disabled' : ''; ?> name="omgf_pro_replace_font[<?= $handle; ?>][<?= $font->id; ?>]" />
316
  </td>
317
  </tr>
318
+ <?php $id = ''; ?>
319
  <?php foreach ($font->variants as $variant) : ?>
320
+ <?php
321
+ /**
322
+ * @since v5.3.0: Variable Fonts are pulled directly from the Google Fonts API,
323
+ * which creates @font-face statements for each separate subset.
324
+ *
325
+ * This deals with the duplicate display of font styles. Which also
326
+ * means unloading and/or preloading will unload/preload all available
327
+ * subsets. It's a bit bloaty, but there's no alternative.
328
+ */
329
+ if ($id == $variant->fontWeight . $variant->fontStyle) continue;
330
+ ?>
331
+ <?php $id = $variant->fontWeight . $variant->fontStyle; ?>
332
  <tr>
333
  <td></td>
334
  <?php
includes/class-optimize.php CHANGED
@@ -33,6 +33,17 @@ class OMGF_Optimize
33
  'muli' => 'mulish'
34
  ];
35
 
 
 
 
 
 
 
 
 
 
 
 
36
  /** @var string $family */
37
  private $family = '';
38
 
@@ -182,7 +193,7 @@ class OMGF_Optimize
182
  $font->family = rawurlencode($font->family);
183
 
184
  foreach ($font->variants as &$variant) {
185
- $filename = strtolower($font_id . '-' . $variant->fontStyle . '-' . $variant->fontWeight);
186
 
187
  /**
188
  * Encode font family, because it may contain spaces.
@@ -323,6 +334,13 @@ class OMGF_Optimize
323
 
324
  $response_code = wp_remote_retrieve_response_code($response);
325
 
 
 
 
 
 
 
 
326
  if ($response_code != 200) {
327
  $error_body = wp_remote_retrieve_body($response);
328
  $error_message = wp_remote_retrieve_response_message($response);
@@ -378,6 +396,99 @@ class OMGF_Optimize
378
  return $response;
379
  }
380
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  /**
382
  * @param $request
383
  * @param $font
@@ -391,6 +502,15 @@ class OMGF_Optimize
391
  */
392
  $requested_variants = array_filter(explode(',', $request));
393
 
 
 
 
 
 
 
 
 
 
394
  /**
395
  * This means by default all fonts are requested, so we need to fill up the queue, before unloading the unwanted variants.
396
  */
33
  'muli' => 'mulish'
34
  ];
35
 
36
+ /**
37
+ * @since 5.2.1 Use this map to convert shorthands (r(egular), i(talic), b(old) and b(old)i(talic)) to
38
+ * to human readable font style values.
39
+ */
40
+ const OMGF_FONT_STYLES_MAP = [
41
+ 'r' => '400',
42
+ 'i' => '400italic',
43
+ 'b' => '700',
44
+ 'bi' => '700italic'
45
+ ];
46
+
47
  /** @var string $family */
48
  private $family = '';
49
 
193
  $font->family = rawurlencode($font->family);
194
 
195
  foreach ($font->variants as &$variant) {
196
+ $filename = strtolower($font_id . '-' . $variant->fontStyle . '-' . (isset($variant->subset) ? $variant->subset . '-' : '') . $variant->fontWeight);
197
 
198
  /**
199
  * Encode font family, because it may contain spaces.
334
 
335
  $response_code = wp_remote_retrieve_response_code($response);
336
 
337
+ /**
338
+ * Let's try and parse the stylesheet if it wasn't found on the API.
339
+ */
340
+ if ($response_code == 404) {
341
+ return $this->parse_stylesheet($this->family, $id, $name);
342
+ }
343
+
344
  if ($response_code != 200) {
345
  $error_body = wp_remote_retrieve_body($response);
346
  $error_message = wp_remote_retrieve_response_message($response);
396
  return $response;
397
  }
398
 
399
+ /**
400
+ * A workaround for font families which are not available on the Helper API, but are still
401
+ * served from the Google Fonts API (e.g. Open Sans Condensed)
402
+ *
403
+ * @param string $request The full request
404
+ * @param string $id Unique identifier for this font family
405
+ * @param string $font_family The full name of font family not available on the Helper API.
406
+ * @return array An empty array (if request to Google Fonts API returns a 404) or a
407
+ * valid Font Object: { }
408
+ */
409
+ public function parse_stylesheet($request, $id, $font_family)
410
+ {
411
+ $requested_families = explode('|', $request);
412
+
413
+ foreach ($requested_families as $requested_family) {
414
+ if (strpos($requested_family, $font_family)) {
415
+ break;
416
+ }
417
+ }
418
+
419
+ $url = 'https://fonts.googleapis.com/css?family=' . urlencode($requested_family);
420
+ $response = wp_remote_get($url, [
421
+ // Retrieve WOFF2 files only.
422
+ 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0'
423
+ ]);
424
+
425
+ $code = wp_remote_retrieve_response_code($response);
426
+
427
+ if ($code !== 200) {
428
+ return [];
429
+ }
430
+
431
+ $stylesheet = wp_remote_retrieve_body($response);
432
+
433
+ return (object) [
434
+ 'id' => $id,
435
+ 'family' => $font_family,
436
+ 'variants' => $this->parse_variants($stylesheet, $font_family),
437
+ 'subsets' => $this->parse_subsets($stylesheet, $font_family)
438
+ ];
439
+ }
440
+
441
+ /**
442
+ * Parse a stylesheet from Google Fonts' API into
443
+ *
444
+ * @param string $stylesheet
445
+ * @param string $font_family
446
+ *
447
+ * @return array
448
+ */
449
+ private function parse_variants($stylesheet, $font_family)
450
+ {
451
+ preg_match_all('/\/\*\s.*?}/s', $stylesheet, $font_faces);
452
+
453
+ if (!isset($font_faces[0]) || empty($font_faces[0])) {
454
+ return [];
455
+ }
456
+
457
+ foreach ($font_faces[0] as $key => $font_face) {
458
+ preg_match('/font-style:\s(normal|italic);/', $font_face, $font_style);
459
+ preg_match('/font-weight:\s([0-9]+);/', $font_face, $font_weight);
460
+ preg_match('/src:\surl\((.*?woff2)\)/', $font_face, $font_src);
461
+ preg_match('/\/\*\s([a-z\-]+?)\s\*\//', $font_face, $subset);
462
+ preg_match('/unicode-range:\s(.*?);/', $font_face, $range);
463
+
464
+ $font_object[$key] = new stdClass();
465
+ $font_object[$key]->id = $font_weight[1] . ($font_style[1] == 'normal' ? '' : $font_style[1]);
466
+ $font_object[$key]->fontFamily = $font_family;
467
+ $font_object[$key]->fontStyle = $font_style[1];
468
+ $font_object[$key]->fontWeight = $font_weight[1];
469
+ $font_object[$key]->woff2 = $font_src[1];
470
+ $font_object[$key]->subset = $subset[1];
471
+ $font_object[$key]->range = $range[1];
472
+ }
473
+
474
+ return $font_object;
475
+ }
476
+
477
+ /**
478
+ * Parse stylesheets for subsets, which in Google Fonts stylesheets are always
479
+ * included, commented above each @font-face statements, e.g. /* latin-ext */ /*
480
+ */
481
+ private function parse_subsets($stylesheet)
482
+ {
483
+ preg_match_all('/\/\*\s([a-z\-]+?)\s\*\//', $stylesheet, $subsets);
484
+
485
+ if (!isset($subsets[1]) || empty($subsets[1])) {
486
+ return [];
487
+ }
488
+
489
+ return array_unique($subsets[1]);
490
+ }
491
+
492
  /**
493
  * @param $request
494
  * @param $font
502
  */
503
  $requested_variants = array_filter(explode(',', $request));
504
 
505
+ /**
506
+ * @since v5.2.1 Run a quick to see if shorthands (e.g. r,i,b,bi) are used in this request. And if so,
507
+ * convert them to human readable values (e.g. 400, 400italic)
508
+ */
509
+ $replacements = self::OMGF_FONT_STYLES_MAP;
510
+ $requested_variants = array_map(function ($value) use ($replacements) {
511
+ return isset($replacements[$value]) ? $replacements[$value] : $value;
512
+ }, $requested_variants);
513
+
514
  /**
515
  * This means by default all fonts are requested, so we need to fill up the queue, before unloading the unwanted variants.
516
  */
includes/class-stylesheet-generator.php CHANGED
@@ -107,6 +107,11 @@ class OMGF_StylesheetGenerator
107
  }
108
 
109
  $stylesheet .= $this->build_source_string($font_src_url);
 
 
 
 
 
110
  $stylesheet .= "}\n";
111
  }
112
  }
107
  }
108
 
109
  $stylesheet .= $this->build_source_string($font_src_url);
110
+
111
+ if (isset($variant->range)) {
112
+ $stylesheet .= " unicode-range: $variant->range;\n";
113
+ }
114
+
115
  $stylesheet .= "}\n";
116
  }
117
  }
includes/frontend/class-process.php CHANGED
@@ -249,13 +249,16 @@ class OMGF_Frontend_Process
249
  foreach ($resource_hints[0] as $key => $match) {
250
  /**
251
  * @since v5.1.5 Filter out any resource hints with a href pointing to Google Fonts' APIs.
 
 
 
252
  *
253
  * @todo: I think I should be able to use an array_filter here or something?
254
  */
255
  foreach (self::RESOURCE_HINTS_URLS as $url) {
256
  if (strpos($match, $url) !== false) {
257
  foreach (self::RESOURCE_HINTS_ATTR as $attr) {
258
- if (strpos($match, $attr) !== false) {
259
  $search[] = $match;
260
  }
261
  }
249
  foreach ($resource_hints[0] as $key => $match) {
250
  /**
251
  * @since v5.1.5 Filter out any resource hints with a href pointing to Google Fonts' APIs.
252
+ * @since v5.2.1 Use preg_match() to exactly match an element's attribute, since 3rd party
253
+ * plugins (e.g. Asset Cleanup) also tend to include their own custom attributes,
254
+ * e.g. data-wpacu-to-be-preloaded
255
  *
256
  * @todo: I think I should be able to use an array_filter here or something?
257
  */
258
  foreach (self::RESOURCE_HINTS_URLS as $url) {
259
  if (strpos($match, $url) !== false) {
260
  foreach (self::RESOURCE_HINTS_ATTR as $attr) {
261
+ if (preg_match("/['\"]{$attr}['\"]/", $match) === 1) {
262
  $search[] = $match;
263
  }
264
  }
readme.md CHANGED
@@ -1,4 +1,4 @@
1
- # OMGF | Host Google Fonts Locally
2
 
3
  OMGF automagically caches the Google Fonts used by your theme/plugins locally. No configuration (or brains) required!
4
 
1
+ # OMGF | GDPR Compliant, Faster Google Fonts. Easy.
2
 
3
  OMGF automagically caches the Google Fonts used by your theme/plugins locally. No configuration (or brains) required!
4
 
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
- === OMGF | Host Google Fonts Locally ===
2
  Contributors: DaanvandenBergh
3
  Tags: google, fonts, gdpr, cache, speed, preload, font-display, webfonts, subsets, remove, minimize, external, requests
4
  Requires at least: 4.6
5
  Tested up to: 6.0
6
- Stable tag: 5.2.0
7
  Requires PHP: 7.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -75,6 +75,12 @@ For the FAQ, [click here](https://ffw.press/docs/omgf-pro-faq/).
75
 
76
  == Changelog ==
77
 
 
 
 
 
 
 
78
  = 5.2.0 | June 14th, 2022 =
79
  * Added: toggle to disable Elementor/Divi compatibility fixes.
80
  * Fixed: when resource hints (e.g. preloads) were located in unusual places (e.g. Themify Builder places its preloads above the `<title>` element) this would cause other elements (e.g. stylesheets) to be removed as well.
1
+ === OMGF | GDPR Compliant, Faster Google Fonts. Easy. ===
2
  Contributors: DaanvandenBergh
3
  Tags: google, fonts, gdpr, cache, speed, preload, font-display, webfonts, subsets, remove, minimize, external, requests
4
  Requires at least: 4.6
5
  Tested up to: 6.0
6
+ Stable tag: 5.2.1
7
  Requires PHP: 7.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
75
 
76
  == Changelog ==
77
 
78
+ = 5.2.1 | June 25th, 2022 =
79
+ * Fixed: shorthand syntax (r,i,b,bi) is now parsed correctly.
80
+ * Added: Basic Variable Fonts support (full support coming in 5.3.0!)
81
+ * Fixed: "preload" attributes added by 3rd party plugins would somehow be misunderstood as preload resource hints.
82
+ * Deprecated: Force Subsets (Pro) and Include File Types (Pro) are marked as deprecated in preparation for the upcoming release which includes full Variable Fonts support, rendering these options useless.
83
+
84
  = 5.2.0 | June 14th, 2022 =
85
  * Added: toggle to disable Elementor/Divi compatibility fixes.
86
  * Fixed: when resource hints (e.g. preloads) were located in unusual places (e.g. Themify Builder places its preloads above the `<title>` element) this would cause other elements (e.g. stylesheets) to be removed as well.