Case Study: Emergency Notice Banner for Hybrid Web site

Share this!

Eaton Academy’s Web site (EatonAcademy.org) is just one of many hybrid projects I’ve built over the years. Namely, the main section of site is custom-built using generous doses of PHP and MySQL for templating while the blog section is built on WordPress. The two sections are visually integrated but fundamentally independent from a functional standpoint.

When Eaton co-founder Brian Uitvlugt wanted me to implement an emergency announcement banner that would appear at the top of all pages of the site (for school closing information and such), he was issuing an interesting and fun challenge.

One option would have been to extend the functionality of the already-existing custom (non-WordPress) Intranet system. I could have added a form through which Brian and other authorized users could add, edit, and delete the notices (along with associated database modifications to store and serve the information). Then I could customize both the main site’s templates and the blog’s templates to display the notices to the public.

Instead, I suggested (and Brian agreed) that we leverage WordPress for the job.

The end result

We launched the banner feature in December of 2012, in anticipation of school closings, late openings, or early dismissals due to extreme weather.

I had almost forgotten about the little-used feature (as had Brian) until today — when the school’s email system went down. Here’s what the Web site looks like at the time of this writing.

Banner on Main Site

Eaton Banner Main Site

Banner as it appears on main section of Web site

Banner Announcement on index page of blog

Here's how the announcement appears on the blog's home page

Here’s how the announcement appears on the blog’s home page

Banner Announcement on single page of blog

Here's how the banner announcement looks on the single page for the article

Here’s how the banner announcement looks on the single page for the article

Functional Specs

Here’s the general approach we took.

  1. We agreed to create a special new WordPress post category called “Banner”. A blog post MUST be assigned to the “Banner” category to be used in the site’s banner.
  2. Only the MOST RECENT blog post assigned to the “Banner” category will be used in the banner.
  3. Optionally, the post should be marked as a STICKY post. This will ensure that it appears as the first post in the blog’s main index page, even if another post has a more recent publication date.
  4. To remove a banner from the public-facing Web site, an authorized user would perform one of the following actions in the WordPress dashboard:
    1. delete the post
    2. change the post’s STATUS to ‘Draft’ or ‘Pending Review’
    3. change the post’s VISIBILITY to ‘Password Protected’ or ‘Private’

Technical Specs

For the techies in the audience, here are some details of how I put the nuts and bolts together. I’m not going to get heavy into explaining the code because (a) you might not care or (b) you might be able to figure it out yourselves. If you do wonder why I’m doing what I’m doing (or if you have a better way), please feel free to post in the comments, and I’ll be happy to respond.

Function to get post data array

Since I’m working outside of WordPress, I couldn’t use WordPress’ internal query methods to grab the post data. Hence the multi-table SQL query code with a fairly involved “where” clause involving the wp_terms, wp_term_taxonomy, and wp_term_relationships tables.

This function (get_blog_posts_recent()) gets and returns a nested array of posts that meet the selection criteria passed in a single line of code in the header template of the main site (keep reading for that).

function get_blog_posts_recent($args=array()) {
	$defaults = array(
		'table' => 'wp_posts',
		'fields' => array('ID', 'post_title', 'post_date', 'guid'),
		'category' => '',
		'limit' => '1'
	);
	$r = array_merge($defaults, $args); 
	extract($r);
	
	// When category is specified:
	if ( !empty($category) ) {
		$new_fields = array();
		for ( $i=0, $n=count($fields); $i<$n; $i++ ) {
			$new_fields[] = 't1.' . $fields[$i];
		}
		$field_list = implode(', ', $new_fields);
		
		$sql = "select " . $field_list . 
		", t3.name 
		from " . $table . " as t1, 
		wp_term_relationships as t2,
		wp_terms as t3,
		wp_term_taxonomy as t4
		
		where t1.post_status = 'publish' 
		and t1.post_type = 'post' 
		and t1.ID = t2.object_id 
		and t2.term_taxonomy_id = t4.term_taxonomy_id 
		and t4.term_id = '$category' 
		and t3.term_id = '$category'
		order by t1.post_date desc limit $limit";
	} else {
		// ANY category:
		$field_list = implode(', ', $fields);
		$sql = "SELECT " . $field_list . " FROM " . $table . " 
		where post_status = 'publish' and post_type = 'post' 
		order by post_date desc limit $limit";
	}
	$result = mysql_query($sql);
	if ( !mysql_num_rows($result) ) return false;
	// Else...
	$data = array();
	while ( $record = mysql_fetch_assoc($result) ) {
		$data[] = $record;
	}
	return $data;
}

