Creating a WordPress Theme from Scratch: Theme files, styles, header and footer

Ready to build your own WordPress theme from scratch, with all the bells and whistles? This guide helps you get started from the very beginning with step-by-step instructions and helpful tips. In this first section, we’ll create the files for the new theme, set up its basic styles and create a header and a footer. […]

This article was posted by Independent Software, a website and database application development company based in Maputo, Mozambique. Our website offers regular write-ups on technical and design issues, ranging from details at code level to 3D Studio Max rendering. Read more about Independent Software's philosophy, or get in touch with Independent Software.

Ready to build your own WordPress theme from scratch, with all the bells and whistles? This guide helps you get started from the very beginning with step-by-step instructions and helpful tips. In this first section, we’ll create the files for the new theme, set up its basic styles and create a header and a footer.

Do you have a WordPress development environment ready on your computer? If not, follow this easy step-by-step guide to setup IIS, PHP, MySQL and WordPress, all on your Windows computer.

Creating an empty theme

In order to create a new, empty theme, find the wp_content/themes directory. In it, create a fresh subdirectory with the name of your theme, e.g. “mytheme”.

A theme needs at least the following files, which you should now create:

  • index.php
  • functions.php
  • style.css

Inside the style.css file, you should put your theme information:

Inside index.php, simply write “hello, world” to see that it works. The functions.php file can be left empty for now.

Inside the WordPress administration panel, navigate to “Appearance”, then “Themes”. Your new theme should be in the list of themes shown. If you’re missing any of the files above, WordPress will warn you about this. Activate the new theme, then refresh your WordPress website. If all is well, you should see “hello world” on a white background.

In order to save disk space, it is now safe to delete the other themes’ subdirectories (twentyfifteen, twentysixteen and twentyseventeen). You’ll save about 3MB.

First HTML

Let’s elaborate on the HTML in the index.php file a little. Change it to:

This is standard HTML that includes a couple of elements that will allow us to fiddle with the theme’s CSS in a moment. Speaking of CSS, note that there’s a special bit of PHP in there: wp_head . This tells WordPress to insert its  <head>  information. This includes references to stylesheets, fonts and JavaScript code.

Let’s try that out. Add a new CSS rule to style.css:

… and refresh the page. Unfortunately, nothing changes.

Adding the stylesheet

Should we place a direct reference to style.css in the <head>  section? No! Key to working with WordPress is letting WordPress manage all files and content, and write only code that focuses on presentation. If you add a reference to a stylesheet directly, WordPress will have no knowledge about it and cannot enqueue the link properly to play nice with other stylesheets, fonts and JavaScript sources.

Instead, add the following to functions.php:

Most things in WordPress are defined as “actions” or “hooks” in functions.php. It’s not a big thing to worry about now, but you’ll see a lot of this as we keep adding code to functions.php. This approach allows WordPress to execute your code at the precise moment is needs it in the page rendering cycle.

WordPress offers a long list of “actions”. One of these is wp_enqueue_scripts  and it executes the function you provide when it’s time to, you guessed it, enqueue scripts. In this code, then, we add the action  wp_enqueue_scripts  and point it to our custom mytheme_scripts  function.

Note: I could have called my function “scripts”, but that might clash with other PHP code. For this reason, it is customary to prefix all functions you write in functions.php with the name of your theme.

Inside the custom function, we tell WordPress to enqueue our stylesheet using the wp_enqueue_style  function provided by WordPress. The  get_stylesheet_uri  function, meanwhile, returns the full path to style.css.

You will gather from this that WordPress development revolves around knowledge of the WordPress API, and knowing which function to call where. Such is WordPress life. On the plus side, once you get the basics done you’ll quickly get the hang of it.

Refreshing the page, you will now see that the H1 element turns red as expected. If you view the source of the page, you will see that WordPress has included our stylesheet, as well as stylesheets for the admin bar and dashboard icons.

Let’s get started on proper CSS for our theme by normalizing the browser style rules, so that we start with a clean slate whichever browser we use. This can be done by including normalization CSS as found here. It’s as simple as including this in style.css:

After this, you should see your text in the browser change from Times New Roman to a more palatable sans-serif.

While we’re at it, we’ll also add CSS for accessibility (dealing with text intended for screen readers). We can use the CSS included in WordPress’s own twentyseventeen theme CSS:

Apart from this generic CSS, WordPress also expects some style rules to exist. For instance, rules for aligning content to the left, center or right is used by WordPress in its editor for posts and pages. These rules are:

You might define these rules differently, but it is important they exist as WordPress will generate HTML that uses them.

Header and footer

We’ve now added quite a bit of CSS. It is important to realize that this CSS should be included in the <head> of every page of our website, and so far we are calling wp_head  (which will insert the CSS reference for us) only in index.php. What if we also have contact.php and news.php? Should we write the header code again for each page?

It will not come as a total surprise that the answer is no. WordPress expects us to do the obvious thing and create separate header and footer files, which will include in our pages.

Our index.php file will be reduced to this:

What we had in index.php moves to header.php, which is the file WordPress will look for when we call get_header:

We’ve added a couple of new WordPress goodies here:

body_class  will automatically add class name for pages vs posts, user logged in or not logged in and page ID, which can be useful if your styles must change based on these properties. The other classes used here must be defined in our style.css and are not WordPress-specific.

For the footer, we’ll create footer.php (which, again, is the default file WordPress will look for when we call get_footer):

As with wp_head , we call wp_footer  here to allow WordPress to insert footer-specific things, like JavaScripts that must be placed just before the closing </body>  element. If you don’t add this, WordPress won’t have a chance to add these things.

With all this done, refresh your page and you’ll see the WordPress administration bar appearing at the top (provided you’re logged into the administration panel as well).


So far, we have:

  • created required theme files index.php, functions.php and style.css
  • added theme information to style.css
  • added some normalization CSS and a couple of WordPress required rules
  • split the header and footer code off into separate files.

In the next section of this guide, we’ll look at adding WordPress content to our theme:

Learn how to add Content to your WordPress Theme

Did this article help you out? Please help us find more time to write useful guides & articles like this by donating a buck or two. It'll keep us coffee-fueled. Thanks!


  1. Setting up a WordPress development environment on Windows with IIS | Independent Software
  2. Creating a WordPress theme from scratch: Content and the WordPress Template Hierarchy | Independent Software


2 2 Responses to “Creating a WordPress theme from scratch: Theme files, styles, header and footer”

Leave a Reply

Your email address will not be published. Required fields are marked *