Let’s Build A WordPress Theme From Scratch Using Timber And Bootstrap

Pre-Prelude

If you are like “Dude, It’s already 2018 and you are still writing about WordPress theme development from scratch ?” Well yes, why not! But trust me its different, its modern and it uses Timber! Read on…

Prelude

If you happen to work in a digital agency, you have pretty much idea how heavy chunk of developers’ time is spent creating themes unique to each client. And I understand the pain of developing a WordPress theme from scratch. Even though It doesn’t feel that difficult after creating dozens and dozens of websites using vanilla WordPress. Right? But It is whatsoever no fun we all know. Luckily there is a smarter way.

Developing themes using vanilla WordPress felt like a chore, therefore the good folks at Boston based Upstatement, developed a plugin for WordPress that makes theme development a cinch.

Enter Timber

Timber, along with the solid templating engine, Twig with it’s object-oriented approach, makes a wonderful and a pretty powerful library which makes WordPress theme development easy and more enjoyable.

With Timber and Twig in your tool-belt, you end up nothing but writing clean, maintainable and modular code in a comparatively shorter amount of time.

Enough Praise, Let’s Get To Work!

OK, let’s stop the praise train for now and get down to business.
So, we’ll develop a basic functional blog theme based on this [Bootstrap 4.x blog example] with the following features:

Main Navigation

About Section sidebar

List paginated blog posts on the homepage

Search box

Search results page

Blog single page and Pages

It will be a striped-down version of the example given on Bootstrap website.

Theme Setup

Timber is a WordPress plug-in as well as a composer package. So, we will be using it as a composer package and include it in our theme which saves us from managing it as an external (to the theme) dependency via something like this plugin.

To set up our brand new theme, assuming we have installed and configured a fresh copy of the latest version of WordPress, in your themes directory (wp-content/themes), create a folder and name it whatever you want or lets call it awe-theme .
Like so,

This comment block will tell WordPress that hey I’m a theme and these are my details. For any theme there are two files which are required, style.css and index.php otherwise WordPress will complain about the presence of a broken theme.

Finally, when we create both files, it will display our theme to be previewed or activated.

If you notice a snapshot of the theme is missing but still we can use the theme. If you want, you can add a file named screenshot.png with dimensions 1200px x 900px to the theme’s directory along with those two files. Pretty simple and straight-forward, Huh.

Now that WordPress has Identified our theme, let’s install the prerequisites.

Install Timber

Make sure you have installed node.js, npm and composer on your system. First lets initialize composer so that it can autoload our PHP packages, Timber library in our case.

Configure Laravel Mix

If you’ve never heard of Laravel Mix, its a wrapper around webpack which provides an elegant API for defining basic build steps for a project. It was developed for Laravel but using it outside Laravel is super easy. Let me show you how easy it is.
Before that lets create directories and blank files for our style and script assets like this:

Create a new file and name it webpack.mix.js in your theme folder. Now paste this and save it:

Now we have three power-packed commands at our disposal which will be really useful throughout our development.
* dev – Compiles all the scripts and other assets without optimization
* watch – Compiles the assets and refreshes your browser as soon as you make any change to the code
* production – generates optimized version of all the assets

These commands can be used like this:

#npm run [command name]
npm run dev

Configure Browsersync

This step is optional but really useful and nice to have. It will save you some precious time between making a change to your code and seeing it on the browser throughout your development process.

Open up webpack.mix.js file and just before the .sass("assets/src/scss/app.scss", "assets/dist/") line, paste this:

Now, replace the proxy URL with your development URL for example http://localhost/my-wp-site.

Run npm run watch to start watching for file changes.

This setup is pretty much reusable and can be reused for most of your real life projects. Same holds true for the next section. If you plan your structure well you will end up reusing things instead of re inventing the well again and again.

Let’s Dive In To Theme Development

We will develop our theme based on this Bootstrap 4.x blog example
In order to use Timber or any other package we must include vendor/autoload.php to functions.php so that its available to the theme.

Go ahead and create a file called functions.php then paste this:

<?php
require_once __DIR__ . '/vendor/autoload.php';

Layout Composition

Timber by default, looks for twig files or views in a views directory in the theme root. Our theme will have a navigation, a footer, an optional sidebar and a content area which we will break in to twig partials. I like to organize my views into self-explanatory directories under the views directory for ease:
* views/layouts
* views/pages
* views/partials

layouts are twig files which are extended (or used) by pages or partials in our case.

Twig has a concept they call Template Inheritance. It helps us break a page in to reusable parts. We will heavily use extends and block tags to break our pages in to composable partials. You can read more about it here.

Partial Views Or Partials

We start by extracting partials from the blog example and save them in twig files then we’ll include them in our master layout we call base.twig.

Sidebar Partial View

Next up, we have the sidebar. If added, it will display the site name and description as well as social links. The social links are hard-coded. So go ahead and add your all of your social links in this partial.

Layouts Views

We have two layouts, a wide one without sidebar we call it base.twig and the second one with a sidebar we call it base-sidebar.twig. base.twig will be used for the homepage, pages and search results page, whereas the base-sidebar.twig will be used for article single page. But you can do whatever and however you want and use whichever base/layout with whichever page you like.

If you notice we are pulling site/page title, description as well as theme URL from timber context which we will discuss when we discuss the PHP files.
And also notice how we are including the header and nav twig files using the include tag. This is similar to include() function in PHP.
Then we define a block using the block and endblock tag named content. It means we can put anything here from another twig file by using the extends tag and defining a block with the same name. We will see it in a moment.