[PS/Update for fellow geeks: I just finished reading Andrew Nacin’s recent post at Make WordPress Core entitled Potential roadmap for taxonomy meta and post relationships. If the ideas in that post are implemented (especially the elimination of the wp_terms table), that multi-table join in the code above could be simplfied considerably. We can hope…]

Is there a post that matches the selection criteria?

This function (eaton_banner_exists()) calls the one above. If there’s no post whose category id is associated with the passed category id, then we can just quit (the good old return false (line 10). Otherwise, go get it or them.

function eaton_banner_exists($category, $limit, $fields) {
	$conn_link = banner_conn();
	if ( $data = get_blog_posts_recent( array ('category' => $category, 'limit' => $limit, 'fields' => $fields ) ) ) {
		mysql_close($conn_link);
		include(SITE_INCLUDES_PATH . 'dbconn.php');
		return $data;
	} else {
		mysql_close($conn_link);
		include(SITE_INCLUDES_PATH . 'dbconn.php');
		return false;
	}
}

Function that looks for the most recent banner post

This function (eaton_banner()) uses the hard-coded category id that corresponds to “Banner” (’56’) and specifies a limit of 1 post to grab. It also passes an array of field names to be selected in the eaton_banner_exists() function.

function eaton_banner( $category_id = '56', $limit = '1' ) {
	$fields = array('ID', 'post_title', 'post_date', 'guid', 'post_content');
	if ( $data = eaton_banner_exists( $category_id, $limit, $fields ) ) {
		//echo_r($data, 'Banner test');
		return $data;
	} else {
		return false;
	}
}

The one-line call in the main site’s header template

I added this one-line script to the header template. If the eaton_banner() function finds and returns a post in the “Banner” category, then we’ll include a simple file at the top of the page. Otherwise, we’ll do nothing.

<?php if ( $banner_content = eaton_banner() ) include(SITE_INCLUDES_PATH . 'inc_banner.php'); ?>

Finally, the include file for the main section of the site

This is the simple HTML (with a little bit of interspersed PHP) that makes the banner display, if it indeed exists. Some CSS markup makes the banner appear inside a centered, bordered box at the very top of each page of the main site.

<?php 
	extract($banner_content[0]);
?>
<div class="eaton-banner">
	<div class="inner">
		<h1><?php echo $post_title;?></h1>
		<div class="text">
			<?php echo nl2br($post_content);?>
		</div>
	</div><!-- .inner -->
</div><!-- .eaton-banner -->

Conclusion

If the Eaton Web site were completely built on WordPress, adding an announcement banner to all pages of the site would have been extremely simple. I probably would have used a plugin like iTheme’s Boom Bar.

But a hybrid Web site needn’t pose insurmountable obstacles. With a little bit of mental elbow grease — and just the right amount of knowledge of PHP, MySQL, and the WordPress database structure, one can accomplish all kinds of nifty things.

Share this!

About JeffCohan.com

The nSiteful Tech Blog (the official blog of nSiteful Web Builders, Inc. since January of 2013) is where I (Jeff Cohan) and (occasionally) associates will be posting articles of potential interest to like-minded techies, nSiteful clients who are playing active roles in the maintenance of their own Web sites and blogs, and pretty much anyone interested in how Web strategies and tools can help them reach their goals.

This entry was posted in Case Studies and tagged , , by Jeff Cohan. Bookmark the permalink.

About Jeff Cohan

Jeff and his wife, Margie, are the proud parents of Sarah and Jake. Jeff is the founder, president and chief cook and bottle washer of nSiteful Web Builders, Inc., a Web development and Internet Consulting firm. In his spare time, Jeff builds Web sites and Web applications, plays guitar, putters around in his basement woodworking shop, mercilessly spoils his grandchildren, and creates videos from more than two decades of home movies. His current video project is an extended montage of people (mainly family members) asking him to stop filming them.

Leave a Reply

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