How to Code a WordPress 3.0 Theme from Scratch

by in WordPress on 8th Mar 2011 · Comments

With the release of WordPress 3.0 came the implementation of many new features to the popular content management system. In this tutorial we are going to show you exactly how to code a WordPress 3.0 theme from the ground up to take advantage of all of these new features, as well as create a blogging-ready, minimal theme.

How to Code a WordPress 3.0 Theme from Scratch

Setting Up the Work Station

To get started with this tutorial we should set up a server on our computer using either XAMPP or WAMP (usually if working on a PC), or MAMP if you are working on a Mac. All of these tools allow for a local testing environment for WordPress and can make it so that you don't have to constantly transfer files through FTP while working on a project.

In terms of code editing I would highly suggest Notepad++. With syntax highlighting, and an easy and clean user interface for coding, I would have to say it is my personal favorite (plus, you can't beat free), but Notepad or Notepad 2 also work as well.

Getting the Necessary Folders and Files Ready

In the folder containing your WordPress installation, go to wp-content/themes/ and create a folder named “New 3.0 Theme”. This is where we will hold all of our files during this tutorial. Now create the following files and folders:

Getting the Necessary Folders and Files Ready

/images
style.css
header.php
index.php
single.php
footer.php
archive.php
page.php
sidebar.php
functions.php

Step 1 – Style.css

The style.css will contain all of the elements that style our WordPress template. First though. we will use it to declare the name of our template as well as the author name and link, and description and version. Now remember when creating a WordPress theme, the style.css is one of the two files required to make the theme work, and the other, which we will be creating later, is the index.php.

/*
Theme Name: New WP 3.0
Theme URI: http://www.onextrapixel.com
Description: A clean and minimal theme that is completely compatible with WordPress 3.0
Author: Keenan Payne
Author URI: http://slackrmedia.com
Version: 1.0
*/

All of this information can be changed at anytime, but it is important that it is all contained within the comments so that it doesn't affect any of the definitions created.

Now we will create some basic definitions that we will later implement in some of the template's PHP files.

body{	
	font-family: Arial, Helvetica, Georgia, Sans-serif;
	font-size: 12px;
	background: #d9d9d9;
	color: #000000;
}

a:link, a:visited{
	text-decoration: none; 
	color: #000000;
}

a:hover{
	color: #5f5f5f;
}

h1 {
	font-size: 54px;
}

h3 {
	font-size: 24px;
}

#wrapper{
	margin: 0 auto;
	width: 750px;
	text-align: left;
	background: #fff;
	padding: 20px;
	
}

#header{
	width: 750px;
	height: 100px;
}

#blog{
	float: left;
	width: 520px;
	padding: 0 10px 10px 10px;
}

.sidebar{
	float: left;
	width: 200px;
	margin: 0 0 0 10px;
	font-size: 14px;
	list-style: none;
}

#footer{
	clear: both;
	text-align: center;
	height: 50px;
	background: #ccc;
	padding: 10px;
}

The tag is just used to declare the specifications for fonts used on the website, as well as the background color (this can be changed to your own liking). We then declare the style attributes for links as well as some of the headers that we will be using throughout our theme.

The #wrapper is going to be the full size of the web page, with #header obviously being the header, and #blog containing just the recent blog posts on the site. Lastly we have .sidebar and #footer which will both just contain the basic definitions for those given areas, which we will get into more depth about later.

Step 2 – Header.php

Next we will create the header.php, which at the moment will contain our website logo, as well as our custom navigation.

Step 2 – Header.php

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>" />
<title><?php wp_title ( '|', true,'right' ); ?></title>

<link rel="profile" href="http://gmpg.org/xfn/11" />
<link rel="stylesheet" type="text/css" media="all" href="<?php bloginfo( 'stylesheet_url' ); ?>" />
<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />

<?php
	/* 
	 * 	Add this to support sites with sites with threaded comments enabled.
	 */
	if ( is_singular() && get_option( 'thread_comments' ) )
		wp_enqueue_script( 'comment-reply' );

	wp_head();
	
	wp_get_archives('type=monthly&format=link');
?>
</head>
<body>

