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

Version Description

| July 20th, 2022 = * Added: Removed Google Webfonts Helper API and implemented a custom Web Font Loader. This adds/fixes: * Added: full support for Variable Fonts * Fixed: Proper (WOFF2) compression, so files generated by OMGF are no longer bigger than files downloaded from the Google Fonts API. * Fixed: The (broken capital A) compression bug is fixed! * Fixed: Changed logo in Help section to Daan.dev logo * Fixed: Remove unused subsets from Optimized Fonts object to reduce db size * Fixed: OMGF_Optimize class will bail earlier, if files and stylesheets already exist, to reduce execution time in the frontend. * Fixed: Invalid Google Fonts API requests (e.g. without a family parameter) are removed from the HTML. * Fixed: A stricter regulax expression is used for matching stylesheet link elements, to prevent backtracking. * Added: Used Subset(s) option, which allows users to specify which subset(s) they'd like to use when generating stylesheets and down-/preloading (variable) font files.

Download this release

Release Info

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

Code changes from version 5.2.2 to 5.3.0

assets/css/omgf-admin.css CHANGED
@@ -134,6 +134,9 @@
134
  .omgf-optimize-fonts-container .omgf-optimize-fonts-manage table tbody td .unload-mass-action {
135
  font-size: 0.9em;
136
  }
 
 
 
