WP Theme Development Tutorials
How to Build a Responsive WordPress Theme with Bootstrap
In this tutorial, we will learn how to make our own responsive WordPress theme using Bootstrap. Bootstrap is a responsive framework for building web sites and applications, and it’s a great starting point for building a responsive WordPress theme.Check out Zac’s other WordPress courses and enjoy a free, two-week trial of Treehouse.
You don’t have to have built a theme from scratch before to successfully follow along. However, we do assume that you are comfortable doing things like adding and editing posts in the admin area or installing plugins.
The theme we will build is based on the Basic marketing site example you can find over on the Bootstrap examples page. For this demo we will build out templates for the following pages and functionality:
- Custom homepage design
- About page
- Contact page
- News section with comments
- A widgetized sidebar
Getting Started
Before we get started there are a few things you will need to do:- Install WordPress
- Download and Unzip Bootstrap
- Install the Theme Test Drive plugin*
Once you have these things ready, open the directory with all your WordPress files and navigate to wp-content > themes.
Once you navigate to that folder create a new folder called “wpbootstrap.” Inside of that folder paste in the bootstrap folder.
Inside of that folder create a new file named index.php.
Now we’re going to copy the source code from the example basic marketing site and copy and paste it into the index.php file. Here is the source code you want to use. We’ve just linked to a txt version of the code since it is too long to embed in the post here.
Now that we have a static HTML page, we’re going to move on to creating the main CSS page. WordPress requires a specially formatted comment to appear at the top of the style.css page. It uses this comment to get all of the meta information about your theme.
In the same folder as your index.php page create a new file named style.css. WordPress requires a CSS file with the specific name style.css, so we can’t name it anything else or our theme won’t work.
Once you have created a style.css file at the same level as your index.php file, add this comment to the top.
/*
Theme Name: WP Bootstrap
Theme URI: http://teamtreehouse.com/wordpress-bootstrap-theme-tutorial
Description: A demo theme built to accompany the Treehouse blog post <a href="http://teamtreehouse.com/wordpress-bootstrap-theme-tutorial">How to Build a WordPress Theme with Bootstrap</a>.
Author: Zac Gordon
Author URI: http://teamtreehouse.com/
Version: 1.0
Tags: responsive, white, bootstrap
License: Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
License URI: http://creativecommons.org/licenses/by-sa/3.0/
This simple theme was built using the example Bootstrap theme "Basic marketing site" found on the Bootstrap web site http://twitter.github.com/bootstrap/examples/hero.html
*/
Your folder structure should now look like this:
We’re now ready to go into the admin area and install our new theme. Login to the admin area and go to Appearances > Theme. You should see WP Bootstrap listed as one of the themes.
Click Activate under the WP Bootstrap theme to set it as the current theme for the site.
NOTE: If you are using a live site and do not want people to see this theme under development, make sure to install and activate Theme Test Drive plugin.
Once it’s activated, visit your site and you should see something like this.
It’s clear that none of the CSS is working on this site currently, so in the next step we’ll start the process of converting this static file into a working WordPress theme.
Converting Bootstrap Files to WordPress Templates
Most WordPress themes include the following files:- index.php
- style.css
- header.php
- footer.php
- sidebar.php
What we are going to do is take all of the HTML that would usually be included at the top of every page and cut and paste it into the header.php file. Then we will do the same for all of the HTML that would normally appear at the bottom of every page and cut and paste it into the footer.php file.
Let’s look at what each of these files look like now. Again these are just .txt files that have been linked to because all of the source code would be too much to list here. You can copy and paste the code from these files into your own .php files.
The sidebar.php file is still empty.
Now we are going to use our first WordPress tags to include the header and footer back into the index.php page.
The two tags we will user are get_header() and get_footer(). These are built in WordPress functions that find the header.php and footer.php files and include them at the top and bottom of the page. WordPress can do this because we named our files header.php and footer.php. If we named the files my-header.php and my-footer.php this would not work.
Here is what our index.php file should look like now:
<?php get_header(); ?>
<!-- Main hero unit for a primary marketing message or call to action -->
<div class="hero-unit">
<h1>Hello, world!</h1>
<p>This is a template for a simple marketing or informational website. It includes a large callout called the hero unit and three supporting pieces of content. Use it as a starting point to create something more unique.</p>
<p><a class="btn btn-primary btn-large">Learn more »</a></p>
</div>
<!-- Example row of columns -->
<div class="row">
<div class="span4">
<h2>Heading</h2>
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
<p><a class="btn" href="#">View details »</a></p>
</div>
<div class="span4">
<h2>Heading</h2>
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
<p><a class="btn" href="#">View details »</a></p>
</div>
<div class="span4">
<h2>Heading</h2>
<p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
<p><a class="btn" href="#">View details »</a></p>
</div>
</div>
<?php get_footer(); ?>
Now that we have this done, we are going to fix all of the broken links to our CSS and JavaScript files.
Let’s start in the header.
Find the links to the CSS files in the header and change them from this
<!-- Le styles -->
<link href="../assets/css/bootstrap.css" rel="stylesheet">
<style type="text/css">
body {
padding-top: 60px;
padding-bottom: 40px;
}
</style>
<link href="../assets/css/bootstrap-responsive.css" rel="stylesheet">
<!-- Le styles -->
<link href="<?php bloginfo('stylesheet_url');?>" rel="stylesheet">
@import url('bootstrap/css/bootstrap.css');
@import url('bootstrap/css/bootstrap-responsive.css');
body {
padding-top: 60px;
padding-bottom: 40px;
}
bloginfo()
function used throughout this tutorial in various ways. Then we used the @import
tag to link to the Bootstrap CSS files from our main style.css file. Your site should now look like this: Much better! Before we move on to the footer, there is one more tag we have to add to the header. The wp_head()
function is an important hook that allows for plugin developers to dynamically add CSS or JavaScript to your site. If we do not include this in our template, some plugins may not work. While we’re at it, we’re also going to remove a few extranious tags from our header. Your header.php template should look like this.<head>
<meta charset="utf-8">
<title>Bootstrap, from Twitter</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Le styles -->
<link href="<?php bloginfo('stylesheet_url');?>" rel="stylesheet">
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<?php wp_enqueue_script("jquery"); ?>
<?php wp_head(); ?>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="<?php echo site_url(); ?>"><?php bloginfo('name'); ?></a>
<div class="nav-collapse collapse">
<ul class="nav">
<?php wp_list_pages(array('title_li' => '', 'exclude' => 4)); ?>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
</div>
<div class="container">
<hr>
<footer>
<p>© Company 2012</p>
</footer>
</div> <!-- /container -->
<!-- Le javascript
================================================== -->
<script src="../assets/js/jquery.js"></script>
<script src="../assets/js/bootstrap.js"></script>
</body>
</html>
wp_footer()
tag that serves the same function as the wp_head(). We will place this right before the closing body tag. We are also going to change the way we load our JavaScript files and move them to the header.php file.So, update your footer.php file so it looks like this:
<hr>
<footer>
<p>© Company 2012</p>
</footer>
</div> <!-- /container -->
<?php wp_footer(); ?>
</body>
</html>
wp_enqueue_script()
function.First, we are going to use this function to load jQuery right about the
wp_head()
. Go ahead and place the following code into your header.php file like so.<?php wp_enqueue_script("jquery"); ?>
<?php wp_head(); ?>
To do this we will have to create a new file called functions.php and load our JavaScript from there. This may seem like a lot of extra steps to load a JavaScript file, but as your themes get more complex it will help everything stay clean and organized.
In the same folder as your header.php file, create and open a functions.php file.
Paste into that file the following code:
<?php
function wpbootstrap_scripts_with_jquery()
{
// Register the script like this for a theme:
wp_register_script( 'custom-script', get_template_directory_uri() . '/bootstrap/js/bootstrap.js', array( 'jquery' ) );
// For either a plugin or a theme, you can then enqueue the script:
wp_enqueue_script( 'custom-script' );
}
add_action( 'wp_enqueue_scripts', 'wpbootstrap_scripts_with_jquery' );
?>
If that dropdown doesn’t work it means something went wrong linking to the JavaScript files. Make sure that you have properly uploaded the bootstrap > js folder and that your code is correct. You don’t want to build a responsive site with a broken mobile and tablet menu!
Creating the WordPress Homepage
Now that we have our basic static template setup, let’s make it dynamic by creating a homepage in WordPress and having it display on our site instead of the hardcoded HTML we have now.To do this, go to the WordPress admin area and click Pages > Add New. Title the page “Home” and then click on the HTML tab above the Content Editor. Now we will cut the remaining markup from the index.php file and paste it into this page and click “Publish”. Your Home page should look like this.
All your index.php file should have in it now are the header and footer includes.
<?php get_header(); ?>
<?php get_footer(); ?>
The WordPress Loop does what it sounds like. It loops through a page or post and pulls in its title and content, as well as a lot of other information like the date it was published, the author who published it, and even any comments associated with the post or page.
The basic loop looks like this.
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>
<?php get_header(); ?>
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>
<?php get_footer(); ?>
the_title()
and the code for the content looks like this the_content()
. You can see that they look very similar to the header and footer tags. Here is what the it looks like along with the loop.<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<h1><?php the_title(); ?></h1>
<?php the_content(); ?>
<?php endwhile; else: ?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>
Click save changes and then reload the homepage. We should now see the contents of the Home page we added in the admin area.
WordPress allows us to use a special file called the front-page.php file just for the home page of the site. Go ahead and save the index.php file as front-page.php and remove the
get_title()
from the template since we don’t want “Home” appearing in an h1 at the top of the page.Your front-page.php file should look like this:
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php the_content(); ?>
<?php endwhile; else: ?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>
To show that this is all working, let’s try editing the homepage content in the admin area and see the changes reflected on the front of the site. Go back and edit the Home page content and remove the the buttons that appear under the three h2 headings. The modified code should look like this.
Now, revisit the front of the site. It should look like this.
Our home page is looking good. Let’s move on to adding the other pages of our site.
Adding More Content and Navigation
Go ahead and add an About, News, and Contact page in the admin area. We are going to use dummy content for now, but you can go back and add your own content later. Go ahead and add two or three blog posts as well.Navigation
The next thing we will do is replace the static navigation menu on the site with one that will show the pages we just added in the admin area. To do this, find the unordered list with the class “nav” and delete the list items. We are also delete the sign in form since we will be logging into the site directly from the WordPress admin login screen.The markup inside of the div with the class “navbar” should now look like this:
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="#">Project name</a>
<div class="nav-collapse collapse">
<ul class="nav">
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
</div>
wp_list_pages()
for listing the pages. We won’t go into depth on the options for this tag, but what it is doing is creating a list item and a link for each of the pages. Add the following code inside of the empty unordered list with the “nav” class.<ul class="nav">
<?php wp_list_pages(array('title_li' => '')); ?>
</ul>
There are two things we have to fix about this. First, we have to correct the order of the pages, and second we have to delete the Sample page. We’ll assume that you can delete (or move to trash) the sample page. To change the order of the pages go to the admin area and click on Pages.
Then hover over the the About page and click Quick Edit. Change the Order field to 1. Click Update. Change the News page order to 2 and the Contact page to 3. The Home page should keep the page order of 0.
When you visit your site now, the navigation should appear in the correct order.
We now have working navigation. However, since the WordPress navigation markup is slightly different from the Bootstrap markup, particularly in terms of the classes they use for current or active pages, we will have to modify the bootstrap.css file slightly.
In your theme folder go into bootstrap > css and open the bootstrap.css file. Around line 4595 you should see some styles for the Bootstrap
.active
class. Add the following styles to the rule..navbar-inverse .nav .active > a,
.navbar-inverse .nav .active > a:hover,
.navbar-inverse .nav .active > a:focus,
.navbar-inverse .nav .current_page_item a,
.navbar-inverse .nav .current_page_item a:hover,
.navbar-inverse .nav .current_page_item a:focus,
.navbar-inverse .nav .current_page_parent a,
.navbar-inverse .nav .current_page_parent a:hover,
.navbar-inverse .nav .current_page_parent a:focus {
In the next section we will create the template for the pages and posts.
Creating the Page, Post and Post Listing Templates
Pages Template
Start with taking the index.php file and saving it as page.php. This will serve as the as the template for our pages.First we should change the text that reads “Sorry, no posts matched your criteria.” to read “Sorry, this page does not exist.”
Next, we are going to add some Bootstrap markup to create a two column layout.
Modify your page.php template to include the Bootstrap “row” class and a “span8” and “span4” class. We’ll use the span8 for the page content and the span4 for sidebar content.
<?php get_header(); ?> <div class="row"> <div class="span8"> <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?> <h1><?php the_title(); ?></h1> <?php the_content(); ?> <?php endwhile; else: ?> <p><?php _e('Sorry, this page does not exist.'); ?></p> <?php endif; ?> </div> <div class="span4"> </div> </div> <?php get_footer(); ?>
get_sidebar()
tag that works in the same way as the get_header()
and get_footer()
tags.To do this we are going to create a new file called sidebar.php and paste in the following code
<h2>Sidebar</h2>
Sidebar Template
We will come back and modify this code later, but this will work for now.Now go back to the page.php file and add in the
get_sidebar()
code inside the “span4” div like this.<?php get_header(); ?>
<div class="row">
<div class="span8">
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<h1><?php the_title(); ?></h1>
<?php the_content(); ?>
<?php endwhile; else: ?>
<p><?php _e('Sorry, this page does not exist.'); ?></p>
<?php endif; ?>
</div>
<div class="span4">
<?php get_sidebar(); ?>
</div>
</div>
<?php get_footer(); ?>
Our page template is looking pretty good. Let’s move on now to the News page.
Posts Listing Page
The news page is going to work a little differently because it needs to list out posts, not just page content. There are a couple ways to go about this, but we are going to take a very simple approach here.To start save the page.php template as home.php. In WordPress, the home.php template is reserved for the page that lists out posts. In our case this is the template we will use for the News page.
The first thing we are going to do is hardcode an h1 tag into the top of the main content area that says News. This tag should be placed above the loop.
On this home.php template, the loop is going to loop through all of the blog posts. So, instead of using an h1 tag for the post titles we are going to change it to an h2, since the h1 will be used for the title of the page.
We are also going to add a new tag,
the_permalink()
, that we can use with an anchor tag to link from the main news page to individual news articles. This is what the markup with around the_title()
should look like now.<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
Next, we’re going to remove the post content from appearing. We’ll just list out the titles as links to the pages and let the viewers read the content after they click on the post title.
In the place of the content we’re going to add in the date of the post using a tag called
the_time()
. If you’ve used PHP before you may recognize you may recognize this tag. This tag is able be customized to display the date in pretty much any format you want. We are going to display the date in the following format:Monday, October 1st, 2012
To do this we are going to use
the_time()
function customized like this:the_time('l, F jS, Y')
The final home.php template should look like this.
<?php get_header(); ?>
<div class="row">
<div class="span8">
<h1>News</h1>
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<p><em><?php the_time('l, F jS, Y'); ?></em></p>
<hr>
<?php endwhile; else: ?>
<p><?php _e('Sorry, there are no posts.'); ?></p>
<?php endif; ?>
</div>
<div class="span4">
<?php get_sidebar(); ?>
</div>
</div>
<?php get_footer(); ?>
Once this is done you should see should see the Posts listed when you go back to the News page.
Single Post Template
This leaves us one template left to do and that is the template to display individual posts. This template is going to look very similar to our page.php template so we’ll start by opening the page.php file and saving it as single.php. In WordPress, the single.php template is used to display individual posts.The first change we will make here are to include the date of the post underneath of the title. We’ll use the same code as before.
<p><em><?php the_time(‘l, F jS, Y’); ?></em></p>
The biggest change we are going to make to this template is adding the ability to post comments. While there is a lot of complex code that is required behind the scenes to make comments work, it is actually pretty easy to add comments to the template thanks to the
comments_template()
tag.Once we add this below the content tag we will have comments enabled on our posts. We’ll also add an hr tag above the comments to help separate them from the post content. Our final single.php template should look like this.
<?php get_header(); ?> <div class="row"> <div class="span8"> <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?> <h1><?php the_title(); ?></h1> <p><em><?php the_time('l, F jS, Y'); ?></em></p> <?php the_content(); ?> <hr> <?php comments_template(); ?> <?php endwhile; else: ?> <p><?php _e('Sorry, this page does not exist.'); ?></p> <?php endif; ?> </div> <div class="span4"> <?php get_sidebar(); ?> </div> </div> <?php get_footer(); ?>
Finishing the Theme
Updates to the Header
One of the first details we need to take care of are the title tags. Title tags are an important part of a web site, especially in regards to its search engine optimization. Ideally we want to have the name of the page or post in the title as well as the name of the site.We can accomplish this using a WordPress tag called the
wp_title()
tag. We will customize this tag slightly in the following waywp_title('|',1,'right');
bloginfo()
function we used before but this time like this bloginfo(“name”)
. If we use these two together with the title tag we will get this.<title><?php wp_title('|',1,'right'); ?> <?php bloginfo('name'); ?></title>
Next we are going to make the site title in the top left of the site match our site name and make it link to the homepage. This is how we will do that.
We will take this:
<a class="brand" href="#">Project name</a>
<a class="brand" href="<?php echo site_url(); ?>"><?php bloginfo('name'); ?></a>
bloginfo(“name”)
that we used in the title tag. The site_url()
tag is new, but it does exactly what you think it would. It creates a link to the homepage of the site.Now that we have created a link to the homepage we can remove the “Home” link from the page listing. We can do this by adding an extra option to the
wp_list_pages()
function. This option is the “exclude” option. In order to use it we have to have to look up the id of the Home page. To do this we navigate to the page in the admin area and look in the URL of the page.In this example the Home page has an ID of 4. It may be different for your site. Once you have this ID, update the
wp_list_pages()
function like so (replacing the 4 with the ID of your homepage):wp_list_pages(array('title_li' => '', 'exclude' => 4))
Widgetizing the Sidebar
The last major step we are going to take is to do what’s called Widgetizing our theme. What this will do is allow us to use WordPress widgets in our sidebar.To do this we will need to add some more code to our functions.php file.
Open the functions.php file and add the following code to the file.
<?php
function wpbootstrap_scripts_with_jquery()
{
// Register the script like this for a theme:
wp_register_script( 'custom-script', get_template_directory_uri() . '/bootstrap/js/bootstrap.js', array( 'jquery' ) );
// For either a plugin or a theme, you can then enqueue the script:
wp_enqueue_script( 'custom-script' );
}
add_action( 'wp_enqueue_scripts', 'wpbootstrap_scripts_with_jquery' );
if ( function_exists('register_sidebar') )
register_sidebar(array(
'before_widget' => '',
'after_widget' => '',
'before_title' => '<h3>',
'after_title' => '</h3>',
));
?>
Update the sidebar.php so it looks like this:
<?php if ( !function_exists('dynamic_sidebar') || !dynamic_sidebar() ) : ?>
<?php endif; ?>
Hello There. I found your blog using msn. This is an extremely well written article. I will be sure to bookmark it and return to read more of your useful information. Thanks for the post. I’ll certainly comeback.
ReplyDeletecheapest panel
This is such a great resource that you are providing and you give it away for free. I love seeing websites that understand the value of providing a quality resource for free. It is the old what goes around comes around routine.
ReplyDeleteBest Divi Theme Alternatives
Thanks for posting this info. I just want to let you know that I just check out your site and I find it very interesting and informative. I can't wait to read lots of your posts.
ReplyDeletewordpress website security