Advertisement

WordPress: Beginner to Master, Part 2

by

Throughout this six-part beginner-to-master series, we'll be using the advanced features of WordPress to create our own portfolio & blog, complete with an options page, multiple styles and support for the new WordPress 2.7 features. Today, we're creating our homepage layout.


Also available in this series:

  1. WordPress: Beginner to Master, Part 1
  2. WordPress: Beginner to Master, Part 2
  3. WordPress: Beginner to Master, Part 3
  4. WordPress: Beginner to Master, Part 4
  5. WordPress: Beginner to Master, Part 5
  6. WordPress: Beginner to Master, Part 6

Jump to a Section


Getting Started

In this part, we will be creating the front-page for our portfolio, making use of our options page and handling custom-fields in posts. Before getting started, create the following files & folders inside the /wp-content/themes/innovation/ folder you created previously:

  • /inc/
    • /cache/
  • header.php
  • footer.php
  • sidebar.php

Also save this TimThumb PHP Image Resizer script as thumb.php inside the /inc/ folder. TimThumb is a 'smart' PHP image resizer script by Darren Hoyt.

Outline

Below is an overview of what our frontpage will look like:


Our header.php file will contain the #head and #nav sections - including the opening tags for #wrap, #content and .contentwrap.

footer.php will then contain the #footer section, and the closing tags for #content and the last section above it (this could either be .contentwrap, .extraswrap or #sidebar depending on the page).

The .contentwrap area will hold the two latest posts from our Portfolio category, and .extraswrap will be a widget-ready area where we can place widgets from the Dashboard.


Header.php

<head>

At the top of the header.php file, include the following code.

 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>> 
<head profile="http://gmpg.org/xfn/11"> 
<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" /> 
 
<title><?php wp_title('&laquo;', true, 'right'); ?> <?php bloginfo('name'); ?></title>

As you can see, this is mainly the code you would include at the top of any xHTML Strict document, only we have replaced some sections with a WordPress function which will output the appropriate code depending on the language WordPress is running

At the end of the code is our title tag which, again, is using WordPress functions to get the name of the current page, and the name of the site.

Colour Schemes & Stylesheets

Next, we include our style.css file using the WordPress bloginfo(); function. It is important to use this function to include the main stylesheet, as opposed to directly entering the file path.

 
<link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>" type="text/css" media="screen" />

Then is the code for grabbing the correct colour-scheme stylesheet selected from the Options we created in the previous part:

 
<?php 
require(TEMPLATEPATH . "/var.php"); 
 
if($ts_colourscheme) { 
	if($ts_colourscheme == "Choose a colour scheme:") { ?> 
		<link rel="stylesheet" type="text/css" media="all" 
		href="<?php bloginfo('template_directory'); ?>/styles/deepblue.css" /><?php 
	} else { ?> 
		<link rel="stylesheet" type="text/css" media="all" 
		href="<?php bloginfo('template_directory'); ?>/styles/<?php echo $ts_colourscheme; ?>" /><?php 
	} 
} else { ?> 
	<link rel="stylesheet" type="text/css" media="all" 
	href="<?php bloginfo('template_directory'); ?>/styles/deepblue.css" /><?php 
} ?>

The chart below explains what the above code does:


We check whether our colour scheme option ($ts_colourscheme) exists from the options page, and that it was set correctly (ie. not left as "Choose a colour scheme:"). If the option isn't set correctly or doesn't exist, it will default to using the deepblue.css colour scheme; otherwise we use the stylesheet that the was selected from the options page.

Continuing on, we include our RSS & Atom feeds, and open the body tag:

 
<link rel="alternate" type="application/rss+xml" title="<?php bloginfo('name'); ?> RSS Feed" href="<?php bloginfo('rss2_url'); ?>" /> 
<link rel="alternate" type="application/atom+xml" title="<?php bloginfo('name'); ?> Atom Feed" href="<?php bloginfo('atom_url'); ?>" /> 
<link rel="pingback" href="<?php bloginfo('pingback_url'); ?>" /> 
<?php wp_head(); ?> 
</head> 
<body>

#head


The next code is a lot more straight-foward than the previous section. As shown in the image above, we will be using more WordPress functions to retrieve information from the WordPress database:

 
<div id="wrap"> 
 
<div id="head"> 
	<h1><?php bloginfo('name'); ?></h1> 
	<h3><?php bloginfo('description'); ?></h3> 
</div>

The bloginfo('name'); and bloginfo('description'); functions retrieve the relevant settings from the 'General Settings' page in the WordPress dashboard:


#nav


Retrieving a list of pages from the database is also very easy. We use the wp_list_pages(); function. Note that we also include a title_li= arguement. This is to stop the function from creating an extra list item called 'Navigation:' before listing the pages.

 
<div id="nav"> 
	<ul> 
	<?php wp_list_pages("title_li="); ?> 
	</ul> 
</div> 
 
<div id="content"> 
<div class="contentwrap">

We've also opened the relevant div's and wrappers for the next section.


Styling the Header

If you goto your WordPress install now, it will look something like this:


Remember we will include any colour styles inside deepblue.css so that we can easily create different colour schemes later. Everything else will go in style.css.

General Styles

The first thing I always include in my stylesheet is a browser reset, followed by some basic styling for paragraphs, lists, headers and links.

 
*{padding:0;margin:0;} 
 
body { 
	font-family: Arial, Helvetica, sans-serif; 
	} 
	 
p { 
	font-size: 0.9em; 
	line-height: 1.5em; 
	margin-bottom: 10px; 
	} 
	 
ul, ol { 
	margin: 0 0 10px 10px; 
	} 
	 
li { 
	font-size: 0.9em; 
	line-height: 1.5em; 
	list-style-position: inside; 
	margin-bottom: 3px; 
	} 
	 
img { 
	border: none; 
	} 
	 
h1, h2, h3, h4, h5, h6 { 
	font-weight: normal; 
	} 
	 
h3, h4 { 
	margin: 15px 0 2px 0; 
	} 
	 
h4, h5, h6 { 
	font-weight: bold; 
	} 
	 
a:link, a:visited { 
	text-decoration: none; 
	} 
	 
a:hover, a:active, a:focus { 
	text-decoration: underline; 
	outline: none; 
	}

This should look very straight forward for anyone with basic understanding of HTML and CSS. We have set the margins and padding for all (*) elements to 0 to over-ride the default styles each browser applies to a page. We then include new margins, font-sizes and line-heights for the main elements to increase readability amongst them.

Header Styling

Next, we create a bit of a layout:

#wrap { 
	margin: 0 auto; 
	width: 980px; 
	} 
	 
#head { 
	margin: 25px 0; 
	overflow: hidden; 
	} 
	 
#head h1 { 
	float: left; 
	margin-left: 20px; 
	} 
	 
#head h3 { 
	font-family: Georgia, "Times New Roman", Times, serif; 
	font-size: 0.8em; 
	font-style: italic; 
	float: right; 
	line-height: 1.7em; 
	text-align: right; 
	margin: 0 20px 0 0; 
	width: 500px; 
	}

The #wrap element is the container which holds everything. We are using a width of 980px (this is about as high as we can go while still accomodating for 1024x768 resolutions). And we have used margin: 0 auto; to center it in the browser.

The title and taglines (h1 and h3 respectively) are then floated to either side of the container.

#head has a property of overflow: hidden; so that it will hold the floated elements correctly. Typically, a div will not wrap around any floated children (as we have here). See the image below as an example (the yellow represents the margin assigned to #head):


Navigation Styling

 
#nav { 
	border-top-left-radius: 15px; 
	border-top-right-radius: 15px; 
	-moz-border-radius-topleft: 15px; 
	-moz-border-radius-topright: 15px; 
	-webkit-border-top-left-radius: 15px; 
	-webkit-border-top-right-radius: 15px; 
	border-bottom: none; 
	clear: both; 
	padding: 0 20px; 
	width: 939px; 
	}

Take a look at the preview images at the top of the tutorial, and you'll notice we are using rounded corners at the top of the navigation section. Instead of achieving this effect through a bunch of images and extra HTML tags, we're going to use the new CSS3 border-radius property to give a 15px radius to both the top corners.

However, current browsers do not yet support this property, but Mozilla and Webkit-based browsers have their own -moz-border-radius and -webkit-border-radius properties which we can also use to get the rounded corners to work in Firefox 3, Safari and Chrome. Internet Explorer and Opera will simply use a squared border until a they support border-radius.

Note: Using these vendor-specific properties in your CSS will stop your stylesheet from validating. But since it will only be these which are stopping the validation - who cares?

Continuing on, we style the list items in the navigation to display inline (horizontally):

 
#nav ul { 
	margin: 0; 
	} 
 
#nav ul li { 
	display: inline; 
	font-size: 1em; 
	line-height: 1.3em; 
	margin-right: 25px; 
	} 
	 
