PluginProbe
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant / 2.0.2
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant v2.0.2
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 / Frontend / Beacon.php

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

129 lines 3.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Frontend script loader: usage beacon + X-ray overlay.
4 *
5 * @package EasyFonts
6 */
7
8 namespace EasyFonts\Frontend;
9
10 use EasyFonts\Settings;
11
12 defined( 'ABSPATH' ) || exit;
13
14 /**
15 * Enqueues the runtime beacon and (for admins) the X-ray overlay.
16 */
17 class Beacon {
18
19 /**
20 * Register hooks.
21 */
22 public function boot(): void {
23 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue' ) );
24
25 // The async blocker must run before any theme/plugin script can inject a
26 // provider <link>, so it loads as early as possible in <head>.
27 add_action( 'wp_head', array( $this, 'print_async_blocker' ), 1 );
28 }
29
30 /**
31 * Print the async-injection blocker inline, very early in <head>.
32 *
33 * It intercepts runtime-injected Google/Bunny stylesheet links (which the
34 * server buffer can't see), neutralises the remote request, and reports the
35 * URLs so the next render self-hosts them. Front-end only; respects the
36 * master + async toggles and skips admins' builder/preview screens.
37 */
38 public function print_async_blocker(): void {
39 if ( is_admin() ) {
40 return;
41 }
42
43 if ( ! Settings::get( 'enabled', 1 ) || ! Settings::get( 'async_blocker', 0 ) ) {
44 return;
45 }
46
47 if ( ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || wp_doing_ajax() || is_feed() ) {
48 return;
49 }
50
51 $cfg = array(
52 'endpoint' => esc_url_raw( rest_url( 'easyfonts/v1/async-fonts' ) ),
53 'nonce' => wp_create_nonce( 'wp_rest' ),
54 );
55
56 $src = EASYFONTS_DIR . 'assets/frontend/async-blocker.min.js';
57
58 if ( ! is_readable( $src ) ) {
59 return;
60 }
61
62 $js = file_get_contents( $src ); // phpcs:ignore WordPress.WP.AlternativeFunctions -- reading a bundled plugin asset.
63
64 if ( false === $js || '' === $js ) {
65 return;
66 }
67
68 // Config first, then the blocker. Printed via core's helper so the tag
69 // is generated and escaped by WordPress (no manual echo of markup), and
70 // runs early in <head> so it beats any font-injecting script.
71 $inline = 'window.EasyFontsAsync=' . wp_json_encode( $cfg ) . ';' . $js;
72
73 wp_print_inline_script_tag( $inline, array( 'id' => 'easyfonts-async-blocker' ) );
74 }
75
76 /**
77 * Enqueue scripts.
78 */
79 public function enqueue(): void {
80 if ( is_admin() ) {
81 return;
82 }
83
84 // Master kill switch: when Easy Fonts is disabled, add nothing to the
85 // front end — no beacon, no X-ray, no inline config.
86 if ( ! Settings::get( 'enabled', 1 ) ) {
87 return;
88 }
89
90 $route = (string) wp_parse_url( home_url( add_query_arg( array() ) ), PHP_URL_PATH );
91 $device = wp_is_mobile() ? 'mobile' : 'desktop';
92
93 if ( Settings::get( 'beacon', 1 ) ) {
94 wp_enqueue_script(
95 'easyfonts-beacon',
96 EASYFONTS_URL . 'assets/frontend/beacon.min.js',
97 array(),
98 EASYFONTS_VERSION,
99 array(
100 'strategy' => 'defer',
101 'in_footer' => true,
102 )
103 );
104
105 wp_localize_script(
106 'easyfonts-beacon',
107 'EasyFontsBeacon',
108 array(
109 'endpoint' => esc_url_raw( rest_url( 'easyfonts/v1/beacon' ) ),
110 'nonce' => wp_create_nonce( 'wp_rest' ),
111 'route' => '' === $route ? '/' : $route,
112 'device' => $device,
113 )
114 );
115 }
116
117 // X-ray overlay: admins only, on demand.
118 if ( current_user_can( 'manage_options' ) && isset( $_GET['easyfonts_xray'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
119 wp_enqueue_script(
120 'easyfonts-xray',
121 EASYFONTS_URL . 'assets/frontend/xray.min.js',
122 array(),
123 EASYFONTS_VERSION,
124 array( 'in_footer' => true )
125 );
126 }
127 }
128 }
129