137
  .omgf-optimize-fonts-container .omgf-optimize-fonts-manage table tbody td .family {
138
  padding: 0 10px 0;
139
  font-weight: 600;
134
  .omgf-optimize-fonts-container .omgf-optimize-fonts-manage table tbody td .unload-mass-action {
135
  font-size: 0.9em;
136
  }
137
+ .omgf-optimize-fonts-container .omgf-optimize-fonts-manage table tbody td .unload-mass-action:hover {
138
+ cursor: pointer;
139
+ }
140
  .omgf-optimize-fonts-container .omgf-optimize-fonts-manage table tbody td .family {
141
  padding: 0 10px 0;
142
  font-weight: 600;
assets/css/omgf-admin.css.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["omgf-admin.less"],"names":[],"mappings":"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"}
1
+ {"version":3,"sources":["omgf-admin.less"],"names":[],"mappings":"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"}
assets/css/omgf-admin.less CHANGED
@@ -161,6 +161,10 @@
161
 
162
  .unload-mass-action {
163
  font-size: .9em;
 
 
 
 
164
  }
165
 
166
  .family {
161
 
162
  .unload-mass-action {
163
  font-size: .9em;
164
+
165
+ &:hover {
166
+ cursor: pointer;
167
+ }
168
  }
169
 
170
  .family {
assets/images/logo-color.png DELETED
Binary file
assets/images/logo.png ADDED
Binary file
assets/js/omgf-admin.js CHANGED
@@ -226,14 +226,12 @@ jQuery(document).ready(function ($) {
226
  /**
227
  * Unload all fonts for current font family.
228
  */
229
- unload_all: function (e) {
230
- e.preventDefault();
 
231
 
232
- var id = $(this).parents('.font-family').data('id');
233
- var unloads = $('.unload');
234
-
235
- unloads.each(function (index, item) {
236
- if (item.dataset.fontId == id && item.checked == false) {
237
  item.click();
238
  }
239
  });
@@ -242,14 +240,12 @@ jQuery(document).ready(function ($) {
242
  /**
243
  * Uncheck all unload checkboxes for the current font family.
244
  */
245
- load_all: function (e) {
246
- e.preventDefault();
 
247
 
248
- var id = $(this).parents('.font-family').data('id');
249
- var unloads = $('.unload');
250
-
251
- unloads.each(function (index, item) {
252
- if (item.dataset.fontId == id && item.checked == true) {
253
  item.click();
254
  }
255
  });
@@ -320,6 +316,7 @@ jQuery(document).ready(function ($) {
320
 
321
  omgf_show_loader = omgf_admin.show_loader;
322
  omgf_unload_all = omgf_admin.unload_all;
 
323
 
324
  omgf_admin.init();
325
  });
226
  /**
227
  * Unload all fonts for current font family.
228
  */
229
+ unload_all: function (e, self = this) {
230
+ var id = $(self).parents('.font-family').data('id'),
231
+ unloads = $('input.unload[data-font-id="' + id + '"]');
232
 
233
+ unloads.each(function (i, item) {
234
+ if (item.checked == false) {
 
 
 
235
  item.click();
236
  }
237
  });
240
  /**
241
  * Uncheck all unload checkboxes for the current font family.
242
  */
243
+ load_all: function () {
244
+ var id = $(this).parents('.font-family').data('id'),
245
+ unloads = $('input.unload[data-font-id="' + id + '"]');
246
 
247
+ unloads.each(function (i, item) {
248
+ if (item.checked == true) {
 
 
 
249
  item.click();
250
  }
251
  });
316
 
317
  omgf_show_loader = omgf_admin.show_loader;
318
  omgf_unload_all = omgf_admin.unload_all;
319
+ omgf_load_all = omgf_admin.load_all;
320
 
321
  omgf_admin.init();
322
  });
host-webfonts-local.php CHANGED
@@ -4,8 +4,8 @@
4
  * Plugin Name: OMGF
5
  * Plugin URI: https://daan.dev/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.2
8
- * Author: Daan from FFW.Press
9
  * Author URI: https://daan.dev
10
  * License: GPL2v2 or later
11
  * Text Domain: host-webfonts-local
4
  * Plugin Name: OMGF
5
  * Plugin URI: https://daan.dev/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.3.0
8
+ * Author: Daan from Daan.dev
9
  * Author URI: https://daan.dev
10
  * License: GPL2v2 or later
11
  * Text Domain: host-webfonts-local
includes/admin/class-optimize.php CHANGED
@@ -74,7 +74,7 @@ class OMGF_Admin_Optimize
74
  */
75
  public function verify_ssl($args)
76
  {
77
- $args['sslverify'] = strpos(home_url(), 'https:') !== false;
78
 
79
  return $args;
80
  }
74
  */
75
  public function verify_ssl($args)
76
  {
77
+ $args['sslverify'] = strpos(get_home_url(), 'https:') !== false;
78
 
79
  return $args;
80
  }
includes/admin/class-settings.php CHANGED
@@ -46,14 +46,7 @@ class OMGF_Admin_Settings extends OMGF_Admin
46
  'fallback' => 'Fallback',
47
  'optional' => 'Optional'
48
  ];
49
- const OMGF_FILE_TYPES_OPTIONS = [
50
- 'woff2' => 'Web Open Font Format 2.0 (WOFF2)',
51
- 'woff' => 'Web Open Font Format (WOFF)',
52
- 'eot' => 'Embedded OpenType (EOT)',
53
- 'ttf' => 'TrueType Font (TTF)',
54
- 'svg' => 'Scalable Vector Graphics (SVG)'
55
- ];
56
- const OMGF_FORCE_SUBSETS_OPTIONS = [
57
  'arabic' => 'Arabic',
58
  'bengali' => 'Bengali',
59
  'chinese-hongkong' => 'Chinese (Hong Kong)',
@@ -121,6 +114,7 @@ class OMGF_Admin_Settings extends OMGF_Admin
121
  * Optimize Fonts
122
  */
123
  const OMGF_OPTIMIZE_SETTING_DISPLAY_OPTION = 'omgf_display_option';
 
124
  const OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS = 'omgf_optimized_fonts';
125
  const OMGF_OPTIMIZE_SETTING_PRELOAD_FONTS = 'omgf_preload_fonts';
126
  const OMGF_OPTIMIZE_SETTING_UNLOAD_FONTS = 'omgf_unload_fonts';
@@ -429,7 +423,7 @@ class OMGF_Admin_Settings extends OMGF_Admin
429
  */
430
  public function footer_text_left()
431
  {
432
- $text = sprintf(__('Coded with %s in The Netherlands @ <strong>FFW.Press</strong>.', $this->plugin_text_domain), '<span class="dashicons dashicons-heart ffwp-heart"></span>');
433
 
434
  return '<span id="footer-thankyou">' . $text . '</span>';
435
  }
46
  'fallback' => 'Fallback',
47
  'optional' => 'Optional'
48
  ];
49
+ const OMGF_SUBSETS = [
 
 
 
 
 
 
 
50
  'arabic' => 'Arabic',
51
  'bengali' => 'Bengali',
52
  'chinese-hongkong' => 'Chinese (Hong Kong)',
114
  * Optimize Fonts
115
  */
116
  const OMGF_OPTIMIZE_SETTING_DISPLAY_OPTION = 'omgf_display_option';
117
+ const OMGF_OPTIMIZE_SETTING_SUBSETS = 'omgf_subsets';
118
  const OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS = 'omgf_optimized_fonts';
119
  const OMGF_OPTIMIZE_SETTING_PRELOAD_FONTS = 'omgf_preload_fonts';
120
  const OMGF_OPTIMIZE_SETTING_UNLOAD_FONTS = 'omgf_unload_fonts';
423
  */
424
  public function footer_text_left()
425
  {
426
+ $text = sprintf(__('Coded with %s in The Netherlands @ <strong>Daan.dev</strong>.', $this->plugin_text_domain), '❤️');
427
 
428
  return '<span id="footer-thankyou">' . $text . '</span>';
429
  }
includes/admin/settings/class-advanced.php CHANGED
@@ -85,7 +85,7 @@ class OMGF_Admin_Settings_Advanced extends OMGF_Admin_Settings_Builder
85
  __("Modify the <code>src</code> attribute for font files and stylesheets generated by OMGF Pro. This can be anything; from an absolute URL pointing to your CDN (e.g. <code>%s</code>) to an alternate relative URL (e.g. <code>/renamed-wp-content-dir/alternate/path/to/font-files</code>) to work with <em>security thru obscurity</em> plugins. Enter the full path to OMGF's files. Default: (empty)", $this->plugin_text_domain),
86
  'https://your-cdn.com/wp-content/uploads/omgf'
87
  ) . ' ' . $this->promo,
88
- true
89
  );
90
  }
91
 
85
  __("Modify the <code>src</code> attribute for font files and stylesheets generated by OMGF Pro. This can be anything; from an absolute URL pointing to your CDN (e.g. <code>%s</code>) to an alternate relative URL (e.g. <code>/renamed-wp-content-dir/alternate/path/to/font-files</code>) to work with <em>security thru obscurity</em> plugins. Enter the full path to OMGF's files. Default: (empty)", $this->plugin_text_domain),
86
  'https://your-cdn.com/wp-content/uploads/omgf'
87
  ) . ' ' . $this->promo,
88
+ !defined('OMGF_PRO_SOURCE_URL')
89
  );
90
  }
91
 
includes/admin/settings/class-builder.php CHANGED
@@ -127,7 +127,7 @@ class OMGF_Admin_Settings_Builder
127
  <?= apply_filters($name . '_setting_label', $label); ?>
128
  </th>
129
  <td>
130
- <select name="<?= $name; ?><?= $is_multiselect ? '[]' : ''; ?>" class="<?= str_replace('_', '-', $name); ?>" <?= $is_multiselect ? 'size="8" multiple="multiple"' : ''; ?> <?= apply_filters($name . '_setting_disabled', $disabled) ? 'disabled' : ''; ?>>
131
  <?php
132
  $options = apply_filters($name . '_setting_options', $options);
133
  ?>
127
  <?= apply_filters($name . '_setting_label', $label); ?>
128
  </th>
129
  <td>
130
+ <select name="<?= $name; ?><?= $is_multiselect ? '[]' : ''; ?>" class="<?= str_replace('_', '-', $name); ?>" <?= $is_multiselect ? 'size="6" multiple="multiple"' : ''; ?> <?= apply_filters($name . '_setting_disabled', $disabled) ? 'disabled' : ''; ?>>
131
  <?php
132
  $options = apply_filters($name . '_setting_options', $options);
133
  ?>
includes/admin/settings/class-detection.php CHANGED
@@ -31,7 +31,7 @@ class OMGF_Admin_Settings_Detection extends OMGF_Admin_Settings_Builder
31
 
32
  // Settings
33
  add_filter('omgf_detection_settings_content', [$this, 'google_fonts_processing'], 30);
34
- add_filter('omgf_detection_settings_content', [$this, 'advanced_processing_promo'], 60);
35
 
36
  // Close
37
  add_filter('omgf_detection_settings_content', [$this, 'do_after'], 100);
@@ -69,7 +69,7 @@ class OMGF_Admin_Settings_Detection extends OMGF_Admin_Settings_Builder
69
  /**
70
  *
71
  */
72
- public function advanced_processing_promo()
73
  {
74
  ?>
75
  <tr>
@@ -79,7 +79,7 @@ class OMGF_Admin_Settings_Detection extends OMGF_Admin_Settings_Builder
79
  <?php foreach ($this->advanced_processing_pro_options() as $name => $data) : ?>
80
  <?php
81
  $checked = defined(strtoupper($name)) ? constant(strtoupper($name)) : false;
82
- $disabled = apply_filters($name . '_setting_disabled', true) ? 'disabled' : '';
83
  ?>
84
  <label for="<?= $name; ?>">
85
  <input type="checkbox" name="<?= $name; ?>" id="<?= $name; ?>" <?= $checked ? 'checked="checked"' : ''; ?> <?= $disabled; ?> /><?= $data['label']; ?>
31
 
32
  // Settings
33
  add_filter('omgf_detection_settings_content', [$this, 'google_fonts_processing'], 30);
34
+ add_filter('omgf_detection_settings_content', [$this, 'promo_advanced_processing'], 60);
35
 
36
  // Close
37
  add_filter('omgf_detection_settings_content', [$this, 'do_after'], 100);
69
  /**
70
  *
71
  */
72
+ public function promo_advanced_processing()
73
  {
74
  ?>
75
  <tr>
79
  <?php foreach ($this->advanced_processing_pro_options() as $name => $data) : ?>
80
  <?php
81
  $checked = defined(strtoupper($name)) ? constant(strtoupper($name)) : false;
82
+ $disabled = !defined(strtoupper($name)) ? 'disabled' : '';
83
  ?>
84
  <label for="<?= $name; ?>">
85
  <input type="checkbox" name="<?= $name; ?>" id="<?= $name; ?>" <?= $checked ? 'checked="checked"' : ''; ?> <?= $disabled; ?> /><?= $data['label']; ?>
includes/admin/settings/class-help.php CHANGED
@@ -65,9 +65,9 @@ class OMGF_Admin_Settings_Help extends OMGF_Admin_Settings_Builder
65
  </ul>
66
  </div>
67
  <div class="column last">
68
- <h3 class="signature"><?= sprintf(__('Coded with %s by', $this->plugin_text_domain), '<i class="dashicons dashicons-heart"></i>'); ?> </h3>
69
  <p class="signature">
70
- <a target="_blank" title="<?= __('Visit FFW Press', $this->plugin_text_domain); ?>" href="https://daan.dev/wordpress-plugins/"><img class="signature-image" alt="<?= __('Visit FFW Press', $this->plugin_text_domain); ?>" src="<?= plugin_dir_url(OMGF_PLUGIN_FILE) . 'assets/images/logo-color.png'; ?>" /></a>
71
  </p>
72
  </div>
73
  </div>
65
  </ul>
66
  </div>
67
  <div class="column last">
68
+ <h3 class="signature"><?= sprintf(__('Coded with %s by', $this->plugin_text_domain), '❤️'); ?> </h3>
69
  <p class="signature">
70
+ <a target="_blank" title="<?= __('Visit Daan.dev', $this->plugin_text_domain); ?>" href="https://daan.dev/wordpress-plugins/"><img class="signature-image" alt="<?= __('Visit Daan.dev', $this->plugin_text_domain); ?>" src="<?= plugin_dir_url(OMGF_PLUGIN_FILE) . 'assets/images/logo.png'; ?>" /></a>
71
  </p>
72
  </div>
73
  </div>
includes/admin/settings/class-optimize.php CHANGED
@@ -42,10 +42,10 @@ class OMGF_Admin_Settings_Optimize extends OMGF_Admin_Settings_Builder
42
  add_filter('omgf_optimize_settings_content', [$this, 'close_task_manager'], 27);
43
 
44
  add_filter('omgf_optimize_settings_content', [$this, 'do_before'], 30);
45
- add_filter('omgf_optimize_settings_content', [$this, 'do_display_option'], 50);
46
- add_filter('omgf_optimize_settings_content', [$this, 'do_promo_force_font_display'], 60);
47
- add_filter('omgf_optimize_settings_content', [$this, 'do_promo_include_file_types'], 70);
48
- add_filter('omgf_optimize_settings_content', [$this, 'do_promo_force_subsets'], 80);
49
  add_filter('omgf_optimize_settings_content', [$this, 'do_after'], 100);
50
 
51
  add_filter('omgf_optimize_settings_content', [$this, 'do_optimize_fonts_container'], 200);
@@ -178,47 +178,46 @@ class OMGF_Admin_Settings_Optimize extends OMGF_Admin_Settings_Builder
178
  /**
179
  * Force Font-Display Option Site Wide
180
  */
181
- public function do_promo_force_font_display()
182
  {
183
  $this->do_checkbox(
184
- __('Force Font-Display Option Site Wide (Pro)', $this->plugin_text_domain),
185
  'omgf_pro_force_font_display',
186
  defined('OMGF_PRO_FORCE_FONT_DISPLAY') ? OMGF_PRO_FORCE_FONT_DISPLAY : false,
187
- __('Force the above <code>font-display</code> attribute on all <code>@font-face</code> statements to ensure all text is user-visible while webfonts and icon sets are loading.', $this->plugin_text_domain),
188
- true
189
  );
190
  }
191
 
192
  /**
193
- * Display WOFF2 Only
194
  *
195
  * @return void
196
  */
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 : [],
204
- __('Select which file types should be included in the stylesheet. Loading <strong>WOFF2</strong> files only will result in a smaller stylesheet, but will make the stylesheet slightly less Cross Browser compatible. Using <strong>WOFF</strong> and <strong>WOFF2</strong> together (default) accounts for +98% of browsers. Add <strong>EOT</strong> for IE 6-10 and <strong>TTF</strong> and <strong>SVG</strong> for legacy Android/iOS browsers. <em>Use CTRL + click to select multiple values</em>.', $this->plugin_text_domain) . ' ' . $this->promo,
205
- true,
206
- true
207
  );
208
  }
209
 
210
  /**
211
- *
 
 
212
  */
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 : [],
220
- __('By default, Google Fonts are loaded in all subsets, which results in unnecessarily large stylesheets. Use this option to force all Google Fonts to be loaded in the selected subset(s). <em>Use CTRL + click to select multiple values</em>.', $this->plugin_text_domain) . ' ' . $this->promo,
221
- true,
222
  true
223
  );
224
  }
@@ -292,15 +291,12 @@ class OMGF_Admin_Settings_Optimize extends OMGF_Admin_Settings_Builder
292
  </tr>
293
  <?php foreach ($fonts as $font) : ?>
294
  <?php if (!is_object($font) || count((array) $font->variants) <= 0) continue; ?>
295
- <?php
296
- $aka = in_array($font->id, OMGF_Optimize::OMGF_RENAMED_GOOGLE_FONTS) ? array_search($font->id, OMGF_Optimize::OMGF_RENAMED_GOOGLE_FONTS) : '';
297
- ?>
298
  <tr class="font-family" data-id="<?= $handle . '-' . $font->id; ?>">
299
  <td colspan="5">
300
- <span class="family"><em><?= rawurldecode($font->family); ?><?= $aka ? ' (' . sprintf(__('formerly known as <strong>%s</strong>', $this->plugin_text_domain) . ')', ucfirst($aka)) : ''; ?></em></span> <span class="unload-mass-action">(<a href="#" class="unload-italics"><?= __('Unload italics', $this->plugin_text_domain); ?></a> <span class="dashicons dashicons-info tooltip"><span class="tooltip-text"><?= __('In most situations you can safely unload all Italic font styles. Modern browsers are capable of mimicking Italic font styles.', $this->plugin_text_domain); ?></span></span> | <a href="#" class="unload-all"><?= __('Unload all', $this->plugin_text_domain); ?></a> | <a href="#" class="load-all"><?= __('Load all', $this->plugin_text_domain); ?></a>)</span>
301
  </td>
302
  <td class="fallback-font-stack">
303
- <select data-handle="<?= $handle; ?>" <?= apply_filters('omgf_pro_fallback_font_stack_setting_disabled', true) ? 'disabled' : ''; ?> name="omgf_pro_fallback_font_stack[<?= $handle; ?>][<?= $font->id; ?>]">
304
  <option value=''><?= __('None (default)', $this->plugin_text_domain); ?></option>
305
  <?php foreach (OMGF_Admin_Settings::OMGF_FALLBACK_FONT_STACKS_OPTIONS as $value => $label) : ?>
306
  <option <?= defined('OMGF_PRO_FALLBACK_FONT_STACK') && isset(OMGF_PRO_FALLBACK_FONT_STACK[$handle][$font->id]) && OMGF_PRO_FALLBACK_FONT_STACK[$handle][$font->id] == $value ? 'selected' : ''; ?> value="<?= $value; ?>"><?= $label; ?></option>
@@ -312,7 +308,7 @@ class OMGF_Admin_Settings_Optimize extends OMGF_Admin_Settings_Builder
312
  $replace = defined('OMGF_PRO_REPLACE_FONT') && isset(OMGF_PRO_REPLACE_FONT[$handle][$font->id]) && OMGF_PRO_REPLACE_FONT[$handle][$font->id] == 'on' ? 'checked' : '';
313
  $fallback = defined('OMGF_PRO_FALLBACK_FONT_STACK') && isset(OMGF_PRO_FALLBACK_FONT_STACK[$handle][$font->id]) && OMGF_PRO_FALLBACK_FONT_STACK[$handle][$font->id] !== '';
314
  ?>
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 = ''; ?>
@@ -325,6 +321,9 @@ class OMGF_Admin_Settings_Optimize extends OMGF_Admin_Settings_Builder
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
  ?>
42
  add_filter('omgf_optimize_settings_content', [$this, 'close_task_manager'], 27);
43
 
44
  add_filter('omgf_optimize_settings_content', [$this, 'do_before'], 30);
45
+ add_filter('omgf_optimize_settings_content', [$this, 'do_display_option'], 40);
46
+ add_filter('omgf_optimize_settings_content', [$this, 'do_promo_apply_font_display_globally'], 50);
47
+ add_filter('omgf_optimize_settings_content', [$this, 'do_promo_remove_async_google_fonts'], 60);
48
+ add_filter('omgf_optimize_settings_content', [$this, 'do_use_subsets'], 70);
49
  add_filter('omgf_optimize_settings_content', [$this, 'do_after'], 100);
50
 
51
  add_filter('omgf_optimize_settings_content', [$this, 'do_optimize_fonts_container'], 200);
178
  /**
179
  * Force Font-Display Option Site Wide
180
  */
181
+ public function do_promo_apply_font_display_globally()
182
  {
183
  $this->do_checkbox(
184
+ __('Apply Font-Display Option Globally (Pro)', $this->plugin_text_domain),
185
  'omgf_pro_force_font_display',
186
  defined('OMGF_PRO_FORCE_FONT_DISPLAY') ? OMGF_PRO_FORCE_FONT_DISPLAY : false,
187
+ __('Apply the above <code>font-display</code> attribute value to all <code>@font-face</code> statements found on your site to <strong>ensure text remains visible during webfont load</strong>.', $this->plugin_text_domain),
188
+ !defined('OMGF_PRO_FORCE_FONT_DISPLAY')
189
  );
190
  }
191
 
192
  /**
193
+ * Block Async Google Fonts option
194
  *
195
  * @return void
196
  */
197
+ public function do_promo_remove_async_google_fonts()
198
  {
199
+ $this->do_checkbox(
200
+ __('Remove Async Google Fonts (Pro)', $this->plugin_text_domain),
201
+ 'omgf_pro_remove_async_fonts',
202
+ defined('OMGF_PRO_REMOVE_ASYNC_FONTS') ? OMGF_PRO_REMOVE_ASYNC_FONTS : false,
203
+ sprintf(__('Remove Google Fonts loaded (asynchronously) by (3rd party) JavaScript libraries used by some themes/plugins. This won\'t work with embedded content (i.e. <code>iframe</code>). <strong>Warning!</strong> Make sure you load the Google Fonts, <a href="%s">either manually</a> or by using a plugin (like <a href="%s" target="_blank">Additional Fonts</a>) to prevent styling breaks.', $this->plugin_text_domain), 'https://daan.dev/docs/omgf-pro/remove-async-google-fonts/', 'https://daan.dev/wordpress/omgf-additional-fonts/'),
204
+ !defined('OMGF_PRO_REMOVE_ASYNC_FONTS')
 
 
205
  );
206
  }
207
 
208
  /**
209
+ * Preload Subsets
210
+ *
211
+ * @return void
212
  */
213
+ public function do_use_subsets()
214
  {
215
  $this->do_select(
216
+ __('Used Subset(s)', $this->plugin_text_domain),
217
+ OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_SUBSETS,
218
+ OMGF_Admin_Settings::OMGF_SUBSETS,
219
+ OMGF_SUBSETS,
220
+ __('Select which subset(s) sgould be used when generating stylesheets and preloads. Default: <code>latin</code>, <code>latin-ext</code>. Limit the selection to subsets your site actually uses. Selecting <u>too many</u> subsets can negatively impact performance! <em>Use CTRL + click to select multiple values.</em>', $this->plugin_text_domain),
 
221
  true
222
  );
223
  }
291
  </tr>
292
  <?php foreach ($fonts as $font) : ?>
293
  <?php if (!is_object($font) || count((array) $font->variants) <= 0) continue; ?>
 
 
 
294
  <tr class="font-family" data-id="<?= $handle . '-' . $font->id; ?>">
295
  <td colspan="5">
296
+ <span class="family"><em><?= rawurldecode($font->family); ?></em></span> <span class="unload-mass-action">(<a class="unload-italics"><?= __('Unload italics', $this->plugin_text_domain); ?></a> <span class="dashicons dashicons-info tooltip"><span class="tooltip-text"><?= __('In most situations you can safely unload all Italic font styles. Modern browsers are capable of mimicking Italic font styles.', $this->plugin_text_domain); ?></span></span> | <a class="unload-all"><?= __('Unload all', $this->plugin_text_domain); ?></a> | <a class="load-all"><?= __('Load all', $this->plugin_text_domain); ?></a>)</span>
297
  </td>
298
  <td class="fallback-font-stack">
299
+ <select data-handle="<?= $handle; ?>" <?= !defined('OMGF_PRO_FALLBACK_FONT_STACK') ? 'disabled' : ''; ?> name="omgf_pro_fallback_font_stack[<?= $handle; ?>][<?= $font->id; ?>]">
300
  <option value=''><?= __('None (default)', $this->plugin_text_domain); ?></option>
301
  <?php foreach (OMGF_Admin_Settings::OMGF_FALLBACK_FONT_STACKS_OPTIONS as $value => $label) : ?>
302
  <option <?= defined('OMGF_PRO_FALLBACK_FONT_STACK') && isset(OMGF_PRO_FALLBACK_FONT_STACK[$handle][$font->id]) && OMGF_PRO_FALLBACK_FONT_STACK[$handle][$font->id] == $value ? 'selected' : ''; ?> value="<?= $value; ?>"><?= $label; ?></option>
308
  $replace = defined('OMGF_PRO_REPLACE_FONT') && isset(OMGF_PRO_REPLACE_FONT[$handle][$font->id]) && OMGF_PRO_REPLACE_FONT[$handle][$font->id] == 'on' ? 'checked' : '';
309
  $fallback = defined('OMGF_PRO_FALLBACK_FONT_STACK') && isset(OMGF_PRO_FALLBACK_FONT_STACK[$handle][$font->id]) && OMGF_PRO_FALLBACK_FONT_STACK[$handle][$font->id] !== '';
310
  ?>
311
+ <input autocomplete="off" type="checkbox" class="replace" <?= $replace; ?> <?= $fallback ? '' : 'disabled'; ?> <?= !defined('OMGF_PRO_REPLACE_FONT') ? 'disabled' : ''; ?> name="omgf_pro_replace_font[<?= $handle; ?>][<?= $font->id; ?>]" />
312
  </td>
313
  </tr>
314
  <?php $id = ''; ?>
321
  * This deals with the duplicate display of font styles. Which also
322
  * means unloading and/or preloading will unload/preload all available
323
  * subsets. It's a bit bloaty, but there's no alternative.
324
+ *
325
+ * To better deal with this, I've introduced the Used Subset(s) feature
326
+ * in this version.
327
  */
328
  if ($id == $variant->fontWeight . $variant->fontStyle) continue;
329
  ?>
includes/class-omgf.php CHANGED
@@ -56,6 +56,7 @@ class OMGF
56
  define('OMGF_CACHE_IS_STALE', esc_attr(get_option(OMGF_Admin_Settings::OMGF_CACHE_IS_STALE)));
57
  define('OMGF_CURRENT_DB_VERSION', esc_attr(get_option(OMGF_Admin_Settings::OMGF_CURRENT_DB_VERSION)));
58
  define('OMGF_DISPLAY_OPTION', esc_attr(get_option(OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_DISPLAY_OPTION, 'swap')) ?: 'swap');
 
59
  define('OMGF_UNLOAD_STYLESHEETS', esc_attr(get_option(OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_UNLOAD_STYLESHEETS, '')));
60
  define('OMGF_CACHE_KEYS', esc_attr(get_option(OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_CACHE_KEYS, '')));
61
  define('OMGF_TEST_MODE', esc_attr(get_option(OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_TEST_MODE)));
@@ -65,6 +66,22 @@ class OMGF
65
  define('OMGF_UPLOAD_URL', apply_filters('omgf_upload_url', WP_CONTENT_URL . '/uploads/omgf'));
66
  }
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  /**
69
  * Needs to run before admin_menu and admin_init.
70
  *
@@ -141,7 +158,7 @@ class OMGF
141
  /**
142
  * If the user entered https:// in the Home URL option, it's safe to assume that SSL is used.
143
  */