<div id="wrapper">
	<div id="header">
		<h1><a href="<?php echo get_option('home'); ?>"><?php bloginfo('name'); ?></a></h1>
	</div>

All of this code doesn't really need to be explained in much depth, but just remember that the above code should be in the header.php of all of your themes. First we declare the doctype, as well as use the standard that will be used to show the name of your website as you type it in your WordPress settings, and then your style.css and the PHP code that will enable WordPress 3.0's threaded comments.

Step 3 – Adding Custom Navigation

Now that we have coded up our header.php with our basic information and our blog's name, we can add our custom navigation menu, a feature that was introduced in WordPress 3.0. Before we actually add the code to our header.php though, we have to first open up the functions.php, and add the necessary code to enable the custom menus.

<?php

//Add support for WordPress 3.0's custom menus
add_action( 'init', 'register_my_menu' );

//Register area for custom menu
function register_my_menu() {
	register_nav_menu( 'primary-menu', __( 'Primary Menu' ) );
}

?>

As you can see via the commented sections of the code, the first part, with add_action is used to add support for custom menus, and next we register a custom menu and name it “Primary Menu”. Now, we will move on to implementing the menu into our theme.

To do this, we will have to add this line of code below at the end of our header.php document.

<?php wp_nav_menu( array( 'sort_column' => 'menu_order', 'menu_class' => 'nav', 'theme_location' => 'primary-menu' ) ); ?>

Now on to understanding exactly what this means. The primary function that is being used is wp_nav_menu, with sort_column, container_class, and theme_location as the arguments being used. What sort_column does is makes sure that the order you pick in your WordPress dashboard is followed. container_class will allow for you to choose the CSS class that you have created to be used to style your menu. Lastly, theme_location just assigns the menu to wherever we choose, which at the moment happens to be primary-menu.

Step 4 – Styling the Navigation

We have our custom header navigation up and running, but at the moment it just looks like a boring old list of links that unfortunately, are aesthetically unappealing. To fix this, we will create a class called nav in our style.css.

Step 4 – Styling the Navigation

.nav{
	width:750px;
	background: #000;
	display:block;
	float:left;
	position:relative;
}

.nav ul{
	list-style:none;
}

.nav li{
	float:left;
	position:relative;
}

As you can see in our .nav we have made some basic declarations, such as the width of the navigation, background, where it will align, as well as the display value. Next we style the basic unordered list by just making sure that no bullets are shown with our links. For our list we float the items to the left, as well as position it relative.

Now we will finish the styling of our navigation by adding styles to the links and dropdown menus.

.nav a{
	display:block;
	text-decoration:none;
	color:#fff;
	padding:0 15px 10px 0;
	font-size:13px; 
	font-weight:bold;
}

.nav ul ul{
	display:none;
	position:absolute;
	top:100%;
	left:0;
	float:left;
	z-index:99999;
	background: #212121;
}

.nav ul ul ul{
	top: 30%;
	left:100%;
	background: #343434;
}

.nav ul ul a{
	height:auto;
	line-height:1em;
	padding:10px;
	width:130px;
}

.nav li:hover > a,.nav ul ul:hover > a{
	color:#ccc;
}

.nav ul li:hover > ul{
	display:block;
}

As you can see we start by styling our links for the menu, and now we get into styling our drop-down menus. In .nav ul ul we set the position to absolute, and put the top property to 100%, so that it is directly beneath it's parent link. We also changed the background to make the drop-down link stand out a little bit, as well as set our z-index to 99999 so that no matter what's below it or in the menu's way, it will always stay on top of all other elements.

For that third drop-down menu, we have changed the background color again just slightly so that it stands out, as well as made left 100% so that it is all the way right of our first drop-down, and set the top to 30% so that it is still attached to that second drop-down, but is separated from the entire menu.

Lastly we style the links for our drop-down menus, as well as the what our navigation will look like when a user hovers over a given link and its drop-down.

Step 5 – Index.php

The index.php will be the home page of our website, and will contain code to include our header, footer, and sidebar, which I will explain below, as well as the code to include the most recent posts from our blog and take advantage of WordPress 3.0's post thumbnails feature.

