Skip to content

Commit 3296195

Browse files
committed
Add admin pointers for new features
1 parent 0423288 commit 3296195

File tree

2 files changed

+152
-38
lines changed

2 files changed

+152
-38
lines changed

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

Lines changed: 108 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,36 @@ function perflab_render_settings_page(): void {
6767
<?php
6868
}
6969

70+
/**
71+
* Gets dismissed admin pointer IDs.
72+
*
73+
* @since n.e.x.t
74+
*
75+
* @return non-empty-string[] Dismissed admin pointer IDs.
76+
*/
77+
function perflab_get_dismissed_admin_pointer_ids(): array {
78+
return array_filter(
79+
explode(
80+
',',
81+
(string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true )
82+
)
83+
);
84+
}
85+
86+
/**
87+
* Gets the admin pointers.
88+
*
89+
* @since n.e.x.t
90+
*
91+
* @return array<non-empty-string, string> Admin pointer messages with the admin pointer IDs as the keys.
92+
*/
93+
function perflab_get_admin_pointers(): array {
94+
return 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+
);
98+
}
99+
70100
/**
71101
* Initializes admin pointer.
72102
*
@@ -84,18 +114,27 @@ function perflab_admin_pointer( ?string $hook_suffix = '' ): void {
84114
return;
85115
}
86116
$current_user = get_current_user_id();
87-
$dismissed = array_filter( explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ) );
117+
$pointers = array_keys( perflab_get_admin_pointers() );
118+
$dismissed = perflab_get_dismissed_admin_pointer_ids();
88119

89-
if ( in_array( 'perflab-admin-pointer', $dismissed, true ) ) {
120+
// All pointers have been dismissed already.
121+
if ( count( array_diff( $pointers, $dismissed ) ) === 0 ) {
90122
return;
91123
}
92124

125+
// Do not show the admin pointer when not on the dashboard or plugins list table.
93126
if ( ! in_array( $hook_suffix, array( 'index.php', 'plugins.php' ), true ) ) {
94127

95-
// Do not show on the settings page and dismiss the pointer.
96-
if ( isset( $_GET['page'] ) && PERFLAB_SCREEN === $_GET['page'] && ( ! in_array( 'perflab-admin-pointer', $dismissed, true ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
97-
$dismissed[] = 'perflab-admin-pointer';
98-
update_user_meta( $current_user, 'dismissed_wp_pointers', implode( ',', $dismissed ) );
128+
// And if we're on the Performance screen, automatically dismiss the pointers.
129+
if ( isset( $_GET['page'] ) && PERFLAB_SCREEN === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
130+
update_user_meta(
131+
$current_user,
132+
'dismissed_wp_pointers',
133+
implode(
134+
',',
135+
array_unique( array_merge( $dismissed, $pointers ) )
136+
)
137+
);
99138
}
100139

101140
return;
@@ -113,53 +152,84 @@ function perflab_admin_pointer( ?string $hook_suffix = '' ): void {
113152
*
114153
* Handles the rendering of the admin pointer.
115154
*
155+
* @todo Eliminate this function in favor of putting it inside of perflab_admin_pointer() which attaches an inline script.
156+
*
116157
* @since 1.0.0
117158
* @since 2.4.0 Optional arguments were added to make the function reusable for different pointers.
118-
*
119-
* @param string $pointer_id Optional. ID of the pointer. Default 'perflab-admin-pointer'.
120-
* @param array{heading?: string, content?: string} $args Optional. Pointer arguments. Supports 'heading' and 'content' entries.
121-
* Defaults are the heading and content for the 'perflab-admin-pointer'.
159+
* @since n.e.x.t Unused arguments removed.
122160
*/
123-
function perflab_render_pointer( string $pointer_id = 'perflab-admin-pointer', array $args = array() ): void {
124-
if ( ! isset( $args['heading'] ) ) {
125-
$args['heading'] = __( 'Performance Lab', 'performance-lab' );
126-
}
127-
if ( ! isset( $args['content'] ) ) {
128-
$args['content'] = sprintf(
129-
/* translators: %s: settings page link */
130-
esc_html__( 'You can now test upcoming WordPress performance features. Open %s to individually toggle the performance features.', 'performance-lab' ),
131-
'<a href="' . esc_url( add_query_arg( 'page', PERFLAB_SCREEN, admin_url( 'options-general.php' ) ) ) . '">' . esc_html__( 'Settings > Performance', 'performance-lab' ) . '</a>'
132-
);
161+
function perflab_render_pointer(): void {
162+
$new_install_pointer_id = 'perflab-admin-pointer';
163+
$perflab_admin_pointers = perflab_get_admin_pointers();
164+
$dismissed_pointer_ids = perflab_get_dismissed_admin_pointer_ids();
165+
166+
if ( ! in_array( $new_install_pointer_id, $dismissed_pointer_ids, true ) ) {
167+
$needed_pointer_ids = array( $new_install_pointer_id );
168+
} else {
169+
$needed_pointer_ids = array_diff( array_keys( $perflab_admin_pointers ), $dismissed_pointer_ids );
133170
}
134171

172+
$args = array(
173+
'heading' => __( 'Performance Lab', 'performance-lab' ),
174+
);
175+
176+
$args['content'] = implode(
177+
'',
178+
array_map(
179+
static function ( string $needed_pointer ) use ( $perflab_admin_pointers ): string {
180+
return '<p>' . $perflab_admin_pointers[ $needed_pointer ] . '</p>';
181+
},
182+
$needed_pointer_ids
183+
)
184+
);
185+
186+
$args['content'] .= '<p>' . sprintf(
187+
/* translators: %s: settings page link */
188+
esc_html__( 'Open %s to individually toggle the performance features.', 'performance-lab' ),
189+
'<a href="' . esc_url( add_query_arg( 'page', PERFLAB_SCREEN, admin_url( 'options-general.php' ) ) ) . '">' . esc_html__( 'Settings > Performance', 'performance-lab' ) . '</a>'
190+
) . '</p>';
191+
135192
$wp_kses_options = array(
136-
'a' => array(
193+
'a' => array(
137194
'href' => array(),
138195
),
196+
'p' => array(),
197+
'strong' => array(),
139198
);
140199

200+
$pointer_ids_to_dismiss = array_values( array_diff( array_keys( $perflab_admin_pointers ), $dismissed_pointer_ids ) );
141201
?>
142-
<script id="<?php echo esc_attr( $pointer_id ); ?>" type="text/javascript">
202+
<script>
143203
jQuery( function() {
204+
const pointerIdsToDismiss = <?php echo wp_json_encode( $pointer_ids_to_dismiss, JSON_OBJECT_AS_ARRAY ); ?>;
205+
const nonce = <?php echo wp_json_encode( wp_create_nonce( 'dismiss_pointer' ) ); ?>;
206+
207+
function dismissNextPointer() {
208+
const pointerId = pointerIdsToDismiss.shift();
209+
if ( ! pointerId ) {
210+
return;
211+
}
212+
213+
jQuery.post(
214+
window.ajaxurl,
215+
{
216+
pointer: pointerId,
217+
action: 'dismiss-wp-pointer',
218+
_wpnonce: nonce,
219+
}
220+
).then( dismissNextPointer );
221+
}
222+
144223
// Pointer Options.
145224
const options = {
146-
content: <?php echo wp_json_encode( '<h3>' . esc_html( $args['heading'] ) . '</h3><p>' . wp_kses( $args['content'], $wp_kses_options ) . '</p>' ); ?>,
225+
content: <?php echo wp_json_encode( '<h3>' . esc_html( $args['heading'] ) . '</h3>' . wp_kses( $args['content'], $wp_kses_options ) ); ?>,
147226
position: {
148227
edge: 'left',
149228
align: 'right',
150229
},
151230
pointerClass: 'wp-pointer arrow-top',
152231
pointerWidth: 420,
153-
close: function() {
154-
jQuery.post(
155-
window.ajaxurl,
156-
{
157-
pointer: <?php echo wp_json_encode( $pointer_id ); ?>,
158-
action: 'dismiss-wp-pointer',
159-
_wpnonce: <?php echo wp_json_encode( wp_create_nonce( 'dismiss_pointer' ) ); ?>,
160-
}
161-
);
162-
}
232+
close: dismissNextPointer
163233
};
164234

165235
jQuery( '#menu-settings' ).pointer( options ).pointer( 'open' );
@@ -207,7 +277,11 @@ function perflab_plugin_action_links_add_settings( $links ) {
207277
* @since 2.3.0
208278
*/
209279
function perflab_dismiss_wp_pointer_wrapper(): void {
210-
if ( isset( $_POST['pointer'] ) && 'perflab-admin-pointer' !== $_POST['pointer'] ) {
280+
if (
281+
isset( $_POST['pointer'] )
282+
&&
283+
! in_array( $_POST['pointer'], array_keys( perflab_get_admin_pointers() ), true )
284+
) {
211285
// Another plugin's pointer, do nothing.
212286
return;
213287
}

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

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,37 @@ public function test_perflab_render_settings_page(): void {
8686
$this->assertStringNotContainsString( "<input type='hidden' name='option_page' value='" . PERFLAB_SCREEN . "' />", $output );
8787
}
8888

89+
/**
90+
* @covers ::perflab_get_dismissed_admin_pointer_ids
91+
*/
92+
public function test_perflab_get_dismissed_admin_pointer_ids(): void {
93+
$user_id = self::factory()->user->create( array( 'role' => 'administrator' ) );
94+
wp_set_current_user( $user_id );
95+
96+
// No dismissed pointers.
97+
$this->assertSame( array(), perflab_get_dismissed_admin_pointer_ids() );
98+
99+
// Dismiss a single pointer.
100+
update_user_meta( $user_id, 'dismissed_wp_pointers', 'perflab-admin-pointer' );
101+
$this->assertSame( array( 'perflab-admin-pointer' ), perflab_get_dismissed_admin_pointer_ids() );
102+
103+
// Dismiss multiple pointers.
104+
update_user_meta( $user_id, 'dismissed_wp_pointers', 'perflab-admin-pointer,another-pointer' );
105+
$this->assertSame( array( 'perflab-admin-pointer', 'another-pointer' ), perflab_get_dismissed_admin_pointer_ids() );
106+
107+
// Dismiss all pointers.
108+
update_user_meta( $user_id, 'dismissed_wp_pointers', implode( ',', array_keys( perflab_get_admin_pointers() ) ) );
109+
$this->assertSame( array_keys( perflab_get_admin_pointers() ), perflab_get_dismissed_admin_pointer_ids() );
110+
}
111+
112+
/**
113+
* @covers ::perflab_get_admin_pointers
114+
*/
115+
public function test_perflab_get_admin_pointers(): void {
116+
$pointers = perflab_get_admin_pointers();
117+
$this->assertArrayHasKey( 'perflab-admin-pointer', $pointers );
118+
}
119+
89120
/**
90121
* @return array<string, array{ hook_suffix: string|null, expected: bool }>
91122
*/
@@ -119,23 +150,32 @@ public function data_provider_test_perflab_admin_pointer(): array {
119150
'assert' => null,
120151
'dismissed_wp_pointers' => '',
121152
),
122-
'dashboard_yes_dismissed' => array(
153+
'dashboard_new_dismissed' => array(
123154
'set_up' => static function (): void {
124155
update_user_meta( wp_get_current_user()->ID, 'dismissed_wp_pointers', 'perflab-admin-pointer' );
125156
},
126157
'hook_suffix' => 'index.php',
127-
'expected' => false,
158+
'expected' => true,
128159
'assert' => null,
129160
'dismissed_wp_pointers' => 'perflab-admin-pointer',
130161
),
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+
},
166+
'hook_suffix' => 'index.php',
167+
'expected' => false,
168+
'assert' => null,
169+
'dismissed_wp_pointers' => implode( ',', array_keys( perflab_get_admin_pointers() ) ),
170+
),
131171
'perflab_screen_first_time' => array(
132172
'set_up' => static function (): void {
133173
$_GET['page'] = PERFLAB_SCREEN;
134174
},
135175
'hook_suffix' => 'options-general.php',
136176
'expected' => false,
137177
'assert' => null,
138-
'dismissed_wp_pointers' => 'perflab-admin-pointer',
178+
'dismissed_wp_pointers' => implode( ',', array_keys( perflab_get_admin_pointers() ) ),
139179
),
140180
'perflab_screen_second_time' => array(
141181
'set_up' => static function (): void {
@@ -145,7 +185,7 @@ public function data_provider_test_perflab_admin_pointer(): array {
145185
'hook_suffix' => 'options-general.php',
146186
'expected' => false,
147187
'assert' => null,
148-
'dismissed_wp_pointers' => 'perflab-admin-pointer',
188+
'dismissed_wp_pointers' => implode( ',', array_keys( perflab_get_admin_pointers() ) ),
149189
),
150190
);
151191
}

0 commit comments

Comments
 (0)