In this WordPress tutorial, you will learn how to create a WordPress theme using HTML5, CSS3, and responsive design principles. You will also learn to separate various parts of your theme into ‘templates’.
Themes, like plugins, are separate from the core WordPress code. Themes allow your website to have a consistent layout for every page and post, and can quickly be modified to change your entire website’s look and feel. To display information from WordPress or the content of a post, you must use template tags that are provided by WordPress, and these will be explained in the tutorial.
After completing this tutorial and creating a new WordPress theme, it’s a great idea to follow the how to create a WordPress child theme tutorial to extend upon what you have learned here. The theme you create in this tutorial will give you the perfect foundation to use in the child theme tutorial.
What You’ll Need
To complete the steps in this WordPress theme development tutorial, you’ll need a text editor such as Notepad++ or NetBeans. You’ll also need FTP access to your hosting account and a working WordPress installation.
It’s also recommended to download CSS cheat sheet and have it opened as in this tutorial you will be editing WordPress style.css file.
What is HTML5 and Why You Should Use It
HTML5 is the latest version of the web markup language HTML and offers a great set of modern features that make it easier to display your content consistently on any computer, laptop, tablet or mobile phone.
The biggest change is that a new set of semantic HTML elements are available. For example, the footer of any HTML page can now be defined using the <footer></footer> element, and this tells the web browser that the content contained within is part of the footer. In older versions of HTML, footer content would be created using generic elements such as <div></div>.
A basic HTML5 document will look like this:
What is Responsive Design?
Responsive design means that your website is automatically displayed in the best format for the visitor based on the size of their screen. The page layout literally ‘responds’ to the available space on the visitor’s screen. The content is placed perfectly so that nothing is cut off, nothing is overflowing off the screen, and your website looks as clean as possible.
You should think of your website’s layout as a series of grids and give content a percentage of the grid’s width. For example, a div could take 50% of the available space, rather than it being 800px in width. A full page width div takes 100% of the available space so if you want four divs inside it in a line, each one gets 25% of the space.
For images, you can set them to have a maximum width of 100% of their actual size and set the height to auto. When the container of the image is in reduces in size, the image automatically reduces in width and height.
For images, using width: 100% instead of max-width: 100% will cause an image to take up 100% of the space available instead of stopping at its actual width in pixels. If the image is 200px in width but is inside a div that takes up 100% of the screen, max-width means the image is never larger than 200px wide.
To make a WordPress theme fully responsive, you can also use a CSS3 feature named media queries. In media queries you optionally define a media type to affect (screen, print etc) at least one media feature (max-width, orientation etc). The media features can be chained together using the and keyword.
- In the first example, the CSS will be applied to any screen (monitor, phone etc) that has a viewable width (the area inside the browser, not the entire window ) between 400px and 800px.
- The second example will be applied to any media type that views it.
- Another media type is ‘print’, which means the CSS is only applied if the user is looking at a print-preview of your page.
A full list of media types and media features is available on the Mozilla Developer Network website.
In your CSS stylesheet, you define rules that dictate when content is changed, what content is changed, and how that content is changed. You can change any CSS attribute this way, such as the width of any text box, or the background colour of a div. Some examples of media-feature rules dictating when the rule is applied:
- max-width – the maximum width of the browser’s viewable area, any wider than this and the rule is not applied
- min-width – the minimum width for the viewable area, any smaller than this and the rule is not applied
- orientation – whether the screen is in portrait or landscape mode
A common example is when you have two text boxes side by side that both take up 50% of the screen. As the browser window gets smaller, the boxes automatically adjust to still take up 50% of the window instead of disappearing off the side. If the browser window gets too small to properly display all the text in those boxes, you can tell them to take up 100% of the window size and display one on top of the other. You can also hide the content entirely if it’s more appropriate.
Step 1 – Storing Your Theme and Its Files
Making even minor changes to a theme can cause errors and make your website unusable. A common problem is that after making changes to your code, you try to load your website and instead get a white screen known as the white screen of death. Debugging the error that caused the white screen can be difficult.
To avoid any disruption to your website, it’s important to test all changes in an offline version. Once your changes are complete, you can upload the working version to your live website. You can learn how to create a local WordPress developent server on Windows here, tutorial on how to run WordPress on Docker (any OS) can be found here.
Let’s start the actual tutorial and learn how to create a WordPress theme!
WordPress themes are stored in their own folder in the wp-content/themes/ folder.
In the wp-content/themes/ folder, create a new folder named my-theme. The folder you created needs a unique, descriptive and short name to easily identify it.
Note: Theme folder names must not contain numbers or spaces. Your theme must not have the same folder name as another theme. If you plan on sharing your theme, you must check that another theme with that name has not already been uploaded to the WordPress.org Theme Directory.
WordPress themes can be created with just two files – index.php and style.css – and WordPress will use these to display every page and post on your site.
Realistically, you’ll want posts, pages, and other sections of your website to have their own layout. Each section of your website is given its own file to hold HTML and PHP that only applies to that section – each file is then called a ‘template’.
If you use custom post types, you can create templates that only apply to posts of that type. If you want posts from a specific category to be styled differently, you can do that using if…then… statements inside the loop.
Each template file must use the correct name as defined by the WordPress documentation.
Some of the template files beyond index.php:
- header.php – contains any HTML that goes at the top of your pages, starting from <!DOCTYPE html>
- single.php – used when displaying a single Post from your blog
- page.php – used when displaying a single Page from your blog
- comments.php – defines how comments and the comment text box are displayed
- footer.php – contains any HTML that goes at the bottom of your pages, including </html>
For a full list of templates, visit the WordPress theme development handbook.
Now that you have a folder to store the theme, you need to create some basic template files.
Step 2 – Creating the templates files and the CSS Stylesheet
In the my-theme folder create the following files PHP files:
In addition to PHP files, create a new CSS file named style.css (the main stylesheet must be called style.css).
The information must be written as a multi-line CSS comment, each header on its own line, starting with a header keyword.
There’s a number of header keywords available to you to define information such as author (your name), author website, a description of the theme, the name of the theme, the version of the theme etc. For the full list of header keywords for themes, visit the WordPress Codex – File Header page.
The format for writing headers is Keyword: Information
NOTE: The seventh and eighth lines are only required if you plan on sharing your theme on WordPress.org. If you will be using the theme on your own website, you can skip those two lines and just close the comment section.
At this point, your theme is already visible in the admin control panel theme section. You will see a white and gray checker box image with My Theme written below it. After your theme is complete you can take a screenshot to be displayed here.
Now, we’ll add a single rule to the CSS file that changes the background colour of the page.
Add a blank line after the comment closure */ on line 10.
On the next line below the new blank line (line 11 of the file), write the following.
The first entry is an important part of responsive styling. * is a wildcard and matches every single class that’s found in the HTML document. It states that the final width and height of every item on the page should include content, padding and border. If you don’t set this and have two 50% wide boxes that are side-by-side with any padding or border, they will not sit side-by-side as their actual size is greater than 100%. A 100% width box with 1% padding is actually 102% wide, as 1% padding is added to the left and right. This rule effectively adds the padding inside the box instead of outside it.
The second entry just changes the background colour of white so we can quickly see whether the stylesheet is being used. We also set default font which will be used in our theme.
Step 3 – Before Starting Development
Before you begin actually creating your WordPress theme layout, you should add a few pieces of code to various files to give yourself a good starting point to build upon. These steps aren’t required but highly recommended.
These steps will have brief explanations so you can quickly move on to actually building a layout.
First, we’ll include a CSS file named normalize.css. Different browsers have different default settings for things like the page margins and padding. Normalize.css explicitly sets a number of attributes to ensure that all browsers display your page exactly the same. If you don’t use a stylesheet to set these defaults, a common problem is that when you try to make your main header start at the very top left of your page, there will actually be blank space above the header.
Open functions.php and dd the following code
Next, you need to enable the sidebar widgets. If you don’t include this code, the widgets menu link will not be visible in the admin control panel and you won’t be able to add any widgets. While still in functions.php, below the previous function, add the following code:
Now we need to register a custom navigation menu to allow usage of the Appearance -> Menu feature in the admin panel. Below the previous code add the following:
Save functions.php and upload it to your theme’s directory.
Now open sidebar.php file and the following code. It makes the sidebar and widgets appear in your theme wherever get_sidebar() is called.
The first line tells WordPress that if no widgets are enabled, the sidebar HTML must not be shown. The second line sets the attributes of the element that contains the widgets. HTML5 provides the ‘aside’ element for sidebars. The third line is the WordPress function to actually display the widgets. The last line closes the initial if statement.
Save and upload sidebar.php to your theme’s directory.
To make it easier to navigate between posts and pages, open the admin control panel and add the Pages and Recent Posts widgets to the sidebar. Now we will move on to building the layout.
Step 4 – Building A Layout With Templates
header.php will define the very top of our document, starting with the DOCTYPE declaration.
All HTML documents must begin with a DOCTYPE declaration, which tells your web browser how to interpret the document. The HTML5 doctype is simply html. The opening <html> tag needs a language attribute, and WordPress provides a function to enter the correct language code for the language you picked during installation – language_attributes().
In the title field, you use a line of code that displays the name of your site, followed by a shorthand if…then… statement to either display the tagline of your website OR the title of the current page or post you are viewing.
The ? character is a PHP conditional operator named the ternary operator. In this line of code, is_front_page() is a WordPress function that returns TRUE if viewing the front page, or FALSE if viewing any post or page. The function before the colon is used if TRUE was returned, and the function after the colon is used if FALSE is returned.
As you will see below, the bloginfo() function is used repeatedly with different parameters to get different pieces of information from the WordPress database. Before the <head> tag is closed with </head>, you must include the wp_head() action hook to ensure any functions attached to it are run.
The body_class() function gives your body the default CSS classes as set by WordPress. The final line allows the navigation menu to be displayed if one has been created in the admin control panel. The final header.php looks like this:
If you want to use a logo as the header, replace <?php bloginfo(‘name’); ?> with your image code inside the <header> tags.
Save header.php and upload it to your theme’s folder.
index.php defines the homepage, and will also be used as the default layout if specific templates (i.e. single.php, page.php) are not found.
We’ll use template tags to make sure the header (get_header), sidebar (get_sidebar) and footer (get_footer) code is included on our homepage.
The WordPress loop will display a list of posts and their excerpts with more template tags. We will also use the HTML5 semantic elements <section>, <main>, <header> and <article>. Some of our elements will have classes assigned to them, and the classes will be written when we get to the style.css file.
The loop starts at <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?> and ends at <?php endif; ?>. Inside the loop, the following template tags are used:
- <?php the_permalink(); ?> – outputs the correct URL of the actual post
- <?php the_title_attribute(); ?> – outputs the title of the post in a safe format for the title attribute of the link
- <?php the_title(); ?> – outputs the title of the post
- <?php the_author(); ?> – outputs the name of the author
- <?php the_excerpt(); ?> – outputs the excerpt of the post, which is auto-generated if you don’t write your own
<header></header> tags can be used multiple times on any page and do not specifically refer to the page header.
Sections and articles should have header elements where any text inside <h1>,<h2>, etc is used. If a section or article has no header text, they can be left out.
Save index.php and upload it to your theme’s directory. If you visit your site now, you will see a very plain looking page.
You can see though that the tab title is your website’s name and tagline. The top of the page has your website’s title (or your logo if you used that instead). Any posts that exist have their title, author and excerpt displayed. Although the page will display fine, you still need to close the open <body> and <html> tags in footer.php.
footer.php defines the footer of every page and must close any open HTML tags in other template files. In this case <body> and <html> are still open from header.php.
We’ll also add the HTML5 semantic element <footer></footer> to explicitly define our footer.
Save footer.php and upload it to your theme’s directory.
single.php defines the layout when viewing a single post on your website. It can be completely different to index.php.
In this case, we will not add the sidebar to posts just to highlight the difference in layout.
The main content takes the full width of the page since we gave it the content-full-width class from the stylesheet. The link was removed from the title as it isn’t needed here. The function to display the full post is the_content():
page.php defines the way pages are displayed and can be different once again from the index and the post layout.
Remember that if templates don’t exist, the index.php template is used instead. If you don’t create page.php, it will not use the same layout as posts.php.
To make the difference more visible, we will once again add the sidebar to this layout, and make the page content take 70% of the page width.
Save page.php and upload it to your theme’s directory.
Add the following to the bottom of the stylesheet. This will cause the various boxes to have a white background and blue border, to help visualise how much space each one actually takes up.
Save style.css and upload it to your theme’s directory.
Now that you have the basic templates and a stylesheet, you can easily navigate through your posts and pages. Your newly created theme should look like this.
Using media queries
Since our basic layout has 2 inline boxes on the front-page, we can easily change the way they behave when the browser window is too small to properly display text.
For this WordPress theme tutorial, we will change the width of the posts in the post list when the browser window is below 800px. Instead of having 2 side-by-side posts, each post will have its own line. We will do this by adding a media query. If you need a refresher on media queries, head back to the What is “Responsive Design”? section of this tutorial before continuing.
When writing media queries, you can write them anywhere in the stylesheet. You can put all media queries at the bottom of the stylesheet, or write specific media queries for specific items right below the original definition. It’s just a matter of what you consider most logical.
We will first write a media query that affects the .article-loop class, which has a width of 49% by default. We will write it directly below the original definition. The media query will state that if the browser window is smaller than 800px wide, the .article-loop class should use 99% of the available space instead.
Then we will write a media query that, when the browser window is smaller than 600px wide, pushes the sidebar below the main content and extends both the main content and sidebar to take 100% width. This would be a much more appropriate layout for a mobile device where space is limited.
Still in style.css, find .article-loop which should be line 73. Below .article-loop class, write the following:
Line one here states that the media query should only affect screens (i.e. not print preview mode) and only affect browser windows that are 800px or less in width. Save and upload style.css to your theme’s directory. Go to the homepage of your website. Change the size of your browser window, and as it passes 800px in width, you will see the boxes for each post change in width and drop one below the other.
Continue reducing the width of the browser window until it is as small as possible. You’ll see that all the text becomes harder to read as it has too little space, but at no point does it disappear off the screen. If the widths were defined as pixel widths instead of percentages, as soon as the window became too small, the sidebar would disappear and require horizontal scrolling.
The next media query we will add will be similar to the one above. It will tell the main content and the sidebar to take 100% of the available space, and the sidebar will drop below the main content.
NOTE: As this affects different classes that are in different places in the stylesheet, it’s worth placing it at the bottom of the stylesheet instead.
Save style.css and upload it to your theme’s directory. Go back to your homepage and resize the browser window until you see the content take up 100% of the width and the sidebar drop below the main content.
Using the sidebar, click on any available page and you will see the sidebar is also below the page content, and everything fits appropriately.
Understanding WordPress Template Tags and Action Hooks
To fully integrate your theme with WordPress, you must use template tags and action hooks. These are two distinctly different things.
Template tags are PHP functions provided by WordPress to easily include template files (such as header.php) from your theme in another file or to show some information from the database.
For example, to show the footer on the home page but not on any other page, add get_footer() at the bottom of index.php, but not in page.php.
Below are two brief lists of some important template tags to give you an idea of what tags are available.
Template tags to include template files:
- get_header() – includes the header.php template
- get_sidebar() – includes the sidebar.php template
- get_footer() – includes the footer.php template
- get_search_form() – includes searchform.php template
Template tags to display information from the database
NOTE: Some template tags must be used in the loop. The loop is explained later in the tutorial, and simply means the code that retrieves any requested posts.
- bloginfo() – displays information requested as a parameter, i.e bloginfo(“name”) shows the name of your website as defined in the Admin Control Panel (view list of parameters)
- single_post_title() – displays the title of the currently viewed post when used in single.php
- the_author() – displays the author of the currently viewed post
- the_content() – displays the main text of a post or page
- the_excerpt() – the excerpt of the post or page
Full list of WordPress template tags can be found here.
Action hooks are PHP functions provided by WordPress that usually have other functions attached to them. Some hooks don’t have functions attached by default and exist for use by plugins. Action hooks allow plugins to attach their own functions and have them run at various points in the loading of a page.
In your theme’s header template, the wp_head() action hook is called to include the default WordPress header HTML inside the <head></head> tags. It has some core WordPress functions to add HTML to the page and allows any functions attached to it by plugins to run.
If you do not use the action hooks while creating WordPress theme, important core code will be missing and plugins will not be able to function correctly.
For example, not calling wp_footer() in your footer.php template will stop the top Admin bar from appearing when you are logged in as an admin. The core WordPress code that causes the admin bar to appear is attached to the wp_footer() action hook, and the attached functions can’t run if the action hook doesn’t exist.
For a full explanation of action hooks, read the Actions and Action Hooks section of the how to create a WordPress plugin tutorial.
The WordPress Loop
The loop is used to actually display posts. It can be used to display a single post or all of your published posts on one single page. The HTML that you write within the loop will be used to display every post requested by the loop. The code continues looping until it reaches the final post.
If displaying one post you use the template tag the_content() inside the loop to display the content of the post. If displaying a list of all published posts, you can use the_excerpt() inside the loop instead so that the entire post is not shown.
The loop is a multi-line shorthand if…then… statement made up of four lines of code. The first line states that if a post is found, while the post is available, use the following code to display the post. If no matching post is found, you can define replacement text instead. The default WordPress example looks like this, and the commented line is where your HTML and template tags are written:
Congratulations! You have created your first responsive HTML5 WordPress theme!
Now that you understand templates and template tags, you should take another look at the WordPress codex’s list of templates and template tags, and experiment with adding new sections to the layout. Experiment with changing the CSS styles and widths and see how your browser responds to various situations. Change the rules for the media queries and see if there are better rules that can be defined.
You can also move on to the How to Create WordPress Child Theme tutorial.