<?php get_header(); ?>

	<div id="blog">
		<?php if(have_posts()) : ?><?php while(have_posts()) : the_post(); ?>
		
		<div class="post">
		<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
		
			<div class="entry">	
				<?php the_post_thumbnail(); ?>
				<?php the_content(); ?>

				<p class="postmetadata">
				<?php _e('Filed under&#58;'); ?> <?php the_category(', ') ?> <?php _e('by'); ?> <?php  the_author(); ?><br />
				<?php comments_popup_link('No Comments &#187;', '1 Comment &#187;', '% Comments &#187;'); ?> <?php edit_post_link('Edit', ' &#124; ', ''); ?>
				</p>

			</div>
		</div>
<?php endwhile; ?>
		
		<div class="navigation">
		<?php posts_nav_link(); ?>
		</div>
		
		<?php endif; ?>
	</div>
<?php get_sidebar(); ?>	
<?php get_footer(); ?>

These lines of code are used to output all of the information in the header.php, sidebar.php, and footer.php wherever you place them in your theme files.

<?php get_header(); ?>
<?php get_sidebar(); ?>
<?php get_footer(); ?>

Other than that, the code here is pretty simple to understand. After we call the header.php, we use our #blog that we created just a little bit ago, and we call the loop that will be used to bring up the latest posts on our WordPress blog. After that we wrap the title of our posts in

, which we also styled earlier.

The one piece of code here that shows how we're going to be taking advantage of WordPress 3.0's post-thumbnail feature is the . As it stands, this code won't do anything, until we activate the feature in our functions.php which we will do in the next step.

Step 6 – Enabling Post Thumbnails

We have added our code to show the post thumbnails on the homepage, but at the moment nothing happens as we have not actually enabled the feature to work. Now open up the functions.php that we worked on before, and the below code should be added after your menu navigation code.

Step 6 – Enabling Post Thumbnails

// Enable post thumbnails
add_theme_support('post-thumbnails');
set_post_thumbnail_size(520, 250, true);

The code above is pretty self-explanatory as it spells out almost exactly what it does. The second line will add the support for post thumbnails in our theme, while the third line defines the exact dimensions of our thumbnail, which for this article, will be set at 520 pixels for width, and 250 pixels for height.

Step 7 – Sidebar.php

The sidebar.php is, as you guessed, the file that will display all of the information we want in the sidebar. Since we have already included the file in our index.php, all we have to do is put the code in this file and our sidebar will show up on the homepage.

<div class="sidebar">
<?php if ( function_exists('dynamic_sidebar') && dynamic_sidebar() ) : else : ?>

<?php endif; ?>
</div>

Yup, that will be all of the code that's added to our sidebar.php to make it functional. We call the div that we created in our style.css, and the code below will make it so that we can add widgets to our sidebar in the order and way we want them via the WordPress backend. However, like many features, we have to modify our functions.php file first to make this feature work properly.

//Some simple code for our widget-enabled sidebar
if ( function_exists('register_sidebar') )
    register_sidebar();

The code just tells WordPress to register a sidebar which we called in our sidebar.php. WordPress can handle multiple sidebars pretty easily if you want more than one, but for the sake of keeping this already-long tutorial relatively short, we'll let Google answer the question on how to do that for you.

Step 8 – Single.php

The single.php is what will be used for a single post page, and most of the code should look pretty similar since we've already coded up our index.php. Really the only thing that's different is that we have added in our comments-template div, and the code to include the comments.php.

<?php get_header(); ?>

	<div id="blog">
		<?php if(have_posts()) : ?><?php while(have_posts()) : the_post(); ?>
		
		<div class="post">
		<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
			<div class="entry">	
				<?php the_post_thumbnail(); ?>
				<?php the_content(); ?>

				<p class="postmetadata">
				<?php _e('Filed under&#58;'); ?> <?php the_category(', ') ?> <?php _e('by'); ?> <?php  the_author(); ?><br />
				<?php comments_popup_link('No Comments &#187;', '1 Comment &#187;', '% Comments &#187;'); ?> <?php edit_post_link('Edit', ' &#124; ', ''); ?>
				</p>

			</div>

			<div class="comments-template">
				<?php comments_template(); ?>
			</div>
	</div>

<?php endwhile; ?>
	
	<div class="navigation">	
		<?php previous_post_link('< %link') ?> <?php next_post_link(' %link >') ?>
	</div>

