WordPress as a CMS

I’ve come across a number of useful “WordPress as a CMS” type posts, but only a few that detail building an actual WordPress site. I’m going to go over how I setup a basic CMS using WordPress in a recent project for the startup lecture management firm, Verbatim Lecture Management.

Verbatim needed a site that would be able to organize speakers in a meaningful way while also allowing flexibility in the content provided on each individual speaker’s page. In addition, the site needed a way to automatically bring “interesting” content to the front page and allow the company’s founder to blog about the company and speakers’ achievements.

My first approach organized content this way: each speaker would be a page (makes sense, right? the speakers’ pages will stay pretty much the same all the time) and the posts would be used as the company blog.

Pretty quickly, however, I realized that not being able to take advantage of categories & tags on individual speakers’ pages would be a huge disadvantage, and at the time, I didn’t feel like any of the existing CMS plugins (although, things are looking good for Flutter) were mature enough to experiment with creating my own content type (a blend of post/page called “speaker page” or something…). So, I decided to use categories to split up the posts into “speaker posts” and “blog posts.” This way, speakers could be organized using tags, which would allow me to use the very nice built-in WordPress tag cloud etc.

Speaker “Pages”

It was clear from the beginning that the speaker “pages” (really posts with the category “Speakers”) would need a custom template and some custom fields as well.

Each speaker needed to have the following attributes: a headshot to be used throughout the site, an excerpt, a shorter excerpt (or “tagline”), links to their website or blog, links to recent articles or reviews, videos on a variety of video sites (YouTube, Blip.tv, Comedy Central, MTV, etc), books listed on Amazon.com, PDFs, and finally, their bios and program descriptions.

The headshots, taglines, links to speakers’ websites or blogs, books, and videos are all controlled by custom fields.

I wanted to make the site relatively simple to update and maintain for Verbatim, so I used the More Fields plugin by Henrik Melin, Kal Ström to add the appropriate input fields to all “Write Post” admin pages.

On each individual speakers page, the headshot is added to div.entry-content using code like this:

<?php if ( in_category('18') ) {
	$headshot_src = get_post_meta($post->ID, 'headshot', true);
	if ($headshot_src) { ?>
	<div class="headshot"><img src="<?php echo get_post_meta($post->ID, 'headshot', true); ?>" alt="<?php get_the_title(); ?>"></div>
<?php } } ?>

The sidebar of each Speaker page is a bit more complicated but follows the same logic: check to see if a specific custom field exists for this post, print it if it does.

The first thing that sidebar.php does is check to see that the post is in the Speaker’s category (18 in this case) and then create a variable with the Speaker’s name (also the title of the post). (If it is not a post in category 18, the dynamic sidebar is loaded, using widgets specified in WP Admin.)

** Disclaimer — I wish that I had had time to turn these sidebar “widgets” into a set of plugins & proper widgets, but the project budget and timeline didn’t allow that, so I made do, and this is what I came up with. If you are more experienced with writing plugins, I think that would be a better way to accomplish this, but here you go anyway…