#nav ul li a:link, #nav ul li a:visited { 
	display: -moz-inline-stack; 
	display: inline-block; 
	font-weight: bold; 
	text-decoration: none; 
	padding: 20px 10px; 
	} 
	 
#nav ul li a:hover, #nav ul li a:active, #nav ul li a:focus { 
	outline: none; 
	}

Note that we are using display: -moz-inline-stack; on the links. This is purely for Firefox 2 and below, which (for some reason) do not support display: inline-block; - even IE6 supports it!

We are giving a lot of padding to the links to increase the clickable area (as opposed to padding the li instead).

Now have a look at the page in your browser and it should look like this. Better, but now needs some colour!


Some Colour

Firstly, save the following image into the /styles/deepblue/ folder as bg.jpg.


And this image into the same folder as trans.png (it's actually a dark 1px semi-transparent image).


Now, open /styles/deepblue.css, and type:

 
/* Innovation default style - deepblue.css */ 
 
body { 
	background: url("deepblue/bg.jpg") no-repeat #101010 top center fixed; 
	color: #333; 
	} 
	 
a:link, a:visited { 
	color: #5c6e80; 
	} 
 
#head h1 { 
	color: #eee; 
	} 
	 
#head h3 { 
	color: #ddd; 
	} 
	 
#nav { 
	background: url("deepblue/trans.png") repeat; 
	border: 1px solid #111; 
	} 
	 
#nav ul li a:link, #nav ul li a:visited { 
	color: #ddd; 
	} 
	 
#nav ul li.current_page_item a:link, #nav ul li.current_page_item a:visited { 
	background: url("deepblue/trans.png") repeat; 
	color: #eee; 
	} 
	 
#nav ul li a:hover, #nav ul li a:active, #nav ul li a:focus { 
	color: #eee; 
	}

We have set the large background image to the body (and fixed it so that it doesn't move when you scroll), the transparent image is used as a background for the navigation, and we also set some font colours.

Preview it, and you'll now have something like:



Portfolio Posts

Before creating the top of our homepage where our two latest Portfolio items go, we'll need a few posts to test with. The theme will be using a few 'Custom Fields' to display extra information for the portfolio items:

  • date (the date the work was completed)
  • client (who the work was for)
  • link (to a live version of your work)
  • preview (URL of a 930px width image of your work)
  • preview-full (larger version of the work, will display in a lightbox)

Create a new blog post, with the Title being the name of the project (as in the image above), and enter some content about the work. Put the post in your 'Portfolio' category.

Before saving the post, scroll down to the 'Custom Fields' section:


Here, enter each of the Custom Fields provided above. Only the preview field is required. You can use the following images for your preview field if you do not yet have one of your own (right-click and save):


Once you have filled in the fields, you may Publish the post. Repeat this process until you have at least two posts (preferably more).



The Homepage

Now we have all the prerequisites done, we can finally code the main part of the homepage. In page-home.php, type the following:

 
<h2>Latest Projects</h2> 
 
<?php query_posts("cat=$ts_portfolio_cat&showposts=2"); 
$counter = 0; 
while (have_posts()) : the_post();

query_posts(); is a WordPress function for getting specific posts from the database. As you can see in the arguements for the function (the parts in the brackets), we are telling WordPress to only get 2 posts from the Portfolio category ($ts_portfolio_cat is getting the information from the options page we created).

With while();, we have started the 'WordPress Loop'. In here we can get tell WordPress which part from each post we need.

 
$counter++; 
$preview = get_post_meta($post->ID, 'preview',true); 
$date = get_post_meta($post->ID, 'date',true); 
?>

On the first line, we have added one to the counter (we will be using this shortly). $counter++; is short-hand for writing $counter = $counter + 1;

We then use the get_post_meta(); functions to get our 'preview' and 'date' custom fields from the post - which are placed into the $preview and $date variables respectively.

 
<div class="work <?php if($counter == 2) { echo "last"; $counter = 0; } ?>">

Above we have created a div with a work class for the portfolio item to be held in. But notice that we are also checking that if our $counter equals 2 (meaning this is the second portfolio item), we add another class to the div named last. This class will come in handy when we style this section.

Next, we output the preview image:

 
<?php if($preview) { ?>

If a preview image exists, then we...

 
<a href="<?php the_permalink(); ?>"> 
	<img src="<?php bloginfo('template_directory'); ?>/inc/thumb.php?src=<?php echo $preview; ?>&amp;w=450&h=210&amp;zc=1&amp;q=100" alt="<?php the_title(); ?>" /> 
</a> 
<?php 
} ?>

The the_permalink(); function is used to output the link to the current post.

Then, we output the preview image. But we are also running it through the TimThumb resizer in order to resize the image to 450px in width and 210px in height (from the 930px image it actually is). Note how we use bloginfo('template_directory'); to ensure WordPress is checking in our theme folder (it's an equivilant of the TEMPLATEPATH we used in the previous part in the series).

We now just need to output the line of text which goes below the image (the title, and the date):

 
<p> 
<a href="<?php the_permalink(); ?>"> 
	<?php the_title(); ?> 
</a> <?php 
 
if($date) { 
	echo"<span>($date)</span>"; 
} ?> 
 
</p>

This is relatively straight-forward. We use the_permalink(); again to get the link for the current post. the_title(); is used to get the current post's title.

We then check whether a 'date' custom-field was entered (in the $date variable) for this post. If so, we output it.

 
</div><!--/work--> 
 
<?php endwhile; ?> 
 
</div><!--/contentwrap-->

Finally, we close the current work div, close the WordPress Loop with endwhile; and close the contentwrap div which was created in the header.

Beauty Therapy

Take a look at the homepage in your browser, to see this wonderful masterpiece:


Ok, maybe not; but nothing a little CSS can't fix up. Add the following into style.css:

 
#content { 
	-moz-border-radius-bottomleft: 5px; 
	-moz-border-radius-bottomright: 5px; 
	-webkit-border-bottom-left-radius: 5px; 
	-webkit-border-bottom-right-radius: 5px; 
	border-bottom-left-radius: 5px; 
	border-bottom-right-radius: 5px; 
	float: left; 
	padding: 19px 19px 30px 0; 
	margin-bottom: 5px; 
	overflow: hidden; 
	width: 960px; 
	} 
	 
.contentwrap { 
	padding-left: 19px; 
	overflow: hidden; 
	} 
	 
#content h2 { 
	font-weight: bold; 
	letter-spacing: -1px; 
	margin-bottom: 10px; 
	}

