Use the coupon code WORDPRESS and save 30% OFF! Buy Now

Add a site-wide dismissible notice bar to your WordPress website

Last Updated On
Add a site-wide dismissible notice bar to your WordPress website WordPress template

Global, site-wide website notices are a pattern as old as websites themselves, and although they are being abused all the time they do have valid use-cases and are extremely useful in situations where we absolutely need to notify our visitors of something important, e.g. a great deal (as we do here at CSSIgniter), any kind of maintenance message or even the EU cookie law notice!

When the need rises for such functionality the first thing on anyone’s mind would probably be to have a look at the WordPress plugin repo for any suitable plugins, and, well, although it’s justified (there are a ton of plugins for this kind of thing) there’s no reason not to implement it ourselves since it’s so easy and fun.

Without any further ado, then, let’s see how we’d go about building a simple, global, dismissible site-wide notice bar.

Our basic architecture

We’ll store our notice’s text as a simple WordPress Customizer setting, and then we’ll use some JavaScript tinkering to handle its display logic. Of course, we’ll also use some basic CSS to style it.

The customizer setting

All we need for our notice currently is a single text field. Ever since version 3.4 WordPress has made it extremely simple to add site settings to our websites with the Theme Customization API; a few lines of code in our theme’s functions.php file will do it:

<?php

add_action( 'customize_register', 'mytheme_customize_register' );

function mytheme_customize_register( $wp_customize ) {
$wp_customize->add_section( 'mytheme_site_notice', array(
'title' => __( 'Site Notice', 'mytheme' ),
'priority' => 30,
) );

$wp_customize->add_setting( 'site_notice_text', array(
'default' => '',
'sanitize_callback' => 'wp_kses_post',
) );

$wp_customize->add_control( 'site_notice_text', array(
'type' => 'text',
'section' => 'mytheme_site_notice',
'label' => __( 'Site notice text', 'mytheme' ),
) );
}
functions.php

Save the file and refresh the website and now navigating to Appearance > Customize from the admin dashboard menu we should see a new Customizer section named “Site Notice”, and in it our site section text field, which should already be functional! Let’s type something and save it.

Displaying the site notice

Time to fetch that text and display it on the front-end of our website. Still in functions.php, we’ll use the wp_footer action to render all the HTML and text of our notice:


add_action( 'wp_footer', 'mytheme_site_notice' );

function mytheme_site_notice() {
$text = get_theme_mod( 'site_notice_text', '' );

if ( is_admin() || empty( $text ) ) {
return;
}
?>
<div
class="site-notice"
data-id="<?php echo esc_attr( md5( $text ) ); ?>"
>
<p><?php echo esc_html( $text ); ?></p>
<button
aria-label="<?php esc_html_e( 'Dismiss site notice', 'mytheme' ); ?>"
class="site-notice-dismiss"
>
×
</button>
</div>
<?php
}
functions.php

Pretty basic stuff, we’re getting the text using get_theme_mod and output the HTML only if it’s not empty (i.e. we haven’t written anything) or if we’re not at the WordPress admin dashboard.

Only one line needs a bit of explaining:

<div
class="site-notice"
data-id="<?php echo esc_attr( md5( $text ) ); ?>"
>
what's that md5 hash doing there?

What we’re doing here is assigning an identifier on our notice (the md5 hash of its text). Of course there are a lot of ways of doing this but this is simple and straightforward. It will also prevent us from accidentally displaying the same notice again a second consecutive time to users that have already dismissed it. Keep this on the back of your mind for now, we’ll pick it up later on with JavaScript and use it to figure out whether we should display the notice or not.

Adding some styles

For styling we’ll definitely need to make our notice bar absolute or fixed positioned so that it sticks to the top or bottom and/or follows the viewport as the user is scrolling (obviously this is a matter of preference, I’ll leave it up to you). Other than that, some aesthetic touches for coloring, and finally positioning the dismissing button:

.site-notice {
font-family: sans-serif;
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 15px 25px;
background-color: #145474;
color: #fff;
text-align: center;
}

.site-notice-dismiss {
background: none;
border: 0;
color: #fff;
font-size: 24px;
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
}

And here’s how it’s going to look:

light

Handling the display logic

All righty, we’ve got the notice bar styled and displaying at the top of our website, but currently there’s no way for our users to dismiss it (and never see it again). We’ll need a bit of JavaScript to make this happen.

The general concept is based on leveraging the browser’s localStorage API to store the “ID” of the notice every time the user clicks on the dismiss button. We’ll always start with the notice hidden (via CSS) and on page load we’ll check (with JavaScript) if the ID matches with the one we have in localStorage. If it does, we’ll do nothing (keep it hidden), if it doesn’t we’ll show it! Simple enough, let’s see how we’ll go about it.

First, we’ll need to start with the notice bar hidden so let’s add that to our previous styles:

.site-notice {
...
display: none;
...
}
style.css

Then the “tricky” part, in our theme’s custom scripts file:

(function () {
var notice, noticeId, storedNoticeId, dismissButton;
notice = document.querySelector('.site-notice');

if (!notice) {
return;
}

dismissButton = document.querySelector('.site-notice-dismiss');
noticeId = notice.getAttribute('data-id');
storedNoticeId = localStorage.getItem('myThemeSiteNotice');

// This means that the user hasn't already dismissed
// this specific notice. Let's display it.
if (noticeId !== storedNoticeId) {
notice.style.display = 'block';
}

dismissButton.addEventListener('click', function () {
// Hide the notice
notice.style.display = 'none';

// Add the current id to localStorage
localStorage.setItem('myThemeSiteNotice', noticeId);
});
}());
scripts.js

