Developing WordPress 2.7 Themes
From ThemesWiki
| Official Page |
| Project Documentation |
| Download |
|
We'll start out with tips on slicing and dicing so that your HTML and CSS files are as WordPress-friendly as possible, and then cover the steps for turning that HTML build into a fully functional theme.
Note that I assume that you are already comfortable writing and working with HTML and CSS. You do not need to be familiar with PHP because I'll be walking you through all of the PHP code.
Contents |
[edit] Setting up your design
Just about any design in the world can be turned into a WordPress theme. However, there are some general guidelines you can follow both in the design and the HTML/CSS build of your theme which will make the design fit very easily into the WordPress theme box.
[edit] Designing your theme to be WordPress-friendly
While you can design your blog any way that you want, a good way to start would be with one of the standard blog layouts.
Note that while these different standard layouts have differing numbers of columns and column widths, they all have these essential parts:
- Header
- Main column
- Side column(s)
- Footer
WordPress expects your theme to follow this pattern, and so it provides functions that make it easier to create a theme that has this pattern. As you're designing your first blog theme, I suggest including these parts. Also, a design that stays within the same general design patterns of WordPress themes will most easily accommodate existing plugins and widgets.
The two-column layout is the simplest and the easiest to implement as a WordPress theme. So, we'll be using this layout as an example in this tutorial. This is a screenshot of the design I created in Photoshop for my food blog:
Note that this layout has a header, main column, side column, and footer:
Now that the design is complete, we're ready for the next step: turning the design into code.
[edit] Converting your design to code
The next step towards turning your ideal design into a WordPress theme is to slice images out of your design and write HTML and CSS files that put it all together. For the purpose of this tutorial, I assume that you already know how to do this in general. We'll cover the ways you can do your slicing and dicing, but in a different way so that your HTML will be best suited for WordPress.
|
If you are interested in the details of both designing a theme and slicing it for WordPress, I highly recommend the tutorial "WordPress Theme Design", Packt Publishing, 9781847193094 by Tessa Blakeley Silver. This tutorial minutely covers topics such as choosing a color scheme, considering typography, writing the best CSS, and laying out your HTML using Rapid Design Comping. |
My HTML build folder, which has my HTML, CSS, and image files, looks like this:
We will now take a look at some of the choices I made when writing these HTML and CSS files so that you can take advantage of these tips and tricks.
[edit] Examining the HTML structure
Here is the very basic (not final) layout of my HTML file for my food blog design:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Blog title</title>
<style type="text/css">@import url("style.css");</style>
</head>
<body>
<div id="container">
<div id="header">
<div id="mainnav">
<ul>
<li>Navigation list item</li>
</ul>
</div><!-- /mainnav -->
<h1><a href="#">My Blog Title</a></h1>
<div id="description">this is My subtitle</div>
</div><!-- /header -->
<div id="content">
<div id="copy">
<div class="post">
<h2><a href="#">Post Title</a></h2>
<div class="post-date">Post Date</div>
<p>Post Content</p>
<div class="categories">Categories</div>
<div class="tags">Tags</div>
<div class="comments">Comments</div>
</div>
</div>
<div id="sidebar">
<h3>Categories</h3>
<ul>
<li>category list item</li>
</ul>
<h3>Archives</h3>
<ul>
<li>archive list item</li>
</ul>
</div><!-- /sidebar -->
</div><!-- /content -->
<div id="footer">
Footer text
</div><!-- /footer -->
</div><!-- /container -->
</body>
</html>
You can see that I've separated out these four major parts:
- The header is in the
divwithid="header" - The side column is in the
divwithid="sidebar" - The main column is in the
divwithid="copy" - The footer is in the
divwithid="footer"
I'd like to call your attention to a few other things I've done here:
- The mainnav is in an unordered list (
ul)
I did this because WordPress has a function that spits out the pages of your site in the order you choose. When WordPress spits out the list, every linked page title is in a list item tag li.
- Archives and Categories are similar
There are going to be a number of items that you may want to add to your sidebar, including widgets. Many of these items will be lists with titles, so I've prepared for that in my HTML.
- Within the div id="copy" is a div with the class="post"
Even though this basic layout has just one post in it, I know that I'll want to show more than one post at a time. I've created this div expecting that it'll be repeated for each post. Also, WordPress expects this div to be called "post". (We'll get into that later.)
Now that I ve got my basic layout, I'm going to add a few more HTML elements to flesh it out a bit, including more information in the <head> as well as the search box, and some additional CSS. Then I ll fill up the sidebar, header, content, and footer with bunch of dummy text so that it looks almost exactly like my theme s design in Photoshop. I m not including the complete HTML here, but you can find it in the code bundle for this tutorial (in the folder called HTML_build) if you d like to do the same. However, note that I've left most of the text a little different. This is my trick to remind myself, later, to replace the static text with dynamic WordPress-generated text.
[edit] Examining the CSS
Let's now take a look at the CSS. First, we'll review the CSS that displays everything you see in the design. Note that I've got styles for my five key parts: header, sidebar, copy, post, and footer. They are as follows:
body {
margin: 0px;
background: #ddd url('images/bg-body.gif') repeat-x;
font-family: "Trebuchet MS", Helvetica, Arial, sans-serif;
font-size: 14px;
}
a, a:visited {
color: #397cc6;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/*** STRUCTURAL PLACEMENT - - - - - - - - - - - - - - - - - - - - */
#container {
margin: 0 auto;
width: 837px
}
#header {
margin: 35px 0 0 0;
height: 343px;
background: url('images/header.jpg') no-repeat;
}
#mainnav {
padding: 40px 0 0 30px;
}
#content {
background: #fff url('images/bg-content.gif');
padding: 0 10px 0 10px;
}
#copy {
width: 590px;
float: right;
}
#sidebar {
width: 200px;
float: left;
background-color: #F7F7F7;
}
#footer {
background: url('images/footer.gif') no-repeat;
height: 79px;
}
/*** STYLING PIECES - - - - - - - - - - - - - - - - - - - - - - - */
/* header title */
#header h1 {
color: #fff;
font-size: 24px;
font-weight: normal;
margin: 140px 0 5px 500px;
text-transform: lowercase;
}
#header h1 a {
color: #fff;
text-decoration: none;
}
#header h1 a:hover {
background-color: #9A8A71;
}
#header #description {
color: #fff;
margin: 0 0 5px 500px;
text-transform: lowercase;
}
/* main (top) navigation */
#mainnav ul {
margin: 0;
padding: 0;
}
#mainnav li {
margin: 0;
padding: 0 30px 0 0;
display: inline;
color: #82aedf;
}
#mainnav ul li:before {
content: "\00A4 \0020 \0020";
}
#mainnav a, #mainnav a:visited {
color: #bad2ee;
text-transform: uppercase;
text-decoration: none;
}
#mainnav a:hover {
text-decoration: underline;
}
/* sidebar */
#sidebar {
padding: 0 0 20px 0;
}
#sidebar h3 {
color: #b7b6b6;
font-weight: normal;
font-size: 18px;
margin: 30px 0 5px 10px;
}
#sidebar h3.first {
margin-top: 0;
}
#sidebar ul {
margin: 0 0 0 10px;
padding: 0;
}
#sidebar li {
margin: 0;
padding: 0;
list-style-type: none;
}
#sidebar input {
background-color: #ededed;
border: 1px solid #ccc;
padding: 4px;
margin-left: 10px;
}
/* posts */
.post {
border-bottom: 3px solid #f7f7f7;
padding: 0 0 15px 0;
}
.post h2 {
color: #c1ae90;
font-weight: normal;
margin: 0;
}
.post h2 a {
color: #c1ae90;
}
.post .categories, .post .tags, .post .post-date {
color: #bababa;
font-size: 12px;
}
.post .post-date {
float: right;
margin-top: -18px;
}
.post .comments {
font-size: 12px;
float: right;
margin-top: -20px;
}
.post .comments a, .post .comments a:visited {
background: url('images/icon-comments.gif') no-repeat 0 3px;
padding: 1px 0 1px 18px;
}
.post img {
padding: 5px;
border: 4px solid #e2e2e2;
}
/* footer */
#footer {
color: #dedede;
font-size: 20px;
text-align: center;
padding-top: 20px;
text-transform: lowercase;
}
#footer a, #footer a:visited {
color: #dedede;
}
#footer a:hover {
color: #bbb;
}
But beyond this, there are some other styles we should add. When WordPress spits out items that include page lists, category lists, archive lists, images, galleries, and so on, it gives many of these items a particular class name. If you know these class names, you can prepare your stylesheet to take advantage of them.
When you add an image to a post or page, WordPress gives you the option to have it to the right, left, or at the centre of the text. Depending on what you choose, WordPress will have the image styled as alignleft,alignright, or aligncenter. Let's add alignleft and alignright to the stylesheet:
/* WordPress styles */
.alignright {
float: right;
}
.alignleft {
float: left;
}
A class is another necessity for the images that WordPress uses when you add an image with a caption. There are three essential entries you'll want to make in your stylesheet to style the caption box, which are:
.wp-caption {
padding-top: 5px;
border: 4px solid #e2e2e2;
text-align: center;
background-color: #fff;
margin: 10px;
}
.wp-caption img {
margin: 0;
padding: 0;
border: 0 none;
}
.wp-caption p.wp-caption-text {
font-size: 11px;
line-height: 17px;
padding: 0 4px 5px;
margin: 0;
}
I've designed my caption box to match my captionless images that I styled in .post img.
Another frequently used class is current_page_item. On the page you are currently working, WordPress adds this to the list item in the pages menu. This gives you the ability to visually mark a page that the user is currently viewing. I'll mark it with an underline using the following code:
#mainnav .current_page_item a,
#mainnav .current_page_item a:visited {
text-decoration: underline;
}
WordPress uses many other classes that you can take advantage of when building your stylesheet.
Now that you've got your HTML and CSS lined up, you're ready for the next step: turning the HTML build into a WordPress theme.
[edit] Converting your build into a theme
You'll be turning your HTML build into a theme, which is composed of a number of template files and other scripts. We are going to first dig into the inner workings of a theme so as to get familiar with how it's put together. Then we'll actually turn the HTML build into a theme folder that WordPress can use. And finally, we'll replace the dummy text in your build with WordPress functions that spit out content.
[edit] Creating the theme folder
The first step to turning your HTML build into a theme is to create your theme folder and give it everything it needs to be recognized as a theme by WordPress. Let's look at an overview of the steps and then take them one by one:
1. Name your folder and create backup copies of your build files.
2. Prepare the essential files.
3. Add a screenshot of your theme called screenshot.png.
4. Upload your folder.
5. Activate your theme.
Let's take these steps one by one now:
1. Name your folder and make backup copies.
You'll want to give your build folder a sensible name. I'm naming my theme Muffin Top because of the muffins in my header image. I'll name the folder muffintop.
Now I suggest creating backup copies of your HTML and CSS files. As you'll eventually be breaking up your build into template files, you can easily lose track of where your code came from. By keeping a copy of your original build, you'll be able to go back to them for reference.
2. Prepare the essential files.
WordPress has only the following two requirements to recognize your folder as a theme:
o A file called index.php
o A file called style.css with an introductory comment
Just re-name index.html to index.php and that takes care of the first requirement.
To satisfy the second requirement, your stylesheet needs to have an introductory comment that describes the basic information for the whole theme: title, author, and so on. Also, it has to be at the very top of the stylesheet. I've added this comment to my style.css file.
/* Theme Name: Muffin Top Theme URI: http://springthistle.com/wordpress/projects Description: Design created especially for April's Food Blog for WordPress Complete. Version: 1.0 Author: April Hodge Silver Author URI: http://springthistle.com/ Tags: brown, fixed width, two columns, widgets, food */
When you add this comment section to your stylesheet, just replace all of the details with those that are relevant to your theme.
3. Add a screenshot.
Remember when we first learned how to activate a new theme that there were thumbnail versions of the themes in your Appearance tab? You'll want a thumbnail of your own design. It has to be a PNG file and with the name screenshot.png. Just do the following:
- Flatten your design in Photoshop.
- Change the image size to 300px.
Save for web as a PNG-8.
Name your file screenshot.pngand save it in your build folder.
Now that I've got my theme ready to upload, my theme folder looks like this:
4. Upload your folder.
Using your FTP software, upload your template folder to wp-content/themes/ in your WordPress build. It will share the themes folder with default and classic (and any other themes you've added since you installed WordPress). In the next image, you can see my muffintop theme (highlighted) living in the themes folder:
5. Activate your theme.
You've got the absolute basic necessities in there now, so you can activate your theme (though it won't look like much yet). Log in to your WP Admin and navigate to Appearance. There you'll see your theme waiting for you.
When you click on the thumbnail or theme title of your theme, an overlay window will appear on top of the page with a preview of what your site will look like. Don't be alarmed if it's not perfect. The stylesheet is not yet being pulled in correctly.
Click on the link in the upper-right corner to activate your theme. This is another good reason to have a development server. You wouldn't want to have this incomplete theme active on a live site while you finish the final pieces!
Speaking of final pieces, your theme is now ready to have all of the WordPress content added.
[edit] Adding WordPress content
Right now, your index.php file is your only theme file. We'll be breaking it up into template files a bit later. First, we need to replace the dummy text with WordPress functions that will spit out your actual content into your theme.
[edit] The <head> tag
First we'll set up the <head> section of your HTML file. Let's start with the stylesheet. WordPress provides a function that knows where your stylesheet lives. Replace the code style.css in your index.php file with this:
<?php bloginfo('stylesheet_url'); ?>
Using this function instead of a hardcoded call to the stylesheet will come in handy if you ever have a need to re-name your theme folder. Now when you look at your site, you see your theme, along with the dummy text, in all its glory.
You need to add another important chunk of code to put header tags into your theme for the RSS feed, the Atom feed, the pingback URL, and other miscellaneous WordPress stuff. Add these three lines in your <head> section:
<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'); ?>" />
And add this line right before the closing </head> tag:<?php wp_head(); ?>
</pre>
Finally, you'll want WordPress to be able to place your blog's name in the title bar of your browser. So replace your dummy title with this code in the title tag:
'''<?php wp_title('«', true, 'right'); ?> <?php bloginfo('name'); ?>'''
This will spit out the title of the current page, then an arrow, and then the title of your blog. Your header now looks something like this:
<head>
<title><?php wp_title('«',
true, 'right'); ?> <?php bloginfo('name'); ?></title>
<meta name="robots" content="index, follow"></meta>
<meta name="distribution" content="global"></meta>
<meta name="description" content="
discovering new recipes and food daily"></meta>
<meta name="keywords" content=
"april hodge silver, food, recipes"></meta>
<style type="text/css"> @import
url("<?php bloginfo('stylesheet_url'); ?>"); </style>
<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>
[edit] The header and footer
It's time to start adding the content that you can see. Let's first replace the dummy text in the main navigation bar and header with WordPress content tags.
WordPress will generate a linked list of pages for you, as I mentioned earlier. Just replace your dummy text with this useful tag, placing it inside the<?php wp_list_pages('title_li=' ); ?>
The reason for the title_li= part is that by default this function will add a title to your list of pages. In this case, I don't want it and so I have to declare it blank.
Next, you can replace your dummy blog title and dummy blog description with the following two tags:
<?php bloginfo('name'); ?>
<?php bloginfo('description'); ?>
These tags pull information from where you set the blog name and description in the WP Admin, and you can simply change them from the Settings | General page.
And finally, if you want to link the blog title in the header to the homepage of the blog, use this for the URL:<?php echo get_option('home'); ?>/
Now the part of your HTML that describes the header looks like this:
<div id="header">
<div id="mainnav">
<ul>
<?php wp_list_pages('title_li=' ); ?>
</ul>
</div><!-- /mainnav -->
<h1>
<a href="<?php echo get_option('home');
?>/"> <?php bloginfo('name'); ?></a>
</h1>
<div id="description"><?php bloginfo('description');
?></div>
</div><!-- /header -->
Are you wondering why you should bother with some of this when you could have just typed your blog title, URL, and description to the theme? One reason is that if you ever want to change your blog's title, you can just do it in one quick step in the WP Admin and it will change all over your site. The other reason is that if you want to share your theme with others, you'll need to give them the ability to easily change the name through their own WP Admin panel.
Now when I refresh the site, my dummy text in the header has been replaced with actual content from my blog:
Just to tie things up, I'm going to add the same code to my footer for displaying the home URL and blog title. My footer section now looks like this:
<div id="footer">
<a href="<?php echo get_option('home'); ?>/">
<?php bloginfo('name'); ?></a> is powered by wordpress
</div><!-- /footer -->
[edit] The sidebar
Now we can move along to adding WordPress-generated content in the sidebar, which still has just the dummy text:
<?php wp_list_categories('title_li='); ?>
Just like with pages, you need to turn off the default title by using title_li=.
Now, replace your dummy text for the list of archives with this tag: <?php wp_get_archives(); ?>
The next item down, the search, is also a simple matter of pasting in the WordPress code. In this case, it's a relatively new function:
<?php get_search_form(); ?>
Now, the part of your HTML that describes the sidebar looks something like this:
<div id="sidebar">
<h3 class="first">Categories</h3>
<ul>
<?php wp_list_categories('title_li='); ?>
</ul>
<h3>Archives</h3>
<ul>
<?php wp_get_archives(); ?>
</ul>
<h3>Search</h3>
<?php get_search_form(); ?>
</div><!-- /sidebar -->
Save this file and re-load your theme, and you'll see that your dummy text has been replaced with WordPress output for the Categories and Archives lists, and the Search form.
In my case, the search form doesn't look quite the way I want:
So I'm going to add these WordPress styles to my stylesheet to hide the label and the submit button:
.hidden, #searchsubmit {
display: none;
}
[edit] Main column the loop
The most important part of the WordPress code comes next. It's called the loop and it's an essential part of your theme. The loop's job is to display your posts in chronological order, choosing only those posts which are appropriate. You need to put all of your other post tags inside the loop. The basic loop text, which has to surround your post information, is displayed using this code:
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<div class="post">
<!-- individual post information -->
</div>
<?php endwhile; ?>
<div class="navigation">
<div class="alignleft">
<?php next_posts_link('« Older Entries') ?></div>
<div class="alignright">
<?php previous_posts_link('Newer Entries »')?></div>
</div>
<?php else : ?>
<h2 class="center">Not Found</h2>
<p class="center">
Sorry, but you are looking for something that isn't here.</p>
<?php get_search_form(); ?>
<?php endif; ?>
There are three basic parts of the loop:
- Individual post information
- Next and previous posts links
- What to do if there are no appropriate posts
Note that you can style your next and previous post links using the navigation class. We already added alignright and alignleft, so we're all set with them. Also, we will reuse the handy get_search_form() function that we used in the sidebar.
We are going to paste the loop we just saw into our index.php file in the place where the main column lives. In my case, that's the div with id="copy". First, however, let's replace the comment with the dummy text from our HTML build. Now the part of your HTML that describes your main column looks something like this:
<div id="copy">
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<div class="post">
<h2><a href="#">Butternut Squash Soup</a></h2>
<div class="post-date">November 21st, 2008</div>
<p>My first paragraph.</p>
<p>My second paragraph.</p>
<div class="categories">Posted in: <a href="#">Recipes Found</a></div>
<div class="tags">Tags: <a href="#">autumn</a>, <a href="#">easy</a>, <a href="#">soups</a> </div>
<div class="comments"> <a href="#">5 Comments</a></div>
</div>
<?php endwhile; ?>
<div class="navigation">
<div class="alignleft">
<?php next_posts_link('« Older Entries') ?>
</div>
<div class="alignright">
<?php previous_posts_link('Newer Entries »')?>
</div>
</div>
<?php else : ?>
<h2 class="center">Not Found</h2>
<p class="center">Sorry,
but you are looking for something that isn't here.</p>
<?php get_search_form(); ?>
<?php endif; ?>
</div><!-- /copy -->
Now that we've got the basic loop in the theme, we can replace our dummy text with more WordPress tags.
The post title and the URL that links to the post can be replaced with these two WordPress tags:
<?php the_permalink() ?> <?php the_title(); ?>
The date of the post is expressed by this tag:
<?php the_time('F jS, Y') ?>
The funny-looking code, F jS, Y, is PHP date formatting code.
|
'Learning more You can look up for more options on how to display the date on a PHP website: http://us3.php.net/manual/en/function.date.php.</blockquote> |
Now replace your dummy placeholder text for the actual content of the post with this code:
<?php the_content(); ?>
Your categories and tags lists get expressed by the following two tags:
<?php the_category(', ') ?>
<?php the_tags(); ?>
By default, the the_category()function spits out your categories in a linked list. Because I want them to display categories separated by comments, I have to add the ','argument that tells the function to put something else. In this case, it is a comma and a space between category names.
Finally, you can set up your comments link with this tag:
<?php comments_popup_link('No Comments »', '1 Comment »', '% Comments »'); ?>
Here, you can see that there are three options separated by commas:
1. The first option tells WordPress the text that it has to display when there are no comments.
2. The second option tells WordPress the text that it has to display when there is just one comment.
3. The third option tells WordPress text that it has to display for more than one comment. The percent symbol (%) gets replaced with the actual number of existing comments.
The section of your HTML that contains your main loop now looks something like this:
<div id="copy">
<?php if (have_posts()) : ?>
<?php while (have_posts()) :
the_post(); ?>
<div class="post">
<h2>
<a href="<?php the_permalink() ?>"> <?php the_title(); ?></a>
</h2>
<div class="post-date">
<?php the_time('F jS, Y') ?></div>
<?php the_content(); ?>
<div class="categories">Posted in:
<?php the_category(', ') ?>
</div>
<div class="tags">Tags:
<?php the_tags(); ?>
</div>
<div class="comments"> <?php comments_popup_link('No Comments »', '1 Comment »', '% Comments »'); ?> </div>
</div>
<?php endwhile; ?>
<div class="navigation">
<div class="alignleft"> <?php next_posts_link('« Older Entries') ?> </div>
<div class="alignright"> <?php previous_posts_link('Newer Entries »') ?> </div>
</div>
<?php else : ?>
<h2 class="center">Not Found</h2>
<p class="center">Sorry, but you are looking for something that isn't here.</p>
<?php get_search_form(); ?>
<?php endif; ?>
</div><!-- /copy -->
Phew! Now save your index.php and re-load your website. Your theme is in action!
[edit] Creating templates within your theme
You've now got a functional basic template for your theme. It works great on the main blog page and successfully loads content for anything you can click on in your site.
However, we want slightly different templates for other types of content on our site. For example, a single post page needs to have a comments form where visitors can post comments. A single page doesn't need to have date, tags, or categories information, but the category page should show the category name.
Before we can create other templates, we need to break up the main index.php file into parts so that these different templates can share the common elements. I've mentioned many times the importance of the header, sidebar, and footer. We're going to break them up now. First, let's take a quick look at how it works.
[edit] Understanding the WordPress theme
The WordPress theme is actually composed of a number of template files. This allows the different parts of the site (such as frontend, blog archive, page, single post, search results, and so on) to have different purposes. Breaking the index.php file into template files allows us to not only share some common parts of the design, but also have different code in the different parts.
As I mentioned earlier, we'll soon be breaking up the four main pieces of the design (header, sidebar, main column, and footer) so that WordPress can make a good use of them. That's because while the header and footer are probably shared by all pages, the content in the main column will be different. Also, you may want the sidebar on some pages, but not on others.
We'll first create these template files, and then move on to other, more optional template files.
[edit] Breaking it up
We're going to break up the index.php file into these four files:
-
index.php -
header.php -
footer.php -
sidebar.php
[edit] header.php
First, cut out the entire top of your index.php file. This means cutting the doctype declaration, the (head), any miscellaneous opening tags, and the header div. In my case, I'm cutting out all the way from this, the first few lines:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> ... through and including these lines: </div><!-- /header --> <div id="content">
Then, paste this text into a new file called header.php that you create within your theme folder.
Now at the very top of the index.php file (that is, where you just cut the header text from) write in this line of WordPress PHP code:
<?php get_header(); ?>
This is a WordPress function that includes the header.php file you just created. If you save everything and re-load your website now, nothing should change. If something changes, then you've made a mistake.
[edit] footer.php
Next, we will create the footer file. To create this, first cut out all of the text at the very bottom of the index.php file, from the footer div, and all the way through the </html> tag. In my case, this is the entire text I cut:
<div style="clear: both"> </div>
</div><!-- /content -->
<div id="footer">
<a href="<?php echo get_option('home'); ?>/">
<?php bloginfo('name'); ?></a> is powered by wordpress
</div><!-- /footer -->
</div><!-- /container -->
</body>
</html>
Paste the text you just cut into a new footer.php file that you create within your theme folder.
Now at the very bottom of the index.php file (where you just cut the footer text from) write in this line of WordPress PHP code:
<?php get_footer(); ?>
This is a special WordPress function that includes the footer.php file you just created. Again, you should save everything and re-load your website to make sure nothing changes.
[edit] sidebar.php
There is just one more essential template file to create. For this one, cut out the entire div containing your sidebar. In my case, it's this text:
<div id="sidebar">
<h3 class="first">Categories</h3>
<ul>
<?php wp_list_categories('title_li='); ?>
</ul>
<h3>Archives</h3>
<ul>
<?php wp_get_archives(); ?>
</ul>
<h3>Search</h3>
<?php get_search_form(); ?>
</div><!-- /sidebar -->
Paste this text into a new file in your theme folder called sidebar.php
Now in index.php, add this function in the place you just cut your sidebar from:
<?php get_sidebar(); ?>
This will include the sidebar. In the case of my design, I will want the sidebar on every page. So it's not very crucial for it to be a separate file. I could have included it in the footer.php file. But in some templates, including the default template that came with your WordPress installation, the designer prefers to not include the sidebar in some views such as the Page and single posts.
[edit] Your four template files
You've now got four template files in your themefolder: header.php, footer.php, sidebar.php, and the now-much-shorter index.php. By the way, my index.php file now has only the three WordPress functions and the loop. This is the entire file:
<?php get_header(); ?>
<div id="copy">
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<div class="post">
<h2><a href="<?php the_permalink() ?>"> <?php the_title(); ?></a></h2>
<div class="post-date"><?php the_time('F jS, Y') ?></div>
<?php the_content(); ?>
<div class="categories">Posted in: <?php the_category(', ') ?></div>
<div class="tags">Tags: <?php the_tags(); ?></div>
<div class="comments"> <?php comments_popup_link('No Comments »
', '1 Comment »', '% Comments »'); ?> </div>
</div>
<?php endwhile; ?>
<div class="navigation">
<div class="alignleft"> <?php next_posts_link('« Older Entries') ?>
</div>
<div class="alignright"> <?php previous_posts_link('Newer Entries »') ?>
</div>
</div>
<?php else : ?>
<h2 class="center">Not Found</h2>
<p class="center">Sorry, but you are looking for something that isn't here.</p>
<?php get_search_form(); ?>
<?php endif; ?>
</div><!-- /copy -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>
After creating individual template files my theme folder looks like this:
This whole cutting-and-pasting process to create these four files was just to set the scene for the real goal of making alternative template files.
[edit] Archive template
WordPress is now using the index.php template file for every view on your site. Let's make a new file one that will be used when viewing a monthly archive, category archive, or tag archive.
To create your archive template, make a copy of index.php and name this copy archive.php. When someone is viewing a category or a monthly archive of my site, I want them to see an excerpt of the post content instead of the full post content. So, I edit archive.php and replace the_content() with the_excerpt().
Now navigate to a monthly archive on the site by clicking on one of the month names in the sidebar. This is how it will look now:
Instead of showing the full body of the post, WordPress has printed the first 55 words of the content followed by [ ]. But if you go back to the main page of the blog, you can see that it still displays the full content. This is the power of template files.
Let's make one more change to the archive template. I'd like it to display a message that lets the users know what type of archive page they are on. To do that, just add this code inside copy div:
<h2 class="pagetitle">
<?php if (is_category()) { ?>
Archive for the '<?php single_cat_title(); ?>' Category
<?php } elseif( is_tag() ) { ?>
Posts Tagged '<?php single_tag_title(); ?>'
<?php } elseif (is_month()) { ?>
Archive for <?php the_time('F, Y'); ?>
<?php } ?>
</h2>
I also added a new style to my stylesheet to color this class dark grey.
Now when I click on a month, category, or tag, I see a new heading at the top of the page that lets me know where I am:
[edit] Single template
The next template we need to create is for the single post view. To view a single post, you can usually just click on the post title. Right now, the single post page looks like the site's front page (because it's using index.php); except with just one post. At the very least, this page should have a comment form added!
To get started, again make a copy of index.php and name the copy single.php. This is the template that WordPress will look for first when it's serving a single post. If it doesn't find single.php, it'll use index.php.
To add a comment form to single.php, simply add the following code just before <?php endwhile; ?>:
<?php comments_template(); ?>
Now when you view an individual post, you'll see that the comment form has appeared.
WordPress prints the <textarea> tag with width="100%", so you may want to add something like this to your stylesheet:
#copy textarea {
width: 550px;
}
There are two other changes I recommend for single.php:
1. Remove the code for next posts and previous posts.
2. Add code to display links for next post and previous post.
To remove the code for the previous and next posts, which is only relevant on pages that show multiple posts at a time, just delete the entire div with class="navigation":
<div class="navigation">
<div class="alignleft"> <?php next_posts_link('« Older Entries') ?></div>
<div class="alignright"> <?php previous_posts_link('Newer Entries »') ?></div>
</div>
<pre>
To add links to the next and previous single post, insert this code near the top of the page just above class="post"<code>div</code>:
<pre>
<div class="navigation">
<div class="alignleft"> <?php previous_post_link('« %link') ?></div>
<div class="alignright"> <?php next_post_link('%link »') ?></div>
</div>
Now your next and previous posts are linked to the current post page by their titles like this:
[edit] Page template
The last template we're going to create is for the static page view. On my food blog site that would be the About page, for example:
I want to get rid of the date, categories, and tags because they don't apply to my pages. Make a copy of index.php and name the copy page.php. When you edit the file, remove the code for the date, categories, and tags:
<div class="post-date"><?php the_time('F jS, Y') ?></div>
<div class="categories">Posted in: <?php the_category(',')
?></div>
<div class="tags">Tags: <?php the_tags(); ?>
</div>
As I do not want to let visitors comment on pages, but only posts, I'll remove the comments link as well:
<div class="comments">
<?php comments_popup_link('No Comments »
','1 Comment »', '% Comments »'); ?>
</div>
For extra credit, you can remove div with class="post" (but keep its contents) to remove the grey underline, and then remove the entire div with class="navigation" because it's not relevant to static pages. Now my About page looks much cleaner.
[edit] Other WordPress templates
In addition to archive.php, single.php, and page.php, there are a number of other standard template files that WordPress looks for before using index.php for particular views. We're not going to create those files here, but you should feel free to experiment on your WordPress installation. These files are:
- archive.php trumps index.php when a category, tag, date, or author page is viewed
- single.php trumps index.php when an individual post is viewed
- page.php trumps index.php when looking at a static page
- search.php trumps index.php when the results from a search are viewed
- 404.php trumps index.php when the URI address finds no existing content.
- home.php trumps index.php when the home page is viewed
- A custom template page, selected via the WP Admin, trumps page.php when that particular page is viewed
- category.php trumps archive.php, which trumps index.php when a category is viewed
- A custom category-ID.php page trumps category.php when a particular category is viewed
- tag.phptrumps archive.php, which trumps index.php when a tag page is viewed
- A custom tag-tagname.php page trumps tag.php when a particular tag is viewed
- author.php trumps archive.phpwhen an author page is viewed
- date.php trumps archive.php when a date page is viewed
|
Learning more You can find a detailed flow chart of the template hierarchy here: http://codex.wordpress.org/Template_Hierarchy. |
Next, we'll explore making custom templates for pages.
[edit] Creating and using a custom template
WordPress allows you to create custom templates. These can be used only for pages, and not posts. In Tutorial 4 we discussed applying the one custom template called Archives that comes with WordPress to one of the pages in the site. Now that we've moved from the default theme to this new custom theme, we no longer have that template. Let's create an archives template for this new theme.
If you click on Blog Archives in the page header's main navigation menu, you'll see that it's displaying only the page content:
It really should display a complete list of categories, monthly archives, and tags in use on the site. To do this, we need to create a template. These are the steps we'll take:
1. Create the template file by copying an existing file in the custom theme.
2. Add WordPress functions to the template file.
3. Tell the Blog Archives page to use the custom template file instead of page.php.
Let's get started.
1. Create the template file.
Make a copy of page.php within your theme and give it a new name. I like to prepend all of my custom template files with tmpl_ so that they are sorted separately from all the WordPress template files that I will create. I'll call this file tmpl_archives.php.
In order for WordPress to be able to identify this file as a template file, we need to add a specially styled comment to the top of the page (just as we did with style.css). The comment needs to be formatted like this:
<?php /* Template Name: Blog Archives */ ?>
In the WP Admin panel the template will be identified by this template name, so make sure the name signals to you what the template is for.
2. Add WordPress functions.
Edit your new template file and remove the loop entirely. That is, remove it from <?php if (have_posts()) : ?> to <?php endif; ?>, and everything in between. Instead of the loop, we'll add some WordPress functions that will display what we want. Because we are creating a custom template, we can add any of the WordPress functions we discovered earlier in the tutorial as well as any other WordPress functions (see Tutorial 11).
First, let's add a complete list of categories and monthly archives. In the spot where the loop was present, insert this code:
<h3>Categories</h3>
<ul>
<?php wp_list_categories('title_li='); ?>
</ul>
<h3>Archives</h3>
<ul>
<?php wp_get_archives(); ?>
</ul>
This should look familiar I copied and pasted it directly from sidebar.php.
3. Apply the template to a page.
Leave your HTML editor and log in to your WP Admin. You need to edit or create the page in which you want to use this template. In this case, I already created the required page and so I'll edit Blog Archives.
On the Edit Page page, look for the Template menu within the Attributes box (at the right, by default).
Change it from Default Template to Blog Archives and click on Update Page. (Note that you can also change a page's template using Quick Edit on the Pages | Edit page). Now when you return to the frontend of your website and re-load the Blog Archives page, you'll see that the categories and monthly archives are listed:
To make this a bit more exciting, let's add one more WordPress function to tmpl_archives.php. Underneath the monthly list, add this code:
<h3>Tags</h3>
<?php wp_tag_cloud(''); ?>
This function prints all of the tags in use on the site, one after the other (inline, not in a list format), and increases the font size of the tags that have been used more often. Save the template file and re-load the Blog Archives page to see the tag cloud (not so impressive right now as I have so few posts and tags in use), shown as follows:
There is no limit to the number of custom templates you can make in your WordPress theme.
[edit] Making your theme widget-friendly
If you want to be able to use the widgets in your theme, you will need to make your theme widget-friendly (also know as widgetizing your theme). Widgetizing is actually pretty easy, and involves just the following three steps:
1. Ensure that your sidebar is one big, unordered list.
2. Add a functions.php file with a special function in it.
2. Add conditional code to your sidebar.
Nearly all of the PHP code you need to add in steps 2 and 3 can be pasted from already existing files, so the non-programmers out there shouldn't be too intimidated! Let's get started.
[edit] Making sure your sidebar is one big (ul) tag
This is actually not a requirement, but it's becoming the standard for WordPress sidebars among the theme-writing community. As we will be editing the sidebar anyway, let's modify it first to be one big (ul) tag. Another standard is that the headings should be (h2), so I'll make that change as well.
For your sidebar to be one long and unordered list, this means every item in the list will be a header and a list. Once I modify my sidebar.php, it looks like this:
<div id="sidebar">
<ul>
<li>
<h2 class="first">Categories</h2>
<ul>
<?php wp_list_categories('title_li='); ?>
</ul>
</li>
<li>
<h2>Archives</h2>
<ul>
<?php wp_get_archives(); ?>
</ul>
</li>
<li>
<h2>Search</h2>
<?php get_search_form(); ?>
</li>
</ul>
</div><!-- /sidebar -->
All I did to change my sidebar.php was add a (ul)at the beginning of the sidebar div and a (/ul) at the end, and I put each item (categories, archives, and search) into a (li) tag.
After making these changes, I also tweaked my stylesheet so that the display isn't affected negatively.
[edit] Adding functions.php
Your theme folder now needs a new file named functions.php with the following as its contents:
<?php
if ( function_exists('register_sidebar') )
register_sidebar();
?>
If your sidebar.php is not in a single big (ul), or your headers are not (h2)s, then you're going to need slightly more complicated code in your functions.php file. You can look up those details in the WordPress Codex.
[edit] Adding conditional code to sidebar
The third and final step is to add a conditional code to your sidebar.php. This code says, "If the person using this theme wants to use widgets, don't show this stuff. If he or she doesn't want to use widgets, do show this stuff." That way, a person not using widgets will see whatever default items you put into the sidebar.php.
At the top of the sidebar.php, just under the opening (ul)tag, add this line of code:
<?php if ( !function_exists('dynamic_sidebar')
|| !dynamic_sidebar() ): ?>
And at the bottom of the sidebar, just above the closing </ul>, add this line of code: <?php endif; ?>
[edit] Adding some widgets
Your theme is ready for widgets! You can now go to WP Admin, navigate to Appearance | Widgets, and add widgets. For example, here I added Recent Posts:
Be sure to click on Save Changes and then return to your website and re-load the page. The default items you had placed in the sidebar have been replaced with widgets, as shown in this screenshot:
[edit] Further widgetizing options
What we just covered is the simplest way to widgetize a theme. There are actually a lot of options that you could utilize when adding the code to your sidebar.php and functions.php pages. For example, there are options that allow you to:
- Widgetize more than one sidebar
- Widgetize a part of your sidebar, but leave in some default items
- Widgetize a sidebar that is not one big long (ul)
- Widgetize a sidebar whose item titles are not (h2)
- Customize the search form widget
Learning more
To learn about the variety of options available and how to take advantage of them, take a look at the Codex: http://codex.wordpress.org/Widgetizing_Themes.
[edit] Sharing your theme
If you want to turn your template into a package that other people can use, you just have to take the following steps:
1. Remove all unnecessary files from your theme's folder. Be sure you don't have backup versions or old copies of any of your files. If you do delete any files, be sure to re-test your theme to ensure you didn't accidentally delete something important.
2. Make sure the comment at the top of the style.css file is complete and accurate.
3. Create a Readme.txt file. This is a good place to let future users know what version of WordPress your theme is compatible with and if it has any special features or requirements.
4. Zip the folder and post your theme ZIP file on your own website for people to download, or post it directly in the WordPress Theme Directory at http://wordpress.org/extend/themes.
[edit] Summary
You have now crossed to the other side of the theming world. You have learned how to make your own theme. With just the most basic HTML and CSS abilities, you can create a design and turn it into a fully functional WordPress theme.
In this tutorial we saw how to:
- Turn your HTML build into a basic theme
- Create WordPress templates to influence the display of a variety of views on your site
- Create custom templates to be applied to pages within your site
- Make your new theme widget-ready
- Share your theme with everyone else in the WordPress community
[edit] Additional References
- For instructions on Troubleshooting WordPress Installation, click here
- For instructions on Developing WordPress 2.7 Themes, click here
- For instructions on Set Up for Word Press 2.7, click here
- For instructions on Theming Wordpress, click here
- For instructions on Troubleshooting WordPress MU 2.8, click here
- For instructions on Installing WordPress MU, click here
- For instructions on Customizing site using WordPress MU 2.8, click here
- For instructions on installing and setting up WordPress, click here
- For instructions on Configuring WordPress Themes, click here
[edit] Source
The source of this content is Chapter 6: Developing WordPress 2.7 Themes of WordPress 2.7 Complete by April Hodge Silver (Packt Publishing, 2009).