#content is the wrapper to hold all the main content. We've added rounded borders to the bottom of it, using the same method we used on the navigation.

Inside deepblue.css add the following to add a light background colour to #content, as well as define the border colour:

 
#content { 
	background-color: #f9f9f3; 
	border: 1px solid #111; 
	border-top: none; 
	}

Obviously the items need to be displayed inline (side-by-side). We'll do this by simply setting float: left; to both along with some margins inside style.css:


 
.work { 
	float: left; 
	margin: 0 20px 40px 0; 
	width: 460px; 
	} 
	 
.work a { 
	outline: none; 
	} 
	 
.work p { 
	font-size: 0.9em; 
	font-weight: bold; 
	margin: 8px 0 10px 0; 
	} 
 
.worksingle p { 
	font-weight: normal; 
	} 
 
.work span { 
	font-size: 0.8em; 
	font-weight: normal; 
	}

Preview it, and you'll notice that the items are still display below each other. A quick check with Firebug reveals it's down to the second item not having enough room for the right margin.

This is where that counter adding class="last" to the second item comes in:

 
.last { 
	margin-right:0 !important; 
	}

We're not quite yet finished. Take a closer look at our final-product image, and you'll notice we also need to set a border around the portfolio image, which changes colour on hover.

Add the following colour styles to deepblue.css:

 
.work a:link img, .work a:visited img { 
	border: 5px solid #e3e8ed; 
	} 
	 
.work a:hover img, .work a:active img, .work a:focus img { 
	border: 5px solid #5c6e80; 
	} 
	 
.work a:link, .work a:visited { 
	color: #333; 
	}


Widgetised Area

The .extraswrap area of the homepage is widget-ready (3 widgets max) - meaning we can add and manage them directly from the WordPress Dashboard - just as you would for a widet-ready sidebar:


Firstly, we need to tell WordPress to create a new widget area using the register_sidebar() function. The following code goes at the end of your functions.php file:

 
if ( function_exists('register_sidebar') ) { 
    register_sidebar(array( 
        'name' => 'Homepage Bottom', 
        'before_widget' => '<div class="extras">', 
        'after_widget' => '</div>', 
        'before_title' => '<h2>', 
        'after_title' => '</h2>', 
    )); 
}

Inside register_sidebar() we pass an array containing some information for our widget-area. The name is used to identify it when we have multiple widget-areas (or sidebars). before_widget and after_widget is the code used to wrap each individual widget. By default, this would be a list item; we're using a div instead.