Let’s go through the code line by line:

(function () {
...
}());
IIFE

Wrapping our whole code in an IIFE (Immediately Invoked Function Expression). Just as a good practice in order to keep our variables scoped and to be able to escape out of the whole logic if we need to by simply returning.

var notice, noticeId, storedNoticeId, dismissButton;
notice = document.querySelector('.site-notice');

if (!notice) {
return;
}

Define our initial variables, get a DOM reference from our site notice HTML element and do nothing (return on line 5) if there’s no site notice to begin with (i.e. we haven’t set any text).

dismissButton = document.querySelector('.site-notice-dismiss');
noticeId = notice.getAttribute('data-id');
storedNoticeId = localStorage.getItem('myThemeSiteNotice');

We’re storing the DOM reference of our dismiss button (so that we can attach a click handler later on) and allocate the two IDs: noticeId is the current notice’s ID (the one that currently is in our document) and storedNoticeId is the one we’ve stored in localStorage from a previous dismiss click. storedNoticeId could be null if, for example, someone is visiting our website for the first time or has never dismissed any of our notices. That’s ok though!

if (noticeId !== storedNoticeId) {
notice.style.display = 'block';
}
Determine if we should display the notice

Remember we always echo our notice’s HTML in the DOM (if there is any text assigned) and we initially just render it hidden via CSS.

By comparing what ID we’ve got stored in localStorage (storedNoticeId) with the current notice’s ID (noticeId) we can determine if the user has already dismissed this specific one, and if they haven’t, we show it.

dismissButton.addEventListener('click', function () {
notice.style.display = 'none';
localStorage.setItem('myThemeSiteNotice', noticeId);
});
Dismissing the notice

Finally the button’s click handler. It’s responsible for hiding the notice (via setting its display property to none) and storing its ID in localStorage. The next time we refresh this ID will be the storedNoticeId variable we mentioned and used before for the displaying logic.

Here’s how the full code looks and behaves (don’t blink or you’ll miss it – you can dismiss the notice and refresh the page, it won’t be there unless you change its ID):

light

And that’s about it! We have a fully functional, dismissible site-wide notice bar on our website ready to go. Building on top of what we just implemented we could also add functionality such as new customizer fields (i.e. images, setting custom colors) or even countdown timers and activation windows! If you happen to experiment with the code and enhance its functionality make sure to share with us in the comments below!

10 responses to “Add a site-wide dismissible notice bar to your WordPress website”

  1. Great article. Can you explain why you are using localstorage as oppose to cookies?

    • Vassilis Mastorostergios says:

      Thanks for the comment!

      No particular reason except for the simplicity localStorage provides for the context of a tutorial as a basis.

      Cookies are a good alternative for achieving the same functionality plus since they’re server-read you could do a bit more, like not echoing the markup at all if the notice is expired.

      It’s up to the curious mind to decide what they’re going to use (as always); in a larger, more complex application maybe this kind of state tracking could belong in a Redis store or a database!

  2. James says:

    Thanks for posting this Vassilis! I’d like to add this notice bar for phone number and a a few links like login and help page on top of my nav bar. I’d like to remove the x close button so that it cannot be dismissed ever. What code can I remove to implement this? Thanks a bunch!

    • Vassilis Mastorostergios says:

      Hi James! Are you interested in doing this on one of our themes or would you like to know how to generally know about this?

      I don’t think a dismissible site notice is what you’re after, you just need a simple top bar. Here’s a minimalistic codepen of how you can achieve something like that: https://codepen.io/vmasto_1470672674/pen/mprzBb

      • James says:

        Thank you very much Vassilis! This is exactly what I was looking for. Is it bad practice to add the html to functions.php? Happy Holidays to you and your family and thank you again!

        • Vassilis Mastorostergios says:

          I’d say it “depends” (doesn’t it always). Depends on the reason you’re adding the HTML to your functions.php file. If it’s going to be a reusable function that outputs something perhaps you’d like to have it in a different “template part” PHP file. If it’s some HTML that is part of a WordPress filter or action then I believe functions.php is the right place. In the case of this site-wide top bar generally the header.php template would be more suitable.

          Happy holidays to you too! :D

  3. Derrick says:

    Well Detailed article Vassilis! I’m very glad I stumbled onto this article. Helped me a lot. :)
    Can you explain how I can allow html tags instead of just text?

    • Vassilis Mastorostergios says:

      Hey! Thanks for the kind words. The text field is sanitized from the `wp_kses_post` so you should be able to add basic HTML tags there, same ones that the content in WP post edit screen allows :)

      • Brian says:

        I know this is a little old, but HTML tags don’t work. Tried adding a simple link in the Site Notice field in Customizer, and it outputs the raw html. Any ideas how to get it to process the HTML correctly, and even better, allow for a shortcode!? Thanks in advance for your help.

        • Anastis Sourgoutsidis says:

          Hi Brian,

          inside mytheme_site_notice(), instead of echo esc_html( $text ); do instead a echo wp_kses_post( $text );

          The above should render HTML properly.

          If you want it to render shortcodes, you can change the same line to: echo do_shortcode( wp_kses_post( $text ) );

Leave a Reply

Your email address will not be published. Required fields are marked *

Get access to all WordPress themes & plugins

24/7 Support Included. Join 115,000+ satisfied customers.

Pricing & Sign Up

30-day money-back guarantee. Not satisfied? Your money back, no questions asked.

Back to top