SOLARISE
DEV

WordPress Dev: Adding Custom Admin Notifications Easily

Improve user experience with simple admin notices

Originally published: November 26th, 2017. Updated on: April 29th, 2025.

When developing a WordPress theme or plugin that involves custom user interactions, providing clear and concise feedback is really helpful. Sometimes users just don’t notice errors or warning notices at all! It happens.

While overly intrusive notifications can be a hindrance, a friendly nudge in the right direction is sometimes useful. WordPress has built-in admin notifications, but setting them up properly can be a bit cumbersome, and the default notices aren't always as visible as you might like.

(Image placeholder: Standard WordPress admin notice)

This article outlines a solution using WordPress's transients API and some optional JavaScript/CSS for added visual flair.

(Quick Link: Download the code demonstrated in this article.)

Adding User Notifications Into Your Code

First, we'll add a custom helper function to our code (place this in your theme's functions.php or within your plugin file).

This function, let's call it my_plugin_add_admin_notice(), will be a simple helper you can call anywhere in your code to queue up a notification message. For example: my_plugin_add_admin_notice('Oh no! Something went wrong', 'error'); will add an error message to the queue.

<?php

/**
    * Add a notification message to be displayed in the WordPress admin.
    *
    * Stores messages in a user-specific transient until the next admin page load.
    *
    * @param string $message The message content. Required.
    * @param string $type    The type of notice ('error', 'warning', 'success', 'info'). Required.
    * @return bool False if not in admin or invalid type, true otherwise.
    */
function my_plugin_add_admin_notice(string $message, string $type): bool
{
    // Only run in the admin area
    if (!is_admin()) {
        return false;
    }

    // Validate the notice type
    $allowed_types = ['error', 'warning', 'success', 'info'];
    if (empty($message) || !in_array($type, $allowed_types, true)) {
        return false;
    }

    // Use a transient to store notices for the current user
    $transient_name = 'my_plugin_admin_notices_' . get_current_user_id();

    // Get existing notices (if any)
    $notices = get_transient($transient_name);
    if (!is_array($notices)) {
        $notices = [];
    }

    // Add the new notice
    $notices[] = [
        'message' => $message,
        'type'    => $type,
    ];

    // Store the updated notices back in the transient.
    // Set a short expiration (e.g., 1 minute) just in case the delete hook fails.
    set_transient($transient_name, $notices, MINUTE_IN_SECONDS);

    return true;
}

/**
    * Display the stored admin notices.
    *
    * Hooks into 'admin_notices' and outputs stored notices, then clears the transient.
    */
function my_plugin_display_admin_notices(): void
{
    // Only run in the admin area
    // Also, let's add a capability check - maybe only show these to admins?
    if (!is_admin() || !current_user_can('manage_options')) {
            return;
    }

    $transient_name = 'my_plugin_admin_notices_' . get_current_user_id();
    $notices = get_transient($transient_name);

    if (is_array($notices) && !empty($notices)) {
        foreach ($notices as $notice) {
            // Ensure type and message exist and are strings
            $type = isset($notice['type']) && is_string($notice['type']) ? $notice['type'] : 'info';
            $message = isset($notice['message']) && is_string($notice['message']) ? $notice['message'] : '';

            if (empty($message)) continue; // Skip empty messages

            // Output the notice HTML - Ensure it's dismissible
            // Added 'my-plugin-notice' class for specific targeting
            printf(
                '<div class="notice notice-%1$s is-dismissible my-plugin-notice my-plugin-notice-%1$s"><p>%2$s</p></div>',
                esc_attr($type), // Sanitize type for class attribute
                wp_kses_post($message) // Sanitize message content allowing basic HTML
            );
        }

        // Clear the transient now that notices have been displayed
        delete_transient($transient_name);
    }
}
// Hook the display function into the 'admin_notices' action
add_action('admin_notices', 'my_plugin_display_admin_notices');

?>

The my_plugin_display_admin_notices function hooks into the admin_notices action. It retrieves any stored notices for the current user from the transient, prints them out using the standard WordPress notice CSS classes (notice-error, notice-success, etc.), and makes them dismissible. Crucially, it then deletes the transient so the messages don't appear again on the next page load.

Testing

To easily test this, you can add a temporary function that triggers notices when a specific query parameter is present in the URL. Visit http://yoursite.com/wp-admin/?test_my_plugin_notices=1 to see them.

<?php

/**
    * Temporary test function to trigger admin notices via URL parameter.
    * REMOVE THIS FUNCTION BEFORE DEPLOYING TO PRODUCTION.
    */