<?php endif; ?>
</div>

<?php get_sidebar(); ?>	
<?php get_footer(); ?>

Step 9 – Comments.php

With the release of WordPress 3.0 has meant the standardizing of comments forms throughout all WordPress themes making it easier for theme authors to and plugin developers since the comments form can be modified via hooks.

Step 9 – Comments.php

Below will be the code you will want to put in your comments.php file in your theme template.

<?php comment_form(); ?> 

This will display a comments form that looks well on our theme, but if you would like to learn more about customization of the comment form, you might want to check out WordPress 3.0 Theme Tip the Comment Form.

Step 10 – Page.php

When you create a page in WordPress, a different file is used to display the content of what you typed into the page, and that is page.php. The code will look almost completely identical to what we typed up in our single.php, except since it is a page we are going to omit the comments template, and change the post navigation slightly to handle a page instead of a post. Other than that, the code will be exactly the same.

<?php get_header(); ?>

	<div id="blog">
		<?php if(have_posts()) : ?><?php while(have_posts()) : the_post(); ?>
		
		<div class="post">
		<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>


			<div class="entry">
			<?php the_content(); ?>

				<p class="postmetadata">
				<?php _e('Filed under&#58;'); ?> <?php the_category(', ') ?> <?php _e('by'); ?> <?php  the_author(); ?><br />
				<?php comments_popup_link('No Comments &#187;', '1 Comment &#187;', '% Comments &#187;'); ?> <?php edit_post_link('Edit', ' &#124; ', ''); ?>
				</p>

			</div>

		</div>
		
<?php endwhile; ?>

	<div class="navigation">
		<?php posts_nav_link(); ?>
	</div>

<?php endif; ?>
</div>

<?php get_sidebar(); ?>	
<?php get_footer(); ?>

Step 11 – Category.php

The category.php will serve as the file that, whenever a user looks at a specific post category, time for posts, or specific author, will be the file that serves up the information to display posts. As with our page.php, most of the code here is going to be the exact same as the single.php we created before, except for a chunk right at the beginning.

Step 11 – Category.php

<?php get_header(); ?>

	<div id="blog">
		<?php if(have_posts()) : ?><?php while(have_posts()) : the_post(); ?>
		
	<?php $post = $posts[0]; // Hack. Set $post so that the_date() works. ?>
 	  <?php /* If this is a category archive */ if (is_category()) { ?>
		<h2>Archive for the &#8216;<?php single_cat_title(); ?>&#8217; Category:</h2>
 	  <?php /* If this is a tag archive */ } elseif( is_tag() ) { ?>
		<h2>Posts Tagged &#8216;<?php single_tag_title(); ?>&#8217;</h2>
 	  <?php /* If this is a daily archive */ } elseif (is_day()) { ?>
		<h2>Archive for <?php the_time('F jS, Y'); ?>:</h2>
 	  <?php /* If this is a monthly archive */ } elseif (is_month()) { ?>
		<h2>Archive for <?php the_time('F, Y'); ?>:</h2>
 	  <?php /* If this is a yearly archive */ } elseif (is_year()) { ?>
		<h2>Archive for <?php the_time('Y'); ?>:</h2>
	  <?php /* If this is an author archive */ } elseif (is_author()) { ?>
		<h2>Author Archive</h2>
 	  <?php /* If this is a paged archive */ } elseif (isset($_GET['paged']) && !empty($_GET['paged'])) { ?>
		<h2>Blog Archives</h2>
 	<?php } ?>
		
		<div class="post">
		<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>

			<div class="entry">
			<?php the_content(); ?>

				<p class="postmetadata">
				<?php _e('Filed under&#58;'); ?> <?php the_category(', ') ?> <?php _e('by'); ?> <?php  the_author(); ?><br />
				<?php comments_popup_link('No Comments &#187;', '1 Comment &#187;', '% Comments &#187;'); ?> <?php edit_post_link('Edit', ' &#124; ', ''); ?>
				</p>

			</div>

		</div>
		
<?php endwhile; ?>

	<div class="navigation">
		<?php posts_nav_link(); ?>
	</div>

<?php endif; ?>

</div>

<?php get_sidebar(); ?>	
<?php get_footer(); ?>

