PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.3.7
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.3.7
1.3.7 1.3.6 1.3.5 1.3.4 1.3.3 1.3.2 1.3.1 1.3.0 1.2.4 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 All 33 releases
← All changes | includes/modules/Heartbeat/HeartbeatModule.php +69 -21 1.0.3 → 1.3.7 View file →
@@ -15,8 +15,10 @@
15 15 declare(strict_types=1);
16 16
17 17 namespace XSpeed\Modules\Heartbeat;
18 18
19 +defined( 'ABSPATH' ) || exit;
20 +
19 21 use XSpeed\Module;
20 22
21 23 final class HeartbeatModule extends Module {
22 24
@@ -32,11 +34,12 @@
32 34 private const CONTEXTS = array( 'dashboard', 'editor', 'frontend' );
33 35
34 36 public function ui_metadata(): array {
35 37 return array(
36 - 'label' => 'Heartbeat',
38 + 'label' => __( 'Heartbeat', 'xspeed' ),
37 39 'icon' => 'Activity',
38 - 'description' => 'Control the WordPress Heartbeat API per context.',
40 + 'description' => __( 'Controls how often WordPress checks in with your server in the background.', 'xspeed' ),
41 + 'group' => 'performance',
39 42 );
40 43 }
41 44
42 45 /**
@@ -58,10 +61,10 @@
58 61 'type' => 'enum',
59 62 'default' => self::BEHAVIOR_THROTTLE,
60 63 'options' => $behavior_options,
61 64 'option_labels' => $behavior_option_labels,
62 - 'label' => 'Dashboard',
63 - 'description' => 'Heartbeat behavior on /wp-admin/ screens (autosave, notifications).',
65 + 'label' => __( 'Dashboard', 'xspeed' ),
66 + 'description' => __( 'Background checks on admin screens, used for notifications.', 'xspeed' ),
64 67 ),
65 68 'behavior_editor' => array(
66 69 'type' => 'enum',
67 70 'default' => self::BEHAVIOR_THROTTLE,
@@ -66,10 +69,10 @@
66 69 'type' => 'enum',
67 70 'default' => self::BEHAVIOR_THROTTLE,
68 71 'options' => $behavior_options,
69 72 'option_labels' => $behavior_option_labels,
70 - 'label' => 'Editor',
71 - 'description' => 'Heartbeat in the post / block editor. Disable only if you do not need autosave or co-edit locks.',
73 + 'label' => __( 'Editor', 'xspeed' ),
74 + 'description' => __( 'Background checks in the post editor. Disable only if you do not need autosave or the warning when someone else is editing.', 'xspeed' ),
72 75 ),
73 76 'behavior_frontend' => array(
74 77 'type' => 'enum',
75 78 'default' => self::BEHAVIOR_DISABLE,
@@ -74,10 +77,10 @@
74 77 'type' => 'enum',
75 78 'default' => self::BEHAVIOR_DISABLE,
76 79 'options' => $behavior_options,
77 80 'option_labels' => $behavior_option_labels,
78 - 'label' => 'Frontend',
79 - 'description' => 'Heartbeat on the public site. Recommended off — most themes never need it and it costs admin-ajax requests per visitor.',
81 + 'label' => __( 'Frontend', 'xspeed' ),
82 + 'description' => __( 'Background checks on the public site, which only some plugins add. Disable is recommended, as it cuts extra requests to your server.', 'xspeed' ),
80 83 ),
81 84 'frequency' => array(
82 85 'type' => 'int',
83 86 'default' => 60,
@@ -82,10 +85,19 @@
82 85 'type' => 'int',
83 86 'default' => 60,
84 87 'min' => 15,
85 88 'max' => 300,
86 - 'label' => 'Throttle Frequency',
87 - 'description' => 'Interval in seconds for contexts set to Throttle. 60 is a sane default; lower = faster sync but more requests.',
89 + 'label' => __( 'Throttle interval', 'xspeed' ),
90 + 'unit' => 'seconds',
91 + 'description' => __( 'Seconds between checks where you chose Throttle. 60 suits most sites; a lower number means more requests.', 'xspeed' ),
92 + 'advanced' => true,
93 + 'dependsOn' => array(
94 + 'any' => array(
95 + array( 'field' => 'behavior_dashboard', 'value' => self::BEHAVIOR_THROTTLE ),
96 + array( 'field' => 'behavior_editor', 'value' => self::BEHAVIOR_THROTTLE ),
97 + array( 'field' => 'behavior_frontend', 'value' => self::BEHAVIOR_THROTTLE ),
98 + ),
99 + ),
88 100 ),
89 101 );
90 102 }
91 103
@@ -97,8 +109,9 @@
97 109 array(
98 110 'name' => 'xspeed heartbeat',
99 111 'callback' => array( $this, 'cli_handler' ),
100 112 'shortdesc' => 'Inspect or modify xSpeed heartbeat settings.',
113 + 'ai_hint' => 'Inspect or change WordPress Heartbeat (admin-ajax polling) frequency. Use for high admin-ajax.php CPU load, or hosting warnings about too many background requests.',
101 114 'synopsis' => array(
102 115 array(
103 116 'type' => 'positional',
104 117 'name' => 'action',
@@ -104,19 +117,25 @@
104 117 'name' => 'action',
105 118 'options' => array( 'show', 'set' ),
106 119 'optional' => false,
107 120 ),
121 + // Use `--for` (not `--context`): WP-CLI silently swallows a
122 + // `--context` assoc arg before it reaches the command, so
123 + // `set --context= --behavior=` always lost the context and
124 + // errored "Nothing to set". `--for` reads naturally
125 + // (set --for=editor --behavior=disable) and is collision-
126 + // free. No `options` constraint either — an options list
127 + // also dropped args from $assoc; we validate in
128 + // cli_handler() instead. (FBS-82153 Bug 2.)
108 129 array(
109 130 'type' => 'assoc',
110 - 'name' => 'context',
131 + 'name' => 'for',
111 132 'optional' => true,
112 - 'options' => self::CONTEXTS,
113 133 ),
114 134 array(
115 135 'type' => 'assoc',
116 136 'name' => 'behavior',
117 137 'optional' => true,
118 - 'options' => array( self::BEHAVIOR_KEEP, self::BEHAVIOR_THROTTLE, self::BEHAVIOR_DISABLE ),
119 138 ),
120 139 array(
121 140 'type' => 'assoc',
122 141 'name' => 'frequency',
@@ -127,12 +146,23 @@
127 146 );
128 147 }
129 148
130 149 public function boot(): void {
131 - // `init` is early enough to register our filters before Heartbeat
132 - // itself enqueues. Stay low priority to defer to plugins that ran
133 - // at plugins_loaded.
134 - add_action( 'init', array( $this, 'apply_settings' ), 5 );
150 + // Context resolution depends on WHEN we can classify the request:
151 + // - Frontend: known at `init` (is_admin() is reliable there), and we
152 + // must act before wp_enqueue_scripts (priority 10) registers the
153 + // heartbeat script.
154 + // - Admin: dashboard-vs-editor needs get_current_screen(), which is
155 + // NULL at `init` and only populated from the `current_screen`
156 + // action onward. Resolving context at init always returned
157 + // "dashboard" on editor screens, so behavior_editor was dead.
158 + // (FBS-82153 Bug 1.) Hook admin on `current_screen` instead, which
159 + // fires before admin_enqueue_scripts so we can still dequeue.
160 + if ( is_admin() ) {
161 + add_action( 'current_screen', array( $this, 'apply_settings' ) );
162 + } else {
163 + add_action( 'init', array( $this, 'apply_settings' ), 5 );
164 + }
135 165 }
136 166
137 167 /**
138 168 * Hook handler — translates our settings into Heartbeat behavior. Runs
@@ -203,17 +233,35 @@
203 233 return;
204 234 }
205 235
206 236 if ( 'set' === $action ) {
207 - $patch = array();
208 - if ( isset( $assoc['context'], $assoc['behavior'] ) ) {
209 - $patch[ 'behavior_' . $assoc['context'] ] = $assoc['behavior'];
237 + $patch = array();
238 + $behaviors = array( self::BEHAVIOR_KEEP, self::BEHAVIOR_THROTTLE, self::BEHAVIOR_DISABLE );
239 +
240 + $has_context = isset( $assoc['for'] ) && '' !== $assoc['for'];
241 + $has_behavior = isset( $assoc['behavior'] ) && '' !== $assoc['behavior'];
242 +
243 + // --for and --behavior are a pair: both or neither.
244 + if ( $has_context xor $has_behavior ) {
245 + \WP_CLI::error( 'Pass --for and --behavior together.' );
246 + return;
210 247 }
248 + if ( $has_context && $has_behavior ) {
249 + if ( ! in_array( $assoc['for'], self::CONTEXTS, true ) ) {
250 + \WP_CLI::error( 'Invalid --for. Use one of: ' . implode( ', ', self::CONTEXTS ) . '.' );
251 + return;
252 + }
253 + if ( ! in_array( $assoc['behavior'], $behaviors, true ) ) {
254 + \WP_CLI::error( 'Invalid --behavior. Use one of: ' . implode( ', ', $behaviors ) . '.' );
255 + return;
256 + }
257 + $patch[ 'behavior_' . $assoc['for'] ] = $assoc['behavior'];
258 + }
211 259 if ( isset( $assoc['frequency'] ) ) {
212 260 $patch['frequency'] = (int) $assoc['frequency'];
213 261 }
214 262 if ( empty( $patch ) ) {
215 - \WP_CLI::error( 'Nothing to set. Provide --context= --behavior= and/or --frequency=' );
263 + \WP_CLI::error( 'Nothing to set. Provide --for= --behavior= and/or --frequency=' );
216 264 return;
217 265 }
218 266 $this->update_settings( $patch );
219 267 \WP_CLI::success( 'Updated heartbeat settings.' );