@@ -88,21 +88,38 @@ function perflab_get_dismissed_admin_pointer_ids(): array {
88
88
*
89
89
* @since n.e.x.t
90
90
*
91
- * @return array<non-empty-string, string> Admin pointer messages with the admin pointer IDs as the keys .
91
+ * @return array<non-empty-string, array{ content: string, plugin: non-empty-string, dismiss_if_installed: bool }> Keys are the admin pointer IDs.
92
92
*/
93
93
function perflab_get_admin_pointers (): array {
94
94
$ pointers = array (
95
- 'perflab-admin-pointer ' => __ ( 'You can now test upcoming WordPress performance features. ' , 'performance-lab ' ),
96
- 'perflab-feature-view-transitions ' => __ ( 'New <strong>View Transitions</strong> feature now available. ' , 'performance-lab ' ),
97
- 'perflab-feature-nocache-bfcache ' => __ ( 'New <strong>No-cache BFCache</strong> feature now available. ' , 'performance-lab ' ),
95
+ 'perflab-admin-pointer ' => array (
96
+ 'content ' => __ ( 'You can now test upcoming WordPress performance features. ' , 'performance-lab ' ),
97
+ 'plugin ' => 'performance-lab ' ,
98
+ 'dismiss_if_installed ' => false ,
99
+ ),
100
+ 'perflab-feature-view-transitions ' => array (
101
+ 'content ' => __ ( 'New <strong>View Transitions</strong> feature now available. ' , 'performance-lab ' ),
102
+ 'plugin ' => 'view-transitions ' ,
103
+ 'dismiss_if_installed ' => true ,
104
+ ),
105
+ 'perflab-feature-nocache-bfcache ' => array (
106
+ 'content ' => __ ( 'New <strong>No-cache BFCache</strong> feature now available. ' , 'performance-lab ' ),
107
+ 'plugin ' => 'nocache-bfcache ' ,
108
+ 'dismiss_if_installed ' => true ,
109
+ ),
98
110
);
99
111
112
+ $ installed_plugins = get_plugins ();
100
113
if (
101
- defined ( ' SPECULATION_RULES_VERSION ' )
114
+ isset ( $ installed_plugins [ ' speculation-rules/load.php ' ][ ' Version ' ] )
102
115
&&
103
- version_compare ( SPECULATION_RULES_VERSION , '1.6.0 ' , '>= ' )
116
+ version_compare ( $ installed_plugins [ ' speculation-rules/load.php ' ][ ' Version ' ] , '1.6.0 ' , '>= ' )
104
117
) {
105
- $ pointers ['perflab-feature-speculation-rules-auth ' ] = __ ( '<strong>Speculative Loading</strong> now includes an opt-in setting for logged-in users. ' , 'performance-lab ' );
118
+ $ pointers ['perflab-feature-speculation-rules-auth ' ] = array (
119
+ 'content ' => __ ( '<strong>Speculative Loading</strong> now includes an opt-in setting for logged-in users. ' , 'performance-lab ' ),
120
+ 'plugin ' => 'speculative-loading ' ,
121
+ 'dismiss_if_installed ' => false ,
122
+ );
106
123
}
107
124
108
125
return $ pointers ;
@@ -120,49 +137,93 @@ function perflab_get_admin_pointers(): array {
120
137
* ensure that `$hook_suffix` is a string when it calls `do_action( 'admin_enqueue_scripts', $hook_suffix )`.
121
138
*/
122
139
function perflab_admin_pointer ( ?string $ hook_suffix = '' ): void {
123
- // Do not show admin pointer in multisite Network admin or User admin UI.
124
- if ( is_network_admin () || is_user_admin () ) {
140
+ // See get_plugin_page_hookname().
141
+ $ is_performance_screen = 'settings_page_ ' . PERFLAB_SCREEN === $ hook_suffix ;
142
+
143
+ // Do not show admin pointer in multisite Network admin, User admin UI, dashboard, or plugins list table. However,
144
+ // do proceed on the Performance screen so that all pointers can be auto-dismissed.
145
+ if (
146
+ is_network_admin () ||
147
+ is_user_admin () ||
148
+ (
149
+ ! in_array ( $ hook_suffix , array ( 'index.php ' , 'plugins.php ' ), true ) &&
150
+ ! $ is_performance_screen
151
+ )
152
+ ) {
125
153
return ;
126
154
}
127
155
128
156
$ admin_pointers = perflab_get_admin_pointers ();
129
157
$ admin_pointer_ids = array_keys ( $ admin_pointers );
130
158
$ dismissed_pointer_ids = perflab_get_dismissed_admin_pointer_ids ();
131
159
132
- // All pointers have been dismissed already.
133
- if ( count ( array_diff ( $ admin_pointer_ids , $ dismissed_pointer_ids ) ) === 0 ) {
134
- return ;
160
+ // And if we're on the Performance screen, automatically dismiss all the pointers.
161
+ $ auto_dismissed_pointer_ids = array ();
162
+ if ( $ is_performance_screen ) {
163
+ $ auto_dismissed_pointer_ids = array_merge ( $ auto_dismissed_pointer_ids , $ admin_pointer_ids );
135
164
}
136
165
137
- // Do not show the admin pointer when not on the dashboard or plugins list table.
138
- if ( ! in_array ( $ hook_suffix , array ( 'index.php ' , 'plugins.php ' ), true ) ) {
139
-
140
- // And if we're on the Performance screen, automatically dismiss the pointers.
141
- if ( isset ( $ _GET ['page ' ] ) && PERFLAB_SCREEN === $ _GET ['page ' ] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
142
- update_user_meta (
143
- get_current_user_id (),
144
- 'dismissed_wp_pointers ' ,
145
- implode (
146
- ', ' ,
147
- array_unique ( array_merge ( $ dismissed_pointer_ids , $ admin_pointer_ids ) )
148
- )
149
- );
166
+ // List of pointer IDs that are tied to feature plugin slugs.
167
+ $ plugin_pointers_dismissed_if_installed = array ();
168
+ foreach ( $ admin_pointers as $ pointer_id => $ admin_pointer ) {
169
+ if ( $ admin_pointer ['dismiss_if_installed ' ] ) {
170
+ $ plugin_pointers_dismissed_if_installed [ $ pointer_id ] = $ admin_pointer ['plugin ' ];
150
171
}
172
+ }
151
173
152
- return ;
174
+ // Preemptively dismiss plugin-specific pointers for plugins which are already installed.
175
+ $ plugin_dependent_pointers_undismissed = array_diff ( array_keys ( $ plugin_pointers_dismissed_if_installed ), $ dismissed_pointer_ids );
176
+ if ( count ( $ plugin_dependent_pointers_undismissed ) > 0 ) {
177
+ /**
178
+ * Installed plugin slugs.
179
+ *
180
+ * @var non-empty-string[] $installed_plugin_slugs
181
+ */
182
+ $ installed_plugin_slugs = array_map (
183
+ static function ( $ name ) {
184
+ return strtok ( $ name , '/ ' );
185
+ },
186
+ array_keys ( get_plugins () )
187
+ );
188
+
189
+ foreach ( $ plugin_dependent_pointers_undismissed as $ pointer_id ) {
190
+ if (
191
+ in_array ( $ plugin_pointers_dismissed_if_installed [ $ pointer_id ], $ installed_plugin_slugs , true ) &&
192
+ ! in_array ( $ pointer_id , $ dismissed_pointer_ids , true )
193
+ ) {
194
+ $ auto_dismissed_pointer_ids [] = $ pointer_id ;
195
+ }
196
+ }
153
197
}
154
198
155
- // Enqueue pointer CSS and JS.
156
- wp_enqueue_style ( 'wp-pointer ' );
157
- wp_enqueue_script ( 'wp-pointer ' );
199
+ // Persist the automatically-dismissed pointers.
200
+ if ( count ( $ auto_dismissed_pointer_ids ) > 0 ) {
201
+ $ dismissed_pointer_ids = array_unique ( array_merge ( $ dismissed_pointer_ids , $ auto_dismissed_pointer_ids ) );
202
+ update_user_meta (
203
+ get_current_user_id (),
204
+ 'dismissed_wp_pointers ' ,
205
+ implode ( ', ' , $ dismissed_pointer_ids )
206
+ );
207
+ }
158
208
209
+ // Determine which admin pointers we need.
159
210
$ new_install_pointer_id = 'perflab-admin-pointer ' ;
160
211
if ( ! in_array ( $ new_install_pointer_id , $ dismissed_pointer_ids , true ) ) {
161
212
$ needed_pointer_ids = array ( $ new_install_pointer_id );
162
213
} else {
163
- $ needed_pointer_ids = array_diff ( $ admin_pointer_ids , $ dismissed_pointer_ids );
214
+ $ needed_pointer_ids = $ admin_pointer_ids ;
215
+ }
216
+ $ needed_pointer_ids = array_diff ( $ needed_pointer_ids , $ dismissed_pointer_ids );
217
+
218
+ // No admin pointers are needed, so abort.
219
+ if ( count ( $ needed_pointer_ids ) === 0 ) {
220
+ return ;
164
221
}
165
222
223
+ // Enqueue pointer CSS and JS.
224
+ wp_enqueue_style ( 'wp-pointer ' );
225
+ wp_enqueue_script ( 'wp-pointer ' );
226
+
166
227
$ args = array (
167
228
'heading ' => __ ( 'Performance Lab ' , 'performance-lab ' ),
168
229
);
@@ -171,7 +232,7 @@ function perflab_admin_pointer( ?string $hook_suffix = '' ): void {
171
232
'' ,
172
233
array_map (
173
234
static function ( string $ needed_pointer ) use ( $ admin_pointers ): string {
174
- return '<p> ' . $ admin_pointers [ $ needed_pointer ] . '</p> ' ;
235
+ return '<p> ' . $ admin_pointers [ $ needed_pointer ][ ' content ' ] . '</p> ' ;
175
236
},
176
237
$ needed_pointer_ids
177
238
)
@@ -197,8 +258,8 @@ static function ( string $needed_pointer ) use ( $admin_pointers ): string {
197
258
?>
198
259
<script>
199
260
jQuery( function() {
200
- const pointerIdsToDismiss = <?php echo wp_json_encode ( $ pointer_ids_to_dismiss , JSON_OBJECT_AS_ARRAY ); ?> ;
201
- const nonce = <?php echo wp_json_encode ( wp_create_nonce ( 'dismiss_pointer ' ) ); ?> ;
261
+ const pointerIdsToDismiss = <?php echo wp_json_encode ( $ pointer_ids_to_dismiss , JSON_HEX_TAG | JSON_UNESCAPED_SLASHES | JSON_OBJECT_AS_ARRAY ); ?> ;
262
+ const nonce = <?php echo wp_json_encode ( wp_create_nonce ( 'dismiss_pointer ' ), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ); ?> ;
202
263
203
264
function dismissNextPointer() {
204
265
const pointerId = pointerIdsToDismiss.shift();
@@ -218,7 +279,7 @@ function dismissNextPointer() {
218
279
219
280
// Pointer Options.
220
281
const options = {
221
- content: <?php echo wp_json_encode ( '<h3> ' . esc_html ( $ args ['heading ' ] ) . '</h3> ' . wp_kses ( $ args ['content ' ], $ wp_kses_options ) ); ?> ,
282
+ content: <?php echo wp_json_encode ( '<h3> ' . esc_html ( $ args ['heading ' ] ) . '</h3> ' . wp_kses ( $ args ['content ' ], $ wp_kses_options ), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ); ?> ,
222
283
position: {
223
284
edge: 'left',
224
285
align: 'right',
0 commit comments