Developing Your First WordPress Theme: Day 2 of 3
Tutorial Details
- Program: HTML/CSS Editor of choice
- Difficulty: Medium
- Estimated Completion Time: 3 hours
- Developing Your First WordPress Theme: Day 1 of 3
- Developing Your First WordPress Theme: Day 2 of 3
- Developing Your First WordPress Theme: Day 3 of 3
Themes are a huge part of what makes WordPress as popular as it is, and in this three-part series we’ll take you through a step-by-step process that results in a completed, functioning WordPress theme. In part two, we delve into coding the bulk of our theme!
Part Two
Welcome to part two of this three-part series on developing a WordPress theme from scratch. Last time we looked at what makes a “good theme”, as well as the general components required for a theme to work. This week we’re going to dive straight in and start creating our very first theme.
- Developing Your First WordPress Theme: Day 1 of 3
- Developing Your First WordPress Theme: Day 2 of 3
- Developing Your First WordPress Theme: Day 3 of 3 (Coming Soon)
Our Theme
I’d like to stress that if you have your own layout to work with, use it – chances are you’ll learn more by experimenting and you’ll have a result that will be tailored to your tastes. If you don’t have a layout to work with, we’re providing a simple personal layout for you to work with.
This layout is something I made a while back as one of many unused designs for a friends personal blog. In the downloadable zip that accompanies this tutorial, you will find two folders; bftheme and bffiles. In the bffiles folder is the layout in its pre-WordPress state, the other folder contains the completed theme.
Open up the theme in a browser to get an idea of what we’re going for, it should look a little something like this:

Breaking It Up
While it would be possible to make a theme work with just one file, it’s very bad practice and not something you’ll see at all in the wild. It’s good to stick to the standard file structure as it makes theme modification easier down the line and lets you use the built in WordPress functions to include files easily (such as get_header()).
First of all, let’s prepare our workspace. In the themes directory of your WordPress installation, create a new folder called blindfaith. Inside that folder, create the following files:
- index.php
- single.php
- page.php
- comments.php
- functions.php
- header.php
- footer.php
- sidebar.php
Now we’ve got our stylesheets and images in place as well a theme skeleton, we’re going to jump right in. First we need to make our theme appear in the WordPress dashboard – to do this we need to modify our style.css file.
WordPress will automatically look for a file called style.css in a theme directory to extract information about the theme. Paste the following code in to the top of style.css:
/* Theme Name: Blind Faith Theme URI: http://www.danwalker.com/ Description: A minimalistic, simple theme for WordPress -- supports widgets in the sidebar, all manors of post/page formatting and comes with an easy to customize stylesheet. Author: Dan Walker Version: 1.0 Tags: minimalistic, simple, widgets, sidebar, elegant */
If we check WordPress now, our theme should appear in the change themes part of the dashboard. Activate our new theme and load up the front page of WordPress. Seeing nothing? Good. Once WordPress has done its magic figuring out what page the user wants and has prepared the results, it calls index.php from our theme directory – except right now that file is blank.
First of all, we need to cut up our HTML in to its four respective parts; header, body, sidebar, footer. If you open up the index.html supplied with this tutorial, you should see this:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html lang='en'> <head> <title>Blind Faith</title> <link rel="stylesheet" href="reset.css" type="text/css"> <link rel="stylesheet" href="style.css" type="text/css"> <!--[if IE]> <link rel="stylesheet" href="ie.css" type="text/css" /> <![endif]--> </head> <body class="home blog"> <div id="top-bar-tile"> <div id="top-bar-content"> <h1><a href="http://www.danwalker.com/themes/blindfaith">Blind Faith</a></h1> <span class="slogan">Just Another Theme by Dan Walker</span> <div id="search-box"> <form method="get" id="searchform" action="" > <input type="text" value="Search..." onfocus="if(this.value == this.defaultValue) this.value = ''" name="s" id="s" /> </form> </div><!-- search-box --> </div><!-- top-bar-content --> </div><!-- top-bar-tile --> <div id="nav-bar-tile"> <div class="nav-bar-content"><ul><li class="current_page_item"><a href="http://www.danwalker.com/themes/blindfaith/" title="Home">Home</a></li><li class="page_item page-item-2"><a href="http://www.danwalker.com/themes/blindfaith/?page_id=2" title="About">About</a></li><li class="page_item page-item-4"><a href="http://www.danwalker.com/themes/blindfaith/?page_id=4" title="Typography">Typography</a></li></ul></div> </div><!-- nav-bar-tile --> <div id="wrapper"> <div id="content"> <div class="post"> <h1><a href="http://www.danwalker.com/themes/blindfaith/?p=1">Hello world!</a></h1> <div class="post-details"> <div class="post-details-left"> Posted on <strong>February 6, 2011</strong> by <span class="author">Dan</span> under <span class="author"><a href="http://www.danwalker.com/themes/blindfaith/?cat=1" title="View all posts in Uncategorized" rel="category">Uncategorized</a></span> </div> <div class="post-details-right"> <span class="comment-count"><a href="http://www.danwalker.com/themes/blindfaith/?p=1#comments" title="Comment on Hello world!">1 Comment</a></span> </div> </div> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam malesuada sem in orci ornare et porta nisi tristique. Integer sodales feugiat interdum. Nunc nec hendrerit velit. Praesent at dolor arcu. Nulla porttitor dui vel justo vehicula fringilla. Nunc condimentum justo ut nibh pharetra tempor. Morbi nulla nisl, blandit eu egestas vel, cursus eget justo. Nulla lectus ante, pellentesque tempor pretium eu, porttitor vitae mi. Nunc et dolor eget purus ultricies sollicitudin. Phasellus luctus tincidunt lobortis. Nunc ac aliquam leo. In tortor orci, auctor non condimentum ultricies, hendrerit et nunc. Nam neque est, laoreet at rhoncus vitae, porttitor at nulla. Maecenas dignissim sagittis massa non ultrices. Cras eros quam, ultrices eu iaculis eu, egestas eget justo. Vivamus diam sapien, volutpat eget luctus nec, lacinia non quam. Duis suscipit nunc eget neque congue pretium. Vestibulum non lectus ut quam tempus varius. Nunc a ligula non metus luctus molestie.</p> <p> <a href="#" class="more-link">Read More</a></p> <div class="dots"></div> </div><!-- post --> <div id="only-page">No newer/older posts</div> <div class="spacer"></div> <div class="dots"></div> <div id="footer"> Copyright © 2011 <a href="http://www.danwalker.com">Dan Walker</a><br /> Don't steal anything etc </div> </div><!-- content --> <div id="sidebar"> <div class="sidebar-box"> <span class="sidebar-title">a bit about me</span> <div class="dots"></div> <div class="textwidget"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam malesuada sem in orci ornare et porta nisi tristique. Integer sodales feugiat interdum. Nunc nec hendrerit velit. Praesent at dolor arcu. Nulla porttitor dui vel justo vehicula fringilla. Nunc condimentum justo ut nibh pharetra tempor. Morbi nulla nisl, blandit eu egestas vel, cursus eget justo.</p> </div> </div> <div class="sidebar-box"> <span class="sidebar-title">recent posts</span><div class="dots"></div> <ul> <li><a href="http://www.danwalker.com/themes/blindfaith/?p=1" title="Hello world!">Hello world!</a></li> </ul> </div> </div><!-- sidebar --> <div class="spacer"></div> </div><!-- wrapper --> </body> </html>
If we load up this HTML in a browser at the moment, we will see the basic layout. Looking at this layout, the first thing we need to do is decide what the header should include. Since we want the title, search box and navigation at the top of every page, that’s what we will put in to our header file.
The main content area will be variable, meaning it could be index.php, page.php, etc. The sidebar is all the content outside of the content box to the right of the layout and the footer will simply be the copyright message. Our theme will be made up like this:

So, copy the code from index.html all the way from the doctype to the content division and paste it in to our header file, we should now have a header.php file that looks like this:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html lang='en'> <head> <title>Blind Faith</title> <link rel="stylesheet" href="reset.css" type="text/css"> <link rel="stylesheet" href="style.css" type="text/css"> <!--[if IE]> <link rel="stylesheet" href="ie.css" type="text/css" /> <![endif]--> </head> <body class="home blog"> <div id="top-bar-tile"> <div id="top-bar-content"> <h1><a href="http://www.danwalker.com/themes/blindfaith">Blind Faith</a></h1> <span class="slogan">Just Another Theme by Dan Walker</span> <div id="search-box"> <form method="get" id="searchform" action="" > <input type="text" value="Search..." onfocus="if(this.value == this.defaultValue) this.value = ''" name="s" id="s" /> </form> </div><!-- search-box --> </div><!-- top-bar-content --> </div><!-- top-bar-tile --> <div id="nav-bar-tile"> <div class="nav-bar-content"><ul><li class="current_page_item"><a href="http://www.danwalker.com/themes/blindfaith/" title="Home">Home</a></li><li class="page_item page-item-2"><a href="http://www.danwalker.com/themes/blindfaith/?page_id=2" title="About">About</a></li><li class="page_item page-item-4"><a href="http://www.danwalker.com/themes/blindfaith/?page_id=4" title="Typography">Typography</a></li></ul></div> </div><!-- nav-bar-tile --> <div id="wrapper"> <div id="content">
For now, we will skip the content section as that is the biggest and most complex part (made up of many different files) and move straight along to the footer. Usually a footer comes last in a layout, however since the sidebar comes after the footer in our code, we will simply call sidebar after footer. Therefore footer.php should contain the following code;
<div class="spacer"></div> <div id="footer"> Copyright © 2011 Blind Faith by <a href="http://www.danwalker.com">Dan Walker</a><br /> </div> </div><!-- content --> <?php get_sidebar(); ?>
You’ll notice that we’re using our first WordPress function above; get_sidebar();. This function is roughly the same as require(“sidebar.php”); and since we’re going to always require the sidebar after the footer, it makes sense to call the sidebar in the footer file at the end.
Finally we need to include the sidebar. Since the footer comes before the sidebar, the sidebar is the last file included and so should close the design too (by closing the remaining tags; wrapper, body and html).
<div id="sidebar"> <div class="sidebar-box"> <span class="sidebar-title">a bit about me</span> <div class="dots"></div> <div class="textwidget"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam malesuada sem in orci ornare et porta nisi tristique. Integer sodales feugiat interdum. Nunc nec hendrerit velit. Praesent at dolor arcu. Nulla porttitor dui vel justo vehicula fringilla. Nunc condimentum justo ut nibh pharetra tempor. Morbi nulla nisl, blandit eu egestas vel, cursus eget justo.</p> </div> </div> <div class="sidebar-box"> <span class="sidebar-title">recent posts</span><div class="dots"></div> <ul> <li><a href="http://www.danwalker.com/themes/blindfaith/?p=1" title="Hello world!">Hello world!</a></li> </ul> </div> </div><!-- sidebar --> <div class="spacer"></div> </div><!-- wrapper --> </body> </html>
For now, open up index.php and enter the following;
<?php get_header(); ?> <?php get_footer(); ?>
If we navigate to our installation of WordPress, we should get something like this

