Admin Notice Generator
Generate a WordPress admin notice with the capability check, the screen it appears on, and a dismissal that is remembered per user.
<?php
/**
* Admin notice: Settings saved. Your changes are live.
*/
/**
* Prints the notice.
*/
function my_plugin_admin_notice() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
if ( get_user_meta( get_current_user_id(), 'my_plugin_notice_dismissed', true ) ) {
return;
}
$html = '<p>' . esc_html__( 'Settings saved. Your changes are live.', 'my-plugin' ) . '</p>';
$dismiss = wp_nonce_url(
admin_url( 'admin-post.php?action=my_plugin_dismiss_notice' ),
'my_plugin_dismiss_notice'
);
$html .= '<p><a href="' . esc_url( $dismiss ) . '">'
. esc_html__( 'Do not show this again', 'my-plugin' )
. '</a></p>';
printf(
'<div class="%1$s">%2$s</div>',
esc_attr( 'notice notice-success is-dismissible' ),
wp_kses_post( $html )
);
}
add_action( 'admin_notices', 'my_plugin_admin_notice' );
/**
* Stores the dismissal against the user, so the notice stays gone.
*/
function my_plugin_dismiss_notice() {
check_admin_referer( 'my_plugin_dismiss_notice' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_die(
esc_html__( 'You are not allowed to do that.', 'my-plugin' ),
'',
array( 'response' => 403 )
);
}
update_user_meta( get_current_user_id(), 'my_plugin_notice_dismissed', 1 );
$back = wp_get_referer();
wp_safe_redirect( $back ? $back : admin_url() );
exit;
}
add_action( 'admin_post_my_plugin_dismiss_notice', 'my_plugin_dismiss_notice' );
Output is valid and updates as you type.
Fix the highlighted fields to update the output.
Pick the type, the screen and who sees it, and the generator writes the whole notice: the capability check, the markup WordPress styles, and a dismissal that is remembered instead of coming back on the next page.
How to use
- Write the message as one finished sentence. It goes through a translation function, so fragments joined with a dot cannot be translated properly.
- Set the capability. Subscribers can open the dashboard, and a notice with no check is a notice every logged-in user reads.
- Narrow the screen.
everywhereputs your notice on top of every other plugin’s settings page, which is how notice fatigue starts. - Leave the remembered dismissal on for anything that is not urgent. The cross alone only hides the notice until the next page load.
- Paste the result into your plugin. Nothing else has to be registered: both the notice and the dismissal handler hook themselves up.
Example
A warning shown only on the plugins screen, to users who can activate plugins, with a button and a dismissal that sticks:
function acme_admin_notice() {
if ( ! current_user_can( 'activate_plugins' ) ) {
return;
}
$screen = get_current_screen();
if ( ! $screen || 'plugins' !== $screen->id ) {
return;
}
if ( get_user_meta( get_current_user_id(), 'acme_notice_dismissed', true ) ) {
return;
}
$html = '<p>' . esc_html__( 'Acme needs an API key before it can sync.', 'acme' ) . '</p>';
printf(
'<div class="%1$s">%2$s</div>',
esc_attr( 'notice notice-warning is-dismissible' ),
wp_kses_post( $html )
);
}
add_action( 'admin_notices', 'acme_admin_notice' );
The dismissal link posts to admin-post.php with a nonce, so no JavaScript and no AJAX endpoint is involved.
Pitfalls
- The dismiss cross is presentation only. WordPress hides the notice in the browser and forgets it; the notice returns on the next screen unless you store the dismissal yourself.
admin_noticesdoes not fire on network admin screens. On multisite, a notice that looks missing is usually hooked to the wrong one.- Without a capability check every logged-in user sees the notice, including subscribers on a membership site who never asked about your plugin.
get_current_screen()can return null early in the request. Check it before reading->id, or the notice fatals on some screens.wp_admin_notice()escapes nothing. Whatever you pass is printed, so escape the message before it goes in.wp_admin_notice()needs WordPress 6.4. Calling it on 6.3 is a fatal error, not a missing notice.- Screen IDs are not post types. The post list table is
edit-post, the editor ispost, and a settings page issettings_page_your-slug. - Printing a notice on every admin screen trains people to ignore notices, including your next important one.
Compatibility
admin_notices, get_current_screen() and the notice classes have been stable since WordPress 4.4. wp_admin_notice() needs WordPress 6.4 or later and is left off by default here. The generated code targets PHP 7.0 and up, and the tool runs entirely in your browser.
Frequently asked questions
Why does my notice come back after I dismiss it?
How do I find a screen ID?
get_current_screen()->id on the page you want, or check the body class in the admin. List tables are edit-<post_type>.