<!-- If this is a Speaker page (in category 18) -->
<?php if ( in_category('18') && is_single() ) {
	$speaker_name = the_title_attribute('echo=0');
?>

Next, each custom content type is checked for and printed.

Amazon Books

<!-- If there is a Book -->
<?php
$amazon = get_post_custom_values('amazon');
if ( $amazon[0] ) { ?>
	<li id="books" class="widget widget_books">
	<h3 class="widgettitle">Books</h3>
	<ul>
		<?php foreach ($amazon as $book) { ?>
			<li><?php echo $book; ?></li>
		<?php } ?>
	</ul>
	<p class="clearfix">&nbsp;</p>
	</li>
<?php } ?>

Videos

<?php
	$video_url = get_post_custom_values('vid1_url');
	$video_img =  get_post_custom_values('vid1_img');
	$video_name = get_post_custom_values('vid1_name');
	if ($video_url[0]) { ?>
	<li id="videos" class="widget widget_videos">
		<h3 class="widgettitle">Videos</h3>
		<ul>
		<?php include('video_snippet.php');
			// Get values for vid2
			$video_url = get_post_custom_values('vid2_url');
			$video_img =  get_post_custom_values('vid2_img');
			$video_name = get_post_custom_values('vid2_name');
			include('video_snippet.php');
			// Get values for vid3
			$video_url = get_post_custom_values('vid3_url');
			$video_img =  get_post_custom_values('vid3_img');
			$video_name = get_post_custom_values('vid3_name');
			include('video_snippet.php');
			// Get values for vid4
			$video_url = get_post_custom_values('vid4_url');
			$video_img =  get_post_custom_values('vid4_img');
			$video_name = get_post_custom_values('vid4_name');
			include('video_snippet.php');
			// Get values for vid5
			$video_url = get_post_custom_values('vid5_url');
			$video_img =  get_post_custom_values('vid5_img');
			$video_name = get_post_custom_values('vid5_name');
			include('video_snippet.php');
		?> 

		</ul>
		<p class="clearfix">&nbsp;</p>
	</li>
<?php } ?>
// video_snippet.php
$vid_service = explode(".", $video_url[0]);
if ($vid_service[1] == "youtube") {
  	$vid_id = explode("=", $video_url[0]);
	echo '<li class="video_thumb">
	<!--[if !IE]><![IGNORE[--><![IGNORE[]]><a title="' .$video_name[0]. '" href="' . $video_url[0] .'" rel="vidbox"><![endif]-->  <!--[if IE]><a href="' . $video .'" target="_blank"><![endif]-->
	<img src="http://i3.ytimg.com/vi/' . $vid_id[1] . '/default.jpg" alt="YouTube Video Thumbnail"></a></li>';
} else if ($vid_service[0] == "http://blip") {
	echo '<div class="video_thumb"><a title="' .$video_name[0]. '"  href="' . $video_url[0] .'" target="_blank" rel="vidbox"><img src="'. $video_img[0] . '"></a></div>';
} else if ( $video_img[0] ) {
	echo '<div class="video_thumb"><a title="' .$video_name[0]. '"  href="' . $video_url[0] .'" target="_blank"><img src="'. $video_img[0] . '"></a></div>';
} else {
	echo '<div class="video_thumb"><a title="' .$video_name[0]. '"  href="' . $video_url[0] .'" target="_blank">'.$video_name[0].'</a></div>';
}
// Reset video variables
$video_url = null; $video_img = null; $video_name = null;

Static links (added by a custom field) and/or blogroll links

<!-- If there are Links -->
<!-- && Add Custom Field Data above Latest Word Archive -->
<?php $lastword =  wp_list_bookmarks('category_name='.$speaker_name.'&order_by=updated&order=DESC&limit=4&echo=0&title_before=<span class="none">&title_after=</span>');
$links = get_post_custom_values('link');
if ($lastword || $links) { ?>

	<li id="links" class="widget widget_links"><div>
	<h3 class="widgettitle">Links &amp; Articles</h3>

	<?php if ($links) { ?>
		<ul id="customlinks">
		<?php foreach ($links as $link) { ?>
			<li><?php echo $link; ?></li>
		<?php } ?>
		</ul>
	<?php } ?>

	<?php if ($lastword) {
		$t1 = explode ('blogroll\'>',$lastword);
		$t2 = $t1[1];
		$trimmed_links = explode ('</ul>',$t2);
		$trimmed_links[0] = html_entity_decode($trimmed_links[0]);
		?>
		<p class="articles">Recent articles by or about <?php echo $speaker_name; ?></p>
		<ul><?php print "$trimmed_links[0]"; ?></ul>
		<p>Visit <a href="latest-word"><i>The Latest Word</i> Archive</a></p>
	<?php } ?>
	</div></li>
<?php }  ?>

Feed

<!-- If there is a Feed -->
<?php
	$url = get_post_custom_values('feed');
	if ( $url ) { ?>
		<li id="feed" class="widget widget_feed">
		<?php require_once(ABSPATH . WPINC . '/rss.php');
		$rss = fetch_rss($url[0]);
		$channel = $rss->channel;
		echo '<h3 class="widgettitle">Feed: <a href='.$channel['link'].' />'.$channel['title'].'</a></h3> <ul>';
		$maxitems = 5;
		$items = array_slice($rss->items, 0, $maxitems);
		foreach ( $items as $item ) {
             printf(
                  '<li><a href="%1$s" title="%2$s">%3$s</a></li>',
                  clean_url( $item['link'] ),
                  attribute_escape( strip_tags( substr($item['description'],0,250).'&#8230;' ) ),
                  htmlentities( $item['title'] )
              );
        } ?>
		</ul>

		<p class="clearfix">&nbsp;</p>
		<?php //wp_rss($url[0]); ?>
		</li>
<?php } ?>

The next post will go over how the Speakers page (a list of all the Speaker posts) was created & also the Ideas & Issues page (a tag cloud that organizes Speaker post excerpts by tag using a modal dialog).

This entry was posted in wordpress and tagged , , , , . Bookmark the permalink. Comments are closed, but you can leave a trackback: Trackback URL.

2 Comments

  1. Posted February 6, 2009 at 4:35 pm | Permalink

    Esther, how exciting to see this!

    Have you been in touch with Jim Groom, UMW, re: WP MU?

    • Esther
      Posted February 6, 2009 at 5:45 pm | Permalink

      Yes — when I was first developing the Smith WPMu install, I got a little help from him. Since then I’ve been watching the developments over at UMW via his blog, bavatuesdays.

One Trackback

  1. By Outta Bounds » WP+jMonthCalendar=Fancy on March 19, 2009 at 2:43 pm

    [...] webpages, blog posts, events, and business listings. After learning a few things about using WordPress as CMS, I decided at the beginning that everything (except for webpages) would need to be some kind of [...]