144
- if (!is_ssl() && strpos(get_site_url(), 'https://') !== false) {
145
  $url = str_replace('http://', 'https://', $url);
146
  }
147
 
@@ -191,7 +208,7 @@ class OMGF
191
  *
192
  * @return array
193
  */
194
- public static function optimized_fonts($maybe_add = [])
195
  {
196
  /** @var array $optimized_fonts Cache layer */
197
  static $optimized_fonts;
@@ -217,7 +234,7 @@ class OMGF
217
  *
218
  * @since v4.5.7
219
  */
220
- if (!empty($maybe_add) && !isset($optimized_fonts[key($maybe_add)])) {
221
  $optimized_fonts = array_merge($optimized_fonts, $maybe_add);
222
  }
223
 
@@ -323,9 +340,9 @@ class OMGF
323
  *
324
  * @return string
325
  */
326
- public static function generate_stylesheet($fonts, $handle = '', $plugin = 'OMGF')
327
  {
328
- $generator = new OMGF_StylesheetGenerator($fonts, $handle, $plugin);
329
 
330
  return $generator->generate();
331
  }
56
  define('OMGF_CACHE_IS_STALE', esc_attr(get_option(OMGF_Admin_Settings::OMGF_CACHE_IS_STALE)));
57
  define('OMGF_CURRENT_DB_VERSION', esc_attr(get_option(OMGF_Admin_Settings::OMGF_CURRENT_DB_VERSION)));
58
  define('OMGF_DISPLAY_OPTION', esc_attr(get_option(OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_DISPLAY_OPTION, 'swap')) ?: 'swap');
59
+ define('OMGF_SUBSETS', $this->esc_array(get_option(OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_SUBSETS, ['latin', 'latin-ext'])) ?: ['latin', 'latin-ext']);
60
  define('OMGF_UNLOAD_STYLESHEETS', esc_attr(get_option(OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_UNLOAD_STYLESHEETS, '')));
61
  define('OMGF_CACHE_KEYS', esc_attr(get_option(OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_CACHE_KEYS, '')));
62
  define('OMGF_TEST_MODE', esc_attr(get_option(OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_TEST_MODE)));
66
  define('OMGF_UPLOAD_URL', apply_filters('omgf_upload_url', WP_CONTENT_URL . '/uploads/omgf'));
67
  }
68
 
69
+ /**
70
+ * Escape each value of an option array.
71
+ */
72
+ private function esc_array($array)
73
+ {
74
+ if (!is_array($array)) {
75
+ return [];
76
+ }
77
+
78
+ foreach ($array as &$element) {
79
+ $element = esc_attr($element);
80
+ }
81
+
82
+ return $array;
83
+ }
84
+
85
  /**
86
  * Needs to run before admin_menu and admin_init.
87
  *
158
  /**
159
  * If the user entered https:// in the Home URL option, it's safe to assume that SSL is used.
160
  */
161
+ if (!is_ssl() && strpos(get_home_url(), 'https://') !== false) {
162
  $url = str_replace('http://', 'https://', $url);
163
  }
164
 
208
  *
209
  * @return array
210
  */