function my_plugin_test_admin_notices_trigger(): void
{
    // Check if the trigger parameter exists and the user has permission
    if (isset($_GET['test_my_plugin_notices']) && current_user_can('manage_options')) {
        my_plugin_add_admin_notice('Custom error notice test!', 'error');
        my_plugin_add_admin_notice('Custom success notice test!', 'success');
        my_plugin_add_admin_notice('Custom warning notice test!', 'warning');
        my_plugin_add_admin_notice('Custom info notice test!', 'info');

        // Redirect back to the dashboard to display the notices
        // Use wp_safe_redirect for security
        wp_safe_redirect(admin_url());
        exit;
    }
}
add_action('admin_init', 'my_plugin_test_admin_notices_trigger');

?>

Remember to remove this test function before deploying your code to a live site! Leaving it in could be a security risk, plain and simple.

Adding Some Custom Animation (Optional)

Sometimes you might want to make certain notices (especially errors or warnings) more visually prominent. Now, I'm not usually a fan of drastically altering a platform's UI, but subtle tweaks can be effective.

Let's implement a simple "wiggle" animation for error and warning notices to grab the user's attention.

(Image placeholder: Animated GIF showing the wiggle effect on error/warning notices)

This animation plays once when the notice appears, not continuously (that would be irritating!).

We'll use CSS keyframes and add the styles and triggering JavaScript to the admin head/footer.

1. Add CSS Styles:

<?php

/**
    * Add custom CSS for notice animations to the admin head.
    */
function my_plugin_add_notice_styling_to_admin_head(): void
{
    // Only add styles on admin pages
    if (!is_admin()) {
        return;
    }
    ?>
    <style>
        @keyframes my-plugin-notice-wiggle {
            /* Simple wiggle animation */
            10%, 90% { transform: translateX(-1px); }
            20%, 80% { transform: translateX(2px); }
            30%, 50%, 70% { transform: translateX(-3px); }
            40%, 60% { transform: translateX(3px); }
        }

        /* Apply animation to our custom error notices when .active-wiggle is added */
        .my-plugin-notice.my-plugin-notice-error.active-wiggle {
            /* Stronger wiggle for errors */
            animation: my-plugin-notice-wiggle 0.6s ease-in-out;
        }

        /* Apply animation to our custom warning notices when .active-wiggle is added */
        .my-plugin-notice.my-plugin-notice-warning.active-wiggle {
                /* Slightly gentler wiggle for warnings */
            animation: my-plugin-notice-wiggle 0.4s ease-in-out;
        }
    </style>
    <?php
}
add_action('admin_head', 'my_plugin_add_notice_styling_to_admin_head');

?>

2. Add Triggering JavaScript:

This small script adds the active-wiggle class shortly after the page loads, triggering the CSS animation.

<?php

/**
    * Add JavaScript to trigger notice animations in the admin footer.
    */
function my_plugin_add_notice_scripting_to_admin_footer(): void // Renamed function
{
        // Only add script on admin pages
    if (!is_admin()) {
        return;
    }
    ?>
    <script type="text/javascript">
        document.addEventListener('DOMContentLoaded', function() {
            // Add a slight delay before adding the class to ensure notice is rendered
            setTimeout(function() {
                    // Target only our specific error and warning notices
                document.querySelectorAll('.my-plugin-notice.my-plugin-notice-error, .my-plugin-notice.my-plugin-notice-warning').forEach(function(notice) {
                    notice.classList.add('active-wiggle');
                });
            }, 100); // 100ms delay
        });
    </script>
    <?php
}
add_action('admin_footer', 'my_plugin_add_notice_scripting_to_admin_footer'); // Use admin_footer for JS

?>

(Note: We could enqueue separate CSS and JS files, which is best practice for larger plugins, but for simplicity here, we're injecting directly into the head/footer.)

Using Animation for All WordPress Notifications?

The code above targets only notices generated by our helper function (using the .my-plugin-notice class). If you wanted the wiggle effect on all WordPress error/warning notices, you would adjust the CSS selectors, removing .my-plugin-notice:

/* Example - Apply to ALL WP error notices */
.notice.notice-error.active-wiggle {
    animation: my-plugin-notice-wiggle 0.6s ease-in-out;
}
/* Example - Apply to ALL WP warning notices */
.notice.notice-warning.active-wiggle {
    animation: my-plugin-notice-wiggle 0.4s ease-in-out;
}

And adjust the JavaScript selector accordingly:

document.querySelectorAll('.notice.notice-error, .notice.notice-warning').forEach(/* ... */);

So there you have it – WordPress admin notifications made simpler, and optionally, a bit more eye-catching. Hopefully, this helps make your plugin or theme's behaviour more transparent to users.

Download the Code {#download-code}

(Link placeholder: Download example code .zip)

Robin Metcalfe

About the Author: Robin Metcalfe

Robin is a freelance web strategist and developer based in Edinburgh, with over 15 years of experience helping businesses build effective and engaging online platforms using technologies like Laravel and WordPress.

Get in Touch