Version Description
- Added: Compatibility with Mesmerize Pro theme; this theme loads Google Fonts asynchronously, which causes CLS.
- Added: UNIX timestamp cached stylesheets to make sure browser cache of visitors is busted, upon cache refresh.
- Fixed: Running Save & Optimize a 2nd time could trigger some firewall rules, due to the serialized array being passed along with the settings form's POST action. This serialized array is now stored in the form using base64_encode() and decoded before being saved to the database.
- Fixed: Since the Google Fonts API has removed the
subsets
paramater and returns all subsets by default, OMGF now does the same. Unlike the Google Fonts API, OMGF does still respect and apply the parameter if it set, because it is still used by many themes and plugins.- Re-worded Force Subsets (Pro) featured to clarify this behavior.
- Fixed: Some resource hints that were added using unconventional methods (i.e. not using
wp_resource_hints()
) weren't removed. - Fixed: If no regular Google Fonts stylesheets were present, the
omgf_processed_html
filter would never be triggered. - Fixed: Stylesheets on AMP pages would be rewritten to local stylesheets, while this is not supported by AMP.
- Removed: AMP handling (Pro) option from Advanced Settings, because it's no longer supported by AMP.
Download this release
Release Info
Developer | DaanvandenBergh |
Plugin | OMGF | GDPR/DSVGO Compliant, Faster Google Fonts. Easy. |
Version | 5.0.5 |
Comparing to | |
See all releases |
Code changes from version 5.0.4 to 5.0.5
- host-webfonts-local.php +1 -1
- includes/admin/class-settings.php +4 -7
- includes/admin/settings/class-advanced.php +0 -14
- includes/admin/settings/class-builder.php +4 -4
- includes/admin/settings/class-optimize.php +4 -4
- includes/class-admin.php +17 -12
- includes/class-ajax.php +1 -0
- includes/class-omgf.php +19 -0
- includes/class-optimize.php +50 -25
- includes/frontend/class-process.php +87 -34
- readme.txt +12 -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.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.0.5
|
8 |
* Author: Daan from FFW.Press
|
9 |
* Author URI: https://ffw.press
|
10 |
* License: GPL2v2 or later
|
includes/admin/class-settings.php
CHANGED
@@ -23,9 +23,10 @@ class OMGF_Admin_Settings extends OMGF_Admin
|
|
23 |
/**
|
24 |
* Transients
|
25 |
*/
|
26 |
-
const OMGF_NEWS_REEL
|
27 |
-
const OMGF_CACHE_IS_STALE
|
28 |
-
const OMGF_CURRENT_DB_VERSION
|
|
|
29 |
|
30 |
/**
|
31 |
* Settings Fields
|
@@ -115,10 +116,6 @@ class OMGF_Admin_Settings extends OMGF_Admin
|
|
115 |
'trebuchet-ms' => 'Trebuchet MS',
|
116 |
'verdana' => 'Verdana'
|
117 |
];
|
118 |
-
const OMGF_AMP_HANDLING_OPTIONS = [
|
119 |
-
'fallback' => 'Fallback (default)',
|
120 |
-
'disable' => 'Disable'
|
121 |
-
];
|
122 |
|
123 |
/**
|
124 |
* Optimize Fonts
|
23 |
/**
|
24 |
* Transients
|
25 |
*/
|
26 |
+
const OMGF_NEWS_REEL = 'omgf_news_reel';
|
27 |
+
const OMGF_CACHE_IS_STALE = 'omgf_cache_is_stale';
|
28 |
+
const OMGF_CURRENT_DB_VERSION = 'omgf_current_db_version';
|
29 |
+
const OMGF_CACHE_TIMESTAMP = 'omgf_cache_timestamp';
|
30 |
|
31 |
/**
|
32 |
* Settings Fields
|
116 |
'trebuchet-ms' => 'Trebuchet MS',
|
117 |
'verdana' => 'Verdana'
|
118 |
];
|
|
|
|
|
|
|
|
|
119 |
|
120 |
/**
|
121 |
* Optimize Fonts
|
includes/admin/settings/class-advanced.php
CHANGED
@@ -33,7 +33,6 @@ class OMGF_Admin_Settings_Advanced extends OMGF_Admin_Settings_Builder
|
|
33 |
add_filter('omgf_advanced_settings_content', [$this, 'do_before'], 20);
|
34 |
|
35 |
// Settings
|
36 |
-
add_filter('omgf_advanced_settings_content', [$this, 'do_promo_amp_handling'], 40);
|
37 |
add_filter('omgf_advanced_settings_content', [$this, 'do_cache_dir'], 70);
|
38 |
add_filter('omgf_advanced_settings_content', [$this, 'do_promo_fonts_source_url'], 80);
|
39 |
add_filter('omgf_advanced_settings_content', [$this, 'do_uninstall'], 110);
|
@@ -54,19 +53,6 @@ class OMGF_Admin_Settings_Advanced extends OMGF_Admin_Settings_Builder
|
|
54 |
<?php
|
55 |
}
|
56 |
|
57 |
-
public function do_promo_amp_handling()
|
58 |
-
{
|
59 |
-
$this->do_select(
|
60 |
-
__('AMP handling (Pro)', $this->plugin_text_domain),
|
61 |
-
'omgf_pro_amp_handling',
|
62 |
-
OMGF_Admin_Settings::OMGF_AMP_HANDLING_OPTIONS,
|
63 |
-
defined('OMGF_PRO_AMP_HANDLING') ? OMGF_PRO_AMP_HANDLING : '',
|
64 |
-
sprintf(__("Decide how OMGF Pro should behave on AMP pages. Only select <strong>enable</strong> if the custom CSS limit of 75kb is not already reached by your theme and/or other plugins and no other <code>amp-custom</code> tag is present on your pages.", $this->plugin_text_domain), OMGF_Admin_Settings::FFWP_WORDPRESS_PLUGINS_OMGF_PRO) . ' ' . $this->promo,
|
65 |
-
false,
|
66 |
-
true
|
67 |
-
);
|
68 |
-
}
|
69 |
-
|
70 |
/**
|
71 |
*
|
72 |
*/
|
33 |
add_filter('omgf_advanced_settings_content', [$this, 'do_before'], 20);
|
34 |
|
35 |
// Settings
|
|
|
36 |
add_filter('omgf_advanced_settings_content', [$this, 'do_cache_dir'], 70);
|
37 |
add_filter('omgf_advanced_settings_content', [$this, 'do_promo_fonts_source_url'], 80);
|
38 |
add_filter('omgf_advanced_settings_content', [$this, 'do_uninstall'], 110);
|
53 |
<?php
|
54 |
}
|
55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
/**
|
57 |
*
|
58 |
*/
|
includes/admin/settings/class-builder.php
CHANGED
@@ -96,7 +96,7 @@ class OMGF_Admin_Settings_Builder
|
|
96 |
<td>
|
97 |
<?php foreach ($inputs as $option => $option_label) : ?>
|
98 |
<label>
|
99 |
-
<input type="radio" <?= strpos($option_label, '(Pro)') !== false ? apply_filters($name . '_' . $option . '_setting_disabled', 'disabled') : ''; ?> class="<?= str_replace('_', '-', $name . '_' . $option); ?>" name="<?= $name; ?>" value="<?= $option; ?>" <?= $option == $checked ? 'checked="checked"' : ''; ?> />
|
100 |
<?= $option_label; ?>
|
101 |
</label>
|
102 |
<br />
|
@@ -139,7 +139,7 @@ class OMGF_Admin_Settings_Builder
|
|
139 |
$is_selected = $selected == $option;
|
140 |
}
|
141 |
?>
|
142 |
-
<option value="<?= $option; ?>" <?= $is_selected ? 'selected="selected"' : ''; ?>><?= $option_label; ?></option>
|
143 |
<?php endforeach; ?>
|
144 |
</select>
|
145 |
<p class="description">
|
@@ -164,7 +164,7 @@ class OMGF_Admin_Settings_Builder
|
|
164 |
<tr valign="top" <?= $visible ? '' : 'style="display: none;"'; ?>>
|
165 |
<th scope="row"><?= apply_filters($name . '_setting_label', $label); ?></th>
|
166 |
<td>
|
167 |
-
<input class="<?= str_replace('_', '-', $name); ?>" type="number" name="<?= $name; ?>" min="<?= $min; ?>" value="<?= $value; ?>" />
|
168 |
<p class="description">
|
169 |
<?= apply_filters($name . '_setting_description', $description); ?>
|
170 |
</p>
|
@@ -189,7 +189,7 @@ class OMGF_Admin_Settings_Builder
|
|
189 |
<tr class="<?= str_replace('_', '-', $name); ?>-row">
|
190 |
<th scope="row"><?= apply_filters($name . '_setting_label', $label); ?></th>
|
191 |
<td>
|
192 |
-
<input <?= apply_filters($name . '_setting_disabled', $disabled) ? 'disabled' : ''; ?> class="<?= str_replace('_', '-', $name); ?>" type="text" name="<?= $name; ?>" placeholder="<?= $placeholder; ?>" value="<?= $value; ?>" />
|
193 |
<p class="description">
|
194 |
<?= apply_filters($name . 'setting_description', $description); ?>
|
195 |
</p>
|
96 |
<td>
|
97 |
<?php foreach ($inputs as $option => $option_label) : ?>
|
98 |
<label>
|
99 |
+
<input type="radio" <?= strpos($option_label, '(Pro)') !== false ? apply_filters($name . '_' . $option . '_setting_disabled', 'disabled') : ''; ?> class="<?= str_replace('_', '-', $name . '_' . $option); ?>" name="<?= $name; ?>" value="<?= esc_attr($option); ?>" <?= $option == $checked ? 'checked="checked"' : ''; ?> />
|
100 |
<?= $option_label; ?>
|
101 |
</label>
|
102 |
<br />
|
139 |
$is_selected = $selected == $option;
|
140 |
}
|
141 |
?>
|
142 |
+
<option value="<?= esc_attr($option); ?>" <?= $is_selected ? 'selected="selected"' : ''; ?>><?= $option_label; ?></option>
|
143 |
<?php endforeach; ?>
|
144 |
</select>
|
145 |
<p class="description">
|
164 |
<tr valign="top" <?= $visible ? '' : 'style="display: none;"'; ?>>
|
165 |
<th scope="row"><?= apply_filters($name . '_setting_label', $label); ?></th>
|
166 |
<td>
|
167 |
+
<input class="<?= str_replace('_', '-', $name); ?>" type="number" name="<?= $name; ?>" min="<?= $min; ?>" value="<?= esc_attr($value); ?>" />
|
168 |
<p class="description">
|
169 |
<?= apply_filters($name . '_setting_description', $description); ?>
|
170 |
</p>
|
189 |
<tr class="<?= str_replace('_', '-', $name); ?>-row">
|
190 |
<th scope="row"><?= apply_filters($name . '_setting_label', $label); ?></th>
|
191 |
<td>
|
192 |
+
<input <?= apply_filters($name . '_setting_disabled', $disabled) ? 'disabled' : ''; ?> class="<?= str_replace('_', '-', $name); ?>" type="text" name="<?= $name; ?>" placeholder="<?= $placeholder; ?>" value="<?= esc_attr($value); ?>" />
|
193 |
<p class="description">
|
194 |
<?= apply_filters($name . 'setting_description', $description); ?>
|
195 |
</p>
|
includes/admin/settings/class-optimize.php
CHANGED
@@ -217,7 +217,7 @@ class OMGF_Admin_Settings_Optimize extends OMGF_Admin_Settings_Builder
|
|
217 |
'omgf_pro_force_subsets',
|
218 |
OMGF_Admin_Settings::OMGF_FORCE_SUBSETS_OPTIONS,
|
219 |
defined('OMGF_PRO_FORCE_SUBSETS') ? OMGF_PRO_FORCE_SUBSETS : [],
|
220 |
-
__('
|
221 |
true,
|
222 |
true
|
223 |
);
|
@@ -343,9 +343,9 @@ class OMGF_Admin_Settings_Optimize extends OMGF_Admin_Settings_Builder
|
|
343 |
<em><?= sprintf(__("This list is populated with all Google Fonts stylesheets captured and downloaded throughout your site. It will grow organically if other Google Fonts stylesheets are discovered throughout your site.", $this->plugin_text_domain), get_site_url()); ?></em>
|
344 |
</p>
|
345 |
</div>
|
346 |
-
<input type="hidden" name="<?= OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS; ?>" value=
|
347 |
-
<input id="<?= OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_UNLOAD_STYLESHEETS; ?>" type="hidden" name="<?= OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_UNLOAD_STYLESHEETS; ?>" value="<?= OMGF_UNLOAD_STYLESHEETS; ?>" />
|
348 |
-
<input id="<?= OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_CACHE_KEYS; ?>" type="hidden" name="<?= OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_CACHE_KEYS; ?>" value="<?= implode(',', $cache_handles); ?>" />
|
349 |
<?php echo apply_filters('omgf_optimize_fonts_hidden_fields', ''); ?>
|
350 |
</div>
|
351 |
<?php
|
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 |
);
|
343 |
<em><?= sprintf(__("This list is populated with all Google Fonts stylesheets captured and downloaded throughout your site. It will grow organically if other Google Fonts stylesheets are discovered throughout your site.", $this->plugin_text_domain), get_site_url()); ?></em>
|
344 |
</p>
|
345 |
</div>
|
346 |
+
<input type="hidden" name="<?= OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS; ?>" value="<?= base64_encode(serialize($this->optimized_fonts)); ?>" />
|
347 |
+
<input id="<?= OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_UNLOAD_STYLESHEETS; ?>" type="hidden" name="<?= OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_UNLOAD_STYLESHEETS; ?>" value="<?= esc_attr(OMGF_UNLOAD_STYLESHEETS); ?>" />
|
348 |
+
<input id="<?= OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_CACHE_KEYS; ?>" type="hidden" name="<?= OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_CACHE_KEYS; ?>" value="<?= esc_attr(implode(',', $cache_handles)); ?>" />
|
349 |
<?php echo apply_filters('omgf_optimize_fonts_hidden_fields', ''); ?>
|
350 |
</div>
|
351 |
<?php
|
includes/class-admin.php
CHANGED
@@ -51,10 +51,7 @@ class OMGF_Admin
|
|
51 |
$this->do_help();
|
52 |
$this->maybe_do_after_update_notice();
|
53 |
|
54 |
-
|
55 |
-
* @since v4.7.0 Fixes a bug where the Optimized Fonts wouldn't be shown after page reload.
|
56 |
-
*/
|
57 |
-
add_filter('pre_update_option_omgf_optimized_fonts', [$this, 'update_optimized_fonts'], 10, 2);
|
58 |
add_filter('pre_update_option_omgf_cache_keys', [$this, 'clean_up_cache'], 10, 3);
|
59 |
add_action('pre_update_option_omgf_cache_dir', [$this, 'validate_cache_dir'], 10, 2);
|
60 |
add_filter('pre_update_option', [$this, 'settings_changed'], 10, 3);
|
@@ -136,17 +133,25 @@ class OMGF_Admin
|
|
136 |
}
|
137 |
|
138 |
/**
|
139 |
-
*
|
140 |
-
*
|
141 |
*
|
142 |
-
* @
|
143 |
-
*
|
144 |
-
*
|
145 |
-
*
|
|
|
146 |
*/
|
147 |
-
public function
|
148 |
{
|
149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
}
|
151 |
|
152 |
/**
|
51 |
$this->do_help();
|
52 |
$this->maybe_do_after_update_notice();
|
53 |
|
54 |
+
add_filter('alloptions', [$this, 'force_optimized_fonts_from_db']);
|
|
|
|
|
|
|
55 |
add_filter('pre_update_option_omgf_cache_keys', [$this, 'clean_up_cache'], 10, 3);
|
56 |
add_action('pre_update_option_omgf_cache_dir', [$this, 'validate_cache_dir'], 10, 2);
|
57 |
add_filter('pre_update_option', [$this, 'settings_changed'], 10, 3);
|
133 |
}
|
134 |
|
135 |
/**
|
136 |
+
* @since v5.0.5 Forces get_option() to fetch a fresh copy of omgf_optimized_fonts from the database,
|
137 |
+
* we're doing plenty to limit reads from the DB already. So, this is warranted.
|
138 |
*
|
139 |
+
* @see OMGF::optimized_fonts()
|
140 |
+
*
|
141 |
+
* @param array $alloptions
|
142 |
+
*
|
143 |
+
* @return array
|
144 |
*/
|
145 |
+
public function force_optimized_fonts_from_db($alloptions)
|
146 |
{
|
147 |
+
if (
|
148 |
+
isset($alloptions[OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS])
|
149 |
+
&& $alloptions[OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS] == false
|
150 |
+
) {
|
151 |
+
unset($alloptions[OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS]);
|
152 |
+
}
|
153 |
+
|
154 |
+
return $alloptions;
|
155 |
}
|
156 |
|
157 |
/**
|
includes/class-ajax.php
CHANGED
@@ -162,6 +162,7 @@ class OMGF_AJAX
|
|
162 |
'exclude' => [],
|
163 |
'queue' => [
|
164 |
OMGF_Admin_Settings::OMGF_CACHE_IS_STALE,
|
|
|
165 |
OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_CACHE_KEYS,
|
166 |
OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS,
|
167 |
OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_UNLOAD_FONTS,
|
162 |
'exclude' => [],
|
163 |
'queue' => [
|
164 |
OMGF_Admin_Settings::OMGF_CACHE_IS_STALE,
|
165 |
+
OMGF_Admin_Settings::OMGF_CACHE_TIMESTAMP,
|
166 |
OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_CACHE_KEYS,
|
167 |
OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_OPTIMIZED_FONTS,
|
168 |
OMGF_Admin_Settings::OMGF_OPTIMIZE_SETTING_UNLOAD_FONTS,
|
includes/class-omgf.php
CHANGED
@@ -36,6 +36,7 @@ class OMGF
|
|
36 |
}
|
37 |
|
38 |
add_action('admin_init', [$this, 'do_optimize']);
|
|
|
39 |
add_filter('content_url', [$this, 'force_ssl'], 1000, 2);
|
40 |
|
41 |
/**
|
@@ -99,6 +100,24 @@ class OMGF
|
|
99 |
return new OMGF_Admin_Optimize();
|
100 |
}
|
101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
/**
|
103 |
* content_url() uses is_ssl() to detect whether SSL is used. This fails for servers behind
|
104 |
* load balancers and/or reverse proxies. So, we double check with this filter.
|
36 |
}
|
37 |
|
38 |
add_action('admin_init', [$this, 'do_optimize']);
|
39 |
+
add_filter('pre_update_option_omgf_optimized_fonts', [$this, 'base64_decode_optimized_fonts']);
|
40 |
add_filter('content_url', [$this, 'force_ssl'], 1000, 2);
|
41 |
|
42 |
/**
|
100 |
return new OMGF_Admin_Optimize();
|
101 |
}
|
102 |
|
103 |
+
/**
|
104 |
+
* @since v5.0.5 omgf_optimized_fonts is base64_encoded in the frontend, to bypass firewall restrictions on
|
105 |
+
* some servers.
|
106 |
+
*
|
107 |
+
* @param $old_value
|
108 |
+
* @param $value
|
109 |
+
*
|
110 |
+
* @return bool|array
|
111 |
+
*/
|
112 |
+
public function base64_decode_optimized_fonts($value)
|
113 |
+
{
|
114 |
+
if (is_string($value) && base64_decode($value, true)) {
|
115 |
+
return base64_decode($value);
|
116 |
+
}
|
117 |
+
|
118 |
+
return $value;
|
119 |
+
}
|
120 |
+
|
121 |
/**
|
122 |
* content_url() uses is_ssl() to detect whether SSL is used. This fails for servers behind
|
123 |
* load balancers and/or reverse proxies. So, we double check with this filter.
|
includes/class-optimize.php
CHANGED
@@ -43,7 +43,7 @@ class OMGF_Optimize
|
|
43 |
private $original_handle = '';
|
44 |
|
45 |
/** @var string $subset */
|
46 |
-
private $subset = '
|
47 |
|
48 |
/** @var string $return */
|
49 |
private $return = 'url';
|
@@ -58,7 +58,7 @@ class OMGF_Optimize
|
|
58 |
* @param string $family Contents of "family" parameters in Google Fonts API URL, e.g. "?family="Lato:100,200,300,etc."
|
59 |
* @param string $handle The cache handle, generated using $handle + 5 random chars. Used for storing the fonts and stylesheet.
|
60 |
* @param string $original_handle The stylesheet handle, present in the ID attribute.
|
61 |
-
* @param string $subset Contents of "subset" parameter
|
62 |
* @param string $return Valid values: 'url' | 'path' | 'object'.
|
63 |
*
|
64 |
* @return string Local URL of generated stylesheet.
|
@@ -79,7 +79,7 @@ class OMGF_Optimize
|
|
79 |
$this->family = $family;
|
80 |
$this->handle = sanitize_title_with_dashes($handle);
|
81 |
$this->original_handle = sanitize_title_with_dashes($original_handle);
|
82 |
-
$this->subset = $subset
|
83 |
$this->path = OMGF_CACHE_PATH . '/' . $this->handle;
|
84 |
$this->return = $return;
|
85 |
}
|
@@ -101,9 +101,13 @@ class OMGF_Optimize
|
|
101 |
return '';
|
102 |
}
|
103 |
|
104 |
-
$font_families
|
105 |
-
$query[
|
106 |
-
$fonts
|
|
|
|
|
|
|
|
|
107 |
|
108 |
foreach ($font_families as $font_family) {
|
109 |
if (empty($font_family)) {
|
@@ -271,19 +275,15 @@ class OMGF_Optimize
|
|
271 |
* an alternate API.
|
272 |
*/
|
273 |
$alternate_fonts = apply_filters('omgf_alternate_fonts', []);
|
274 |
-
$alternate_url =
|
275 |
-
$
|
276 |
|
277 |
if (in_array($family, array_keys($alternate_fonts))) {
|
278 |
-
$alternate_url =
|
279 |
-
|
280 |
-
$url = apply_filters('omgf_alternate_api_url', '', $family);
|
281 |
unset($query);
|
282 |
}
|
283 |
|
284 |
-
$
|
285 |
-
|
286 |
-
if (isset($query)) {
|
287 |
$query_string = '?' . http_build_query($query);
|
288 |
}
|
289 |
|
@@ -295,19 +295,10 @@ class OMGF_Optimize
|
|
295 |
}
|
296 |
|
297 |
if (!$alternate_url) {
|
298 |
-
$response =
|
299 |
-
sprintf(self::OMGF_GOOGLE_FONTS_API_URL . '%s', $family) . $query_string
|
300 |
-
);
|
301 |
-
|
302 |
-
// Try with mirror, if first request failed.
|
303 |
-
if (is_wp_error($response) && $response->get_error_code() == 'http_request_failed') {
|
304 |
-
$response = wp_remote_get(
|
305 |
-
sprintf(self::OMGF_GOOGLE_FONTS_API_FALLBACK . '%s', $family) . $query_string
|
306 |
-
);
|
307 |
-
}
|
308 |
} else {
|
309 |
$response = wp_remote_get(
|
310 |
-
sprintf($
|
311 |
);
|
312 |
}
|
313 |
|
@@ -315,6 +306,16 @@ class OMGF_Optimize
|
|
315 |
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);
|
316 |
}
|
317 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
318 |
$response_code = wp_remote_retrieve_response_code($response);
|
319 |
|
320 |
if ($response_code != 200) {
|
@@ -349,6 +350,30 @@ class OMGF_Optimize
|
|
349 |
return json_decode(wp_remote_retrieve_body($response));
|
350 |
}
|
351 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
352 |
/**
|
353 |
* @param $font_families
|
354 |
* @param $font
|
43 |
private $original_handle = '';
|
44 |
|
45 |
/** @var string $subset */
|
46 |
+
private $subset = '';
|
47 |
|
48 |
/** @var string $return */
|
49 |
private $return = 'url';
|
58 |
* @param string $family Contents of "family" parameters in Google Fonts API URL, e.g. "?family="Lato:100,200,300,etc."
|
59 |
* @param string $handle The cache handle, generated using $handle + 5 random chars. Used for storing the fonts and stylesheet.
|
60 |
* @param string $original_handle The stylesheet handle, present in the ID attribute.
|
61 |
+
* @param string $subset Contents of "subset" parameter. If left empty, the downloaded files will support all subsets.
|
62 |
* @param string $return Valid values: 'url' | 'path' | 'object'.
|
63 |
*
|
64 |
* @return string Local URL of generated stylesheet.
|
79 |
$this->family = $family;
|
80 |
$this->handle = sanitize_title_with_dashes($handle);
|
81 |
$this->original_handle = sanitize_title_with_dashes($original_handle);
|
82 |
+
$this->subset = $subset;
|
83 |
$this->path = OMGF_CACHE_PATH . '/' . $this->handle;
|
84 |
$this->return = $return;
|
85 |
}
|
101 |
return '';
|
102 |
}
|
103 |
|
104 |
+
$font_families = explode('|', $this->family);
|
105 |
+
$query = [];
|
106 |
+
$fonts = [];
|
107 |
+
|
108 |
+
if ($this->subset) {
|
109 |
+
$query['subsets'] = $this->subset;
|
110 |
+
}
|
111 |
|
112 |
foreach ($font_families as $font_family) {
|
113 |
if (empty($font_family)) {
|
275 |
* an alternate API.
|
276 |
*/
|
277 |
$alternate_fonts = apply_filters('omgf_alternate_fonts', []);
|
278 |
+
$alternate_url = '';
|
279 |
+
$query_string = '';
|
280 |
|
281 |
if (in_array($family, array_keys($alternate_fonts))) {
|
282 |
+
$alternate_url = apply_filters('omgf_alternate_api_url', '', $family);
|
|
|
|
|
283 |
unset($query);
|
284 |
}
|
285 |
|
286 |
+
if (!empty($query)) {
|
|
|
|
|
287 |
$query_string = '?' . http_build_query($query);
|
288 |
}
|
289 |
|
295 |
}
|
296 |
|
297 |
if (!$alternate_url) {
|
298 |
+
$response = $this->remote_get($family, $query_string);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
299 |
} else {
|
300 |
$response = wp_remote_get(
|
301 |
+
sprintf($alternate_url . '%s', $family) . $query_string
|
302 |
);
|
303 |
}
|
304 |
|
306 |
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);
|
307 |
}
|
308 |
|
309 |
+
/**
|
310 |
+
* If no subset was set, do a quick refresh to make sure all available subsets are included.
|
311 |
+
*/
|
312 |
+
if (!$query_string && !$alternate_url) {
|
313 |
+
$response_body = wp_remote_retrieve_body($response);
|
314 |
+
$body = json_decode($response_body);
|
315 |
+
$query_string = '?subsets=' . (isset($body->subsets) ? implode(',', $body->subsets) : 'latin,latin-ext');
|
316 |
+
$response = $this->remote_get($family, $query_string);
|
317 |
+
}
|
318 |
+
|
319 |
$response_code = wp_remote_retrieve_response_code($response);
|
320 |
|
321 |
if ($response_code != 200) {
|
350 |
return json_decode(wp_remote_retrieve_body($response));
|
351 |
}
|
352 |
|
353 |
+
/**
|
354 |
+
* Wrapper for wp_remote_get() which tries a mirror API if the first request fails. (It tends to timeout sometimes)
|
355 |
+
*
|
356 |
+
* @param string $family
|
357 |
+
* @param string $query
|
358 |
+
*
|
359 |
+
* @return array|WP_Error
|
360 |
+
*/
|
361 |
+
private function remote_get($family, $query)
|
362 |
+
{
|
363 |
+
$response = wp_remote_get(
|
364 |
+
sprintf(self::OMGF_GOOGLE_FONTS_API_URL . '%s', $family) . $query
|
365 |
+
);
|
366 |
+
|
367 |
+
// Try with mirror, if first request failed.
|
368 |
+
if (is_wp_error($response) && $response->get_error_code() == 'http_request_failed') {
|
369 |
+
$response = wp_remote_get(
|
370 |
+
sprintf(self::OMGF_GOOGLE_FONTS_API_FALLBACK . '%s', $family) . $query
|
371 |
+
);
|
372 |
+
}
|
373 |
+
|
374 |
+
return $response;
|
375 |
+
}
|
376 |
+
|
377 |
/**
|
378 |
* @param $font_families
|
379 |
* @param $font
|
includes/frontend/class-process.php
CHANGED
@@ -34,11 +34,22 @@ class OMGF_Frontend_Process
|
|
34 |
'vc_action'
|
35 |
];
|
36 |
|
|
|
|
|
|
|
37 |
/**
|
38 |
* OMGF_Frontend_Functions constructor.
|
39 |
*/
|
40 |
public function __construct()
|
41 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
$this->init();
|
43 |
}
|
44 |
|
@@ -56,13 +67,16 @@ class OMGF_Frontend_Process
|
|
56 |
return;
|
57 |
}
|
58 |
|
|
|
59 |
add_action('template_redirect', [$this, 'maybe_buffer_output'], 3);
|
|
|
60 |
add_filter('omgf_buffer_output', [$this, 'parse']);
|
61 |
-
add_action('wp_head', [$this, 'add_preloads'], 3);
|
62 |
-
add_filter('wp_resource_hints', [$this, 'remove_resource_hints']);
|
63 |
|
64 |
/** Smart Slider 3 compatibility */
|
65 |
add_filter('wordpress_prepare_output', [$this, 'parse'], 11);
|
|
|
|
|
|
|
66 |
}
|
67 |
|
68 |
/**
|
@@ -113,31 +127,6 @@ class OMGF_Frontend_Process
|
|
113 |
}
|
114 |
}
|
115 |
|
116 |
-
/**
|
117 |
-
* We're downloading the fonts, so preconnecting to Google is a waste of time. Literally.
|
118 |
-
*
|
119 |
-
* @param array $urls
|
120 |
-
* @return array
|
121 |
-
*/
|
122 |
-
public function remove_resource_hints($urls)
|
123 |
-
{
|
124 |
-
foreach ($urls as $key => &$url) {
|
125 |
-
if (is_array($url)) {
|
126 |
-
$url = $this->remove_resource_hints($url);
|
127 |
-
|
128 |
-
continue;
|
129 |
-
}
|
130 |
-
|
131 |
-
foreach (self::RESOURCE_HINTS as $hint) {
|
132 |
-
if (strpos($url, $hint) !== false) {
|
133 |
-
unset($urls[$key]);
|
134 |
-
}
|
135 |
-
}
|
136 |
-
}
|
137 |
-
|
138 |
-
return $urls;
|
139 |
-
}
|
140 |
-
|
141 |
/**
|
142 |
* Start output buffer.
|
143 |
*
|
@@ -148,7 +137,7 @@ class OMGF_Frontend_Process
|
|
148 |
public function maybe_buffer_output()
|
149 |
{
|
150 |
/**
|
151 |
-
* Always run, if the omgf_optimize (added by Save & Optimize) is set.
|
152 |
*/
|
153 |
if (isset($_GET['omgf_optimize'])) {
|
154 |
return ob_start([$this, 'return_buffer']);
|
@@ -231,6 +220,39 @@ class OMGF_Frontend_Process
|
|
231 |
return apply_filters('omgf_buffer_output', $html);
|
232 |
}
|
233 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
234 |
/**
|
235 |
* This method uses Regular Expressions to parse the HTML. It's tested to be at least
|
236 |
* twice as fast compared to using Xpath.
|
@@ -246,23 +268,27 @@ class OMGF_Frontend_Process
|
|
246 |
*
|
247 |
* Using Xpath proved to be untestable, because it varied anywhere between 38 seconds and, well, timeouts.
|
248 |
*
|
249 |
-
* @param string $html
|
250 |
*
|
251 |
-
* @return string
|
252 |
*/
|
253 |
public function parse($html)
|
254 |
{
|
|
|
|
|
|
|
|
|
255 |
preg_match_all('/<link.*fonts\.googleapis\.com\/css.*?[\/]?>/', $html, $links);
|
256 |
|
257 |
if (!isset($links[0]) || empty($links[0])) {
|
258 |
-
return $html;
|
259 |
}
|
260 |
|
261 |
$google_fonts = $this->build_fonts_set($links[0]);
|
262 |
$search_replace = $this->build_search_replace($google_fonts);
|
263 |
|
264 |
if (empty($search_replace['search']) || empty($search_replace['replace'])) {
|
265 |
-
return $html;
|
266 |
}
|
267 |
|
268 |
$html = str_replace($search_replace['search'], $search_replace['replace'], $html);
|
@@ -270,6 +296,17 @@ class OMGF_Frontend_Process
|
|
270 |
return apply_filters('omgf_processed_html', $html, $this);
|
271 |
}
|
272 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
273 |
/**
|
274 |
* Builds a processable array of Google Fonts' ID and (external) URL.
|
275 |
*
|
@@ -396,7 +433,7 @@ class OMGF_Frontend_Process
|
|
396 |
*/
|
397 |
if (!isset($_GET['omgf_optimize']) && file_exists(OMGF_CACHE_PATH . "/$handle/$handle.css")) {
|
398 |
$search[$key] = $stack['href'];
|
399 |
-
$replace[$key] = content_url(OMGF_CACHE_DIR . "/$handle/$handle.css");
|
400 |
|
401 |
continue;
|
402 |
}
|
@@ -418,7 +455,7 @@ class OMGF_Frontend_Process
|
|
418 |
}
|
419 |
|
420 |
$search[$key] = $stack['href'];
|
421 |
-
$replace[$key] = $cached_url;
|
422 |
}
|
423 |
|
424 |
return ['search' => $search, 'replace' => $replace];
|
@@ -523,4 +560,20 @@ class OMGF_Frontend_Process
|
|
523 |
|
524 |
return ['family' => implode('|', $fonts)];
|
525 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
526 |
}
|
34 |
'vc_action'
|
35 |
];
|
36 |
|
37 |
+
/** @var string $timestamp */
|
38 |
+
private $timestamp = '';
|
39 |
+
|
40 |
/**
|
41 |
* OMGF_Frontend_Functions constructor.
|
42 |
*/
|
43 |
public function __construct()
|
44 |
{
|
45 |
+
$this->timestamp = get_option(OMGF_Admin_Settings::OMGF_CACHE_TIMESTAMP, '');
|
46 |
+
|
47 |
+
if (!$this->timestamp) {
|
48 |
+
$this->timestamp = time();
|
49 |
+
|
50 |
+
update_option(OMGF_Admin_settings::OMGF_CACHE_TIMESTAMP, $this->timestamp);
|
51 |
+
}
|
52 |
+
|
53 |
$this->init();
|
54 |
}
|
55 |
|
67 |
return;
|
68 |
}
|
69 |
|
70 |
+
add_action('wp_head', [$this, 'add_preloads'], 3);
|
71 |
add_action('template_redirect', [$this, 'maybe_buffer_output'], 3);
|
72 |
+
add_filter('omgf_buffer_output', [$this, 'remove_resource_hints'], 9);
|
73 |
add_filter('omgf_buffer_output', [$this, 'parse']);
|
|
|
|
|
74 |
|
75 |
/** Smart Slider 3 compatibility */
|
76 |
add_filter('wordpress_prepare_output', [$this, 'parse'], 11);
|
77 |
+
|
78 |
+
/** Mesmerize Pro theme compatibility */
|
79 |
+
add_filter('style_loader_tag', [$this, 'remove_mesmerize_filter'], 12, 1);
|
80 |
}
|
81 |
|
82 |
/**
|
127 |
}
|
128 |
}
|
129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
/**
|
131 |
* Start output buffer.
|
132 |
*
|
137 |
public function maybe_buffer_output()
|
138 |
{
|
139 |
/**
|
140 |
+
* Always run, if the omgf_optimize parameter (added by Save & Optimize) is set.
|
141 |
*/
|
142 |
if (isset($_GET['omgf_optimize'])) {
|
143 |
return ob_start([$this, 'return_buffer']);
|
220 |
return apply_filters('omgf_buffer_output', $html);
|
221 |
}
|
222 |
|
223 |
+
/**
|
224 |
+
* We're downloading the fonts, so preconnecting to Google is a waste of time. Literally.
|
225 |
+
*
|
226 |
+
* @since v5.0.5 Use a regular expression to match all resource hints.
|
227 |
+
*
|
228 |
+
* @param string $html Valid HTML.
|
229 |
+
*
|
230 |
+
* @return string Valid HTML.
|
231 |
+
*/
|
232 |
+
public function remove_resource_hints($html)
|
233 |
+
{
|
234 |
+
preg_match_all('/<link.*?(dns-prefetch|preconnect).*?>/', $html, $resource_hints);
|
235 |
+
|
236 |
+
if (!isset($resource_hints[0]) || empty($resource_hints[0])) {
|
237 |
+
return $html;
|
238 |
+
}
|
239 |
+
|
240 |
+
$search = [];
|
241 |
+
|
242 |
+
foreach ($resource_hints[0] as $key => $match) {
|
243 |
+
if (
|
244 |
+
strpos($match, 'fonts.googleapis.com') === false
|
245 |
+
&& strpos($match, 'fonts.gstatic.com') === false
|
246 |
+
) {
|
247 |
+
continue;
|
248 |
+
}
|
249 |
+
|
250 |
+
$search[] = $match;
|
251 |
+
}
|
252 |
+
|
253 |
+
return str_replace($search, '', $html);
|
254 |
+
}
|
255 |
+
|
256 |
/**
|
257 |
* This method uses Regular Expressions to parse the HTML. It's tested to be at least
|
258 |
* twice as fast compared to using Xpath.
|
268 |
*
|
269 |
* Using Xpath proved to be untestable, because it varied anywhere between 38 seconds and, well, timeouts.
|
270 |
*
|
271 |
+
* @param string $html Valid HTML.
|
272 |
*
|
273 |
+
* @return string Valid HTML, filtered by @filter omgf_processed_html.
|
274 |
*/
|
275 |
public function parse($html)
|
276 |
{
|
277 |
+
if ($this->is_amp()) {
|
278 |
+
return apply_filters('omgf_processed_html', $html, $this);
|
279 |
+
}
|
280 |
+
|
281 |
preg_match_all('/<link.*fonts\.googleapis\.com\/css.*?[\/]?>/', $html, $links);
|
282 |
|
283 |
if (!isset($links[0]) || empty($links[0])) {
|
284 |
+
return apply_filters('omgf_processed_html', $html, $this);
|
285 |
}
|
286 |
|
287 |
$google_fonts = $this->build_fonts_set($links[0]);
|
288 |
$search_replace = $this->build_search_replace($google_fonts);
|
289 |
|
290 |
if (empty($search_replace['search']) || empty($search_replace['replace'])) {
|
291 |
+
return apply_filters('omgf_processed_html', $html, $this);
|
292 |
}
|
293 |
|
294 |
$html = str_replace($search_replace['search'], $search_replace['replace'], $html);
|
296 |
return apply_filters('omgf_processed_html', $html, $this);
|
297 |
}
|
298 |
|
299 |
+
/**
|
300 |
+
* @since v5.0.5 Check if current page is AMP page.
|
301 |
+
*
|
302 |
+
* @return bool
|
303 |
+
*/
|
304 |
+
private function is_amp()
|
305 |
+
{
|
306 |
+
return (function_exists('is_amp_endpoint') && is_amp_endpoint())
|
307 |
+
|| (function_exists('ampforwp_is_amp_endpoint') && ampforwp_is_amp_endpoint());
|
308 |
+
}
|
309 |
+
|
310 |
/**
|
311 |
* Builds a processable array of Google Fonts' ID and (external) URL.
|
312 |
*
|
433 |
*/
|
434 |
if (!isset($_GET['omgf_optimize']) && file_exists(OMGF_CACHE_PATH . "/$handle/$handle.css")) {
|
435 |
$search[$key] = $stack['href'];
|
436 |
+
$replace[$key] = content_url(OMGF_CACHE_DIR . "/$handle/$handle.css") . '?ver=' . $this->timestamp;
|
437 |
|
438 |
continue;
|
439 |
}
|
455 |
}
|
456 |
|
457 |
$search[$key] = $stack['href'];
|
458 |
+
$replace[$key] = $cached_url . '?ver=' . $this->timestamp;
|
459 |
}
|
460 |
|
461 |
return ['search' => $search, 'replace' => $replace];
|
560 |
|
561 |
return ['family' => implode('|', $fonts)];
|
562 |
}
|
563 |
+
|
564 |
+
/**
|
565 |
+
* Because all great themes come packed with extra Cumulative Layout Shifting.
|
566 |
+
*
|
567 |
+
* @param string $tag
|
568 |
+
*
|
569 |
+
* @return string
|
570 |
+
*/
|
571 |
+
public function remove_mesmerize_filter($tag)
|
572 |
+
{
|
573 |
+
if (wp_get_theme()->template == 'mesmerize-pro' && strpos($tag, 'fonts.googleapis.com') !== false) {
|
574 |
+
return str_replace('href="" data-href', 'href', $tag);
|
575 |
+
}
|
576 |
+
|
577 |
+
return $tag;
|
578 |
+
}
|
579 |
}
|
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: 5.9
|
6 |
-
Stable tag: 5.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,17 @@ For the FAQ, [click here](https://docs.ffw.press/category/76-omgf-pro---faq).
|
|
75 |
|
76 |
== Changelog ==
|
77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
= 5.0.4 =
|
79 |
* Fixed: don't allow starting buffer twice.
|
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: 5.9
|
6 |
+
Stable tag: 5.0.5
|
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.0.5 =
|
79 |
+
* Added: Compatibility with Mesmerize Pro theme; this theme loads Google Fonts asynchronously, which causes CLS.
|
80 |
+
* Added: UNIX timestamp cached stylesheets to make sure browser cache of visitors is busted, upon cache refresh.
|
81 |
+
* Fixed: Running Save & Optimize a 2nd time could trigger some firewall rules, due to the serialized array being passed along with the settings form's POST action. This serialized array is now stored in the form using base64_encode() and decoded before being saved to the database.
|
82 |
+
* Fixed: Since the Google Fonts API has removed the `subsets` paramater and returns all subsets by default, OMGF now does the same. Unlike the Google Fonts API, OMGF does still respect and apply the parameter if it set, because it is still used by many themes and plugins.
|
83 |
+
* Re-worded Force Subsets (Pro) featured to clarify this behavior.
|
84 |
+
* Fixed: Some resource hints that were added using unconventional methods (i.e. *not* using `wp_resource_hints()`) weren't removed.
|
85 |
+
* Fixed: If no regular Google Fonts stylesheets were present, the `omgf_processed_html` filter would never be triggered.
|
86 |
+
* Fixed: Stylesheets on AMP pages would be rewritten to local stylesheets, while this is not supported by AMP.
|
87 |
+
* Removed: AMP handling (Pro) option from Advanced Settings, because it's no longer supported by AMP.
|
88 |
+
|
89 |
= 5.0.4 =
|
90 |
* Fixed: don't allow starting buffer twice.
|
91 |
|