211
+ public static function optimized_fonts($maybe_add = [], $force_add = false)
212
  {
213
  /** @var array $optimized_fonts Cache layer */
214
  static $optimized_fonts;
234
  *
235
  * @since v4.5.7
236
  */
237
+ if (!empty($maybe_add) && (!isset($optimized_fonts[key($maybe_add)]) || $force_add)) {
238
  $optimized_fonts = array_merge($optimized_fonts, $maybe_add);
239
  }
240
 
340
  *
341
  * @return string
342
  */
343
+ public static function generate_stylesheet($fonts, $plugin = 'OMGF')
344
  {
345
+ $generator = new OMGF_StylesheetGenerator($fonts, $plugin);
346
 
347
  return $generator->generate();
348
  }
includes/class-optimize.php CHANGED
@@ -18,34 +18,12 @@ defined('ABSPATH') || exit;
18
 
19
  class OMGF_Optimize
20
  {
21
- const OMGF_GOOGLE_FONTS_API_URL = 'https://google-webfonts-helper.herokuapp.com/api/fonts/';
22
- const OMGF_GOOGLE_FONTS_API_FALLBACK = 'https://omgf-google-fonts-api.herokuapp.com/api/fonts/';
23
- const OMGF_USE_FALLBACK_API_TRANSIENT = 'omgf_use_fallback_api';
24
-
25
- /**
26
- * If a font changed names recently, this array will map the old name (key) to the new name (value).
27
- *
28
- * The key of an element should be dashed (no spaces) if necessary, e.g. open-sans.
29
- */
30
- const OMGF_RENAMED_GOOGLE_FONTS = [
31
- 'crimson-text' => 'crimson-pro',
32
- 'ek-mukta' => 'mukta',
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
 
50
  /** @var string */
51
  private $handle = '';
@@ -53,56 +31,51 @@ class OMGF_Optimize
53
  /** @var string $original_handle */
54
  private $original_handle = '';
55
 
56
- /** @var string $subset */
57
- private $subset = '';
58
-
59
  /** @var string $return */
60
  private $return = 'url';
61
 
 
 
 
62
  /** @var string */
63
  private $path = '';
64
 
 
 
 
 
 
 
 
65
  /** @var string */
66
  private $plugin_text_domain = 'host-webfonts-local';
67
 
68
  /**
69
- * @param string $family Contents of "family" parameters in Google Fonts API URL, e.g. "?family="Lato:100,200,300,etc."
70
  * @param string $handle The cache handle, generated using $handle + 5 random chars. Used for storing the fonts and stylesheet.
71
  * @param string $original_handle The stylesheet handle, present in the ID attribute.
72
- * @param string $subset Contents of "subset" parameter. If left empty, the downloaded files will support all subsets.
73
  * @param string $return Valid values: 'url' | 'path' | 'object'.
74
- *
75
- * @return string Local URL of generated stylesheet.
76
- *
77
- * @throws SodiumException
78
- * @throws SodiumException
79
- * @throws TypeError
80
- * @throws TypeError
81
- * @throws TypeError
82
  */
83
  public function __construct(
84
- string $family,
85
  string $handle,
86
  string $original_handle,
87
- string $subset = '',
88
- string $return = 'url'
89
  ) {
90
- $this->family = $family;
91
  $this->handle = sanitize_title_with_dashes($handle);
92
  $this->original_handle = sanitize_title_with_dashes($original_handle);
93
- $this->subset = $subset;
94
  $this->path = OMGF_UPLOAD_DIR . '/' . $this->handle;
95
  $this->return = $return;
 
96
  }
97
 
98
  /**
99
  * @return string|array
100
- *
101
- * @throws SodiumException
102
- * @throws SodiumException
103
- * @throws TypeError
104
- * @throws TypeError
105
- * @throws TypeError
106
  */
107
  public function process()
108
  {
@@ -112,79 +85,38 @@ class OMGF_Optimize
112
  return '';
113
  }
114
 
115
- $font_families = explode('|', $this->family);
116
- $query = [];
117
- $fonts = [];
118
-
119
- if ($this->subset) {
120
- $query['subsets'] = $this->subset;
121
- }
122
-
123
- foreach ($font_families as $key => $font_family) {
124
- /**
125
- * Prevent duplicate entries by generating a unique identifier, all lowercase,
126
- * with (multiple) spaces replaced by dashes.
127
- *
128
- * @since v5.1.4
129
- */
130
- $font_name = explode(':', $font_family)[0];
131
- $font_id = strtolower(preg_replace("/[\s\+]+/", '-', $font_name));
132
-
133
- $font_families[$font_id] = $font_family;
134
- unset($font_families[$key]);
135
  }
136
 
137
- foreach ($font_families as $font_id => $font_family) {
138
- if (empty($font_family)) {
139
- continue;
140
- }
141
 
142
- if (!isset($fonts[$font_id])) {
143
- $fonts[$font_id] = $this->grab_font_object($font_id, $query, $font_name);
 
 
 
 
 
 
 
 
 
144
  }
145
  }
146
 
147
- // Filter out empty elements, i.e. failed requests.
148
- $fonts = array_filter($fonts);
 
149
 
150
  if (empty($fonts)) {
151
  return '';
152
  }
153
 
154
  foreach ($fonts as $id => &$font) {
155
- $fonts_request = $font_families[$id];
156
-
157
- /**
158
- * If no colon is found, @var string $requested_variants will be an empty string.
159
- *
160
- * @since v5.1.4
161
- */
162
- list(, $requested_variants) = array_pad(explode(':', $fonts_request), 2, '');
163
-
164
- $requested_variants = $this->parse_requested_variants($requested_variants, $font);
165
-
166
- if ($unloaded_fonts = OMGF::unloaded_fonts()) {
167
- $font_id = $font->id;
168
-
169
- // Now we're sure we got 'em all. We can safely dequeue those we don't want.
170
- if (isset($unloaded_fonts[$this->original_handle][$font_id])) {
171
- $requested_variants = $this->dequeue_unloaded_variants($requested_variants, $unloaded_fonts[$this->original_handle], $font->id);
172
- }
173
- }
174
-
175
- $font->variants = $this->process_unload_queue($font->id, $font->variants, $requested_variants, $this->original_handle);
176
- }
177
-
178
- /**
179
- * Which file types should we download and include in the stylesheet?
180
- *
181
- * @since v4.5
182
- */
183
- $file_types = apply_filters('omgf_include_file_types', ['woff2', 'woff', 'eot', 'ttf', 'svg']);
184
-
185
- foreach ($fonts as &$font) {
186
- $font_id = $font->id;
187
-
188
  /**
189
  * Sanitize font family, because it may contain spaces.
190
  *
@@ -192,8 +124,15 @@ class OMGF_Optimize
192
  */
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.
@@ -202,16 +141,22 @@ class OMGF_Optimize
202
  */
203
  $variant->fontFamily = rawurlencode($variant->fontFamily);
204
 
205
- foreach ($file_types as $file_type) {
206
- if (isset($variant->$file_type)) {
207
- $variant->$file_type = OMGF::download($variant->$file_type, $filename, $file_type, $this->path);
208
- }
 
 
 
 
 
 
 
209
  }
210
  }
211
  }
212
 
213
- $local_file = $this->path . '/' . $this->handle . '.css';
214
- $stylesheet = OMGF::generate_stylesheet($fonts, $this->original_handle);
215
 
216
  if (!file_exists($this->path)) {
217
  wp_mkdir_p($this->path);
@@ -219,21 +164,15 @@ class OMGF_Optimize
219
 
220
  file_put_contents($local_file, $stylesheet);
221
 
222
- $current_stylesheet = [$this->original_handle => $fonts];
 
223
 
224
  /**
225
  * $current_stylesheet is added to temporary cache layer, if it isn't present in database.
226
  *
227
  * @since v4.5.7
228
  */
229
- $optimized_fonts = OMGF::optimized_fonts($current_stylesheet);
230
-
231
- /**
232
- * When unload is used, this takes care of rewriting the font style URLs in the database.
233
- *
234
- * @since v4.5.7
235
- */
236
- $optimized_fonts = $this->rewrite_variants($optimized_fonts, $current_stylesheet);
237
 
238
  update_option(OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS, $optimized_fonts);
239
 
@@ -250,196 +189,49 @@ class OMGF_Optimize
250
  }
251
 
252
  /**
253
- * @param $variants
254
- * @param $unloaded_fonts
255
- * @param $font_id
256
- *
257
- * @return array
258
- */
259
- private function dequeue_unloaded_variants($variants, $unloaded_fonts, $font_id)
260
- {
261
- return array_filter(
262
- $variants,
263
- function ($variant) use ($unloaded_fonts, $font_id) {
264
- if ($variant == '400') {
265
- // Sometimes the font is defined as 'regular', so we need to check both.
266
- return !in_array('regular', $unloaded_fonts[$font_id]) && !in_array($variant, $unloaded_fonts[$font_id]);
267
- }
268
-
269
- if ($variant == '400italic') {
270
- // Sometimes the font is defined as 'italic', so we need to check both.
271
- return !in_array('italic', $unloaded_fonts[$font_id]) && !in_array($variant, $unloaded_fonts[$font_id]);
272
- }
273
-
274
- return !in_array($variant, $unloaded_fonts[$font_id]);
275
- }
276
- );
277
- }
278
-
279
- /**
280
- * @param $id Unique identifier for this Font Family, lowercase, dashes instead of spaces.
281
- * @param $query
282
- * @param $name The full name of the requested Font Family, e.g. Roboto Condensed, Open Sans or Roboto.
283
  *
284
- * @return mixed|void
285
  */
286
- private function grab_font_object($id, $query, $name)
287
  {
288
- /**
289
- * Add fonts to the request's $_GET 'family' parameter. Then pass an array to 'omgf_alternate_fonts'
290
- * filter. Then pass an alternate API url to the 'omgf_alternate_api_url' filter to fetch fonts from
291
- * an alternate API.
292
- */
293
- $alternate_fonts = apply_filters('omgf_alternate_fonts', []);
294
- $alternate_url = '';
295
- $query_string = '';
296
-
297
- if (in_array($id, array_keys($alternate_fonts))) {
298
- $alternate_url = apply_filters('omgf_alternate_api_url', '', $id);
299
- unset($query);
300
- }
301
-
302
- if (!empty($query)) {
303
- $query_string = '?' . http_build_query($query);
304
- }
305
-
306
- /**
307
- * If a font changed names recently, map their old name to the new name, before triggering the API request.
308
- */
309
- if (in_array($id, array_keys(self::OMGF_RENAMED_GOOGLE_FONTS))) {
310
- $id = self::OMGF_RENAMED_GOOGLE_FONTS[$id];
311
- }
312
-
313
- if (!$alternate_url) {
314
- $response = $this->remote_get($id, $query_string);
315
- } else {
316
- $response = wp_remote_get(
317
- sprintf($alternate_url . '%s', $id) . $query_string
318
- );
319
- }
320
-
321
- if (is_wp_error($response)) {
322
- OMGF_Admin_Notice::set_notice(sprintf(__('OMGF encountered an error while trying to fetch fonts: %s', $this->plugin_text_domain), $response->get_error_message()), $response->get_error_code(), 'error', 408);
323
- }
324
-
325
- /**
326
- * If no subset was set, do a quick refresh to make sure all available subsets are included.
327
- */
328
- if (!$query_string && !$alternate_url) {
329
- $response_body = wp_remote_retrieve_body($response);
330
- $body = json_decode($response_body);
331
- $query_string = '?subsets=' . (isset($body->subsets) ? implode(',', $body->subsets) : 'latin,latin-ext');
332
- $response = $this->remote_get($id, $query_string);
333
- }
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);
347
- $message = sprintf(__('OMGF couldn\'t find <strong>%s</strong> while parsing %s. The API returned the following error: %s.', $this->plugin_text_domain), $name, isset($_GET['omgf_optimize']) ? 'your homepage' : $_SERVER['REQUEST_URI'], is_wp_error($response) ? $response->get_error_message() : $error_message);
348
-
349
- OMGF_Admin_Notice::set_notice($message, 'omgf_api_error', 'error');
350
-
351
- if ($error_message == 'Service Unavailable') {
352
- $message = __('OMGF\'s Google Fonts API is currently unavailable. Try again later.', $this->plugin_text_domain);
353
-
354
- OMGF_Admin_Notice::set_notice($message, 'omgf_api_error', 'error', $response_code);
355
- }
356
-
357
- if ($error_body == 'Not found') {
358
- $message = sprintf(__('Please verify that %s is available for free at Google Fonts by doing <a href="%s" target="_blank">a manual search</a>. Maybe it\'s a Premium font?', $this->plugin_text_domain), $name, 'https://fonts.google.com/?query=' . str_replace('-', '+', $id));
359
-
360
- OMGF_Admin_Notice::set_notice($message, 'omgf_api_info_not_found', 'info');
361
- }
362
-
363
- if ($error_body == 'Internal Server Error') {
364
- $message = sprintf(__('Try using the Force Subsets option (available in OMGF Pro) to force loading %s in a subset in which it\'s actually available. Use the Language filter <a href="%s" target="_blank">here</a> to verify which subsets are available for %s.', $this->plugin_text_domain), $name, 'https://fonts.google.com/?query=' . str_replace('-', '+', $id), $name);
365
-
366
- OMGF_Admin_Notice::set_notice($message, 'omgf_api_info_internal_server_error', 'info');
367
- }
368
-
369
- return [];
370
- }
371
 
372
- return json_decode(wp_remote_retrieve_body($response));
373
- }
374
 
