Change is the only constant, and developers all know it. WordPress admin notices have changed and the good old PHP-based hooks no longer work for Gutenberg.
This blog post covers the easy way to add admin notices when a post gets added or updated, focusing mainly on the Gutenberg notices.

Let’s start with this working example and customize it to your needs.
Hook into save action.
Here we are using the publish_post action to add our callback after every time a post gets saved. Add a did_action check to make sure this callback executes on the first time and doesn’t repeat.
Other plugins or customizations may also use this action hook, so it is recommended to perform this did_action check.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function email_notification_response_cb( $post_id, $post ) { | |
| if ( did_action( 'publish_post' ) === 1 ) { | |
| set_notification_status( $post_id, $post ); | |
| } | |
| } | |
| add_action( 'publish_post', 'email_notification_response_cb', 20, 2 ); |
Set the message on the callback.
Here is an example of a typical editorial workflow:
- Author submits a blog post
- Saved as Draft
- Editor approves and publishes
The background action is sending email notifications to the author when the post gets published. Let your callback process the data and return the message you want to show in the notice. To keep this data easily accessible, we are using post meta.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php function set_notification_status( $post_id, $post ) { | |
| if ( ! $post ) { | |
| return; // Exit if there is no response. | |
| } | |
| // @see https://developer.wordpress.org/reference/hooks/new_status_post-post_type/#comment-4335 | |
| $author = $post->post_author; | |
| $name = get_the_author_meta( 'display_name', $author ); | |
| $email = get_the_author_meta( 'user_email', $author ); | |
| $title = $post->post_title; | |
| $permalink = get_permalink( $post_id ); | |
| $to[] = sprintf( '%s <%s>', $name, $email ); | |
| $subject = sprintf( 'Published: %s', $title ); | |
| $message = sprintf( 'Congratulations, %s! Your article "%s" has been published.' . "\n\n", $name, $title ); | |
| $message .= sprintf( 'View: %s', $permalink ); | |
| $headers[] = ''; | |
| $sent = wp_mail( $to, $subject, $message, $headers ); | |
| if ( $sent ) { | |
| $response = array( | |
| 'code' => 'success', | |
| 'message' => 'Email notification(s) sent sucessfully', | |
| ); | |
| } else { | |
| $response = array( | |
| 'code' => 'error', | |
| 'message' => 'Failed to send email notification(s)', | |
| ); | |
| } | |
| update_post_meta( $post_id, 'email_notification', wp_json_encode( $response ) ); | |
| } |
Create a custom endpoint.
Register an endpoint using register_rest_route. We will be using the namespace and route during the AJAX call.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Custom route to check email notification status. | |
| * | |
| * @return void | |
| * @since 1.0 | |
| * @author Lax Mariappan <[email protected]> | |
| */ | |
| function gnotice_rest_init() { | |
| $namespace = 'api-gnotice/v1'; | |
| $route = 'check-email-response'; | |
| register_rest_route( | |
| $namespace, | |
| $route, | |
| array( | |
| 'methods' => \WP_REST_Server::READABLE, | |
| 'callback' => 'get_email_notification', | |
| 'permission_callback' => 'permission_callback' => function() { return current_user_can('edit_posts'); }, | |
| ) | |
| ); | |
| } | |
| add_action( 'rest_api_init', 'gnotice_rest_init' ); |
AJAX call
Now that we have an error message on meta, we have to fetch it via an AJAX request. To keep this simple, the admin script is added directly along with the PHP code. You can make it a separate file and enqueue it.
We need ‘subscribe’ and ‘select’ from WP data module.
const { subscribe,select } = wp.data;
Subscribe allows you to listen to changes in the state. By subscribing to isSavingPost(), you can call the AJAX request.
We are sending the post ID to the custom REST endpoint and displaying the message via createNotice.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| add_action( 'rest_api_init', 'gnotice_rest_init' ); | |
| add_action( 'admin_footer-post.php', 'email_notification_script' ); | |
| add_action( 'admin_footer-post-new.php', 'email_notification_script' ); | |
| /** | |
| * Adds script to make ajax call – checking notifications via REST. | |
| * | |
| * @return void | |
| * @since 1.0 | |
| * @author Lax Mariappan <[email protected]> | |
| */ | |
| function email_notification_script() { | |
| // @see https://wordpress.stackexchange.com/a/398805/103640 | |
| // @see https://github.com/WordPress/gutenberg/issues/17632#issuecomment-583772895 | |
| ?> | |
| <script type="text/javascript"> | |
| const { subscribe,select } = wp.data; | |
| const { isSavingPost } = select( 'core/editor' ); | |
| var checked = true; | |
| subscribe( () => { | |
| if ( isSavingPost() ) { | |
| checked = false; | |
| } else { | |
| if ( ! checked ) { | |
| checkNotificationAfterPublish(); | |
| checked = true; | |
| } | |
| } | |
| } ); | |
| function checkNotificationAfterPublish(){ | |
| const postId = wp.data.select("core/editor").getCurrentPostId(); | |
| const url = wp.url.addQueryArgs( | |
| '/wp-json/api-gnotice/v1/check-email-response', | |
| { id: postId }, | |
| ); | |
| wp.apiFetch({ | |
| url, | |
| }).then( | |
| function(response){ | |
| if(response.message){ | |
| wp.data.dispatch("core/notices").createNotice( | |
| response.code, | |
| response.message, | |
| { | |
| id: 'email_status_notice', | |
| isDismissible: true | |
| } | |
| ); | |
| } | |
| } | |
| ); | |
| }; | |
| </script> | |
| <?php | |
| } |
Get the error and render it.
Now we have the error, custom endpoint, and the AJAX callback. Retrieve the message from post_meta and send it to the response.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Send error response to REST endpoint. | |
| * | |
| * @return Error object | |
| * @since 1.0 | |
| * @author Lax Mariappan <[email protected]> | |
| */ | |
| function get_email_notification() { | |
| if ( isset( $_GET['id'] ) ) { | |
| $id = sanitize_text_field( | |
| wp_unslash( $_GET['id'] ) | |
| ); | |
| $error = get_post_meta( $id, 'email_notification', true ); | |
| if ( $error ) { | |
| $data = json_decode( $error ); | |
| return new \WP_REST_Response( | |
| array( | |
| 'code' => $data->code, | |
| 'message' => wp_unslash( $data->message ), | |
| ) | |
| ); | |
| } | |
| } | |
| } |
Here is the plugin with the complete code in the repo. I hope you find this quick tip useful. Follow our blog for more WordPress tutorials.