PluginProbe
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant / 2.0.3
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant v2.0.3
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
easyfonts / src / Fonts / MetricsBackfill.php

MetricsBackfill.php in EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant 2.0.3, at src/Fonts/MetricsBackfill.php

111 lines 2.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Metric backfill.
4 *
5 * Metric extraction needs an extra round-trip to Google (a TTF copy, since
6 * served woff2 can't be parsed without Brotli). Doing that during a visitor's
7 * page render risks slow responses or timeouts, so it runs here instead — on
8 * admin page loads, throttled and capped, fully off the front-end critical
9 * path. The metric-matched fallback faces appear as soon as the backfill has
10 * populated each family's metrics.
11 *
12 * @package EasyFonts
13 */
14
15 namespace EasyFonts\Fonts;
16
17 use EasyFonts\Parser\FontMetricsReader;
18 use EasyFonts\Settings;
19
20 defined( 'ABSPATH' ) || exit;
21
22 /**
23 * Fills in font metrics for families that don't have them yet.
24 */
25 class MetricsBackfill {
26
27 /**
28 * Families processed per admin load.
29 */
30 const BATCH = 3;
31
32 /**
33 * Minimum seconds between backfill runs.
34 */
35 const THROTTLE = 60;
36
37 /**
38 * Register hooks.
39 */
40 public function boot(): void {
41 add_action( 'admin_init', array( $this, 'maybe_run' ) );
42 }
43
44 /**
45 * Run a small backfill batch if due and enabled.
46 */
47 public function maybe_run(): void {
48 if ( ! Settings::get( 'metric_fallbacks', 1 ) || ! Settings::get( 'enabled', 1 ) ) {
49 return;
50 }
51
52 if ( get_transient( 'easyfonts_metrics_lock' ) ) {
53 return;
54 }
55
56 $families = $this->families_missing_metrics( self::BATCH );
57
58 if ( empty( $families ) ) {
59 return;
60 }
61
62 // Short lock so concurrent admin loads don't pile on Google requests.
63 set_transient( 'easyfonts_metrics_lock', 1, self::THROTTLE );
64
65 $downloader = new Downloader();
66 $reader = new FontMetricsReader();
67 $registry = new Registry();
68
69 foreach ( $families as $family ) {
70 $bytes = $downloader->fetch_family_ttf( $family['family'], (string) $family['weight'] );
71
72 if ( ! $bytes ) {
73 continue;
74 }
75
76 $metrics = $reader->read( $bytes );
77
78 if ( $metrics ) {
79 $registry->set_family_metrics( $family['family'], $metrics );
80 }
81 }
82 }
83
84 /**
85 * Find Google families with no metrics yet.
86 *
87 * @param int $limit Max families.
88 * @return array<int,array{family:string,weight:string}>
89 */
90 private function families_missing_metrics( int $limit ): array {
91 global $wpdb;
92
93 $table = $wpdb->prefix . 'easyfonts_fonts';
94
95 // phpcs:ignore WordPress.DB.DirectDatabaseQuery
96 $rows = $wpdb->get_results(
97 $wpdb->prepare(
98 "SELECT family, MIN(weight) AS weight
99 FROM {$table}
100 WHERE provider = 'google' AND ( metrics IS NULL OR metrics = '' )
101 GROUP BY family
102 LIMIT %d",
103 $limit
104 ),
105 ARRAY_A
106 );
107
108 return $rows ? $rows : array();
109 }
110 }
111