375
- /**
376
- * Wrapper for wp_remote_get() which tries a mirror API if the first request fails. (It tends to timeout sometimes)
377
- *
378
- * @param string $family
379
- * @param string $query
380
- *
381
- * @return array|WP_Error
382
- */
383
- private function remote_get($family, $query)
384
- {
385
- $response = wp_remote_get(
386
- sprintf(self::OMGF_GOOGLE_FONTS_API_URL . '%s', $family) . $query
387
- );
388
-
389
- // Try with mirror, if first request failed.
390
- if (is_wp_error($response) && $response->get_error_code() == 'http_request_failed') {
391
- $response = wp_remote_get(
392
- sprintf(self::OMGF_GOOGLE_FONTS_API_FALLBACK . '%s', $family) . $query
393
- );
394
  }
395
 
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
@@ -448,27 +240,49 @@ class OMGF_Optimize
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;
@@ -490,101 +304,188 @@ class OMGF_Optimize
490
  }
491
 
492
  /**
493
- * @param $request
494
- * @param $font
495
- *
496
- * @return array
497
  */
498
- private function parse_requested_variants($request, $font)
499
  {
500
- /**
501
- * Build an array and filter out empty elements.
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
- */
517
- if (count($requested_variants) == 0) {
518
- foreach ($font->variants as $variant) {
519
- $requested_variants[] = $variant->id;
520
- }
521
  }
522
 
523
- return $requested_variants;
524
  }
525
 
526
  /**
 
 
 
527
  *
528
- * @param string $font_id
529
- * @param array $all_variants An array of all available font family variants.
530
- * @param array $wanted_variants An array of requested variants in this font family request.
531
- * @param string $stylesheet_handle
532
- * @return mixed
533
  */
534
- private function process_unload_queue($font_id, $all_variants, $wanted_variants, $stylesheet_handle)
535
  {
536
- /**
537
- * If $variants is empty and this is the first run, i.e. there are no unloaded fonts (yet)
538
- * return all available variants.
539
- */
540
- if (empty($wanted_variants) && !isset(OMGF::unloaded_fonts()[$stylesheet_handle][$font_id])) {
541
- return $all_variants;
542
- }
543
 
544
- return array_filter(
545
- $all_variants,
546
- function ($font) use ($wanted_variants) {
547
- $id = $font->id;
548
 
549
- if ($id == 'regular' || $id == '400') {
550
- return in_array('400', $wanted_variants) || in_array('regular', $wanted_variants);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
551
  }
 
552
 
553
- if ($id == 'italic') {
554
- return in_array('400italic', $wanted_variants) || in_array('italic', $wanted_variants);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
555
  }
 
 
 
 
 
 
 
556
 
557
- return in_array($id, $wanted_variants);
558
  }
559
- );
 
 
 
 
560
  }
561
 
562
  /**
563
  * When unload is used, insert the cache key in the font URLs for the variants still in use.
564
  *
565
- * @param array $all_stylesheets Contains all font styles, loaded and unloaded.
566
- * @param array $current_stylesheet Contains just the loaded font styles of current stylesheet.
 
 
 
 
 
 
 
 
 
 
567
  *
568
- * @return mixed
569
  */
570
- private function rewrite_variants($all_stylesheets, $current_stylesheet)
571
  {
572
- foreach ($all_stylesheets as $stylesheet => &$fonts) {
573
- foreach ($fonts as $index => &$font) {
574
- if (empty((array) $font->variants)) {
575
- continue;
 
 
 
 
 
 
 
576
  }
577
 
578
- foreach ($font->variants as $variant_index => &$variant) {
579
- $replace_variant = $current_stylesheet[$stylesheet][$index]->variants[$variant_index] ?? (object) [];
580
 
581
- if (!empty((array) $replace_variant)) {
582
- $variant = $replace_variant;
583
- }
584
  }
585
  }
586
  }
587
 
588
- return $all_stylesheets;
589
  }
590
  }
18
 
19
  class OMGF_Optimize
20
  {
21
+ const USER_AGENT = [
22
+ 'woff2' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  ];
24
 
25
+ /** @var string $url */
26
+ private $url = '';
27
 
28
  /** @var string */
29
  private $handle = '';
31
  /** @var string $original_handle */
32
  private $original_handle = '';
33
 
 
 
 
34
  /** @var string $return */
35
  private $return = 'url';
36
 
37
+ /** @var bool $return_early */
38
+ private $return_early = false;
39
+
40
  /** @var string */
41
  private $path = '';
42
 
43
+ /**
44
+ * @var array $variable_fonts An array of font families in the current stylesheets that're Variable Fonts.
45
+ *
46
+ * @since v5.3.0
47
+ */
48
+ private $variable_fonts = [];
49
+
50
  /** @var string */
51
  private $plugin_text_domain = 'host-webfonts-local';
52
 
53
  /**
54
+ * @param string $url Google Fonts API URL, e.g. "fonts.googleapis.com/css?family="Lato:100,200,300,etc."
55
  * @param string $handle The cache handle, generated using $handle + 5 random chars. Used for storing the fonts and stylesheet.
56
  * @param string $original_handle The stylesheet handle, present in the ID attribute.
 
57
  * @param string $return Valid values: 'url' | 'path' | 'object'.
58
+ * @param bool $return_early If this is set to true, the optimization will skip out early if the object already exists in the database.
59
+ *
60
+ * @return void
 
 
 
 
 
61
  */
62
  public function __construct(
63
+ string $url,
64
  string $handle,
65
  string $original_handle,
66
+ string $return = 'url',
67
+ bool $return_early = false
68
  ) {
69
+ $this->url = apply_filters('omgf_optimize_url', $url);
70
  $this->handle = sanitize_title_with_dashes($handle);
71
  $this->original_handle = sanitize_title_with_dashes($original_handle);
 
72
  $this->path = OMGF_UPLOAD_DIR . '/' . $this->handle;
73
  $this->return = $return;
74
+ $this->return_early = $return_early;
75
  }
76
 
77
  /**
78
  * @return string|array
 
 
 
 
 
 
79
  */
80
  public function process()
81
  {
85
  return '';
86
  }
87
 
88
+ /**
89
+ * Convert protocol relative URLs.
90
+ */
91
+ if (strpos($this->url, '//') === 0) {
92
+ $this->url = 'https:' . $this->url;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  }
94
 
95
+ $local_file = $this->path . '/' . $this->handle . '.css';
 
 
 
96
 
97
+ /**
98
+ * @since v3.6.0 Allows us to bail early, if a fresh copy of files/stylesheets isn't necessary.
99
+ */
100
+ if (file_exists($local_file) && $this->return_early) {
101
+ switch ($this->return) {
102
+ case 'path':
103
+ return $local_file;
104
+ case 'object':
105
+ return [$this->original_handle => OMGF::optimized_fonts()[$this->original_handle]];
106
+ default:
107
+ return str_replace(OMGF_UPLOAD_DIR, OMGF_UPLOAD_URL, $local_file);
108
  }
109
  }
110
 
111
+ $fonts_bak = $this->grab_fonts_object($this->url);
112
+ $url = $this->unload_variants($this->url);
113
+ $fonts = $this->grab_fonts_object($url);
114
 
115
  if (empty($fonts)) {
116
  return '';
117
  }
118
 
119
  foreach ($fonts as $id => &$font) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  /**
121
  * Sanitize font family, because it may contain spaces.
122
  *
124
  */
125
  $font->family = rawurlencode($font->family);
126
 
127
+ foreach ($font->variants as $variant_id => &$variant) {
128
+ /**
129
+ * @since v5.3.0 Variable fonts use one filename for all font weights/styles. That's why we drop the weight from the filename.
130
+ */
131
+ if (isset($this->variable_fonts[$id])) {
132
+ $filename = strtolower($id . '-' . $variant->fontStyle . '-' . (isset($variant->subset) ? $variant->subset : ''));
133
+ } else {
134
+ $filename = strtolower($id . '-' . $variant->fontStyle . '-' . (isset($variant->subset) ? $variant->subset . '-' : '') . $variant->fontWeight);
135
+ }
136
 
137
  /**
138
  * Encode font family, because it may contain spaces.
141
  */
142
  $variant->fontFamily = rawurlencode($variant->fontFamily);
143
 
144
+ /**
145
+ * @since v5.3.0 No need to keep this if this variant belongs to a subset we don't need.
146
+ */
147
+ if (isset($variant->subset) && !in_array($variant->subset, apply_filters('omgf_used_subsets', OMGF_SUBSETS))) {
148
+ unset($font->variants[$variant_id]);
149
+
150
+ continue;
151
+ }
152
+
153
+ if (isset($variant->woff2)) {
154
+ $variant->woff2 = OMGF::download($variant->woff2, $filename, 'woff2', $this->path);
155
  }
156
  }
157
  }
158
 
159
+ $stylesheet = OMGF::generate_stylesheet($fonts);
 
160
 
161
  if (!file_exists($this->path)) {
162
  wp_mkdir_p($this->path);
164
 
165
  file_put_contents($local_file, $stylesheet);
166
 
167
+ $fonts_bak = $this->rewrite_variants($fonts_bak, $fonts);
168
+ $current_stylesheet = [$this->original_handle => $fonts_bak];
169
 
170
  /**
171
  * $current_stylesheet is added to temporary cache layer, if it isn't present in database.
172
  *
173
  * @since v4.5.7
174
  */
175
+ $optimized_fonts = OMGF::optimized_fonts($current_stylesheet, true);
 
 
 
 
 
 
 
176
 
177
  update_option(OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS, $optimized_fonts);
178
 
189
  }
190
 
191
  /**
192
+ * @since v5.3.0 Parse the stylesheet and build it into a font object which OMGF can understand.
193
+ *
194
+ * @param $url Google Fonts API request, e.g. https://fonts.googleapis.com/css?family=Open+Sans:100,200,300,400italic
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  *
196
+ * @return stdClass
197
  */
