Let's say that you're a launching new product, giving away freebies or organizing an event. How do you deliver the message to your readers? Popular choice is to display a modal dialog in a lightbox, thus forcing the user to take notice. But there's another, less obtrusive, yet still effective way, to get a user's attention. In this tutorial we'll be creating a plugin that displays custom site-wide announcements across the top of the page, with the ability to schedule messages to appear between two given dates.
Step 1 Creating the Plugin
Our first step is to create a plugin folder and the main plugin file, with properly formatted header. Head on to wp-content/plugins and create a folder named simple-announcements. Now open your favorite editor and create a new php file called simple-announcements.php - the main file for our plugin. All the following PHP code should be placed in this file. Next, add the following code at the very beginning of the file:
<?php /* Plugin Name: Simple Announcements Plugin URI: http://wp.tutsplus.com Description: A simple announcements plugin. Version: 1.0 Author: Aleksandra Laczek Author URI: http://webtuts.pl */ ?>
It's a standard plugin header, and you could extend it with other information if you like (read more in Plugins section of the WordPress Codex).
Once it's done, go to Plugins section of WordPress administration area, and you should see the plugin, ready to be activated.
Before we move any further, we will define a constant to store our plugin path. This constant will be used throughout the plugin, and will make our job a little easier. Drop this line of code into simple-announcements.php, below the header.
<?php define('SIMPLE_ANNOUNCEMENTS_PATH', plugin_dir_url( __FILE__ )); ?>
Step 2 Creating Custom Post Type
To make it easy to edit and add new announcements, we're going to create a dedicated custom post type called Announcements.
<?php function sap_register_announcements() { $labels = array( 'name' => _x( 'Announcements', 'post type general name' ), 'singular_name' => _x( 'Announcement', 'post type singular name' ), 'add_new' => _x( 'Add New', 'Announcement' ), 'add_new_item' => __( 'Add New Announcement' ), 'edit_item' => __( 'Edit Announcement' ), 'new_item' => __( 'New Announcement' ), 'view_item' => __( 'View Announcement' ), 'search_items' => __( 'Search Announcements' ), 'not_found' => __( 'No Announcements found' ), 'not_found_in_trash' => __( 'No Announcements found in Trash' ), 'parent_item_colon' => '' ); $args = array( 'labels' => $labels, 'singular_label' => __('Announcement', 'simple-announcements'), 'public' => true, 'capability_type' => 'post', 'rewrite' => false, 'supports' => array('title', 'editor'), ); register_post_type('announcements', $args); } add_action('init', 'sap_register_announcements'); ?>
Now head to the administration area. There should be a new item in the menu, just below Comments.
Step 3 Creating Custom Meta Boxes
Announcements are rather simple, and all we really need is the post edit section to input our message. But to be able to schedule announcements, we'll need two additional fields to input a start and end date. For this purpose we're going to create a meta box and put our fields inside (we could also use custom fields instead).
Adding Meta Box
<?php function sap_add_metabox() { add_meta_box( 'sap_metabox_id', 'Scheduling', 'sap_metabox', 'announcements', 'side', 'high' ); } add_action( 'add_meta_boxes', 'sap_add_metabox' ); ?>
Wptuts+ has a great step by step tutorial on Custom Meta Boxes.
This piece of code adds a meta box named 'Schedule' to the right column on the Announcements post edit screen. You can read more about the add_meta_box
function and its parameters in the WordPress Codex.
I just want you to take notice of the third parameter - sap_metabox
. It's the name of callback function that renders HTML for the meta box content. We'll be writing that function in a moment.
Adding the Fields
We're going to add two fields to store the start and end date of the announcements.
<?php function sap_metabox( $post ) { $values = get_post_custom( $post->ID ); $start_date = isset( $values['sap_start_date'] ) ? esc_attr( $values['sap_start_date'][0] ) : ''; $end_date = isset( $values['sap_end_date'] ) ? esc_attr( $values['sap_end_date'][0] ) : ''; wp_nonce_field( 'sap_metabox_nonce', 'metabox_nonce' ); ?> <p> <label for="start_date">Start date</label> <input type="text" name="sap_start_date" id="sap_start_date" value="<?php echo $start_date; ?>" /> </p> <p> <label for="end_date">End date</label> <input type="text" name="sap_end_date" id="sap_end_date" value="<?php echo $end_date; ?>" /> </p> <?php } ?>
First thing we do here, is get all current custom fields' values. Then we create a nonce field, that will be needed for validation later.
Finally we're printing out HTML code for the two input fields, with values that we determined at the beginning.
Step 4 Registering JavaScript and CSS Files
We just created two custom meta boxes to input the dates for scheduling announcements. To make this task easier, we're going to add a JavaScript date picker. For this purpose I decided to use jQuery Datepicker. The script is actually bundled in with WordPress, so we just need to enqueue it, but for the CSS we need a jQuery UI theme. As we've mentioned before Helen Hou-Sandi, core WordPress contributor, has worked on two jQuery UI themes which complement WordPress. We'll use the 'fresh' theme which matches the default WordPress admin, so download the jquery-ui-fresh.css file from her GitHub repository, and save it to your simple-announcements/js folder.
We need one more JavaScript file to store all custom JavaScript code related to front and back end. We will call this file announcements.js. For now just create an empty JavaScript file and put it in the js folder, we'll get to writing custom code later.
After this, the plugin folder should be organized as shown below.
Now it's time to enqueue scripts and stylesheets, so that we can actually use them.
<?php function sap_backend_scripts($hook) { global $post; if( ( !isset($post) || $post->post_type != 'announcements' )) return; wp_enqueue_style( 'jquery-ui-fresh', SIMPLE_ANNOUNCEMENTS_PATH . 'css/jquery-ui-fresh.css'); wp_enqueue_script( 'announcements', SIMPLE_ANNOUNCEMENTS_PATH . 'js/announcements.js', array( 'jquery', 'jquery-ui-datepicker' ) ); } add_action( 'admin_enqueue_scripts', 'sap_backend_scripts' ); ?>
Our script will be used only in admin section, and what is more, only while adding or editing Announcements Post Type. Therefore we should make sure, that any scripts and styles are loaded only when needed.
Step 5 Adding Datepicker to Date Fields
In order to use the datepicker, we need to add some custom JavaScript code to assign date pickers to input fields. This code goes into the announcements.js file created in the previous step.
jQuery(document).ready(function($) { if($('#sap_start_date').length) { $(function() { var pickerOpts = { dateFormat: "yy-mm-dd" }; jQuery("#sap_start_date").datepicker(pickerOpts); jQuery("#sap_end_date").datepicker(pickerOpts); }); } });
Notice the dateFormat
option. We need to separate elements of the date with a '-' character. This will be important later, during validation.
More documentation on how to use Datepicker can be found in jQuery UI website.
To see the datepicker in action, go ahead and add a new Announcement. Try to add a start or end date and you'll notice the datepicker calendar pop up.
Step 6 Saving Meta Box Data
Now that we've got all the needed fields, we can proceed to saving the data from the meta box to the database. We do that by calling the sap_metabox_save
function on the save_post
action.
<?php function sap_metabox_save( $post_id ) { if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return $post_id; if( !isset( $_POST['metabox_nonce'] ) || !wp_verify_nonce( $_POST['metabox_nonce'], 'sap_metabox_nonce' ) ) return $post_id; if( !current_user_can( 'edit_post' ) ) return $post_id; // Make sure data is set if( isset( $_POST['sap_start_date'] ) ) { $valid = 0; $old_value = get_post_meta($post_id, 'sap_start_date', true); if ( $_POST['sap_start_date'] != '' ) { $date = $_POST['sap_start_date']; $date = explode( '-', (string) $date ); $valid = checkdate($date[1],$date[2],$date[0]); } if ($valid) update_post_meta( $post_id, 'sap_start_date', $_POST['sap_start_date'] ); elseif (!$valid && $old_value) update_post_meta( $post_id, 'sap_start_date', $old_value ); else update_post_meta( $post_id, 'sap_start_date', ''); } if ( isset( $_POST['sap_end_date'] ) ) { if( $_POST['sap_start_date'] != '' ) { $old_value = get_post_meta($post_id, 'sap_end_date', true); $date = $_POST['sap_end_date']; $date = explode( '-', (string) $date ); $valid = checkdate($date[1],$date[2],$date[0]); } if($valid) update_post_meta( $post_id, 'sap_end_date', $_POST['sap_end_date'] ); elseif (!$valid && $old_value) update_post_meta( $post_id, 'sap_end_date', $old_value ); else update_post_meta( $post_id, 'sap_end_date', ''); } } add_action( 'save_post', 'sap_metabox_save' ); ?>
This is a fairly standard way of saving meta box data. First, we check that:
- the post is not being auto saved,
- the nonce is present and valid,
- current user can actually edit the post.
After that we proceed with data validation, and finally save both dates to the database.
Step 7 Displaying Announcements
It's time to display our announcement! It'll be a two step process - first we need to create a function that selects relevant announcements using WP_Query
and creates HTML markup, and then we'll write some JavaScript and CSS to style the output.
Display Function
<?php function sap_filter_where( $where = '' ) { // ...where dates are blank $where .= " OR (mt1.meta_key = 'sap_start_date' AND CAST(mt1.meta_value AS CHAR) = '') OR (mt2.meta_key = 'sap_end_date' AND CAST(mt2.meta_value AS CHAR) = '')"; return $where; } function sap_display_announcement() { global $wpdb; $today = date('Y-m-d'); $args = array( 'post_type' => 'announcements', 'posts_per_page' => 0, 'meta_key' => 'sap_end_date', 'orderby' => 'meta_value_num', 'order' => 'ASC', 'meta_query' => array( array( 'key' => 'sap_start_date', 'value' => $today, 'compare' => '<=', ), array( 'key' => 'sap_end_date', 'value' => $today, 'compare' => '>=', ) ) ); // Add a filter to do complex 'where' clauses... add_filter( 'posts_where', 'sap_filter_where' ); $query = new WP_Query( $args ); // Take the filter away again so this doesn't apply to all queries. remove_filter( 'posts_where', 'sap_filter_where' ); $announcements = $query->posts; if($announcements) : ?> <div id="announcements" class="hidden"> <div class="wrapper"> <a class="close" href="#" id="close"><?php _e('x', 'simple-announcements'); ?></a> <div class="sap_message"> <?php foreach ($announcements as $announcement) { ?> <?php echo do_shortcode(wpautop(($announcement->post_content))); ?> <?php } ?> </div> </div> </div> <?php endif; } add_action('wp_footer', 'sap_display_announcement'); ?>
The key is to select the right announcements from the database, based on the start and end date. We need only those which start before, and end after, the current date. Also, since we didn't make the start and end date fields mandatory, we should include announcements without a scheduled date.
Start and end date are saved in the postmeta
table, assigned to a specific post via the post_id
column. We use a meta_query
with WP_Query
to fetch the right posts.
Finally, we loop through all selected announcements with simple foreach statement and display them with custom HTML markup.
Frontend JavaScript and CSS
Right now you should be able to see the announcements displayed on the home page, but you'll notice a few problems:
- announcements are at the bottom of the page
- it's impossible to close them
- they lack styling
Taking care of those issues will require writing some custom JavaScript code. But before we get to that, we need two more external JavaScript plugins:
- jQuery Cookie - we don't need the whole package, just the jquery.cookie.js file
- jQuery Cycle - we'll be using the Lite version - jquery.cycle.min.js.
Copy both files to simple-announcements/js folder. Now, remember how we loaded JavaScript in admin to show the datepicker? It's time to add some scripts and styles to the front end. Don't worry about the announcements.css, we'll create it shortly.
<?php function sap_frontend_scripts() { wp_enqueue_style( 'announcements-style', SIMPLE_ANNOUNCEMENTS_PATH . 'css/announcements.css'); wp_enqueue_script( 'announcements', SIMPLE_ANNOUNCEMENTS_PATH . 'js/announcements.js', array( 'jquery' ) ); wp_enqueue_script( 'cookies', SIMPLE_ANNOUNCEMENTS_PATH . 'js/jquery.cookie.js', array( 'jquery' ) ); wp_enqueue_script( 'cycle', SIMPLE_ANNOUNCEMENTS_PATH . 'js/jquery.cycle.lite.js', array( 'jquery' ) ); } add_action('wp_enqueue_scripts', 'sap_frontend_scripts'); ?>
Now that we have all the necessary tools we can write the final piece of JavaScript. This code goes in announcements.js, below scripts added in step 5, inside the main jQuery(document).ready()
function.
if($('#announcements').length) { if($.cookie('sap_active') == 'false') { $("#announcements").hide(); }; $("#close").click(function() { $("#announcements").slideUp("normal"); $.cookie('sap_active', 'false', { expires: 2, path: '/'}); return false; }); $("body").prepend($("#announcements")); $('#announcements .sap_message').cycle('fade'); }
Let's break down the code.
The Close Button
We don't want to annoy our visitors, that's why we added a closing button to the announcement. But right now it doesn't do anything. With a little JavaScript we're going to hide the announcement on the click event, with a nice slide effect. To make sure that the announcement doesn't pop up when a user visits us next time, we're creating a cookie that will expire in two days (that's what we needed the jQuery Cookie plugin for).
if($.cookie('sap_active') == 'false') { $("#announcements").hide(); }; $("#close").click(function() { $("#announcements").slideUp("normal"); $.cookie('sap_active', 'false', { expires: 2, path: '/'}); return false; });
First thing we need to do, is to check if our cookie named 'sap_active
' is present. If it is and its value equals to 'false
', we simply hide the whole announcements bar. The cookie is created when the user hits the close button.
Moving Announcement to Top of the Page
$("body").prepend($("#announcements"));
Next we move the announcements bar to top of the page. To display the announcement bar, we hooked into wp_footer
, since themes are required to implement it. wp_footer
is a hook that is fired right before the closing </body>
tag, which means that our announcement will be appended to the end of the document (that's why it's displayed at the bottom). Here we're using jQuery to display it at the very top of the page, at the same time pushing down the content.
Cycle Through Announcements
$('#announcements').cycle('fade');
Remember when I said that it's possible to have more than one announcement active on any given date? If that happens, we don't want to display all of them at once, but rather cycle through them. That's exactly what this last piece of code does.
Step 8 Styling the Announcement Bar
Right now our announcements bar doesn't look like much. Let's add some CSS rules and style it up a bit. All CSS rules should be placed in the announcements.css file in the simple-announcements/css folder.
#announcements {display: hidden; text-align: center; background: #FF7F00; height: 35px;} #announcements .wrapper {width: 1000px; text-align: left; margin: 0 auto; padding: 5px 0;} #announcements .wrapper .close {float: right; font-weight: bold; padding: 0 5px;} #announcements .wrapper .close:hover{background: #000; border-radius: 5px;} #announcements .wrapper .sap_message p{margin: 0;color: #fff;}
With these few rules we changed the background color of the announcement bar to orange, positioned the close button to the right and centered announcements on the page. What we've done here is really basic, you could certainly go further, and play with the background or add a shadow, change the font etc.
That's it! Let's take a look at the end result.
Conclusion
Announcements bar is simple yet effective way to communicate with visitors. You could definitely do more in terms of styling and functionality, but I believe this tutorial should be a good starting point. Feel free to use this code as a canvas for your own custom plugins, and let us know about your ideas in comments below.
Comments