17 Jan, 2008
Using WordPress (with some modifications) as a CMS
Posted by: Jennifer In: WordPress|WordPress Hacks
For a long time one of the things I've liked about WordPress is it's flexibility. I recently did a project for Savvydog Design for one of their clients: the National WASP WWII Museum – that involved doing some customizations to WordPress. They wanted most of the pages on the site to be editable (I used WordPress' pages functionality here), they also wanted to be able to enter in news items (these would be standard blog posts with a category of "news"), as well as be able to enter in events (these would also be standard blog posts with a category of "events"). They wanted the home page of the site to show some (editable) content at the top, and then list the last 3 news or event items. On the side bar, they wanted to be able to list the next 3 upcoming events. Here is how I put it all together:
*Please note – some of the customizations take a few things as assumptions – (for example how you have your permalinks set up, etc.) So if you use any of this, do so at your own risk (most especially the part about editing a core WordPress file – I'm sure I'll get heat for that from SOMEONE.) Your mileage may vary, and I don't guarantee this will work with your setup, yadda yadda yadda…
1) Home Page
So we set this up as a page. The page had a custom template.
By the way, to make a custom template for the page – all you need to do is create the template – which will probably look similar to your index.php, except with any modifications you want to make – and then at the top, above any other code, have the following code so that WordPress knows it's a custom page template:
<?php
/*
Template Name:CustomHomePage
*/
?>
So in this case – I wanted the top portion to be editable as a page… So where the content belonged I had this:
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
<h1><?php the_title(); ?></h1>
<?php the_content('<p class="serif">Read the rest of this page »</p>'); ?>
<?php endwhile; endif; ?>
<?php edit_post_link('Edit this entry.', '<p>', '</p>'); ?>
Now to list news and events – I wanted to allow them the ability to post news and event items that didn't have to show up on the home page. So I created a third category called "Show on home page". So they could enter an event or a news item in – indicate if it was a news or event item by selecting the appropriate category – and then if they wanted to have it show up on the home page, they would also indicate it as being in the "show on home page" category… To display that list of "posts" I had this:
<?php
$pageposts = $wpdb->get_results ("SELECT * FROM wp_posts, wp_term_relationships WHERE wp_term_relationships.object_id = wp_posts.ID && wp_term_relationships.term_taxonomy_id = '4' && wp_posts.post_status = 'publish' && wp_posts.post_category = '0' && wp_posts.post_type = 'post' order by post_date desc limit 3");
foreach ($pageposts as $post):
setup_postdata($post);
?>
<h2><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title(); ?>"><?php the_title(); ?></a></h2>
<small><?php the_time('F jS, Y') ?></small>
<?php the_content('Read the rest of this entry »'); ?>
<?php endforeach; ?>
So that's doing a custom query to the database. It so happens that "show on home page" category has an id of 4 (you can see each category's ID by looking at the manage->categories page.) So you put that "4" in where I have it in bold and red in the code…
This file gets uploaded to your theme directory. Then, to create a page using this template, create a new page (or "Write Page") – and on the right hand side, you'll see a box "Page Template" – your template should be in the list by what you named it at the top (in this example it would be "CustomHomePage"). The title for the page is what the page will be named.
Then, to get THAT page to show up as the "home" page – go to Options -> Reading – and where you see Front page displays: select "static page" – and for "front page" select the page you created.
2) Sidebar
So there were a few tricky things with the events. I wanted the user to be able to enter in all the information about an event, but to set the DATE of that event as the "date" of the "post" so it would show up chronologically – kind of like an events calendar. The problem is that WordPress gives all posts with a date in the future a "post_status" of "future"… so if you're looking for posts with a status of "publish" – you won't find them. There was a plugin that I found that considered all posts with "future" status to be "publish" without making any core file modifications – but I found it also has a side effect of showing those "future" posts mixed in with my list of pages. I was concerned that this would cause too much confusion and opted instead to make a very minor change to one of the core files. (I've now gotten into the habit of keeping a log of any core file changes I make so that upgrades aren't too stressful. If the changes are kept to a minimum -upgrading shouldn't be too bad and the changes can be made again to the new updated files)
So, in order to change the status of those posts – and get them to show up normally, I edited wp-includes/post.php, at about line 667, and changed this line:
$post_status = 'future';
to this instead:
$post_status = 'publish';
Now, in order to pull out JUST the next 3 upcoming events, I again did a custom post query. (in my sidebar.php template file)
<?php
//first set up what is the current date/time
$now = gmdate('Y-m-d H:i:59');
$pageposts = $wpdb->get_results ("SELECT * FROM wp_posts, wp_term_relationships WHERE wp_term_relationships.object_id = wp_posts.ID && wp_term_relationships.term_taxonomy_id = '3' && wp_posts.post_status = 'publish' && wp_posts.post_category = '0' && wp_posts.post_type = 'post' && wp_posts.post_date_gmt > '".$now."' order by post_date asc limit 3");
foreach ($pageposts as $post):
setup_postdata($post);
?>
<h3><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title(); ?>"><?php the_title(); ?></a></h3>
<p class="date"><?php the_time('F jS, Y') ?></p>
<?php the_excerpt(); ?>
<?php
// to find out if there ARE any future events being displayed, I set this variable up so I can test for it later...
$nextevents = true; ?>
<?php endforeach; ?>
FYI – That "3" in red/bold… that's the category ID for my events category.
So that's all well and good – but what if it's a slow month and there aren't any future events yet. I don't want that bar to empty… So I figure I'll show the last (just past) event instead…
<?php
//if no future events show last (1) event
if (!isset($nextevents)) {
$now = gmdate('Y-m-d H:i:59');
$pageposts = $wpdb->get_results ("SELECT * FROM wp_posts, wp_term_relationships WHERE wp_term_relationships.object_id = wp_posts.ID && wp_term_relationships.term_taxonomy_id = '3' && wp_posts.post_status = 'publish' && wp_posts.post_category = '0' && wp_posts.post_type = 'post' && wp_posts.post_date_gmt < '".$now."' order by post_date asc limit 1");
foreach ($pageposts as $post):
setup_postdata($post);
?>
<h3><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title(); ?>"><?php the_title(); ?></a></h3>
<p class="date"><?php the_time('F jS, Y') ?></p>
<?php the_excerpt(); ?>
<?php endforeach; ?>
<?php } ?>
Those two things were probably the toughest. I do wish there was a setting in WordPress somewhere so I can turn that setting posts in the future to PUBLISH instead of future. But I don't think there's a hook for it. Maybe they'll add it in – and a plugin can be written to do that – so that no core modifications are necessary…
3) Fun with navigation
**Updated 6/3/08** I've since been having some trouble with the code I posted originally. The new code that I've been using is simpler and works consistently. I just use this where I want the subnavigation to go:
<?php
if($post->post_parent)
$children = wp_list_pages("title_li=&child_of=".$post->post_parent."&echo=0"); else
$children = wp_list_pages("title_li=&child_of=".$post->ID."&echo=0");
if ($post->post_parent) {
$parentpage = $wpdb->get_row("SELECT ID, post_title, post_name FROM $wpdb->posts WHERE ID = '".$post->post_parent."'");
} else {
$parentpage = $wpdb->get_row("SELECT ID, post_title, post_name FROM $wpdb->posts WHERE ID = '".$post->ID."'");
}
if ($children) { ?>
<ul id="subnav" class="clearfix">
<li<?php if ($post->post_parent == "0") { echo ' class="current_page_item"'; } ?>><a href="<?php echo get_permalink($parentpage->ID); ?>"><?php echo $parentpage->post_title; ?></a></li>
<?php echo $children; ?>
</ul>
<?php } ?>
**end update.** I'm leaving the old code up in this post in case it ends up being useful for some reason – but with the new version of wordpress (2.5) it doesn't work and the code above is simpler anyway.
So the next trick was getting the subnavigation to work the way we wanted. There was some main nav items (pages) and some of them would have subnavigation. If the page did have subnavigation, we wanted to make the main page part of the list of pages under that main heading. So for example… Here is some main nav items:
About the museum – Donations – Photo Gallery
About the museum has the following sub pages: (Directions – Membership) But when you click on the "About the museum" main navigation – we want that page to be the "default" first page… so in the sub nav area you'd have:
About the muesum
Directions
Membership
Otherwise, I think it wouldn't be clear how you get to that first (top-level) page…
But I don't ALWAYS want to show that main nav item in the sub navigation… Photo Gallery is only one page – there's no need for subnavigation on that page at all… (will probably make more sense if you go see the finished version of the site and click around on the pages…)
In any case, this is how I did the subnavigation. Using a trick I'd posted about before – I get the list of subpages this way: (This goes at the very top of my header.php template file)
<?php
$page = $wp_query->post;
$parent_id = $wpdb->get_var("SELECT ID FROM $wpdb->posts WHERE ID ='$page->post_parent;'");
if(!$parent_id) $parent_id = $post->ID;
?>
But now I also need to know if the page I'm on has subpages at all… and I need the name and the title of the parent page.. (you'll see why and how I use this shortly)
<?php
$getasubpage = $wpdb->get_var("SELECT ID FROM $wpdb->posts WHERE post_parent = '$parent_id'");
$hassubpages = false;
if ($getasubpage) {
$hassubpages = true;
$parentpage = $wpdb->get_row("SELECT post_title, post_name FROM $wpdb->posts WHERE ID = '$parent_id'");
}
?>
Now where I want to list our subnavigation:
<ul id="subnav">
<?php if(wp_list_pages("child_of=".$parent_id."&echo=0")): ?>
<li<?php if ($parent_id == $post->ID) { echo ' class="current_page_item"'; } ?>><a href="<?php echo "/".$parentpage->post_name."/"; ?>"><?php echo $parentpage->post_title; ?></a></li>
<?php wp_list_pages("title_li=&child_of=".$parent_id."&sort_column=menu_order&depth=1");?>
<?php endif; ?>
</ul>