I recently finished a big project, a few months in the making, that tests the limits of "WordPress as a CMS." At some points in development, I wondered if it was a crazy idea to do this all in WordPress -- but the easy UI (for my client) and quick development (for me) made it work & made it worth it.
The site is a re-design of a custom ASP.NET site developed 2002-2006 for Jerry Rupiper, the owner of Washington Island Realty and webmaster of washingtonisland.com (see washingtonisland.com circa October 2007). The WI.com website is mostly for tourists interested in visiting the island for the first time or planning a return trip. The original site featured information about the island, a comprehensive directory of local businesses, an events calendar, as well as some hosted advertiser sites. The new site would do the same thing (better), add a blog for residents and people interested in what's happening on the island, and a more active calendar.
So, to make this project useful for other WordPress developers, I'll go through some of the more interesting parts of the site and explain: How'd you do that?! The project uses the Thematic WordPress Thematic Framework by ThemeShaper, relies heavily on the Flutter WordPress CMS Plugin by Freshout, and uses a handful of other WordPress plugins (see the bottom of the post for a list) in addition to jQuery and Google Apps. The rest of this post will go through features of the site and briefly explain how they were accomplished.Homepage Slideshow
What better way to welcome people to the site (and island) than with big, colorful pictures?! But, slow-loading photos are not going to keep people on the site, so (in addition to compressing the photos), the slideshow uses the jQuery Cycle plugin combined with a callback function to dynamically add slides after the page has been loaded. The homepage template contains the loop (like normal), and then below the#container div, the following chunk of code:
<div id="supersize">
<img src="<?php echo get_bloginfo( 'stylesheet_directory' ); ?>/images/slideshow/1.jpg">
<img src="<?php echo get_bloginfo( 'stylesheet_directory' ); ?>/images/slideshow/2.jpg">
</div>
This #supersize div contains the first two slides of the homepage slideshow, enough to get Cycle going once the page has loaded. The page also contains this JavaScript:
<?php wp_enqueue_script('cycle', get_stylesheet_directory_uri() .'/js/jquery.cycle.js', 'jquery'); ?>
<script type="text/javascript">
jQuery(function($){
$('#supersize').cycle({
random: 0,
delay: -2000,
speed: 500,
fx: 'fade',
timeout: 6000,
before: onBefore
});
var slidesAdded = false;
function onBefore(curr, next, opts) {
if (!opts.addSlide || slidesAdded) return;
for (var i=3; i < 10; i++) opts.addSlide('<img src="http://src of slides/'+i+'.jpg" width="1024" height="768" />');
slidesAdded = true;
};
});
</script>
The onBefore callback adds the rest of the slides to #supersize after the page is loaded. This speeds up the page loading, especially if the user doesn't plan on sticking around for all 10 slides and just clicks into the site.
Flickr Photostream
The Visitor's Guide intro page shows off more of the island's sites with thumbnails from the Washington Island Flickr photostream. The photostream is added to the page by the simple flickrRSS plugin by Dave Kellam combined with this quick plugin, which I wrote to add a shortcode to the site: http://gist.github.com/154365Local Businesses: Custom Write Panel #1
Local Business listings are a key part of WI.com, powering the directories (Local Business Directory & Accommodations directory), banner advertisements, and advertiser pages hosted by WI.com. There are three types local businesses listed on WI.com: advertisers with hosted pages, advertisers with banner ads that link to their own website, and un-paid listings that the owner of WI.com lists to make the directory more useful. Using the Flutter WordPress CMS Plugin by Freshout, I setup a "Custom Write Panel" (Freshout's name for a custom content type or post type) called "Local Business." The Local Business write panel is where all local businesses are defined, regardless of the type of listing. The tools that make this custom write panel useful are:- Local Business Directory template,
- Accommodations directory template,
- Advertisements Widget, and
- Local Business Page template.
The Local Business & Accommodations directories are very similar to category listings (template pages that use multiple loops to only display posts within the correct categories) with some added CSS & jQuery for display and behavior. Both pages use the jQuery plugins quickSearch by Rik Lomas and Smart Lists by Benjamin Keen.
The Advertisements widget is defined in functions.php, it uses WP_Query() to retrieve Local Business posts and then display their banner ads (uploaded as "Ad Image" in the custom write panel defined by Flutter). Then, depending on whether the advertiser has an "External Link" defined or not, the banner ad will either link to the advertiser's website or their WI.com hosted page.
Advertiser pages hosted on WI.com are displayed by the Local Business template, (see Category Templates in the WordPress codex), which can be customized in the Custom Write Panel using the "Template Options" defined by Flutter. Although this implementation crosses the line I like to draw between content and presentation, this is how the template handles customization:
<?php $border_color = get('template_border');
$content_bkg_color = get('template_content_bkg');
$bkg_img = get('template_bkg');
echo '<span id="bkg_img" style="display:none;">'.$bkg_img.'</span>';
$bkg_color = get('template_bkg_color');
echo '<span id="bkg_color" style="display:none;">'.$bkg_color.'</span>';
$banner = get('template_banner'); ?>
<div id="container">
<div id="content" style="<?php if ($border_color) { ?> border:5px solid <?php echo $border_color; ?>;<?php } if ($content_bkg_color) { ?>background-color:<?php echo $content_bkg_color; }?>">
<?php the_post(); ?>
<?php if ($banner) { echo '<div><img src="'.$banner.'">'; } ?>
...
<script type="text/javascript">
jQuery(function($){
var bkg_img = $('span#bkg_img').text();
if (bkg_img == 'Painted Blue') {
$('body').css("background", "url(http://imgsrc.gif) top center fixed no-repeat" );
}
if (bkg_img == 'Painted Green') {
$('body').css("background", "url(http://imgsrc.gif) top center fixed no-repeat" );
}
var bkg_color = $('span#bkg_color').text();
if (bkg_color) {
$('body').css("background", bkg_color );
}
});
</script>
News (Blog Posts): Custom Write Panel #2
To keep things simple, blog posts are also a custom write panel. This lets me hide Custom Fields, and Categories, and guarantees that the WI.com bloggers will always have the appropriate "News" category attached to their blog posts.
The Island News page (the blog), uses multiple loops to only display posts in the "News" category, and an action in the functions.php file excludes Local Businesses (the only other category used on the site) from the RSS Feed and Post Archives.
function gloss_remove_glossary_cat( ) {
global $wp_query;
if( is_home() || is_feed() || ( is_archive() && !is_category() )) {
$wp_query->query_vars['cat'] = '-3'; // Local Businesses
}
}
add_action('pre_get_posts', 'gloss_remove_glossary_cat' );
Events Calendar
I initially tried to approached events as a third custom write panel (see this post: WP+jMonthCalendar=Fancy), but found that handling multi-day events within Flutter's custom write panels (at that time, could be better now -- the plugin is constantly being updated) was too big of a stumbling block to work though. Dealing with archives of previous months' events and trying to minimize the number of queries to the WP database was also something I was unprepared to handle. I quickly switched to Google Calendar + FullCalendar, a jQuery plugin by Adam Shaw.
My client can login to Google Calendar, create events there, and then see them automatically added to the calendar on his site. He can also give friends & colleagues permission to add events to the calendar, the same way he can add users to the WordPress site as bloggers. FullCalendar reads the calendar's public feed and turns it into an easy-to-theme and quick-to-load full-month calendar.
Using FullCalendar is incredibly easy, the only thing I had trouble with was when Google spontaneously (and erratically) started sending the feed in German, which was fixed by adding&hl=en to the end of the feed's URL.
Google Maps
After trying Google Map plugins for WordPress, and finding that they really slowed down the site (even on pages that didn't have embedded maps!), I decided to switch to direct iframe embedding. This can open up a site to some vulnerabilities (if you don't trust people posting to use iframes responsibly), but in this situation, I wasn't worried about my client abusing iframes.
By adding the following filter to functions.php, the Google Maps embed code is now allowed by TinyMCE:
add_filter('tiny_mce_before_init', create_function( '$a', '$a["extended_valid_elements"] = "iframe[id|class|title|style|align|frameborder|height|longdesc|marginheight|marginwidth|name|scrolling|src|width]"; return $a;') );
List of Plugins
- Admin Menu Editor - used to hide menus from my client's user account and "keep things simple"
- Akismet - my favorite comment SPAM plugin, I generated an API for the site using an @washingtonisland.com email address
- Cleaner Gallery - a must-have if you're using galleries, also helpful for including Thickbox
- Dagon Design Sitemap Generator - auto-geneartes the a simple Site Map
- DB Cache - caches DB queries, was faster than WP Super Cache (my normal favorite for WP caching) for this site
- flickrRSS - generates a simple flickr photostream
- flickRSS Shortcode - adds a shortcode to fickrRSS
- Flutter - allows creation of "Custom Write Panels", a WordPress CMS plugin
- Hackadelic SEO Table of Contents - generates table of contents based on page headers, used on the Attractions, Island History & Culture, Services, and Recreation pages
- Hyper Cache - a caching plugin that can be used in conjunction with DB Cache
- My Page Order - allows on-the-fly re-ordering of pages
- Page Menu Editor - allows the user to specify distinct menu titles and page titles
- Redirection - manages 301 redirects
- Role Manager - used to create custom roles, like "Site Admin" (my client, with only a few privileges denied) and "Blogger"
- Search Everything - customizes search results
- Smart Youtube - allows simple YouTube embedding in posts
- TinyMCE Advanced - extends TinyMCE
- Ultimate Google Analytics - adds Google Analytics tracking code
- WordPress Database Backup - allows client to backup the database without logging into PHPMyAdmin







17 Comments
I found your article from the Flutter site. I really like what you’ve done with the washington site, not only from a technical point of view but also design. The site looks so much better, a lot less scary and off putting than the previous site. Nice one.
Wow.
That’s pretty impressive. Especially considering how relatively little crazy custom programming there was to make it happen!
Oh, and, FYI, I got here via an Ian Stewart Tweet.
Nicely done! thanks for the writeup.
Useful article. Thanks for sharing.
Congratulations, excellent work, truly an inspiration for us non-coders.
Great article, great rebuild and thanks for opening my eyes to some new plugins here.
You’ve done an amazing job with the website. Thanks for writing this case study. Its very helpful.
This is an excellent article. Just the kind of thing I love to read!!
Wanted to let you know that HeadSpace2 by John Godley does a few of the things you’ve got other plugins for, aside from all its SEO goodness.
It would replace in the list above Page Menu Editor and Ultimate Google Analytics. It also does loads of other nifty things.
Since you’ve got a few other of John’s plugins there, I thought you might like to stick with him some more
I do!
Cheers,
-Alister
—
Alister Cameron // Blogologist
http://www.alistercameron.com
Mob. 04 0404 5555
Fax 03 8610 0050
Click here to find me online:
http://clicktoadd.me/alicam
Wow, this post was like a life preserver. I’m building a website for a nonprofit using WP as the CMS (and a bit of Google apps) for just the reasons you listed, but I’ve been completely stumped by what to use for a calendar. I began with Google calendar but none of the WP plugins I found had the features the client wanted. I was just tonight looking at how I might embed an AJAX or PHP calendar in the WP site when I found your post. FullCalendar is new to me but it looks just right. So thanks for taking the time to write up this case study.
Hi. I’m having a complete failure of imagination here. How do I integrate FullCalendar into WordPress? I’m just realizing that all the jQuery scripts I’ve used in WP had already been converted to a WP plugin by some kind, clever person.
If it helps here’s my skill level: Good with html & CSS but just starting to learn PHP.
This is the code I use in my calendar.php (WordPress template file):
And this is my JavaScript:
<script type="text/javascript"> jQuery(function($){ $('#full-calendar').fullCalendar({ events: $.fullCalendar.gcalFeed('http://mygooglefeedURL', { className: 'gcal-events' } ), eventClick: function(event) { window.open(event.url, 'gcalevent', 'width=700,height=600'); return false; }, loading: function(bool) { if (bool) $('#loading').show(); else $('#loading').hide(); }, abbrevDayHeadings: false }); }); </script>You’ll also need to make sure that you include the jQuery FullCalendar plugin and GCal support. Use the
wp_enqueue_script()function to include/js/fullcalendar/fullcalendar.min.js,/js/fullcalendar/gcal.js, and/js/fullcalendar/jquery/ui.core.js.Excellent. I was just looking up the wp_enqueue_script () function. Thanks so much for your help.
Great case study Esther!
I wish I took the time to document my projects this well. And really nice redesign!
Excellent case study! washingtonisland.com sure looks (and I bet, functions) a lot better.
What made you choose wordpress as opposed to drupal or joomla btw?
Very interesting case study, really learning alot from your post.
Thank you for the blog and for the list of plugins, that’s a real help. Keep up the excellent work!
Hey there! Thanks for the great tutorial. I’ll be bookmarking this page and passing it onto my friends too. Keep writing, cheers!
3 Trackbacks
[...] may appreciate their work getting exposure. A case study found via Ian Stewarts tweets: http://blog.estherswhite.net/2009/07…-a-case-study/ Opinions ? Other case study urls [...]
[...] Shared Outta Bounds – One BIG WordPress Site: A Case Study [...]
Terrell Boldt…
Thanks-a-mundo for the blog post. Want more….