Allow Users to Dismiss Messages with jQuery and Cookies

While developing a social network for an company’s intranet, I needed to provide users with the ability to hide announcements.

So a user comes to the site, there’s a message like, “It’s Jim’s birthday!”, with a link to the post and little close button associated with it. If the user clicks either the link to read the post or the close button, they won’t see the announcement again.

Here I’ll show you the code I’m using to create this thing in it’s entirety.

The Loop

Like just about everything I do, the site is built on WordPress, and is therefore using the loop.

First we’ll create our loop of “announcements”. I’ll show you how to do it here with just regular Posts, but I created a custom post type called Announcements so that they could be created independently of actual blog posts. Here’s the loop:

<?php $args = array(
'post_type' => 'post',
'posts_per_page' => -1
);
$the_query = new WP_Query($args);
if ($the_query->have_posts()) : ?>
<aside class="announcements">
<?php while ($the_query->have_posts()) : $the_query->the_post(); ?>
<article class="announcement" id="announcement-<?php the_ID(); ?>">
<p class="icon icon-announcement"><a class="close" href="<?php the_permalink(); ?>"><?php the_title(); ?></a></p>
<a class="close icon icon-close icon-replacement" href="#">Close</a>
</article>
<?php endwhile; ?>
</aside>
<?php endif; ?>

The WP_Query is loading all posts. Again, with my custom post type setup, this makes more sense. With a real blog, you would want to limit the 'posts_per_page' => -1 to something other than -1, typically a positive number, as -1 in this case means “load everything”.

After I apply some CSS, I end up with something like this:

screenshot showing two announcements as described above

Setting Cookies with jQuery

Firstly, you’ll need to download this small jQuery plugin, and upload it somewhere to your theme. I keep all of my JS in an /assets/js/ folder.

Now we’ll add the script to your site, open up functions.php and add this code:

function yeast_scripts() {
if (!is_admin()) {
wp_register_script(
'jquery-cookie',
'/wp-content/themes/yeast/assets/js/jquery.cookie.js',
'jquery',
null,
true
);
if (is_front_page()) {
wp_enqueue_script('jquery-cookie');
}
}
}
add_action('wp_enqueue_scripts', 'yeast_scripts');

The code above assumes jQuery is loading onto your page, and should also force it to do so if it isn’t already. For this reason, you may want to use additional WordPress conditionals to only load this on pages where it’s necessary. If you’re not showing the announcements on every page, no need to load the script every time.

Next, open up your footer.php file and paste in the following:

<script>
jQuery(document).ready(function($) {
<?php $args = array(
'post_type' => 'post',
'posts_per_page' => -1
);
$the_query = new WP_Query($args);
while ($the_query->have_posts()) : $the_query->the_post(); ?>
$("#announcement-<?php the_ID(); ?> .close").click(function() {
$.cookie("announcement<?php the_ID(); ?>", "dismissed");
var a<?php the_ID(); ?> = $.cookie("announcement<?php the_ID(); ?>");
$("#announcement-<?php the_ID(); ?>").fadeOut();
});
var a<?php the_ID(); ?> = $.cookie("announcement<?php the_ID(); ?>");
if (a<?php the_ID(); ?> == 'dismissed') {
$("#announcement-<?php the_ID(); ?>").hide();
}
<?php endwhile; ?>
<?php } ?>
});
</script>

There may be more sophisticated ways of doing this in jQuery without running the same loop again, but this works for me. Essentially, we are saying “if anyone clicks on the link or close button (both have a class of .close), set a cookie. If that cookie exists, use jQuery to hide that element from the user from then on.”

Enjoy!

Up Next: Why I'm Switching Back to Crossbrowsertesting (vs. Browserstack)