198
+ private function grab_fonts_object($url)
199
  {
200
+ $response = wp_remote_get($url, [
201
+ 'user-agent' => self::USER_AGENT['woff2']
202
+ ]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
+ $code = wp_remote_retrieve_response_code($response);
 
205
 
206
+ if ($code !== 200) {
207
+ return new stdClass();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
209
 
210
+ $stylesheet = wp_remote_retrieve_body($response);
 
211
 
212
+ preg_match_all('/font-family:\s\'(.*?)\';/', $stylesheet, $font_families);
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
+ if (!isset($font_families[1]) || empty($font_families[1])) {
215
+ return new stdClass();
 
 
216
  }
217
 
218
+ $font_families = array_unique($font_families[1]);
 
 
 
 
 
 
219
 
220
+ foreach ($font_families as $font_family) {
221
+ $id = strtolower(str_replace(' ', '-', $font_family));
222
+ $object[$id] = (object) [
223
+ 'id' => $id,
224
+ 'family' => $font_family,
225
+ 'variants' => apply_filters('omgf_optimize_fonts_object_variants', $this->parse_variants($stylesheet, $font_family), $stylesheet, $font_family, $this->url),
226
+ 'subsets' => apply_filters('omgf_optimize_fonts_object_subsets', $this->parse_subsets($stylesheet, $font_family), $stylesheet, $font_family, $this->url)
227
+ ];
228
  }
229
 
230
+ return $object;
 
 
 
 
 
 
 
231
  }
232
 
233
  /**
234
+ * Parse a stylesheet from Google Fonts' API into a valid Font Object.
235
  *
236
  * @param string $stylesheet
237
  * @param string $font_family
240
  */
241
  private function parse_variants($stylesheet, $font_family)
242
  {
243
+ /**
244
+ * This also captures the commented Subset name.
245
+ */
246
+ preg_match_all(apply_filters('omgf_optimize_parse_variants_regex', '/\/\*\s.*?}/s', $this->url), $stylesheet, $font_faces);
247
 
248
  if (!isset($font_faces[0]) || empty($font_faces[0])) {
249
  return [];
250
  }
251
 
252
  foreach ($font_faces[0] as $key => $font_face) {
253
+ if (strpos($font_face, $font_family) === false) {
254
+ continue;
255
+ }
256
+
257
  preg_match('/font-style:\s(normal|italic);/', $font_face, $font_style);
258
  preg_match('/font-weight:\s([0-9]+);/', $font_face, $font_weight);
259
  preg_match('/src:\surl\((.*?woff2)\)/', $font_face, $font_src);
260
  preg_match('/\/\*\s([a-z\-]+?)\s\*\//', $font_face, $subset);
261
  preg_match('/unicode-range:\s(.*?);/', $font_face, $range);
262
 
263
+ $key = $subset[1] . '-' . $font_weight[1] . ($font_style[1] == 'normal' ? '' : '-' . $font_style[1]);
264
+
265
  $font_object[$key] = new stdClass();
266
  $font_object[$key]->id = $font_weight[1] . ($font_style[1] == 'normal' ? '' : $font_style[1]);
267
  $font_object[$key]->fontFamily = $font_family;
268
  $font_object[$key]->fontStyle = $font_style[1];
269
  $font_object[$key]->fontWeight = $font_weight[1];
270
  $font_object[$key]->woff2 = $font_src[1];
271
+
272
+ if (!empty($subset) && isset($subset[1])) {
273
+ $font_object[$key]->subset = $subset[1];
274
+ }
275
+
276
+ if (!empty($range) && isset($range[1])) {
277
+ $font_object[$key]->range = $range[1];
278
+ }
279
+
280
+ /**
281
+ * @since v5.3.0 Is this a variable font i.e. one font file for multiple font weights/styles?
282
+ */
283
+ if (substr_count($stylesheet, $font_src[1]) > 1) {
284
+ $this->variable_fonts[strtolower(str_replace(' ', '-', $font_family))] = true;
285
+ }
286
  }
287
 
288
  return $font_object;
304
  }
305
 
306
  /**
307
+ * Modifies the URL to not include unloaded variants.
308
+ *
309
+ * @param mixed $url
310
+ * @return void
311
  */
312
+ private function unload_variants($url)
313
  {
314
+ if (!isset(OMGF::unloaded_fonts()[$this->original_handle])) {
315
+ return $url;
316
+ }
 
317
 
318
+ $url = urldecode($url);
 
 
 
 
 
 
 
319
 
320
+ if (strpos($url, '/css2') !== false) {
321
+ $url = $this->unload_css2($url);
322
+ } else {
323
+ $url = $this->unload_css($url);
 
 
 
324
  }
325
 
326
+ return apply_filters('omgf_optimize_unload_variants_url', $url);
327
  }
328
 
329
  /**
330
+ * Process unload for Variable Fonts API requests.
331
+ *
332
+ * @param string $url full request to Variable Fonts API.
333
  *
334
+ * @return string full requests (excluding unloaded variants)
 
 
 
 
335
  */
336
+ private function unload_css2($url)
337
  {
338
+ $query = parse_url($url, PHP_URL_QUERY);
 
 
 
 
 
 
339
 
340
+ foreach ($font_families = explode('&', $query) as $key => $family) {
341
+ preg_match('/family=(?<name>[A-Za-z\s]+)[\:]?/', $family, $name);
342
+ preg_match('/:(?P<axes>[a-z,]+)@/', $family, $axes);
343
+ preg_match('/@(?P<tuples>[0-9,;]+)[&]?/', $family, $tuples);
344
 
345
+ if (!isset($name['name']) || empty($name['name'])) {
346
+ continue;
347
+ }
348
+
349
+ $name = $name['name'];
350
+ $id = str_replace(' ', '-', strtolower($name));
351
+
352
+ if (!isset(OMGF::unloaded_fonts()[$this->original_handle][$id])) {
353
+ continue;
354
+ }
355
+
356
+ if (!isset($axes['axes']) || empty($axes['axes'])) {
357
+ $axes = 'wght';
358
+ } else {
359
+ $axes = $axes['axes'];
360
+ }
361
+
362
+ if (!isset($tuples['tuples']) || empty($tuples['tuples'])) {
363
+ /**
364
+ * Variable Fonts API returns only regular (normal, 400) if no variations are defined.
365
+ */
366
+ $tuples = ['400'];
367
+ } else {
368
+ $tuples = explode(';', $tuples['tuples']);
369
+ }
370
+
371
+ $unloaded_fonts = OMGF::unloaded_fonts()[$this->original_handle][$id];
372
+ $tuples = array_filter(
373
+ $tuples,
374
+ function ($tuple) use ($unloaded_fonts) {
375
+ return !in_array(preg_replace('/[0-9]+,/', '', $tuple), $unloaded_fonts);
376
  }
377
+ );
378
 
379
+ /**
380
+ * The entire font-family appears to be unloaded, let's remove it.
381
+ */
382
+ if (empty($tuples)) {
383
+ unset($font_families[$key]);
384
+
385
+ continue;
386
+ }
387
+
388
+ $font_families[$key] = 'family=' . $name . ':' . $axes . '@' . implode(';', $tuples);
389
+ }
390
+
391
+ return 'https://fonts.googleapis.com/css2?' . implode('&', $font_families);
392
+ }
393
+
394
+ /**
395
+ * Process unload for Google Fonts API.
396
+ *
397
+ * @param string $url Full request to Google Fonts API.
398
+ *
399
+ * @return string Full request (excluding unloaded variants)
400
+ */
401
+ private function unload_css($url)
402
+ {
403
+ $query = parse_url($url, PHP_URL_QUERY);
404
+
405
+ parse_str($query, $font_families);
406
+
407
+ foreach ($font_families = explode('|', $font_families['family']) as $key => $font_family) {
408
+ list($name, $tuples) = array_pad(explode(':', $font_family), 2, []);
409
+
410
+ $id = str_replace(' ', '-', strtolower($name));
411
+
412
+ if (!isset(OMGF::unloaded_fonts()[$this->original_handle][$id])) {
413
+ continue;
414
+ }
415
+
416
+ /**
417
+ * Google Fonts API returns 400 if no tuples are defined.
418
+ */
419
+ if (empty($tuples)) {
420
+ $tuples = ['400'];
421
+ } else {
422
+ $tuples = explode(',', $tuples);
423
+ }
424
+
425
+ $unloaded_fonts = OMGF::unloaded_fonts()[$this->original_handle][$id];
426
+ $tuples = array_filter(
427
+ $tuples,
428
+ function ($tuple) use ($unloaded_fonts) {
429
+ return !in_array($tuple, $unloaded_fonts);
430
  }
431
+ );
432
+
433
+ /**
434
+ * The entire font-family appears to be unloaded, let's remove it.
435
+ */
436
+ if (empty($tuples)) {
437
+ unset($font_families[$key]);
438
 
439
+ continue;
440
  }
441
+
442
+ $font_families[$key] = urlencode($name) . ':' . implode(',', $tuples);
443
+ }
444
+
445
+ return 'https://fonts.googleapis.com/css?family=' . implode('|', $font_families);
446
  }
447
 
448
  /**
449
  * When unload is used, insert the cache key in the font URLs for the variants still in use.
450
  *
451
+ * @param array $current Contains all font styles, loaded and unloaded.
452
+ * @param array $replacement Contains just the loaded font styles of current stylesheet.
453
+ *
454
+ * Both parameters follow this structure:
455
+ *
456
+ * (string) Font Family {
457
+ * (string) id, (string) family, (array) variants {
458
+ * (string) id => (object) {
459
+ * (string) id, (string) fontFamily, (string) fontStyle, (string) fontWeight, (string) woff2, (string) subset = null, (string) range
460
+ * }
461
+ * }
462
+ * }
463
  *
464
+ * @return array
465
  */
466
+ private function rewrite_variants($current, $replacement)
467
  {
468
+ foreach ($current as $font_family => &$properties) {
469
+ if (!isset($properties->variants) || empty($properties->variants)) {
470
+ continue;
471
+ }
472
+
473
+ foreach ($properties->variants as $id => &$variant) {
474
+ /**
475
+ * @since v5.3.0 Get rid of any subsets that aren't in use.
476
+ */
477
+ if (isset($variant->subset) && !in_array($variant->subset, apply_filters('omgf_used_subsets', OMGF_SUBSETS))) {
478
+ unset($properties->variants[$id]);
479
  }
480
 
481
+ $replacement_variant = $replacement[$font_family]->variants[$id] ?? '';
 
482
 
483
+ if ($replacement_variant && $replacement_variant != $variant) {
484
+ $variant = $replacement_variant;
 
485
  }
486
  }
487
  }
488
 
489
+ return $current;
490
  }
491
  }
includes/class-stylesheet-generator.php CHANGED
@@ -21,9 +21,6 @@ class OMGF_StylesheetGenerator
21
  /** @var $fonts */
22
  private $fonts;
23
 
24
- /** @var string $handle */
25
- private $handle;
26
-
27
  /** @var string $plugin */
28
  private $plugin;
29
 
@@ -32,11 +29,9 @@ class OMGF_StylesheetGenerator
32
  */
33
  public function __construct(
34
  $fonts,
35
- string $handle,
36
  string $plugin
37
  ) {
38
  $this->fonts = $fonts;
39
- $this->handle = $handle;
40
  $this->plugin = $plugin;
41
  }
42
 
@@ -47,66 +42,25 @@ class OMGF_StylesheetGenerator
47
  */
48
  public function generate()
49
  {
50
- /**
51
- * Which file types should we download and include in the stylesheet?
52
- *
53
- * @since v4.5
54
- */
55
- $file_types = apply_filters('omgf_include_file_types', ['woff2', 'woff', 'eot', 'ttf', 'svg']);
56
  $font_display = OMGF_DISPLAY_OPTION;
57
  $stylesheet = "/**\n * Auto Generated by $this->plugin\n * @author: Daan van den Bergh\n * @url: https://daan.dev\n */\n\n";
58
 
59
  foreach ($this->fonts as $font) {
60
- /**
61
- * If Font Family's name was recently renamed, the old name should be used so no manual changes have to be made
62
- * to the stylesheet after processing.
63
- */
64
- $renamed_font_family = in_array($font->id, OMGF_Optimize::OMGF_RENAMED_GOOGLE_FONTS)
65
- ? array_search($font->id, OMGF_Optimize::OMGF_RENAMED_GOOGLE_FONTS)
66
- : '';
67
-
68
  foreach ($font->variants as $variant) {
69
  /**
70
  * Filter font_family name.
71
  *
72
  * @since v4.5.1
73
  */
74
- $font_family = apply_filters('omgf_generate_stylesheet_font_family', $renamed_font_family ? ucfirst(rawurldecode($renamed_font_family)) : rawurldecode($variant->fontFamily));
75
  $font_style = $variant->fontStyle;
76
  $font_weight = $variant->fontWeight;
77
  $stylesheet .= "@font-face {\n";
78
- $stylesheet .= " font-family: $font_family;\n";
79
  $stylesheet .= " font-style: $font_style;\n";
80
  $stylesheet .= " font-weight: $font_weight;\n";
81
  $stylesheet .= " font-display: $font_display;\n";
82
-
83
- /**
84
- * For IE compatibility, EOT is added before the local family name is defined.
85
- */
86
- if (in_array('eot', $file_types)) {
87
- $stylesheet .= " src: url('" . urldecode($variant->eot) . "');\n";
88
- $eot_key = array_search('eot', $file_types);
89
- unset($file_types[$eot_key]);
90
- }
91
-
92
- $local_src = '';
93
-
94
- if (isset($variant->local) && is_array($variant->local)) {
95
- foreach ($variant->local as $local) {
96
- $local_src .= "local('$local'), ";
97
- }
98
- }
99
-
100
- $stylesheet .= " src: $local_src\n";
101
- $font_src_url = [];
102
-
103
- foreach ($file_types as $file_type) {
104
- if (isset($variant->$file_type)) {
105
- $font_src_url = array_merge($font_src_url, [$file_type => urldecode($variant->$file_type)]);
106
- }
107
- }
108
-
109
- $stylesheet .= $this->build_source_string($font_src_url);
110
 
111
  if (isset($variant->range)) {
112
  $stylesheet .= " unicode-range: $variant->range;\n";
21
  /** @var $fonts */
22
  private $fonts;
23
 
 
 
 
24
  /** @var string $plugin */
25
  private $plugin;
26
 
29
  */
30
  public function __construct(
31
  $fonts,
 
32
  string $plugin
33
  ) {
34
  $this->fonts = $fonts;
 
35
  $this->plugin = $plugin;
36
  }
37
 
42
  */
43
  public function generate()
44
  {
 
 
 
 
 
 
45
  $font_display = OMGF_DISPLAY_OPTION;
46
  $stylesheet = "/**\n * Auto Generated by $this->plugin\n * @author: Daan van den Bergh\n * @url: https://daan.dev\n */\n\n";
47
 
48
  foreach ($this->fonts as $font) {
 
 
 
 
 
 
 
 
49
  foreach ($font->variants as $variant) {
50
  /**
51
  * Filter font_family name.
52
  *
53
  * @since v4.5.1
54
  */
55
+ $font_family = apply_filters('omgf_generate_stylesheet_font_family', rawurldecode($variant->fontFamily));
56
  $font_style = $variant->fontStyle;
57
  $font_weight = $variant->fontWeight;
58
  $stylesheet .= "@font-face {\n";
59
+ $stylesheet .= " font-family: '$font_family';\n";
60
  $stylesheet .= " font-style: $font_style;\n";
61
  $stylesheet .= " font-weight: $font_weight;\n";
62
  $stylesheet .= " font-display: $font_display;\n";
63
+ $stylesheet .= " src: " . $this->build_source_string(['woff2' => $variant->woff2]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
  if (isset($variant->range)) {
66
  $stylesheet .= " unicode-range: $variant->range;\n";
includes/frontend/class-process.php CHANGED
@@ -79,7 +79,11 @@ class OMGF_Frontend_Process
79
  add_action('wp_head', [$this, 'add_preloads'], 3);
80
  add_action('template_redirect', [$this, 'maybe_buffer_output'], 3);
81
  add_filter('omgf_buffer_output', [$this, 'remove_resource_hints'], 9);
82
- add_filter('omgf_buffer_output', [$this, 'parse']);
 
 
 
 
83
 
84
  /** Smart Slider 3 compatibility */
85
  add_filter('wordpress_prepare_output', [$this, 'parse'], 11);
@@ -119,16 +123,23 @@ class OMGF_Frontend_Process
119
  }
120
  );
121
 
 
 
 
 
 
122
  foreach ($preload_variants as $variant) {
123
  $url = rawurldecode($variant->woff2);
124
 
125
  /**
126
  * @since v5.0.1 An extra check, because people tend to forget to flush their caches when changing fonts, etc.
127
  */
128
- if (!file_exists(str_replace(OMGF_UPLOAD_URL, OMGF_UPLOAD_DIR, $url))) {
129
  continue;
130
  }
131
 
 
 
132
  echo "<link id='omgf-preload-$i' rel='preload' href='$url' as='font' type='font/woff2' crossorigin />\n";
133
  $i++;
134
  }
@@ -193,7 +204,7 @@ class OMGF_Frontend_Process
193
  * - Cache Enabler v1.8.7
194
  * - Default Settings
195
  * - Kinsta Cache (Same as Cache Enabler?)
196
- * - Works on ffw.press
197
  * - LiteSpeed Cache
198
  * - Don't know (Gal Baras tested it: @see https://wordpress.org/support/topic/completely-broke-wp-rocket-plugin/#post-15377538)
199
  * - W3 Total Cache v2.2.1:
@@ -209,8 +220,8 @@ class OMGF_Frontend_Process
209
  * - WP Super Cache v1.7.4
210
  * - Page Cache: Enabled
211
  *
212
- * @todo Not tested (yet):
213
- * - Swift Performance
214
  *
215
  * @return void
216
  */
@@ -253,7 +264,7 @@ class OMGF_Frontend_Process
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) {
@@ -294,7 +305,10 @@ class OMGF_Frontend_Process
294
  return apply_filters('omgf_processed_html', $html, $this);
295
  }
296
 
297
- preg_match_all('/<link.*fonts\.googleapis\.com\/css.*?[\/]?>/', $html, $links);
 
 
 
298
 
299
  if (!isset($links[0]) || empty($links[0])) {
300
  return apply_filters('omgf_processed_html', $html, $this);
@@ -371,7 +385,7 @@ class OMGF_Frontend_Process
371
  * identifier to the string, to make sure we can make a difference between
372
  * different Google Fonts configurations.
373
  *
374
- * @since v5.2.0 Allow Divi/Elementor) compatibility fixes to be disabled, for those who have too
375
  * many different Google Fonts stylesheets configured throughout their pages and
376
  * blame OMGF for the fact that it detects all those different stylesheets. :-/
377
  */
@@ -391,6 +405,7 @@ class OMGF_Frontend_Process
391
  $google_fonts[$key]['id'] = $id;
392
  }
393
 
 
394
  $google_fonts[$key]['href'] = $href['href'];
395
  }
396
 
@@ -460,14 +475,18 @@ class OMGF_Frontend_Process
460
  $replace = [];
461
 
462
  foreach ($google_fonts as $key => $stack) {
463
- $handle = $stack['id'];
 
 
 
 
464
 
465
  /**
466
- * If stylesheet with $handle is completely marked for unload, just clean the 'href'
467
- * attribute to prevent it from loading.
468
  */
469
  if (OMGF::unloaded_stylesheets() && in_array($handle, OMGF::unloaded_stylesheets())) {
470
- $search[$key] = $stack['href'];
471
  $replace[$key] = '';
472
 
473
  continue;
@@ -492,16 +511,20 @@ class OMGF_Frontend_Process
492
  continue;
493
  }
494
 
495
- $query = $this->build_query($stack['href'], $handle, $stack['id']);
 
496
 
497
  /**
498
- * Required parameters.
499
  */
500
- if (!isset($query['family']) || !isset($query['handle']) || !isset($query['original_handle'])) {
 
 
 
501
  continue;
502
  }
503
 
504
- $optimize = new OMGF_Optimize($query['family'], $query['handle'], $query['original_handle'], apply_filters('omgf_optimize_query_subset', $query['subset'] ?? ''));
505
  $cached_url = $optimize->process();
506
 
507
  if (!$cached_url) {
@@ -515,109 +538,6 @@ class OMGF_Frontend_Process
515
  return ['search' => $search, 'replace' => $replace];
516
  }
517
 
518
- /**
519
- * The generated request URL includes all required parameters for OMGF's Download API.
520
- *
521
- * @param string $url e.g. https://fonts.googleapis.com/css?family=Open+Sans:100,200,300|Roboto:100,200,300 etc.
522
- * @param string $updated_handle e.g. example-handle-xvfdo
523
- * @param string $handle e.g. example-handle
524
- *
525
- * @return array [ 'family' => string, 'display' => string, 'handle' => string, 'original_handle' => string ]
526
- */
527
- public function build_query($url, $updated_handle, $handle)
528
- {
529
- // Filter out HTML (&#038;, etc) and URL encoded characters, so we can properly parse it.
530
- $url = htmlspecialchars_decode(urldecode($url));
531
- $parsed_url = parse_url($url);
532
- $query = $parsed_url['query'] ?? '';
533
-
534
- if ($parsed_url['path'] == '/css2') {
535
- // Request to fonts.googleapis.com/css2?etc.
536
- $original_query = $this->parse_css2($query);
537
- } elseif (strpos($parsed_url['path'], 'earlyaccess') !== false) {
538
- // Request to https://fonts.googleapis.com/earlyaccess/etc. should be left for OMGF Pro to deal with.
539
- $original_query = ['family' => ''];
540
- } else {
541
- /**
542
- * Request to fonts.googleapis.com/css?etc. (default)
543
- *
544
- * Decode, just to be sure.
545
- */
546
- parse_str($query, $original_query);
547
- }
548
-
549
- $params = array_merge(
550
- $original_query,
551
- [
552
- 'handle' => $updated_handle,
553
- 'original_handle' => $handle,
554
- ]
555
- );
556
-
557
- return apply_filters('omgf_request_url', $params);
558
- }
559
-
560
- /**
561
- * Convert CSS2 query to regular CSS API query.
562
- *
563
- * @param string $query
564
- *
565
- * @return array
566
- */
567
- private function parse_css2($query)
568
- {
569
- // array_filter() removes empty elements.
570
- $families = array_filter(explode('&', $query));
571
-
572
- foreach ($families as $param) {
573
- if (strpos($param, 'family') === false) {
574
- continue;
575
- }
576
-
577
- parse_str($param, $parts);
578
-
579
- $font_families[] = $parts['family'];
580
- }
581
-
582
- if (empty($font_families)) {
583
- return $query;
584
- }
585
-
586
- $weights = '';
587
-
588
- foreach ($font_families as $font_family) {
589
- if (strpos($font_family, ':') !== false) {
590
- list($family, $weights) = explode(':', $font_family);
591
- } else {
592
- $family = $font_family;
593
- $weights = '';
594
- }
595
-
596
- /**
597
- * @var string $weights [ '300', '400', '500', etc. ] || ''
598
- */
599
- $weights = strpos($weights, ';') !== false ? explode(';', substr($weights, strpos($weights, '@') + 1)) : [substr($weights, strpos($weights, '@') + 1)];
600
-
601
- if (!$weights) {
602
- $fonts[] = $family;
603
-
604
- continue;
605
- }
606
-
607
- /**
608
- * @var array $weights Multiple weights, e.g. [ '300', '400', '500', '0,600', '1,700' ] || Single weight, e.g. [ '500' ] or [ '1,600' ]
609
- */
610
- foreach ($weights as &$weight) {
611
- $properties = explode(',', $weight);
612
- $weight = $properties[0] == '1' && isset($properties[1]) ? $properties[1] . 'italic' : ($properties[0] != '0' ? $properties[0] : $properties[1]);
613
- }
614
-
615
- $fonts[] = $family . ':' . implode(',', $weights);
616
- }
617
-
618
- return ['family' => implode('|', $fonts)];
619
- }
620
-
621
  /**
622
  * Because all great themes come packed with extra Cumulative Layout Shifting.
623
  *
79
  add_action('wp_head', [$this, 'add_preloads'], 3);
80
  add_action('template_redirect', [$this, 'maybe_buffer_output'], 3);
81
  add_filter('omgf_buffer_output', [$this, 'remove_resource_hints'], 9);
82
+
83
+ /** Only hook into our own filter if Smart Slider 3 isn't active, as it has its own filter. */
84
+ if (!function_exists('smart_slider_3_plugins_loaded')) {
85
+ add_filter('omgf_buffer_output', [$this, 'parse']);
86
+ }
87
 
88
  /** Smart Slider 3 compatibility */
89
  add_filter('wordpress_prepare_output', [$this, 'parse'], 11);
123
  }
124
  );
125
 
126
+ /**
127
+ * @since v5.3.0 Store all preloaded URLs temporarily, to make sure no duplicate files (Variable Fonts) are preloaded.
128
+ */
129
+ $preloaded = [];
130
+
131
  foreach ($preload_variants as $variant) {
132
  $url = rawurldecode($variant->woff2);
133
 
134
  /**
135
  * @since v5.0.1 An extra check, because people tend to forget to flush their caches when changing fonts, etc.
136
  */
137
+ if (!file_exists(str_replace(OMGF_UPLOAD_URL, OMGF_UPLOAD_DIR, $url)) || in_array($url, $preloaded)) {
138
  continue;
139
  }
140
 
141
+ $preloaded[] = $url;
142
+
143
  echo "<link id='omgf-preload-$i' rel='preload' href='$url' as='font' type='font/woff2' crossorigin />\n";
144
  $i++;
145
  }
204
  * - Cache Enabler v1.8.7
205
  * - Default Settings
206
  * - Kinsta Cache (Same as Cache Enabler?)
207
+ * - Works on Daan.dev
208
  * - LiteSpeed Cache
209
  * - Don't know (Gal Baras tested it: @see https://wordpress.org/support/topic/completely-broke-wp-rocket-plugin/#post-15377538)
210
  * - W3 Total Cache v2.2.1:
220
  * - WP Super Cache v1.7.4
221
  * - Page Cache: Enabled
222
  *
223
+ * Not tested (yet):
224
+ * TODO: [OMGF-41] - Swift Performance
225
  *
226
  * @return void
227
  */
264
  * plugins (e.g. Asset Cleanup) also tend to include their own custom attributes,
265
  * e.g. data-wpacu-to-be-preloaded
266
  *
267
+ * TODO: [OMGF-42] I think I should be able to use an array_filter here or something?
268
  */
269
  foreach (self::RESOURCE_HINTS_URLS as $url) {
270
  if (strpos($match, $url) !== false) {
305
  return apply_filters('omgf_processed_html', $html, $this);
306
  }
307
 
308
+ /**
309
+ * Use positive lookaround for stricter matching.
310
+ */
311
+ preg_match_all('/(?=\<link).+?href=[\'"](https:)?\/\/fonts\.googleapis\.com\/css.+?[\'"].+?(?<=>)/', $html, $links);
312
 
313
  if (!isset($links[0]) || empty($links[0])) {
314
  return apply_filters('omgf_processed_html', $html, $this);
385
  * identifier to the string, to make sure we can make a difference between
386
  * different Google Fonts configurations.
387
  *
388
+ * @since v5.2.0 Allow Divi/Elementor compatibility fixes to be disabled, for those who have too
389
  * many different Google Fonts stylesheets configured throughout their pages and
390
  * blame OMGF for the fact that it detects all those different stylesheets. :-/
391
  */
405
  $google_fonts[$key]['id'] = $id;
406
  }
407
 
408
+ $google_fonts[$key]['link'] = $link;
409
  $google_fonts[$key]['href'] = $href['href'];
410
  }
411
 
475
  $replace = [];
476
 
477
  foreach ($google_fonts as $key => $stack) {
478
+ /**
479
+ * Handles should be all lowercase to prevent duplication issues on some filesystems.
480
+ */
481
+ $handle = strtolower($stack['id']);
482
+ $original_handle = $handle;
483
 
484
  /**
485
+ * If stylesheet with $handle is completely marked for unload, just remove the element
486
+ * to prevent it from loading.
487
  */
488
  if (OMGF::unloaded_stylesheets() && in_array($handle, OMGF::unloaded_stylesheets())) {
489
+ $search[$key] = $stack['link'];
490
  $replace[$key] = '';
491
 
492
  continue;
511
  continue;
512
  }
513
 
514
+ $query = parse_url($stack['href'], PHP_URL_QUERY);
515
+ parse_str($query, $query);
516
 
517
  /**
518
+ * If required parameters aren't set, this request is most likely invalid. Let's just remove it.
519
  */
520
+ if (!isset($query['family'])) {
521
+ $search[$key] = $stack['link'];
522
+ $replace[$key] = '';
523
+
524
  continue;
525
  }
526
 
527
+ $optimize = new OMGF_Optimize($stack['href'], $handle, $original_handle);
528
  $cached_url = $optimize->process();
529
 
530
  if (!$cached_url) {
538
  return ['search' => $search, 'replace' => $replace];
539
  }
540
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
541
  /**
542
  * Because all great themes come packed with extra Cumulative Layout Shifting.
543
  *
readme.md CHANGED
@@ -9,7 +9,7 @@ OMGF automagically caches the Google Fonts used by your theme/plugins locally. N
9
 
10
  **Leverage Browser Cache**, **reduce DNS lookups/requests**, **reduce Cumulative Layout Shift** and make your Google Fonts **100% GDPR compliant** with OMGF!
11
 
12
- OMGF is written with performance and user-friendliness in mind. It uses the Google Fonts Helper API to automatically cache the fonts your theme and plugins use to **minimize DNS requests** and speed up your WordPress website.
13
 
14
  ## How Does It Work?
15
 
@@ -24,10 +24,11 @@ All Google Fonts are listed in the **Manage Optimized Fonts** section of OMGF's
24
 
25
  ### Other Features include
26
 
 
 
27
  - **Remove Resource Hints** (preload, preconnect, dns-prefetch) pointing to `fonts.googleapis.com` or `fonts.gstatic.com`,
28
  - **Ensure text remains visible during webfont load** by forcing the *font-display* attribute to your Google Fonts,
29
  - **Ensure text remains visible during webfont load** by forcing the *font-display* attribute to all your other fonts! (OMGF Pro required),
30
- - **Reduce the filesize** of your fonts and stylesheets, by using the *Force subset* and *Include File Types* feature (OMGF Pro required),
31
 
32
  ### Additional Features in OMGF Pro
33
  - **Multisite** support,
9
 
10
  **Leverage Browser Cache**, **reduce DNS lookups/requests**, **reduce Cumulative Layout Shift** and make your Google Fonts **100% GDPR compliant** with OMGF!
11
 
12
+ OMGF is written with performance and user-friendliness in mind. It uses the Google Fonts API to automatically cache the fonts your theme and plugins use to **minimize DNS requests** and speed up your WordPress website.
13
 
14
  ## How Does It Work?
15
 
24
 
25
  ### Other Features include
26
 
27
+ - **Variable Fonts** support,
28
+ - **Remove unused subsets** to reduce the size of the CSS stylesheet,
29
  - **Remove Resource Hints** (preload, preconnect, dns-prefetch) pointing to `fonts.googleapis.com` or `fonts.gstatic.com`,
30
  - **Ensure text remains visible during webfont load** by forcing the *font-display* attribute to your Google Fonts,
31
  - **Ensure text remains visible during webfont load** by forcing the *font-display* attribute to all your other fonts! (OMGF Pro required),
 
32
 
33
  ### Additional Features in OMGF Pro
34
  - **Multisite** support,
readme.txt CHANGED
@@ -3,7 +3,7 @@ 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.2
7
  Requires PHP: 7.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -17,7 +17,7 @@ OMGF automagically caches the Google Fonts used by your theme/plugins locally. N
17
 
18
  **Leverage Browser Cache**, **reduce DNS lookups/requests**, **reduce Cumulative Layout Shift** and make your Google Fonts **100% GDPR compliant** with OMGF!
19
 
20
- OMGF is written with performance and user-friendliness in mind. It uses the Google Fonts Helper API to automatically cache the fonts your theme and plugins use to **minimize DNS requests** and speed up your WordPress website.
21
 
22
  = How Does It Work? =
23
 
@@ -32,10 +32,11 @@ All Google Fonts are listed in the **Manage Optimized Fonts** section of OMGF's
32
 
33
  = Other Features include =
34
 
 
 
35
  - **Remove Resource Hints** (preload, preconnect, dns-prefetch) pointing to `fonts.googleapis.com` or `fonts.gstatic.com`,
36
  - **Ensure text remains visible during webfont load** by forcing the *font-display* attribute to your Google Fonts,
37
  - **Ensure text remains visible during webfont load** by forcing the *font-display* attribute to all your other fonts! (OMGF Pro required),
38
- - **Reduce the file size** of your fonts and stylesheets, by using the *Force subset* and *Include File Types* feature (OMGF Pro required),
39
 
40
  = Additional Features in OMGF Pro =
41
  - **Multisite** support,
@@ -75,6 +76,18 @@ For the FAQ, [click here](https://daan.dev/docs/omgf-pro-faq/).
75
 
76
  == Changelog ==
77
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  = 5.2.2 | June 28th, 2022 =
79
  * Fixed: updated links from ffw.press to daan.dev after the migration.
80
 
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.3.0
7
  Requires PHP: 7.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
17
 
18
  **Leverage Browser Cache**, **reduce DNS lookups/requests**, **reduce Cumulative Layout Shift** and make your Google Fonts **100% GDPR compliant** with OMGF!
19
 
20
+ OMGF is written with performance and user-friendliness in mind. It uses the Google Fonts API to automatically cache the fonts your theme and plugins use to **minimize DNS requests** and speed up your WordPress website.
21
 
22
  = How Does It Work? =
23
 
32
 
33
  = Other Features include =
34
 
35
+ - **Variable Fonts** support,
36
+ - **Remove unused subsets** to reduce the size of the CSS stylesheet,
37
  - **Remove Resource Hints** (preload, preconnect, dns-prefetch) pointing to `fonts.googleapis.com` or `fonts.gstatic.com`,
38
  - **Ensure text remains visible during webfont load** by forcing the *font-display* attribute to your Google Fonts,
39
  - **Ensure text remains visible during webfont load** by forcing the *font-display* attribute to all your other fonts! (OMGF Pro required),
 
40
 
41
  = Additional Features in OMGF Pro =
42
  - **Multisite** support,
76
 
77
  == Changelog ==
78
 
79
+ = 5.3.0 | July 20th, 2022 =
80
+ * Added: Removed Google Webfonts Helper API and implemented a custom Web Font Loader. This adds/fixes:
81
+ * Added: full support for Variable Fonts
82
+ * Fixed: Proper (WOFF2) compression, so files generated by OMGF are no longer bigger than files downloaded from the Google Fonts API.
83
+ * Fixed: The (broken capital A) compression bug is fixed!
84
+ * Fixed: Changed logo in Help section to Daan.dev logo
85
+ * Fixed: Remove unused subsets from Optimized Fonts object to reduce db size
86
+ * Fixed: OMGF_Optimize class will bail earlier, if files and stylesheets already exist, to reduce execution time in the frontend.
87
+ * Fixed: Invalid Google Fonts API requests (e.g. without a `family` parameter) are removed from the HTML.
88
+ * Fixed: A stricter regulax expression is used for matching stylesheet `link` elements, to prevent backtracking.
89
+ * Added: Used Subset(s) option, which allows users to specify which subset(s) they'd like to use when generating stylesheets and down-/preloading (variable) font files.
90
+
91
  = 5.2.2 | June 28th, 2022 =
92
  * Fixed: updated links from ffw.press to daan.dev after the migration.
93