before_title and after_title is what's used to wrap the individual widget's title.

Now, to include this widget onto our homepage, add the following on to the end of page-home.php:

 
<div class="extraswrap">
 
<?php dynamic_sidebar('Homepage Bottom'); 
get_footer(); ?>

We first open our wrapping div, and then use the dynamic_sidebar(); function - through which we pass the name of the widget-area we used previously, when registering the area. Finally, we include our footer.php file using the get_footer() function (in the same way we included the header).

Go ahead and add three test widgets to the area via Appearance -> Widgets -> 'Homepage Bottom'.


And preview it:


To display them all inline, use the following code in style.css:

 
.extraswrap { 
	margin-top: 10px; 
	overflow: hidden; 
	} 
 
.extras { 
	float: left; 
	margin: 0 0 0 20px; 
	width: 300px; 
	}

We're also going to style a Flickr & Twitter plugin. Firstly, install the FlickrRSS and Twitter for WordPress plugins.

From Settings -> FlickrRSS, enter your Flickr ID number using the instructions provided (or use mine: 31912870@N03), set it to use 9 square images; and for the HTML Wrapper section, use:

Before Image: <div class="flickr">

After Image: </div>

This will allow us to style & position the images easily.

Go ahead and swap two widgets on the homepage area to the Flickr and Twitter ones (remember to enter your Twitter details under the 'Edit' section on the widget).



Enter the following styling into style.css:

 
/* style FlickrRSS widget */ 
.flickr { 
	display: inline; 
	} 
	 
.flickr a:link img, .flickr a:visited img { 
	margin: 0 10px 10px 9px; 
	} 
 
/* style Twitter widget */ 
ul.twitter { 
	margin: 0; 
	} 
	 
ul.twitter li.twitter-item { 
	-moz-border-radius: 10px; 
	-webkit-border-radius: 10px; 
	border-radius: 10px; 
	list-style: none; 
	margin-bottom: 20px; 
	padding: 8px 10px; 
	} 
	 
ul.twitter li.twitter-item span abbr { 
	border-bottom: none; 
	display: block; 
	font-size: 0.8em; 
	font-style: italic; 
	margin-top: 3px; 
	}

The Flickr styling displays each image inline, and sets appropriate margins to fit three images per row. In the Twitter styles, we've added some margin & padding to seperate each tweet, and we've also used border-radius again.

Also add the following to deepblue.css:

 
.flickr a:link img, .flickr a:visited img { 
	border: 3px solid #e3e8ed; 
	} 
	 
.flickr a:hover img, .flickr a:active img, .flick a:focus img { 
	border: 3px solid #5c6e80; 
	} 
 
ul.twitter li.twitter-item { 
	background-color: #f6f5ed; 
	border: 1px solid #eae9de; 
	}

Each Flickr image now has a border we can hover over, similar to what we used for the portfolio images.



Inside footer.php insert the following code. We close the appropriate tags and include a copyright notice. Feel free to remove the mention of myself & NETTUTS from it, although it'd be appreciated if you gave a link back to us somehow. We also include the Google Analytics code from the options page.

 
</div><!--/contentwrap or /sidebar or /extraswrap on homepage--> 
</div><!--/content--> 
 
<p class="footer">Copyright &copy;  
<?php bloginfo('name'); echo ' 2008 - ' . date('y'); ?>. 
Design by <a href="http://www.danharper.me">Dan Harper</a> for  
<a href="http://www.nettuts.com">NETTUTS</a>. 
Powered by <a href="http://www.wordpress.org">WordPress</a>.</p> 
 
</div><!--/wrap--> 
<?php 
wp_footer(); 
include(TEMPLATEPATH . "/var.php"); 
echo stripslashes($ts_analytics_code); ?> 
</body> 
</html>

Add the following to style.css:

 
p.footer { 
    clear: both; 
    font-size: 0.7em; 
    font-style: italic; 
    padding: 5px 20px; 
    }

And to deepblue.css:

 
p.footer { 
	color: #ccc; 
	} 
	 
p.footer a:link, p.footer a:visited { 
	color: #ccc; 
	border-bottom: 1px dashed; 
	} 
	 
p.footer a:hover { 
	border-bottom: 1px solid; 
	text-decoration: none; 
}

Summary

That concludes Day 2 of WordPress Week, and we got quite a lot done! Tomorrow, we're moving to the 'Blog' page layout and learning how to style 'single posts' differently dependent on what category they are in.

Part 3 - Styling The Blog

Advertisement