Skip to content

Commit 1baf227

Browse files
authored
Merge pull request #2143 from ShyamGadde/update/omit-admin-pointer
Omit admin pointer for new plugin if plugin is already active
2 parents 6274111 + 19e7bd7 commit 1baf227

File tree

4 files changed

+152
-88
lines changed

4 files changed

+152
-88
lines changed

plugins/performance-lab/includes/admin/load.php

Lines changed: 95 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -88,21 +88,38 @@ function perflab_get_dismissed_admin_pointer_ids(): array {
8888
*
8989
* @since n.e.x.t
9090
*
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.
9292
*/
9393
function perflab_get_admin_pointers(): array {
9494
$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+
),
98110
);
99111

112+
$installed_plugins = get_plugins();
100113
if (
101-
defined( 'SPECULATION_RULES_VERSION' )
114+
isset( $installed_plugins['speculation-rules/load.php']['Version'] )
102115
&&
103-
version_compare( SPECULATION_RULES_VERSION, '1.6.0', '>=' )
116+
version_compare( $installed_plugins['speculation-rules/load.php']['Version'], '1.6.0', '>=' )
104117
) {
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+
);
106123
}
107124

108125
return $pointers;
@@ -120,49 +137,93 @@ function perflab_get_admin_pointers(): array {
120137
* ensure that `$hook_suffix` is a string when it calls `do_action( 'admin_enqueue_scripts', $hook_suffix )`.
121138
*/
122139
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+
) {
125153
return;
126154
}
127155

128156
$admin_pointers = perflab_get_admin_pointers();
129157
$admin_pointer_ids = array_keys( $admin_pointers );
130158
$dismissed_pointer_ids = perflab_get_dismissed_admin_pointer_ids();
131159

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 );
135164
}
136165

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'];
150171
}
172+
}
151173

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+
}
153197
}
154198

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+
}
158208

209+
// Determine which admin pointers we need.
159210
$new_install_pointer_id = 'perflab-admin-pointer';
160211
if ( ! in_array( $new_install_pointer_id, $dismissed_pointer_ids, true ) ) {
161212
$needed_pointer_ids = array( $new_install_pointer_id );
162213
} 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;
164221
}
165222

223+
// Enqueue pointer CSS and JS.
224+
wp_enqueue_style( 'wp-pointer' );
225+
wp_enqueue_script( 'wp-pointer' );
226+
166227
$args = array(
167228
'heading' => __( 'Performance Lab', 'performance-lab' ),
168229
);
@@ -171,7 +232,7 @@ function perflab_admin_pointer( ?string $hook_suffix = '' ): void {
171232
'',
172233
array_map(
173234
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>';
175236
},
176237
$needed_pointer_ids
177238
)
@@ -197,8 +258,8 @@ static function ( string $needed_pointer ) use ( $admin_pointers ): string {
197258
?>
198259
<script>
199260
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 ); ?>;
202263