At the moment, the website content (or what we’ve done so far) seems to be loading but the stylesheets are not. This is because in our header file, the calls to the stylesheets now use a path that does not exist. They now reside in /wp-content/themes/blindfaith/, but there’s an easier way of pasting that everywhere it’s needed – a more dynamic way.
The bloginfo() Function
WordPress comes with a built in function called bloginfo() that’s great for getting all sorts of useful local information such as; blog name, description, stylesheet URL, stylesheet directory and more. For more information on what we can get with bloginfo, read this page in the WordPress codex.
Let’s open up our header file and change a few things to use the dynamic information provided by WordPress rather than the static information in the theme. Our current header.php file looks like this up until the nav-bar-tile tag:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html lang='en'> <head> <title>Blind Faith</title> <link rel="stylesheet" href="reset.css" type="text/css"> <link rel="stylesheet" href="style.css" type="text/css"> <!--[if IE]> <link rel="stylesheet" href="ie.css" type="text/css" /> <![endif]--> </head> <body class="home blog"> <div id="top-bar-tile"> <div id="top-bar-content"> <h1><a href="http://www.danwalker.com/themes/blindfaith">Blind Faith</a></h1> <span class="slogan">Just Another Theme by Dan Walker</span> <div id="search-box"> <form method="get" id="searchform" action="" > <input type="text" value="Search..." onfocus="if(this.value == this.defaultValue) this.value = ''" name="s" id="s" /> </form> </div><!-- search-box --> </div><!-- top-bar-content --> </div><!-- top-bar-tile -->
First of all, let’s fix the missing stylesheets. We’ll use two values from bloginfo; stylesheet_directory and stylesheet_url. The URL value is a direct link to style.css, whereas directory lists the directory style.css resides in. It’s important to remember that WordPress functions like this do not append a trailing slash to values.
Replace the stylesheet lines with the following;
<link rel="stylesheet" href="<?php bloginfo('stylesheet_directory'); ?>/reset.css" type="text/css">
<link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>" type="text/css">
<!--[if IE]>
<link rel="stylesheet" href="<?php bloginfo('stylesheet_directory'); ?>/ie.css" type="text/css" />
<![endif]-->
Our theme now has properly linked stylesheets. Next up, whilst we’re in the header file, let’s change the blog title, slogan and link.
The <title> tag doesn’t simply have the bloginfo property that represents the name of the blog, we can also add another function; wp_title(). This function returns the title of the page or post currently being viewed, prepended with ». To turn off the » before the page name, simply change the parentheses of wp_title() to wp_title(“”, true);
<title><?php bloginfo('name'); ?> <?php wp_title(); ?></title>
This will produce something along the lines of;
Local Test Blog >> Hello World
Now we can simply change the logo/title text, slogan and URL using the following bloginfo() properties;
<h1><a href=""><?php bloginfo('name'); ?></a></h1>
<span class="slogan"><?php bloginfo('description'); ?></span>
Our page should now look something like this;