This piece of code right here will be the only thing that is added, and we have included it right after our WordPress loop.

<?php $post = $posts[0]; // Hack. Set $post so that the_date() works. ?>
 	  <?php /* If this is a category archive */ if (is_category()) { ?>
		<h2>Archive for the &#8216;<?php single_cat_title(); ?>&#8217; Category:</h2>
 	  <?php /* If this is a tag archive */ } elseif( is_tag() ) { ?>
		<h2>Posts Tagged &#8216;<?php single_tag_title(); ?>&#8217;</h2>
 	  <?php /* If this is a daily archive */ } elseif (is_day()) { ?>
		<h2>Archive for <?php the_time('F jS, Y'); ?>:</h2>
 	  <?php /* If this is a monthly archive */ } elseif (is_month()) { ?>
		<h2>Archive for <?php the_time('F, Y'); ?>:</h2>
 	  <?php /* If this is a yearly archive */ } elseif (is_year()) { ?>
		<h2>Archive for <?php the_time('Y'); ?>:</h2>
	  <?php /* If this is an author archive */ } elseif (is_author()) { ?>
		<h2>Author Archive</h2>
 	  <?php /* If this is a paged archive */ } elseif (isset($_GET['paged']) && !empty($_GET['paged'])) { ?>
		<h2>Blog Archives</h2>
 	<?php } ?>

What this does is use a bunch of if/elseif statements in PHP to show what we are currently browsing on our blog. So if we're looking at a specific category called “Test Category 1”, it will show in the h2 heading “Archive for the ‘Test Category 1’ Category:” before all posts, and it will do this for certain dates, authors, and so on.

Step 12 – Custom Backgrounds, Feed Links

As described before, one feature that has been implemented in WordPress 3.0 is the ability to create or modify the background of your site, be it an image or basic color, just through the WordPress backend. All we need for this feature to work fully? This one little line of code:

Step 12 – Custom Backgrounds, Feed Links

//Code for custom background support
add_custom_background();

And like that, custom backgrounds are now enabled. Next, we are going to be adding some equally simple code to make it so that relevant feed links are available everywhere on the site. Be it the standard feed, comments, tags, categories, all of these will be added to the header without any extra code.

Let's add the following code to our functions.php, to make this feature work as it should.

//Enable post and comments RSS feed links to head
add_theme_support( 'automatic-feed-links' );

Step 13 – Footer.php

To finish off our work here, we are going to create our footer.php file, which too will use the #footer that we declared in our style.css, and will just contain some basic copyright information as well as a link to the stories and comments RSS feed at the bottom.

<div id="footer">
	<p>
	<strong>Copyright 2011 <?php bloginfo('name'); ?> | All Rights Reserved.</strong> </a> 
	Designed by <a href="http://slackrmedia.com">SlackrMedia</a>
	</p>
	<p><a href="<?php bloginfo('rss2_url'); ?>">Latest Stories RSS</a> | <a href="<?php comments_rss_link('comment feed'); ?>">Comments RSS</a></p>
	</div>
</div>

</body>
</html>

Step 14 – Other Features?

Here are a couple of features that aren't necessary by any means but could be of use to those that are interested and could prove to be quiet useful. First, how to enable the multisite feature for WordPress 3.0 so you can run multiple blogs from a single WordPress install. Again, we're going to add this code to our functions.php.

Step 14 – Other features?

//Enable multisite feature (WordPress 3.0)
define('WP_ALLOW_MULTISITE', true); 

You can also download all the files for this tutorial.

Conclusion

So that does it for our tutorial. By this point you have successfully coded a WordPress 3.0 theme from scratch that takes advantage of the most popular features and is minimal enough so that it could be modified into something a bit more graphically impressive. What else could you do with this theme?

Well now that you have all of your basic options and styles set up you can modify the theme even further and add another sidebar to the theme, or perhaps even use How to Create a Better WordPress Options Panel to create just that, an admin panel for your new theme.

Keenan Payne is a full time student and a freelance web designer in his spare time. Besides writing and web design, he loves to skateboard and snowboard, and has been doing both for 11 and 6 years respectively, although some would say it's getting progressively harder for him to step away from his work and wander outside.