How to Build a Custom WordPress Theme from Scratch
If you’re confident with your CSS and HTML, it’s not hard at all to step up to the challenge of building a custom WordPress theme. This overview shows the process of how my latest custom WordPress theme was built from design concept through to completed theme. See how the static design is split up into the various WordPress theme files, and discover how the simple PHP snippets can add that dynamic functionality of a blog.
The design concept
The theme I'm working on is named Sticky. The main feature of the design is its sticky sidebar (hence the name Sticky!), which stays in place while the main content scrolls past it. There's also a few fancy effects such as the shadows and inset text appearance that I'll be building with the help of CSS3.
With the post focusing on the production of the theme, I won't go into too many details on how the design was built, but you can see from the Photoshop previews that it uses a 16 column grid with 24px baseline; a fairly muted colour palette of a beige and grey, with a dark red as a highlighting colour for links; typography is set to serif font throughout for that touch of class!; and the whole design uses very subtle textures to give a more realistic and tactile feel.
Anatomy of a WordPress theme
Before getting stuck into the build process, it's important to know how WordPress themes work. If you've looked at any prebuilt theme, you'll notice that it's all contained in a folder, and there's around 12 core files. Some themes, including the Default WordPress theme, include more files which allow extra customisation, but aren't mandatory additions. Here's an overview of the main files you'll be working with:
- header.php - Contains everything you'd want to appear at the top of your site.
- index.php - The core file that loads your theme, also acts as the homepage (unless you set your blog to display a static page).
- sidebar.php - Contains everything you'd want to appear in a sidebar.
- footer.php - Contains everything you'd want to appear at the bottom of your site.
- archive.php - The template file used when viewing categories, dates, posts by author, etc.
- single.php - The template file that's used when viewing an individual post.
- comments.php - Called at the bottom of the single.php file to enable the comments section.
- page.php - Similar to single.php, but used for WordPress pages.
- search.php - The template file used to display search results.
- 404.php - The template file that displays when a 404 error occurs.
- style.css - All the styling for your theme goes here.
- functions.php - A file that can be used to configure the WordPress core, without editing core files.
Each of these files then contains a series of PHP template tags. These tags tell WordPress where to insert the dynamic content. A good example is the
<?php the_title(); ?> tag, which pulls in the post title and displays it in your theme:
There's stacks of template tags available, and more often than not there will be one that does exactly what you want - It's just a case of finding it in the WordPress Codex. I've seen many themes that include some complicated PHP coding to achieve a function that's already available as a simple template tag, so remember to browse the WordPress Codex whenever you're stuck!
The basic HTML and CSS
Seeing as a WordPress Theme is basically made up of HTML and CSS, but with a few extra PHP tags inserted here and there, it's important to build your website concept as you would a good old static site. I tend to build the complete page with dummy content, then do my browser testing before starting work on the theme. Here's an overview of my HTML code:
Building the WordPress theme
Configuring the stylesheet
All the details of a WordPress theme are contained within the stylesheet. At the top of your style.css add the following code, then amend the details to suit.
/* Theme Name: Sticky Theme URI: http://www.blog.spoongraphics.co.uk Description: Sticky WordPress theme Version: 1 Author: Chris Spooner Author URI: http://www.spoongraphics.co.uk */
Also remember to ensure that the paths to any background images are correct in your CSS properties.
Populating the header
Open up your header.php file, and paste in the head section from your concept HTML file. Then we need to go in and replace certain elements with the correct WordPress template tags to ensure it all works correctly. First we can strip out the title and insert some WordPress template tags.
bsg_title(); will display the title of the page, which is followed by
bloginfo('name'), which will place the blog's name (set in the admin panel).
bloginfo('template_url'); tag. This renders the path to the theme folder in HTML.
</head> tag, add
bsg_head();, this is where any additional head elements are placed by WordPress plugins etc.
Building the index
The next step is to flesh out the main body of the website. Open up the index.php file and paste in the main bulk of the concept HTML.
This is where all the meaty stuff begins! At the top we have the
get_sidebar(); tags, these call the header.php and sidebar.php files and render the content according to where the tags appear. The WordPress loop is then used to check for content, if there's content available it's rendered onto the page. Within the loop we have various tags that display the post information, such as
the_permalink();. These are wrapped in the usual HTML elements according to their purpose, so the permalink is wrapped in an anchor tag and the title in a header 2 tag.
the_post_thumbnail(); is an optional addition, but this code simply makes use of the new post thumbnail feature in WordPress 2.9. Below this is where we want all the article content to appear, and it's simply inserted with the
In the meta section, there's various tags that can display specific information about the post, such as the time it was posted, the category it was posted in and how many comments it has. All of these can be called using a template tag such as
the_time('F jS, Y');, each one also has certain parameters to further tailor the tag to suit. For instance the time can be changed to display in various formats. This is where the WordPress Codex comes in handy, to double check any parameter options you have.
Skipping down a little, the loop then displays an
else tag, which will display if no posts are found, and the loop is finally closed with an
endif. At the bottom we can use
get_footer(); to call the rest of the page, which resides in the footer.php file.
Filling out the sidebar
The sidebar in my design is where the list of pages and categories are held. The sidebar.php file was called from the index using the
get_sidebar(); tag, so anything within this sidebar.php file is inserted into the theme in the right place.
There's only three elements in my sidebar; the logo, the pages list and the categories list. The logo is wrapped in a h1 tag and uses the tags
echo get_option('home'); and
bloginfo('name'); to render the URL of the blog and the blog name in the appropriate places. The pages list is simply added using
bsg_list_pages('title_li=' );, where the parameter stops the usual 'Pages' title from being added. The list of categories is also pretty similar,
bsg_list_categories(); is used along with various parameters to customise the tag, such as
show_count=0 to stop WordPress showing how many posts appear in each category,
hide_empty=0 to show the category even if it doesn't have any posts, and
exclude=1 to exclude the category with the ID of 1, which is the Uncategorized category.
Rounding off the footer
The footer.php file is probably the most simple file for this theme. The only thing that goes in here is the
bsg_footer(); tag just before the
</body>, so that any extra info can be inserted in the correct place. In your theme you might display a list of popular posts, latest comments or a list of archives. All of these can be done using specific WordPress template tags.
Creating the archive
The archive.php file is used to display a list of posts whenever they're viewed by category, by author, by tag etc. It's basically the same as the index file, but with the addition of a tag at the very top that renders a useful page title, so the user knows where they are. 'Browsing the Articles category' for instance.
Constructing the page and single view
WordPress is made up of posts and pages. Posts use the single.php template file, whereas pages use the page.php template file. They're pretty much the same, apart from that you tend to include the
comments_template(); tag for posts, and not for pages.
Configuring the comments template
I usually copy the comments template from the Default theme, then make my changes because it includes some important lines of WordPress code.
Once you have a comments file created, the same file can be used on pretty much all your future WordPress theme projects. The hard part is finding the CSS hooks to style up your comments. This is when the Firebug plugin for Firefox comes in handy. Otherwise, the comments file just has a few parameter options here and there that you might want to tweak. One that springs to mind is the
avatar_size parameter, which tells WordPress how large to make the user's Gravatar image.
Finishing off the search and 404
This pretty much just leaves the search feature, which is basically a copy of the archive.php file. A handy additions might be the line
Search results for <?php the_search_query() ?>, which will display the user's search term as a title. As for the 404 page, this is where your creativity comes into play. This template can be configured to display whatever error information you like, just remember to include the usual
get_footer(); tags where necessary
The final theme
When all your theme files are complete, it's time to install a test and see how it all works. Filling out a temporary install with a couple of dummy posts can really help test drive a theme surface any errors. If you take a glance at the source code, you'll see how each of the template files has been inserted into the correct place, as well as how content has been dynamically generated by the template tags.
If you like the look of the Sticky theme, it's due to be released exclusively to Access All Areas members next week.