Now we’ll take a look at the index.php file. This is the file called by default and should be able to display lists of posts for the front page, categories, archives and search results – or an error message if none exist. Obviously each one of these different lists can contain variable amounts of posts, we can work with this by using something in WordPress known as “The Loop”.
The Loop
WordPress figures out what posts to display before the index file is executed — after all we are making a theme, and the theme comes last as it’s simply a way of displaying output. Using some in-built functions, we can avoid having to do complex PHP loops with constant checks for valid data – this aspect of WordPress theme development makes the process a lot easier and causes less headaches.
First of all, let’s look at our post structure;
<div class="post"> <h1><a href="http://www.danwalker.com/themes/blindfaith/?p=1">Hello world!</a></h1> <div class="post-details"> <div class="post-details-left"> Posted on <strong>February 6, 2011</strong> by <span class="author">Dan</span> under <span class="author"><a href="http://www.danwalker.com/themes/blindfaith/?cat=1" title="View all posts in Uncategorized" rel="category">Uncategorized</a></span> </div> <div class="post-details-right"> <span class="comment-count"><a href="http://www.danwalker.com/themes/blindfaith/?p=1#comments" title="Comment on Hello world!">1 Comment</a></span> </div> </div> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam malesuada sem in orci ornare et porta nisi tristique. Integer sodales feugiat interdum. Nunc nec hendrerit velit. Praesent at dolor arcu. Nulla porttitor dui vel justo vehicula fringilla. Nunc condimentum justo ut nibh pharetra tempor. Morbi nulla nisl, blandit eu egestas vel, cursus eget justo. Nulla lectus ante, pellentesque tempor pretium eu, porttitor vitae mi. Nunc et dolor eget purus ultricies sollicitudin. Phasellus luctus tincidunt lobortis. Nunc ac aliquam leo. In tortor orci, auctor non condimentum ultricies, hendrerit et nunc. Nam neque est, laoreet at rhoncus vitae, porttitor at nulla. Maecenas dignissim sagittis massa non ultrices. Cras eros quam, ultrices eu iaculis eu, egestas eget justo. Vivamus diam sapien, volutpat eget luctus nec, lacinia non quam. Duis suscipit nunc eget neque congue pretium. Vestibulum non lectus ut quam tempus varius. Nunc a ligula non metus luctus molestie.</p> <p> <a href="#" class="more-link">Read More</a></p> <div class="dots"></div> </div><!-- post -->
Since we know what the structure of a post looks like and we have a copy with dummy information, we can replace the dummy information with some functions that will return actual post values. There are several pieces of information we can display with each post, such as;
- the_title
- the_tags
- the_ID
- the_category
- the_date
- the_content
- many more (which you can find at http://codex.wordpress.org/Template_Tags#Post_tags)
When any one of these functions is called within the loop, they display the correct information for the current post being looped through.
Using the link above (or just the functions supplied before the link), try to replace the dummy content on your own with the correct replacement functions before carrying on.
The correct code should look like this;
<div class="post">
<h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
<div class="post-details">
<div class="post-details-left">
Posted on <strong><?php the_date(); ?></strong> by <span class="author"><?php the_author(); ?></span> under <span class="author"><?php the_category(', '); ?></span>
</div>
<div class="post-details-right">
<?php edit_post_link('Edit', '<span class="comment-count"> ' , '</span>'); ?><span class="comment-count"><?php comments_popup_link('Leave a comment', '1 Comment', '% Comments'); ?></span>
</div>
</div>
<?php if ( is_archive() || is_search() ) : // Only display excerpts for archives and search. ?>
<?php the_excerpt(); ?>
<?php else : ?>
<?php the_content('Read More'); ?>
<?php endif; ?>
<div class="dots"></div>
</div><!-- post -->
There are a few bits you may not have been able to do, let’s look at them.
First of all, when displaying categories, WordPress likes to print a default style using a list. To override this, we can provide our own separator, which in our case is simply a comma and a space.
<?php the_category(', '); ?
Next up to display an edit link, followed by how many comments a post has, we can use a function that creates the link and can output three different states for; no comments, single comment and multiple comments (where the percentage sign is the placeholder for the comment count).
<?php comments_popup_link('Leave a comment', '1 Comment', '% Comments'); ?>
Finally we have a simple if statement to decide what type of content to show. If we use the_excerpt() then only an excerpt of the content is shown, if we use the_content() then all of the content is shown (or until a <–more–> appears in the content). On a search or archive page, it isn’t important to show the full article – just enough to get the gist – so we use the_excerpt().
Now in order to make this code work, we have to supply it with posts, and to do that we need to put it inside the loop. Our index.php file should currently resemble this;
<?php get_header(); ?>
<div class="post">
<h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
<div class="post-details">
<div class="post-details-left">
Posted on <strong><?php the_date(); ?></strong> by <span class="author"><?php the_author(); ?></span> under <span class="author"><?php the_category(', '); ?></span>
</div>
<div class="post-details-right">
<?php edit_post_link('Edit', '<span class="comment-count"> ' , '</span>'); ?><span class="comment-count"><?php comments_popup_link('Leave a comment', '1 Comment', '% Comments'); ?></span>
</div>
</div>
</div>
<?php if ( is_archive() || is_search() ) : // Only display excerpts for archives and search. ?>
<?php the_excerpt(); ?>
<?php else : ?>
<?php the_content('Read More'); ?>
<?php endif; ?>
<div class="dots"></div>
</div><!-- post -->
<?php get_footer(); ?>
Put this code after the header function;
<?php if ( ! have_posts() ) : ?> <h1>Not Found</h1> <p>Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post</p> <?php endif; ?> <?php while ( have_posts() ) : the_post(); ?>
and this one just before the footer function;
<?php endwhile; ?>
Loading up the WordPress blog should now look something like this;

Now our theme will show a list of WordPress posts according to how many should be displayed (changed under general settings in Dashboard). But what if there are more posts? What if the blog contains 6 posts but only displays 5? To combat this we need to add simple next/previous or new/old links.
Of course there’s no point displaying these links if there are no newer or older posts to jump to as it’s misleading, therefore we will use the following code after the loop;
<?php if ( $wp_query->max_num_pages > 1 ) : ?>
<div id="older-posts"><?php next_posts_link('Older Posts'); ?></div>
<div id="newer-posts"><?php previous_posts_link('Newer Posts'); ?></div>
<?php else: ?>
<div id="only-page">No newer/older posts</div>
<?php endif; ?>
The next_posts_link() and previous_posts_link() will only display when they are needed, using the text provided in the first parameter. Of course it is possible to remove the if statement and only use the following two lines;
<div id="older-posts"><?php next_posts_link('Older Posts'); ?></div>
<div id="newer-posts"><?php previous_posts_link('Newer Posts'); ?></div>
But using the if statement above, we have the option of showing a message if there are no pages to skip to, which can make things less confusing for the user (which is always a good thing).
Our completed index.php file should look like this;
<?php get_header(); ?>
<?php /* If there are no posts to display, such as an empty archive page */ ?>
<?php if ( ! have_posts() ) : ?>
<h1>Not Found</h1>
<p>Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post</p>
<?php endif; ?>
<?php while ( have_posts() ) : the_post(); ?>
<div class="post">
<h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
<div class="post-details">
<div class="post-details-left">
Posted on <strong><?php the_date(); ?></strong> by <span class="author"><?php the_author(); ?></span> under <span class="author"><?php the_category(', '); ?></span>
</div>
<div class="post-details-right">
<?php edit_post_link('Edit', '<span class="comment-count"> ' , '</span>'); ?><span class="comment-count"><?php comments_popup_link('Leave a comment', '1 Comment', '% Comments'); ?></span>
</div>
</div>
<?php if ( is_archive() || is_search() ) : // Only display excerpts for archives and search. ?>
<?php the_excerpt(); ?>
<?php else : ?>
<?php the_content('Read More'); ?>
<?php endif; ?>
<div class="dots"></div>
</div><!-- post -->
<?php endwhile; ?>
<?php if ( $wp_query->max_num_pages > 1 ) : ?>
<div id="older-posts"><?php next_posts_link('Older Posts'); ?></div>
<div id="newer-posts"><?php previous_posts_link('Newer Posts'); ?></div>
<?php else: ?>
<div id="only-page">No newer/older posts</div>
<?php endif; ?>
<div class="spacer"></div>
<?php get_footer(); ?>
Single Posts
We now have a working index, but now we need a way to display single posts. Due to the simplicity of our design, our single.php file and index.php are near identical, the difference being that we don’t need next/previous links in single.php but we do need comments. The code for single.php is as follows;
<?php get_header(); ?>
<?php /* If there are no posts to display, such as an empty archive page */ ?>
<?php if ( ! have_posts() ) : ?>
<h1>Not Found</h1>
<p>Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post</p>
<?php endif; ?>
<?php while ( have_posts() ) : the_post(); ?>
<div class="post">
<h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
<div class="post-details">
<div class="post-details-left">
Posted on <strong><?php the_date(); ?></strong> by <span class="author"><?php the_author(); ?></span> under <span class="author"><?php the_category(', '); ?></span>
</div>
<div class="post-details-right">
<?php edit_post_link('Edit', '<span class="comment-count"> ' , '</span>'); ?><span class="comment-count"><?php comments_popup_link('Leave a comment', '1 Comment', '% Comments'); ?></span>
</div>
</div>
<?php if ( is_archive() || is_search() ) : // Only display excerpts for archives and search. ?>
<?php the_excerpt(); ?>
<?php else : ?>
<?php the_content('Read More'); ?>
<?php endif; ?>
<div class="dots"></div>
</div><!-- post -->
<div class="spacer"></div>
<?php comments_template( '', true ); ?>
<?php endwhile; ?>
<div class="spacer"></div>
<?php get_footer(); ?>
As you can see, not much has changed except around the bottom of the file. We’ve simply removed the code for the links and added a new function called comments_template(). The parameters for this function are simply the file to load (comments.php if left blank or by default) and whether or not to sort comments by type (default to false).
As you’ve probably guessed, the file that handles comments is comments.php – it is kept in a separate file so we can use it on both single.php and page.php alike.
Page
The file for displaying a page is almost identical to the single post file with the exception that information about time of post, author and so on is removed. This means the page file looks like this;
<?php get_header(); ?>
<?php /* If there are no posts to display, such as an empty archive page */ ?>
<?php if ( ! have_posts() ) : ?>
<h1>Not Found</h1>
<p>Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post</p>
<?php endif; ?>
<?php while ( have_posts() ) : the_post(); ?>
<div class="post">
<h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
<?php if ( is_archive() || is_search() ) : // Only display excerpts for archives and search. ?>
<?php the_excerpt(); ?>
<?php else : ?>
<?php the_content('Read More'); ?>
<?php endif; ?>
<div class="dots"></div>
</div><!-- post -->
<div class="spacer"></div>
<?php comments_template( '', true ); ?>
<?php endwhile; ?>
<div class="spacer"></div>
<?php get_footer(); ?>
Navigation
The final part we’ll be adding today is the navigation up top (as it’s so simple)! Open up header.php and replace the nav-bar-tile division with this;
<div id="nav-bar-tile"> <?php wp_nav_menu(array( 'menu' => 'mainnav', 'menu_class' => 'nav-bar-content', 'menu_id' => 'navigation', 'container' => false, 'theme_location' => 'primary-menu', 'show_home' => '1')); ?> </div><!-- nav-bar-tile -->
The wp_nav_menu function spits out a list of pages, however it also takes arguments in the form of an array. The arguments we have supplied, in order, are;
- menu – The desired menu
- menu_class – The CSS class to be used
- menu_id – The UL element ID
- container – Whether or not to wrap the list
- theme_location – The location of the menu within the theme (for multiple menus)
- show_home – Whether or not to display a ‘Home’ link
The CSS we’re using is coded to adapt to the way WordPress spits out a navigation list, it’s important to consider how a list will be outputted in code by WordPress when coding a design.
Our WordPress installation should now look like this;

Next Time…
Next time we will look at adding a functional sidebar that’s widget ready, dynamic post types, custom fields and wrapping up the final few elements in the theme!
If there is anything you were unsure of in this post, or if you just have questions, feel free to leave a comment below. For those with questions or just those wanting to know more, the WordPress Codex is goldmine of information for all the functions and so on that WordPress uses.


This seems to be the same tutorial as that in net.tutplus but it was in video right?
It’s similar, but we’ll end up re-treading a lot of what was on Nettuts over the next month or so as we add in these “staple” tutorials to the library here. You can also expect quite a bit of brand new content though, so there’ll be something for everyone. Thanks for the comment wpfu!
Re tread till the cows come home I say.
i thaught it was a videos tutorial.
harm!!!!!!
Awesome tut, looking forward to reading more. You guys do a hell of a good work here.
I think the workfiles are missing ?! Can you put them online please? Thanks for these series by the way
They should be up now Julien – let me know if you still can’t access them though
Perfect
Recently I’ve been grappling with using $wpdb to submit a registration form. A really in depth tutorial on this would be great!
Rich
Here, try this tutorial I wrote: Registeration Tricks
While it was written specifically for the Members plugin by Justin Tadlock the principles of code still apply to any base registration. You request for a tutorial on the registration form is very general as there are so many things that can be done. Specifics, my man, specifics.
“In the downloadable zip that accompanies this tutorial…”
Where do we find the downloadable zip file?
Thanks!
WBR
First of all… Keep it going! Love this! And the way you write it, it’s also easy to understand, not too overly in depth, but still ppl should get the basic idea. Good job, and can’t wait for part 3.
Though, as William Rouse mentions here…
What downloadable .zip file? *loooks around*
Ware
Reloaded the page, and there it was.. :S
Ohhh well, as said, great going! Keep it up!
Thanks for the detailed tutorial, it was pretty good!
I really hope in the next tutorial you will show us how to use multiple dynamic sidebars.
Moar HTML5 pleasee that doctype makes me sadface
Haha. I was always feel the same way!
Clean and simple theme, nice tut!
Nice tutorial I followed step by step… and I am succeed…. till the comment template section.
comments.php is blank file.. it only worked when I replaced with twentyten theme’s comments.php file.
please add comment.php code on this tutorial… your download also not attached the proper comments.php…
Please advice…
Thank You.
works great!!!
Thanks for sharing the tutorial.
Super-awesome… I was waiting for this… Now its time to complete my website.
Excelente este nuevo tutorial para crear un theme en wordpress.
Saludos!
Cool series, keep it coming.
Just a few things i would like to mention
I would recommend placing the reset.css inside of style.css, placed at the top in a single line, one less file request so it’s a bit faster.
And you used bloginfo(‘stylesheet_directory’); when you included the reset.css. That means if a child theme is used it’ll get the reset.css from the child theme, and there’s a big chance there won’t be one. Use get_template_directory_uri(); instead.
Also your theme would get soft rejected on Themeforest for using bloginfo(‘stylesheet_url’); instead of get_stylesheet_uri(); and bloginfo(‘stylesheet_directory’); instead of get_stylesheet_directory_uri. Same goes for the “template” instead of “stylesheet” version.
Instead of bloginfo(‘url’) i suggest home_url(); (usually in WordPress, functions that return a value start with “get_”, this one does not but it does return the value so needs echo).
The loop part seems a bit odd
I guess it works ok, but not sure since there’s no checking if there are posts before doing the loop. It’s usually:
if (have_posts()) : while (have_posts()) : the_post();
//loop posts
endwhile; else:
//no posts
endif;
That’s all
Cheers.
Thanks for the tips about Themeforest and the Loop!
Can you please explain? The official WordPress 3.2 theme ‘Twenty Eleven’ uses:
href=”"
Thank you
Fix:
href=”"
hey hey, slow down a sec.. lol
noob question., so the different between get_bloginfo() and bloginfo() is that get_bloginfo() going to need echo to write it to the browser?
quote from wordpress codex :
” Displays information about your blog, mostly gathered from the information you supply in your User Profile and General Options from the WordPress Administration panels (Settings → General). It can be used anywhere within a page template. This always prints a result to the browser. If you need the values for use in PHP, use get_bloginfo(). ”
Thanks
Yeah, those are good tips to know about themeforest
Boba,
Although I have to agree with most of what you say here – your recommendations are good. I have downloaded a few different themes over the past couple of months that use the ‘bloginfo’ tag for linking to stylesheets. This code is still valid and doesn’t seem to have caused any approval issues with even some of the newest themes being approved.
That being said – what is the real advantage to using get_stylesheet_uri(); over bloginfo?
Thanks
Mike
Should there be a semi colon instead of colon ?
it’s great! i follow the steps..
Yups, i wait the next…
Hi,
I just completed your “Developing Your First WordPress Theme: Day 2 of 3″.
Just want to say it was great and inspiring, learned a lot, thanx!
Also just wondering if you have any suggestion on how to build this kind of product javascript or spry-meny in wordpress?
http://www.nordchark.se/v2/falukorv_basturokt.html
How do i connect the text and images feilds?
thru custom feils? It has to be easy to update the product info for the client.
Keep up the great work.
Best,
Maggy
Awesome, thanks for sharing this. waiting for next tutorial
Thanks for hepinlg me to see things in a different light.
That`s amazing man, that`s all i needed !!!
Wow, looks awesome. I am no web developer, but always wanted to understand how to use WP. Great series.
At the moment I am pretty busy at work, but after I find a minute, I’ll jump to this tutorial. I have no background in coding, so wonder if I need some extra stuff to follow this tutorial? Like a server or whatever? And what good software could you please advise? I am on MAC.
I guess simple text editor will do, right? But maybe you could suggest something better for coding?
Any ways, great series. Great new site. Keep it up!
The best code editor on a mac is Coda ($99). It is made by panic software, who also have the best FTP client out there, Transmit ($40 – but cyberduck is a close second and its free). The nice thing with Coda is not only is it a great code editor, but it has FTP built right into it, plus all your syntax highlighting and auto completion which not only helps but saves you time typing commonly repeated lines of code. Coda also have a clip system in it, which allows you to save long series of code and access it with a single keyword. I have hundreds of clips but one example is a CSS Reset. I have a CSS reset in there (which is like 100 lines of code) and all I have to do is type “cssreset” and then press tab after it and it instantly inserts the whole reset in there, no copy paste or anything, saves a lot of time. It also has a preview window built in too (preview your site changes without switching to safari and refreshing), and a CSS editor for doing fast CSS edits visually. The last great thing about it is that there is a “books” tab where you can have reference books to access quickly in you need a reminder of what parameters are needed for a particular function, or to look up more information about a function or usage. I also have the wordpress codex on there, so I have access to the whole wordpress codex without leaving the program.
I don’t belong to Panic, I just really like Coda. Its the best thing out there, but the price is not the easiest thing to swallow. http://www.panic.com/coda/
Great… A must read post for all WordPress lovers.
Thanks for the writeup! Very informative.
Great comments too.
Great tutorial. Looking forward to part 3!
Hi,
You did not mention how to setup functions in this tutorials as i am a beginner in php so i am stuck on how to setup those functions.
Thank You.
I’d really like to know how to utilize the wp_nav_menu function, so that the admin can adjust menu items in the ‘Appearance’ tab of the dashboard.
It is difficult to remember all things to add to a tutorial, especially if you actually know what you are doing.
Experienced programmers often overlook things simply because it is common sense to them. This is where tutorial editors come in – preferable one who can code (to test the tutorial) and one who is not so proficient (to test comprehension level).
Anyway, for your question about adding menus there are many tutorials available, but my favourite is Justin Tadlock’s
Although slightly outdated it is current enough with the most recent version of WordPress and I don’t see it changing in the next few dozen WordPress updates.
Neil, I completely understand. 95% of what I know is self-taught on a need basis, so I often come against really simple things that I’ve overlooked or were simply not an issue for the specific projects I was working on. I keep trying to make myself go back and learn things from the ground up, but it’s definitely a long road.
Thanks very much for posting the other tutorial, I’ll check that out today!
I would advise against closing HTML tag in sidebar. For certain pages in a custom theme you might not want to include a sidebar but that’s where you closed the HTML elements. I would consider re coding slightly to utilize wordpress template hierarchy to be expandable. Great writup though. Keep em coming!
Hi,
I am using my design for WordPress theme and it has images but they don’t display on WordPress any idea on how to display images in WordPress?
i had same problem at first.. just change all the paths to “absolut path” instead “relative”.. At least for that ones wasn’t in CSS..
to display images the right way: create a folder ‘images’ in the wp-content/themes/yourtheme/
put the images in this folder.
In the header.php file put: <link rel="stylesheet" href="” type=”text/css”>
In the style sheet (css) make a path to your images, for example: background:url(images/logo.png);
Now just must see them.
(this took me 3 2 days!!!)
greetzz, Toon
Sorry!
This is the right reply text :
To display images the right way: create a folder ‘images’ in the wp-content/themes/yourtheme/
Put your images in this folder. So that you have:
wp-content/themes/yourtheme/images
In the header.php file of your site, put:
<link rel="stylesheet" href="” type=”text/css”>
In the style sheet (style.css) make a path to your images, for example:
background:url(images/logo.png);
You see: ‘naming’ the folder is doing the trick.
Now images are loading, because it’s the right path for WordPress to load them.
(…Took me 2 days to figure this out. Since I find so much worthy tips and tutorials I assumed this is another good one to share…)
Succes, Toon
Very strange,
The programm is not showing my code line.
Here it is aganin:
header.php file, put:
<link rel="stylesheet" href="” type=”text/css”>
I assume it shows correctly.
greetzzz, Toon
Last try! (grrrrr….)
code in header.php is:
code is:
/pre>
Drive me nuts!
last time: code in header.php is: ?php bloginfo(‘stylesheet_url’); ?
<link rel="stylesheet" href=" (….. code….. in between ) ” type=”text/css”>
Any idea when part 3 will be coming along?
Thanks for great Tutorial!!
Great tutorial following on from what Boba said if your going to use get_stylesheet_uri() remember you need to echo it out like this:
<link rel=”stylesheet” href=”<?php echo get_stylesheet_uri(); ?>” type=”text/css”>
can someone give my the video tutorial for building this WordPress theme cause i cant find the link to the video.
I am having difficulty with the “Leave Comment” link. I can not get a space to go between “Leave Comment” and “Edit.” They are smashed together. When I click on Leave Comment it does nothing. I’m guessing it is not supposed to work at this point because we have not edited comments.php, correct?
It looks like this:
<?php edit_post_link(' Edit ', ' ‘ , ”); ?>
Also, is supposed to make the blog posts on the index.php page display as excerpts at this point? I had one article that was 6 paragraphs long and it is displaying 100% of it on the home page.
Any idea on how to resolve these two issues?
Sorry, this is what I have for the edit and comments links:
Posted on by under
<?php edit_post_link('Edit', ' ‘ , ”); ?>
Have you tried adding a class to the edit link and applying margin with CSS?
hi,
Thanks for the tutorial.
I’m very new to wp, but managed to install and got wp in my mamp. I can see TwentyTen them when activated.
However, when following the tutorial, I couldn’t see anything in Blindfaith theme.
I copy/paste the 4 php files. header.php , footer.php , sidebar.php , index.php
Nothing show up when i click on “visit site” from the dashboard.
Anyone knows what I’m doing wrong or missing?
thank you for your kind reply
you need a ‘style.css’ file too. downloadthe source filesat the top of the post
wordpress pulls it’s display info for themes from the style.css file(as well as the style for the theme obviously lol) like the theme name, author, dscription etc. the stuff that’s displayed when you go to the themes page in the wordpress dashboard
Great guide to clip and back for Copy & paste while building a new wp theme
thanks
A great tut. But the steps are far to big for someone who never touched the code behind a theme.
I can handle HTML and CSS very well and I heard of all the template Tags before. Nevertheless it wasn’t easy for me to follow the steps. The reader has to do many things by himself that aren’t explained.
This code works for wordpress 3.0+ right?
Thanks!
Great tutorial! Ive been looking for something more descriptive and step based like this.
The only thing that I wished it had more of was comment lines in the coding. I think that would have made it easier for some of the more “beginner” users. Nothing drastic, just simple things so the people know where to go for specific things.
These are examples from my HEADER.PHP file
oops, forgot about the code snippet thing.repost
Great tutorial! Ive been looking for something more descriptive and step based like this.
The only thing that I wished it had more of was comment lines in the coding. I think that would have made it easier for some of the more “beginner” users. Nothing drastic, just simple things so the people know where to go for specific things.
These are examples from my HEADER.PHP file
-CALL THE DOCUMENTS INFORMATION
-CALL THE STYLE SHEETS
-START THE TOP HEADER BAR
-CHANGE THE LOGO/TITLE TEXT, SLOGAN AND URL
-ADD A SEARCH BAR
-START THE NAV HEADER
Finaly I found a decent explaination of the famous ‘wordpress loop’… and you weren’t even trying to explain! I’ve never been on this site before but I’m sure there is more knowledge hidden in the rest of these posts. I’ve tried and given up so many times to make my own unique theme but have never once made it to a finished product. Bonus is that I have dozens of unique HTML and CSS layouts to finally bring to life. I’m too tired to read part 3 of this post but I’m leaving it open so it’s the first thing I see tomorrow morning haha Ain’t even risking loosing this site in my masses of booksmarks lol
Hi, i downloaded the files and run it using wordpresss 3.2.. The NAVIGATIONS are not aligned together all in all.. Sample Page2 menu is doing a break line or next line.. In the example above, all of the menus in the navigation are aligned.. Anyone might know why is this happening?? Tnx.
I decided to start developing a site based on this theme and I’m finding it doesn’t handle subpages in the menu area.
Has anyone else run into this issue? If so, do you have a fix?
Thanks so much in advance.
Hi,
Is this one can be used as stater for a parent theme?..
and why didn’t you suggested to change Theme Name,Theme URI,Description and Author on top of the page in the css.style file? so it would be the reader theme…
Thanks
ron
functions.php doesn’t seems to work. Is it supposed to be linked somewhere ?
Hi,
I can’t seem to find the zip file that I need to download. Whenever I click the Download button it just opens a blank screen in my browser. Any recommendations?
Aaaaah, help, why am I not getting your layout after putting bloginfo() Function in place. I’m suspecting that I need to do something more on style.css…. My page still looked like a straight top-to-bottom page without much formatting -everything is left-aligned, even the side bar where it should go to the right side….. Is there something missing? Should I look into adding something in style.css besides just the description of the theme? Please HALP!!