Pages Views

We have three views which we have categorized in to pages because of their nature. The rule I have set for calling any view a page and putting it under views/pages directory is simple, if it extends a layout, it’s page otherwise its a partial and is placed under views/partials.

Notice we have defined a block named content in the base.twig already.
This means we have made base.twig aware that we can replace this part with whatever we like and whenever we like. So index.twig wants to display its own markup between {% block content %} and {% endblock %} by defining the block here and putting our markup.

This is similar to single but this is for pages. For WordPress, page is a post with post type of page. so you can use the same file for both or if you want to make posts appear different than pages you should separate them.

View Controllers

Now that all our views are created, we will move towards the PHP files responsible to render these views. I like to call them controllers because they do control the views. We have a controller for each of our page view.

Note that by default WordPress reads the .php files/templates from theme’s directory in a certain order. To get a better understanding of which template (.php files) of a theme are called and when, carefully read this section from the WordPress documentation and also check this interactive diagram to help you better understand how template hierarchy in WordPress works.

Timber::get_context() is the sauce of Timber library. It gives you almost everything about your website as well as the current theme. Which includes the current user, all the posts, site details like title, description, body classes, all the details about the current theme (as Said earlier) and what not, all in an Object-Oriented manner, which can be accessed from the twig file with little to no effort!

For example, to get the site’s title, you write site.title and to get the current theme URL, you’d write site.theme.link. Can’t be more simple than this!

As I explained in the earlier that get_context() function besides other useful bits of information, also has a list of posts, but if you notice I’ve still called PostQuery() with $args in the index.php why? Because I want to tell WordPress, “hey, I want posts with post_typepost and ten of them and yes, enable pagination as well”. This will override the posts in the context and with paginated ones. The code is pretty self explanatory.

The rest of the controllers are similar they just call the relevant view.

Are We Missing Something?

Looks like we are. Because we are using a navigation menu and also featured image in our theme and never told WordPress about it. This is a good time we do in functions.php. Go ahead and open it and paste this:

Notice we have defined a class named mySite. This allows us to configure our Timber theme and add features like menu, thumbnail and many more.

Also notice in views/partials/nav.twig we are calling menu.get_items(). menu is referring to $context['menu'] which is assigned a instance of Timber\Menu which loads the menu we have defined in our WordPress dashboard.

Thats pretty much all. If you want you can move this class to its own file for the sake of keeping functions.php light and clean.

Home Work

To get you hands-on, I have left the footer in the base.twig and base-sidebar. All you have to do is extract it out in to a footer.twig and include it in both layouts just like we did with header.twig. The second assignment is add the featured image to the post’s single view. At the moment we only display the featured image on the articles list on the home page.

Finally thank you very much for taking the time to read till here. If you have followed along, great! If not you can check out the code on GitHub.

Like this:

Related

Comments

To respond on your own website, enter the URL of your response which should contain a link to this post's permalink URL. Your response will then appear (possibly after moderation) on this page. Want to update or remove your response? Update or delete your post and re-enter your post's URL again. (Learn More)

shuja uddin says

can it be a video tutorial then it will be really useful.

Junaid Qadir says

Thanks Shuja for your time. Well it's already difficult to takeout time to write an in-depth post. A video takes more time and energy. I won't promise but I'd love to work on your suggestion. Please keep an eye on my website for more such articles related to WordPress, Timber, React and Vuejs.

Al Avery says

Thanks for the detailed write-up. I would love a more in-depth look at other Timber classes, like Timber/Term. The controller part of Timber can be a bit tricky for me. Thanks again!

Junaid Qadir says

Thank very much.

Chris Allen says

It’s write ups like this that make me glad to be a developer in 2018. Thanks, hope you realise how much this is appreciated 😉

Junaid Qadir says

Thanks for appreciating and Thanks for your time reading it.

Rémi says

Hello , i tried to follow your tutorial but when i lauch ‘npm run dev’ i have an error : “NODE_ENV” is not recognized as an internal or external command, operable command or batch file . Can you help me ? thanks

Also you did not mention that in your app.js you have to add : import 'bootstrap';

Many thanks for this tutorial and help.

Junaid Qadir says

Anytime.
Glad to hear!
I imported Bootstrap in the app.scss
I'd love to see how you went about it.
It would be great if you can share some code on github.

Hab says

Two minor issues in this article: 1. For "Post Single View", you are missing this first line in the code: "{# File views/pages/single.twig #}". A newb wouldn't know. 2. In the code for base.twig, there's a typo when calling wp_footer... you have it spelt with a strange character "đ" (wp_đooter).

Junaid Qadir says

Thank you very much for pointing out the issues. I have fixed them.
And So sorry I couldn't respond timely.

Boogey says

How can you render partials per content type? For example, I have a custom post type "Book" and would like to have a header-book.twig

Junaid Qadir says

You can do this by creating a twig file named views/pages/single-book.twig. Then inside this view you can do anything you want for example create a different layout which loads your header-book.twig and footer-book.twig and load the layout using {% extends 'layouts/your-layout.twig' %}.

Please let me know that's what you are trying to do.

Junaid Qadir says

Please read the WordPress documentation. This link might help you https://developer.wordpress.org/themes/basics/template-hierarchy/

Sorry for replying late

Ramil Yabbarov says

Hello, can you tell, how to do a sidebar on all pages (base.twig) ? In documentation very strange things about this.

Junaid Qadir says

Hi, please check code for base-sidebar.twig. Either use this layout for all pages or use the code from this layout and copy it to your base.twig.