PluginProbe
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant / 2.0.4
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant v2.0.4
2.0.4 2.0.3 2.0.2 2.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2 1.3 2.0.0
← All changes | src/Frontend/OutputBuffer.php +30 -10 2.0.2 → 2.0.4 View file →
@@ -133,12 +133,12 @@
133 133 // A warm/probe is never scoped, so it downloads every declared font
134 134 // and keeps the shared cache complete.
135 135 $tracker = new UsageTracker();
136 136 $profile = $this->force
137 - ? array( 'scope_out' => array(), 'above_fold' => array(), 'measured' => false )
137 + ? array( 'scope_out' => array(), 'fold_faces' => array(), 'measured' => false )
138 138 : $tracker->route_render_profile( $route );
139 139 $scope_out = $profile['scope_out'];
140 - $above_fold = $profile['above_fold'];
140 + $fold_faces = $profile['fold_faces'];
141 141 $measured = ! empty( $profile['measured'] );
142 142
143 143 // 1. Detect + localise. The consolidator is transactional: it only
144 144 // rewrites the page when every font it needs is already hosted
@@ -158,9 +158,9 @@
158 158 $buffer = $stripped['html'];
159 159 }
160 160
161 161 // 3. Inject preloads → consolidated stylesheet → metric fallbacks.
162 - $head = $this->build_head( $route, $device, $above_fold );
162 + $head = $this->build_head( $route, $device, $fold_faces );
163 163
164 164 if ( '' !== $head ) {
165 165 $buffer = $this->html->before_head_close( $buffer, $head );
166 166 }
@@ -207,10 +207,17 @@
207 207 if ( get_transient( $lock ) ) {
208 208 return;
209 209 }
210 210
211 - set_transient( $lock, 1, 60 );
211 + // Claim with a per-request token and re-read: if two requests raced
212 + // through the check above, only the one whose token survived proceeds.
213 + $claim = wp_generate_password( 8, false, false );
214 + set_transient( $lock, $claim, 60 );
212 215
216 + if ( get_transient( $lock ) !== $claim ) {
217 + return;
218 + }
219 +
213 220 $target = add_query_arg(
214 221 array(
215 222 'easyfonts_probe' => Settings::warm_key(),
216 223 'efbust' => (string) time(),
@@ -235,18 +242,18 @@
235 242 * stylesheet, then the metric-matched fallback faces.
236 243 *
237 244 * @param string $route Canonical route for this page.
238 245 * @param string $device Device ('mobile'|'desktop').
239 - * @param array<string,bool> $above_fold Lowercased families above the fold on this route.
246 + * @param array<string,array<string,bool>> $fold_faces Above-the-fold faces per family rendered on this route.
240 247 * @return string
241 248 */
242 - private function build_head( string $route = '', string $device = 'any', array $above_fold = array() ): string {
249 + private function build_head( string $route = '', string $device = 'any', array $fold_faces = array() ): string {
243 250 $out = '';
244 251 $stylesheet = Consolidator::stylesheet_url();
245 252
246 253 // Preloads — above the stylesheet, deduped inside SmartPreload, scoped
247 254 // to the fonts actually emitted on this page (Consolidator::touched).
248 - $out .= ( new SmartPreload() )->build( $route, $device, $this->present_families(), $above_fold );
255 + $out .= ( new SmartPreload() )->build( $route, $device, $this->present_families(), $fold_faces );
249 256
250 257 // The single consolidated stylesheet — either inlined (non-render-
251 258 // blocking: no extra request) or as a normal <link>.
252 259 if ( '' !== $stylesheet ) {
@@ -255,13 +262,26 @@
255 262 if ( Settings::get( 'inline_css', 0 ) ) {
256 263 $file = Consolidator::stylesheet_file();
257 264
258 265 if ( '' !== $file ) {
259 - $storage = new Storage();
260 - $css = $storage->exists( $file ) ? (string) @file_get_contents( $storage->path( $file ) ) : ''; // phpcs:ignore WordPress.WP.AlternativeFunctions
266 + // The stylesheet content is deterministic for its filename
267 + // (content-hash keyed), so cache the minified result instead
268 + // of re-reading + re-minifying the file on every request.
269 + $cache_key = 'easyfonts_inline_' . md5( $file );
270 + $css = get_transient( $cache_key );
261 271
272 + if ( ! is_string( $css ) || '' === $css ) {
273 + $storage = new Storage();
274 + $raw = $storage->exists( $file ) ? (string) @file_get_contents( $storage->path( $file ) ) : ''; // phpcs:ignore WordPress.WP.AlternativeFunctions
275 + $css = '' !== $raw ? $this->minify_css( $raw ) : '';
276 +
277 + if ( '' !== $css ) {
278 + set_transient( $cache_key, $css, DAY_IN_SECONDS );
279 + }
280 + }
281 +
262 282 if ( '' !== $css ) {
263 - $out .= '<style id="easyfonts-fonts">' . $this->minify_css( $css ) . '</style>' . "\n";
283 + $out .= '<style id="easyfonts-fonts">' . $css . '</style>' . "\n";
264 284 $inlined = true;
265 285 }
266 286 }
267 287 }