203264
function dismissNextPointer() {
204265
const pointerId = pointerIdsToDismiss.shift();
@@ -218,7 +279,7 @@ function dismissNextPointer() {
218279

219280
// Pointer Options.
220281
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 ); ?>,
222283
position: {
223284
edge: 'left',
224285
align: 'right',

plugins/performance-lab/tests/includes/admin/test-load.php

Lines changed: 52 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -118,73 +118,77 @@ public function test_perflab_get_admin_pointers(): void {
118118
}
119119

120120
/**
121-
* @return array<string, array{ hook_suffix: string|null, expected: bool }>
121+
* @return array<string, array{
122+
* initial_wp_pointers: string,
123+
* hook_suffix: string|null,
124+
* expected: bool,
125+
* dismissed_wp_pointers: string,
126+
* }>
122127
*/
123128
public function data_provider_test_perflab_admin_pointer(): array {
124129
return array(
125-
'null' => array(
126-
'set_up' => null,
130+
'null' => array(
131+
'initial_wp_pointers' => '',
127132
'hook_suffix' => null,
128133
'expected' => false,
129-
'assert' => null,
130134
'dismissed_wp_pointers' => '',
131135
),
132-
'edit.php' => array(
133-
'set_up' => null,
136+
'edit.php' => array(
137+
'initial_wp_pointers' => '',
134138
'hook_suffix' => 'edit.php',
135139
'expected' => false,
136-
'assert' => null,
137140
'dismissed_wp_pointers' => '',
138141
),
139-
'dashboard_not_dismissed' => array(
140-
'set_up' => null,
142+
'dashboard_not_dismissed' => array(
143+
'initial_wp_pointers' => '',
141144
'hook_suffix' => 'index.php',
142145
'expected' => true,
143-
'assert' => null,
144-
'dismissed_wp_pointers' => '',
146+
'dismissed_wp_pointers' => 'perflab-feature-view-transitions',
145147
),
146-
'plugins_not_dismissed' => array(
147-
'set_up' => null,
148+
'plugins_not_dismissed' => array(
149+
'initial_wp_pointers' => '',
148150
'hook_suffix' => 'plugins.php',
149151
'expected' => true,
150-
'assert' => null,
151-
'dismissed_wp_pointers' => '',
152+
'dismissed_wp_pointers' => 'perflab-feature-view-transitions',
153+
),
154+
'dashboard_new_dismissed' => array(
155+
// Note: If the No-cache BFCache plugin (not part of the monorepo) is installed, then this test will likely fail and it should be skipped.
156+
'initial_wp_pointers' => 'perflab-admin-pointer',
157+
'hook_suffix' => 'index.php',
158+
'expected' => true,
159+
'dismissed_wp_pointers' => 'perflab-admin-pointer,perflab-feature-view-transitions',
160+
),
161+
'dashboard_last_auto_dismissed' => array(
162+
// Note: The No-cache BFCache plugin is not part of the monorepo, so it is not automatically installed in the dev environment.
163+
'initial_wp_pointers' => 'perflab-admin-pointer,perflab-feature-nocache-bfcache,perflab-feature-speculation-rules-auth',
164+
'hook_suffix' => 'index.php',
165+
'expected' => false,
166+
'dismissed_wp_pointers' => 'perflab-admin-pointer,perflab-feature-nocache-bfcache,perflab-feature-speculation-rules-auth,perflab-feature-view-transitions',
152167
),
153-
'dashboard_new_dismissed' => array(
154-
'set_up' => static function (): void {
155-
update_user_meta( wp_get_current_user()->ID, 'dismissed_wp_pointers', 'perflab-admin-pointer' );
156-
},
168+
'dashboard_one_not_auto_dismissed' => array(
169+
// Note: The No-cache BFCache plugin is not part of the monorepo, so it is not automatically installed in the dev environment.
170+
// Note: The Speculative Loading admin pointer 'perflab-feature-speculation-rules-auth' does not get auto-dismissed because it is for a new feature of an existing feature plugin.
171+
'initial_wp_pointers' => 'perflab-admin-pointer,perflab-feature-nocache-bfcache',
157172
'hook_suffix' => 'index.php',
158173
'expected' => true,
159-
'assert' => null,
160-
'dismissed_wp_pointers' => 'perflab-admin-pointer',
174+
'dismissed_wp_pointers' => 'perflab-admin-pointer,perflab-feature-nocache-bfcache,perflab-feature-view-transitions',
161175
),
162-
'dashboard_all_dismissed' => array(
163-
'set_up' => static function (): void {
164-
update_user_meta( wp_get_current_user()->ID, 'dismissed_wp_pointers', implode( ',', array_keys( perflab_get_admin_pointers() ) ) );
165-
},
176+
'dashboard_all_dismissed' => array(
177+
'initial_wp_pointers' => implode( ',', array_keys( perflab_get_admin_pointers() ) ),
166178
'hook_suffix' => 'index.php',
167179
'expected' => false,
168-
'assert' => null,
169180
'dismissed_wp_pointers' => implode( ',', array_keys( perflab_get_admin_pointers() ) ),
170181
),
171-
'perflab_screen_first_time' => array(
172-
'set_up' => static function (): void {
173-
$_GET['page'] = PERFLAB_SCREEN;
174-
},
175-
'hook_suffix' => 'options-general.php',
182+
'perflab_screen_first_time' => array(
183+
'initial_wp_pointers' => '',
184+
'hook_suffix' => 'settings_page_' . PERFLAB_SCREEN,
176185
'expected' => false,
177-
'assert' => null,
178186
'dismissed_wp_pointers' => implode( ',', array_keys( perflab_get_admin_pointers() ) ),
179187
),
180-
'perflab_screen_second_time' => array(
181-
'set_up' => static function (): void {
182-
$_GET['page'] = PERFLAB_SCREEN;
183-
update_user_meta( wp_get_current_user()->ID, 'dismissed_wp_pointers', 'perflab-admin-pointer' );
184-
},
185-
'hook_suffix' => 'options-general.php',
188+
'perflab_screen_second_time' => array(
189+
'initial_wp_pointers' => 'perflab-admin-pointer',
190+
'hook_suffix' => 'settings_page_' . PERFLAB_SCREEN,
186191
'expected' => false,
187-
'assert' => null,
188192
'dismissed_wp_pointers' => implode( ',', array_keys( perflab_get_admin_pointers() ) ),
189193
),
190194
);
@@ -194,18 +198,15 @@ public function data_provider_test_perflab_admin_pointer(): array {
194198
* @covers ::perflab_admin_pointer
195199
* @dataProvider data_provider_test_perflab_admin_pointer
196200
*
197-
* @param Closure|null $set_up Set up.
198-
* @param string|null $hook_suffix Hook suffix.
199-
* @param bool $expected Expected.
200-
* @param Closure|null $assert Assert.
201-
* @param string $dismissed_wp_pointers Dismissed admin pointers.
201+
* @param string $initial_wp_pointers Set up.
202+
* @param string|null $hook_suffix Hook suffix.
203+
* @param bool $expected Expected.
204+
* @param string $dismissed_wp_pointers Dismissed admin pointers.
202205
*/
203-
public function test_perflab_admin_pointer( ?Closure $set_up, ?string $hook_suffix, bool $expected, ?Closure $assert, string $dismissed_wp_pointers ): void {
206+
public function test_perflab_admin_pointer( string $initial_wp_pointers, ?string $hook_suffix, bool $expected, string $dismissed_wp_pointers ): void {
204207
$user_id = self::factory()->user->create( array( 'role' => 'administrator' ) );
205208
wp_set_current_user( $user_id );
206-
if ( $set_up instanceof Closure ) {
207-
$set_up();
208-
}
209+
update_user_meta( wp_get_current_user()->ID, 'dismissed_wp_pointers', $initial_wp_pointers );
209210
$this->assertFalse( is_network_admin() || is_user_admin() );
210211
perflab_admin_pointer( $hook_suffix );
211212

@@ -214,14 +215,14 @@ public function test_perflab_admin_pointer( ?Closure $set_up, ?string $hook_suff
214215
if ( $script_dependency instanceof _WP_Dependency ) {
215216
$after_script = implode( "\n", array_filter( $script_dependency->extra['after'] ?? array() ) );
216217
}
218+
$this->assertSame( $dismissed_wp_pointers, get_user_meta( $user_id, 'dismissed_wp_pointers', true ) );
219+
$this->assertSame( $expected, wp_script_is( 'wp-pointer', 'enqueued' ) );
220+
$this->assertSame( $expected, wp_style_is( 'wp-pointer', 'enqueued' ) );
217221
if ( $expected ) {
218222
$this->assertStringContainsString( 'pointerIdsToDismiss', $after_script );
219223
} else {
220224
$this->assertStringNotContainsString( 'pointerIdsToDismiss', $after_script );
221225
}
222-
$this->assertSame( $expected, wp_script_is( 'wp-pointer', 'enqueued' ) );
223-
$this->assertSame( $expected, wp_style_is( 'wp-pointer', 'enqueued' ) );
224-
$this->assertSame( $dismissed_wp_pointers, get_user_meta( $user_id, 'dismissed_wp_pointers', true ) );
225226
}
226227

227228
/**

plugins/speculation-rules/load.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Description: Enables browsers to speculatively prerender or prefetch pages to achieve near-instant loads based on user interaction.
66
* Requires at least: 6.6
77
* Requires PHP: 7.2
8-
* Version: 1.5.0
8+
* Version: 1.6.0
99
* Author: WordPress Performance Team
1010
* Author URI: https://make.wordpress.org/performance/
1111
* License: GPLv2 or later
@@ -65,7 +65,7 @@ static function ( string $global_var_name, string $version, Closure $load ): voi
6565
}
6666
)(
6767
'plsr_pending_plugin_info',
68-
'1.5.0',
68+
'1.6.0',
6969
static function ( string $version ): void {
7070

7171
// Define the constant.

plugins/speculation-rules/readme.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Contributors: wordpressdotorg
44
Tested up to: 6.8
5-
Stable tag: 1.5.0
5+
Stable tag: 1.6.0
66
License: GPLv2 or later
77
License URI: https://www.gnu.org/licenses/gpl-2.0.html
88
Tags: performance, javascript, speculation rules, prerender, prefetch
@@ -122,6 +122,8 @@ Contributions are always welcome! Learn more about how to get involved in the [C
122122

123123
== Changelog ==
124124

125+
= 1.6.0 =
126+
125127
= 1.5.0 =
126128

127129
**Enhancements**

0 commit comments

Comments
 (0)