If you have basic PHP skills, and are looking to develop a responsive Bootstrap WordPress theme using the popular CSS framework Bootstrap, then this step by step tutorial is for you. I will cover the basics of building a WordPress theme using a starter Bootstrap template and create a basic blog feed (latest posts) page. I am assuming you have WordPress installed and running.
We will use one of the starter example templates from the Bootstrap website for this tutorial: the blog template which is a simple two-column blog layout with custom navigation, header, and type. So head on over to http://getbootstrap.com/examples/blog/ and take a good look at what we would end up incorporating into our very own theme.
Create Bootstrap WordPress Theme From Scratch
This is part 1 of the tutorial, which will have future installations that I will continue to list here as soon as they are written and complete. In this part, we will create all the basic files required for the Bootstrap WordPress theme and write code to list the latest posts (The Loop). The navigation and sidebar, along with other items such as widgets and some customization will be handled in the next part of the tutorial. In the third installment, we discuss adding a slider to the theme.
Hope you find this helpful and if you have any questions, please go ahead and ask away in the comments section and I’d be happy to help!
If you’d rather download the source code for this tutorial right away, here you go: Download Source
Step 1: Create Your Theme Folder
The first thing to do is to create a new folder inside wp-content/themes. For now, leave this folder empty. Give it a relevant name – this is going to be your main theme folder. For the purposes of this tutorial, lets call it “bootstrapstarter”.
Step 2: Download Bootstrap
Download the latest Bootstrap (currently version 3.3.6) framework by going to this link. When extracted, the Bootstrap files are organized into three folders: css, js, and fonts. You can either extract them directly into your theme folder or create a folder called “bootstrap” and extract the files into that. I have used the latter option: I created a folder called “bootstrap” and then extracted the bootstrap-3.3.6-dist.zip file into it. So my folder structure now looks like this:
Step 3: Create Some Files
For the purpose of this template, we are doing the bare minimum required to get our theme up and running using Bootstrap. Create these six files in your theme folder:
- style.css
- functions.php
- header.php
- footer.php
- sidebar.php
- index.php
They can all be left blank for now. I’ll go through them one by one.
Step 4: Edit style.css
This is one of the required files for a valid WordPress theme. In your favorite code editor (I recommend Notepad++) edit your currently empty style.css and add a comment header. The style.css file always starts with a comment header which enables WordPress to identify the theme and display it in the Administration Panel under Appearance > Themes as an available theme option, along with any other installed themes. At minimum, you should include the following lines:
/* Theme Name: Boostrap Starter Theme Theme URI: https://www.lyrathemes.com/blog/bootstrap-wordpress-theme-tutorial/ Author: Abby Author URI: https://www.lyrathemes.com Description: A basic theme using the Bootstrap framework. Version: 1.0 Text Domain: bootstrapstarter */
You can amend each of these lines to include information specific to you and your them. There are several other items that can be added to this header.
Step 5: Edit functions.php
This is an optional file but you would hardly see a WordPress theme out in the wild without one. If this file is present in a theme that you are using (the activated theme), it is automatically loaded during the WordPress initialization – both for the admin area and the external website. Read more about the functions.php file here but mainly, this file can be used to (but is not limited to) perform the following tasks:
- Include or enqueue any CSS and JavaScript files and scripts. This is the recommended method of including stylesheet(s) in a theme instead of directly adding them to the theme HTML <head>.
- Enable and declare theme support for features such as Sidebars, Navigation Menus, Post Thumbnails, Post Formats, Custom Headers, Custom Backgrounds and others.
- Define any functions you wish to use throughout your theme – since this file will always be loaded, these custom functions of yours will be available to all your theme files.
- At an advanced level, this file can also be used to set up options for theme customization that is available under Appearance > Customize.
So for our theme, edit functions.php add the following code to it – I will go through each line right after.
<?php function bootstrapstarter_enqueue_styles() { wp_register_style('bootstrap', get_template_directory_uri() . '/bootstrap/css/bootstrap.min.css' ); $dependencies = array('bootstrap'); wp_enqueue_style( 'bootstrapstarter-style', get_stylesheet_uri(), $dependencies ); } function bootstrapstarter_enqueue_scripts() { $dependencies = array('jquery'); wp_enqueue_script('bootstrap', get_template_directory_uri().'/bootstrap/js/bootstrap.min.js', $dependencies, '3.3.6', true ); } add_action( 'wp_enqueue_scripts', 'bootstrapstarter_enqueue_styles' ); add_action( 'wp_enqueue_scripts', 'bootstrapstarter_enqueue_scripts' ); ?>
To summarize, this block of code includes the Bootstrap CSS and Javascript files as well as your own theme style.css (created in the previous step). We do this by creating a function that includes or enqueues the files and then hook the function to “wp_enqueue_scripts”. This hook is used to enqueue or include items that are meant to appear on the front end. Despite the name, this hook is used for both scripts (JS) and styles (CSS).
I have created two functions: one for including the CSS files and one for including the JS files. You can also go with a different approach and create one function that lumps together the enqueuing of both the CSS and JS files.
The first function, bootstrapstarter_enqueue_styles(), first registers the Bootstrap CSS file using wp_register_style(). This function is used to safely register a CSS style file for later use with wp_enqueue_style(). The reason we register first instead of directly including (enqueuing) the file is because we want to create a dependency between our style.css file and the Bootstrap CSS file – in other words, we do not want our style sheet to be loaded before the Bootstrap CSS file. This makes sense since we will be relying heavily on the base functionality provided in the Bootstrap framework and then adding custom rules in our theme style.css that build and depend upon the framework rules.
So after registering the Bootstrap CSS file, we go ahead and enqueue our main style sheet and pass an array of all dependencies i.e. an array of all registered script handles that this script depends on. In our case, our main style sheet only depends on the Bootstrap CSS file so our $dependencies array only has one handle in it: “bootstrap” (which we registered in just the line before).
Understanding the second function, that handles the inclusion of the Javascript files, should be easy to understand now that you know the basics. bootstrapstarter_enqueue_scripts() first defines a dependency array, which includes just ‘jquery’. By default, the WordPress installation includes and pre registers many popular scripts commonly used by web developers besides the scripts used by WordPress itself, jQuery being one of them. Since it has already been registered by WordPress for you, all we need to do is define it as a dependency for our Bootstrap JS file.
Quick note: we’re using “false” as the last argument in the wp_enqueue_script() function while enqueuing the Bootstrap Javascript file in order to tell WordPress to load the file(s) in the footer just before the closing </body> tag instead of in the <head>.
Okay, that’s it for the functions.php file. Now lets move on to the actual presentation files: header.php, footer.php, sidebar.php and index.php.
Step 6: Page Structure
Looking at the page at http://getbootstrap.com/examples/blog/, we need to determine how to “cut up” or organize our template into our main page components. Here is a visual guide of the template that we are about to follow:
Now, head on over to http://getbootstrap.com/examples/blog/, and view the source of the page. We need to copy the source and save it in 4 parts, in 4 different files according to the map above.
So the header area (site title and navigation) goes in header.php. The sidebar goes into sidebar.php. The footer area along with the footer navigation and copyright information goes into footer.php. Whatever is left is the page content and it goes into index.php. So based on the diagram above, here is the content of each of the files, extracted from the starter template and split into the four files.
header.php:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> <meta name="description" content=""> <meta name="author" content=""> <link rel="icon" href="../../favicon.ico"> <title>Blog Template for Bootstrap</title> <!-- Bootstrap core CSS --> <link href="../../dist/css/bootstrap.min.css" rel="stylesheet"> <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> <link href="../../assets/css/ie10-viewport-bug-workaround.css" rel="stylesheet"> <!-- Custom styles for this template --> <link href="blog.css" rel="stylesheet"> <!-- Just for debugging purposes. Don't actually copy these 2 lines! --> <!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]--> <script src="../../assets/js/ie-emulation-modes-warning.js"></script> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div class="blog-masthead"> <div class="container"> <nav class="blog-nav"> <a class="blog-nav-item active" href="#">Home</a> <a class="blog-nav-item" href="#">New features</a> <a class="blog-nav-item" href="#">Press</a> <a class="blog-nav-item" href="#">New hires</a> <a class="blog-nav-item" href="#">About</a> </nav> </div> </div> <div class="container"> <div class="blog-header"> <h1 class="blog-title">The Bootstrap Blog</h1> <p class="lead blog-description">The official example template of creating a blog with Bootstrap.</p> </div> <div class="row">
footer.php:
</div><!-- /.row --> </div><!-- /.container --> <footer class="blog-footer"> <p>Blog template built for <a href="http://getbootstrap.com">Bootstrap</a> by <a href="https://twitter.com/mdo">@mdo</a>.</p> <p><a href="#">Back to top</a></p> </footer> <!-- Bootstrap core JavaScript ================================================== --> <!-- Placed at the end of the document so the pages load faster --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script> <script src="../../dist/js/bootstrap.min.js"></script> <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> <script src="../../assets/js/ie10-viewport-bug-workaround.js"></script> </body> </html>
sidebar.php:
<div class="col-sm-3 col-sm-offset-1 blog-sidebar"> <div class="sidebar-module sidebar-module-inset"> <h4>About</h4> <p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p> </div> <div class="sidebar-module"> <h4>Archives</h4> <ol class="list-unstyled"> <li><a href="#">March 2014</a></li> <li><a href="#">February 2014</a></li> <li><a href="#">January 2014</a></li> <li><a href="#">December 2013</a></li> <li><a href="#">November 2013</a></li> <li><a href="#">October 2013</a></li> <li><a href="#">September 2013</a></li> <li><a href="#">August 2013</a></li> <li><a href="#">July 2013</a></li> <li><a href="#">June 2013</a></li> <li><a href="#">May 2013</a></li> <li><a href="#">April 2013</a></li> </ol> </div> <div class="sidebar-module"> <h4>Elsewhere</h4> <ol class="list-unstyled"> <li><a href="#">GitHub</a></li> <li><a href="#">Twitter</a></li> <li><a href="#">Facebook</a></li> </ol> </div> </div><!-- /.blog-sidebar -->
index.php:
<div class="col-sm-8 blog-main"> <div class="blog-post"> <h2 class="blog-post-title">Sample blog post</h2> <p class="blog-post-meta">January 1, 2014 by <a href="#">Mark</a></p> <p>This blog post shows a few different types of content that's supported and styled with Bootstrap. Basic typography, images, and code are all supported.</p> <hr> <p>Cum sociis natoque penatibus et magnis <a href="#">dis parturient montes</a>, nascetur ridiculus mus. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum.</p> <blockquote> <p>Curabitur blandit tempus porttitor. <strong>Nullam quis risus eget urna mollis</strong> ornare vel eu leo. Nullam id dolor id nibh ultricies vehicula ut id elit.</p> </blockquote> <p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p> <h2>Heading</h2> <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> <h3>Sub-heading</h3> <p>Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> <pre><code>Example code block</code></pre> <p>Aenean lacinia bibendum nulla sed consectetur. Etiam porta sem malesuada magna mollis euismod. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa.</p> <h3>Sub-heading</h3> <p>Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean lacinia bibendum nulla sed consectetur. Etiam porta sem malesuada magna mollis euismod. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p> <ul> <li>Praesent commodo cursus magna, vel scelerisque nisl consectetur et.</li> <li>Donec id elit non mi porta gravida at eget metus.</li> <li>Nulla vitae elit libero, a pharetra augue.</li> </ul> <p>Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue.</p> <ol> <li>Vestibulum id ligula porta felis euismod semper.</li> <li>Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</li> <li>Maecenas sed diam eget risus varius blandit sit amet non magna.</li> </ol> <p>Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis.</p> </div><!-- /.blog-post --> <div class="blog-post"> <h2 class="blog-post-title">Another blog post</h2> <p class="blog-post-meta">December 23, 2013 by <a href="#">Jacob</a></p> <p>Cum sociis natoque penatibus et magnis <a href="#">dis parturient montes</a>, nascetur ridiculus mus. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum.</p> <blockquote> <p>Curabitur blandit tempus porttitor. <strong>Nullam quis risus eget urna mollis</strong> ornare vel eu leo. Nullam id dolor id nibh ultricies vehicula ut id elit.</p> </blockquote> <p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p> <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> </div><!-- /.blog-post --> <div class="blog-post"> <h2 class="blog-post-title">New feature</h2> <p class="blog-post-meta">December 14, 2013 by <a href="#">Chris</a></p> <p>Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean lacinia bibendum nulla sed consectetur. Etiam porta sem malesuada magna mollis euismod. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p> <ul> <li>Praesent commodo cursus magna, vel scelerisque nisl consectetur et.</li> <li>Donec id elit non mi porta gravida at eget metus.</li> <li>Nulla vitae elit libero, a pharetra augue.</li> </ul> <p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p> <p>Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue.</p> </div><!-- /.blog-post --> <nav> <ul class="pager"> <li><a href="#">Previous</a></li> <li><a href="#">Next</a></li> </ul> </nav> </div><!-- /.blog-main -->
Now that the HTML code is all split into the correct files, lets edit each file and integrate it with WordPress.
Step 7: Edit header.php
Right now, your header.php file contains the static HTML content that we took from the Bootstrap example file, without any changes. We are now going to make the following edits:
- Remove all references to any CSS files since we are using our enqueue functions and hooks to take care of including the style sheets.
- We are also going to remove the meta tags (for author and description, since these can and should be added and managed using a plugin such as Yoast SEO) and the favicon (the favicon can be added using core WordPress functions as well).
- Remove the <title> tag as well. We are going to let WordPress manage the title for us. For this, we need to make a small addition to our functions.php file – discussed below.
- Use the language_attributes() function to display the language attributes for the <html> tag.
- Use the bloginfo(‘charset’) function to display the encoding for pages and feeds set in Settings > Reading. It always echoes “UTF-8”, which is the default encoding of WordPress.
- And lastly, use the wp_head() function right before the closing </head> tag. Any background functions and gathering of CSS and/or JS files etc. is performed by this function (hook) and this is crucial for the functionality and performance of most plugins.
- Lastly, use the body_class() function which gives the body element different classes based on the page that is being generated.
So your final header.php file, for this tutorial, becomes:
<!DOCTYPE html> <html <?php language_attributes(); ?>> <head> <meta charset="<?php bloginfo( 'charset' ); ?>"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> <?php wp_head(); ?> </head> <body <?php body_class(); ?>> <div class="blog-masthead"> <div class="container"> <nav class="blog-nav"> <a class="blog-nav-item active" href="#">Home</a> <a class="blog-nav-item" href="#">New features</a> <a class="blog-nav-item" href="#">Press</a> <a class="blog-nav-item" href="#">New hires</a> <a class="blog-nav-item" href="#">About</a> </nav> </div> </div> <div class="container"> <div class="blog-header"> <h1 class="blog-title">The Bootstrap Blog</h1> <p class="lead blog-description">The official example template of creating a blog with Bootstrap.</p> </div> <div class="row">
Step 8: Edit functions.php, Again
So I just removed the <title> tag from the header.php file, which as we all know is a vital component of any web page. Without going into too much detail, lets just say that you can let WordPress plugins and themes to manage the document title tag by adding support for it by using add_theme_support(). This functionality became available in WordPress 4.1 An alternate but older approach is to use the wp_title() function. So, add this code to your functions.php in order to allow WordPress to take care of the title tag for you:
function bootstrapstarter_wp_setup() { add_theme_support( 'title-tag' ); } add_action( 'after_setup_theme', 'bootstrapstarter_wp_setup' );
Step 9: Edit footer.php
We’ll do the same here as we did with header.php – remove all references of any Javascript files. We also use the wp_footer() function just before the closing </body> tag to fire the ‘wp_footer’ action. So your final footer.php file becomes:
</div><!-- /.row --> </div><!-- /.container --> <footer class="blog-footer"> <p>Blog template built for <a href="http://getbootstrap.com">Bootstrap</a> by <a href="https://twitter.com/mdo">@mdo</a>.</p> <p><a href="#">Back to top</a></p> </footer> <?php wp_footer(); ?> </body> </html>
Step 10: Edit index.php
We finally have all the files in place and all we need now is the main file that will display the recent posts in the default chronological order. We basically need to replace all our static content inside index.php with The Loop that uses standard WordPress functions to display the title, content, author name, date, etc.
The final index.php will look like this:
<?php get_header(); ?> <div class="col-sm-8 blog-main"> <?php if ( have_posts() ) { while ( have_posts() ) : the_post(); ?> <div class="blog-post"> <h2 class="blog-post-title"><?php the_title(); ?></h2> <p class="blog-post-meta"><?php the_date(); ?> by <?php the_author(); ?></p> <?php the_content(); ?> </div><!-- /.blog-post --> <?php endwhile; } ?> <nav> <ul class="pager"> <li><?php next_posts_link('Previous'); ?></li> <li><?php previous_posts_link('Next'); ?></li> </ul> </nav> </div><!-- /.blog-main --> <?php get_footer(); ?>
Please note, we’ve used these functions in place of the static HTML for the post block:
These are pretty self-explanatory but you can read more at the WordPress Codex about these functions. We start the loop by testing if there are any posts to be displayed on this page – if there are, we go ahead and start the while loop and for each of the post components, we replace the HTML with the corresponding function. So for the post title, we replaced the line
<h2 class="blog-post-title">Sample blog post</h2>
with
<h2 class="blog-post-title"><?php the_title(); </h2>
The next and previous links for the posts are the pagination links and can be generated using the functions:
Also note, we’ve used the get_header() and get_footer() functions at the very top and bottom of the page. These ensure that the header and footer of your theme are included on this page.
Step 11: Edit style.css, Again
Lastly, lets just copy all the rules from the starter template blog.css file (which is being referenced by the example template in the <head>) into our own theme style.css file. Be sure to add the CSS code after the comment header for your style.css file.
Conclusion
So that’s it – for now. This is a basic bare bones WordPress theme created using the blog template on the official Bootstrap website. There are elements that are not integrated such as the navigation, site header and description, sidebar, and footer which are all still static HTML. We will work on integrating them in the coming tutorials.
Now log into your WordPress administration area, go to Appearance > Themes and you will see something like this:
Activate your new theme and then go to the front end website – and voila!
That wraps up the first part of this tutorial series. Hope it helped and that you enjoyed it. You can download the source for this part below.