I was tempted to see how easy (or difficult) it is to make a Ghost theme. So, I took Twenty Thirteen and give it go. Here is a step by step review of how I did it and what problems there are still in Ghost (mind that this version 0.3, it is normal that some things don’t work).
Luckily, there is only one things that did not work, and that is overriding of partial templates…in this case pagination template. I will update this tutorial as more documentation become available or bugs are fixed, so do not hesitate to come back often and check new stuff.
Table of Contents
Ghost theme anatomy
The file structure of Ghost theme looks like this:
- /css
- style.css
- /fonts
- /img
- /js
- /lib
- /partials
- default.hbs
- index.hbs [required]
- post.hbs [required]
Basically, we only need index.hbs, post.hbs and default.hbs to make a theme. Default.hbs is actually a layout file with header and footer and it renders our two other templates inside it. Index.hbs is used for a home page and other pages with list of posts, while post.hbs is used for single post view.
Preparation
First step is to copy the default Casper theme, paste inside /content/themes folder and rename it. I called it twentythirteen.
If you go to settings of your Ghost blog, you will see that there is no new theme listed. We need to restart node.js server to ake it appear, so do it and select twentythirteen as your theme.
Now, copy style.css from Twenty Thrteen WordPress theme to /content/themes/twentythirteen/assets/css and all images from images folder of Twenty Thirteen theme to /content/themes/twentythirteen/assets/img.
Open the /content/themes/twentythirteen/assets/style.css and replace all images/ urls inside this css file with ..img/ as now our images are in folder above CSS.
Default layout
Now, open up /content/themes/twentythirteen/default.hbs and paste this in:
[code lang=”js”]
<!DOCTYPE html>
<html>
<head>
{{! Document Settings }}
<meta http-equiv="Content-Type" content="text/html" charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
{{! Page Meta }}
<title>{{meta_title}}</title>
<meta name="description" content="{{meta_description}}" />
<meta name="HandheldFriendly" content="True" />
<meta name="MobileOptimized" content="320" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{{! Styles’n’Scripts }}
<link rel="stylesheet" type="text/css" href="/assets/css/style.css" />
<link rel=’stylesheet’ href=’//fonts.googleapis.com/css?family=Source+Sans+Pro%3A300%2C400%2C700%2C300italic%2C400italic%2C700italic%7CBitter%3A400%2C700&subset=latin%2Clatin-ext’ type=’text/css’ media=’all’ />
{{! Ghost outputs important style and meta data with this tag }}
{{ghost_head}}
</head>
<body class="{{body_class}}">
<div id="page" class="hfeed site">
{{! Everything else gets inserted here }}
{{{body}}}
<footer id="colophon" class="site-footer" role="contentinfo">
<div class="site-info">
Proudly published with <a class="icon-ghost" href="http://tryghost.org">Ghost</a>
</div><!– .site-info –>
</footer><!– #colophon –>
</div><!– #page –>
{{! Ghost outputs important scripts and data with this tag }}
{{ghost_foot}}
{{! The main JavaScript file for TwentyThirteen }}
<script type="text/javascript" src="/assets/js/index.js"></script>
</body>
</html>
[/code]
Basically, this is our layout file with proper path to CSS, proper fonts included and proper markup for Twenty Thirteen theme.
Index template
Now, open your /content/themes/twentythirteen/index.hbs file and paste this in:
[code lang=”js”]
{{! The comment above "< default" means – insert everything in this file into
the {body} of the default.hbs template, which contains our header/footer. }}
{{! The big featured header on the homepage, with the site logo and description }}
<header id="masthead" class="site-header" {{#if @blog.cover}}style="background-image: url({{@blog.cover}})"{{/if}}>
{{#if @blog.logo}}
<a id="blog-logo" title="{{@blog.title}}" class="home-link" href="{{@blog.url}}"><img src="{{@blog.logo}}" alt="{{@blog.title}}" /></a>
{{else}}
<a href="{{@blog.url}}" class="home-link">
<h1 class="site-title">{{@blog.title}}</h1>
<h2 class="site-description">{{@blog.description}}</h2>
</a>
{{/if}}
</header>
{{! The main content area on the homepage }}
<div id="main" class="site-main">
<div id="primary" class="content-area">
<div id="content" class="site-content" role="main">
{{! Each post will be output using this markup }}
{{#foreach posts}}
<article class="type-post post format-standard hentry">
<header class="entry-header">
<h1 class="entry-title">
<a rel="bookmark" href="{{url}}">{{title}}</a>
</h1>
<div class="entry-meta">
<span class="date"><time datetime="{{date format=’YYYY-MM-DD’}}">{{date format="DD MMM YYYY"}}</time></span>
<span class="categories-links">{{#if tags}}on {{tags}}{{/if}}</span>
</div>
</header><!– .entry-header –>
<div class="entry-content">
{{excerpt}} …
</div><!– .entry-content –>
<footer class="entry-meta">
</footer><!– .entry-meta –>
</article>
{{/foreach}}
{{!! After all the posts, we have the previous/next pagination links }}
{{!! pagination}}
</div>
</div>
</div>
[/code]
Again, just changing markup to match that of Twenty Thirteen theme. I commented out pagination, will tell you why when I get to it.
Post template
One more template is left and that is /content/themes/twentythirteen/post.hbs:
[code lang=”php”]
{{!< default}}
{{! The comment above "< default" means – insert everything in this file into
the {body} of the default.hbs template, which contains our header/footer. }}
<header id="masthead" class="site-header" {{#if @blog.cover}}style="background-image: url({{@blog.cover}})"{{/if}}>
{{#if @blog.logo}}
<a id="blog-logo" title="{{@blog.title}}" class="home-link" href="{{@blog.url}}"><img src="{{@blog.logo}}" alt="{{@blog.title}}" /></a>
{{else}}
<a href="{{@blog.url}}" class="home-link">
<h1 class="site-title">{{@blog.title}}</h1>
<h2 class="site-description">{{@blog.description}}</h2>
</a>
{{/if}}
</header>
<div id="primary" class="content-area">
<div id="content" class="site-content" role="main">
{{! Everything inside the #post tags pulls data from the post }}
{{#post}}
<article class="type-post post format-standard hentry">
<header class="entry-header">
<h1 class="entry-title">
{{title}}
</h1>
<div class="entry-meta">
<span class="date"><time datetime="{{date format=’YYYY-MM-DD’}}">{{date format="DD MMM YYYY"}}</time></span>
<span class="categories-links">{{#if tags}}on {{tags}}{{/if}}</span>
</div>
</header><!– .entry-header –>
<div class="entry-content">
{{content}}
</div><!– .entry-content –>
<footer class="entry-meta">
</footer><!– .entry-meta –>
</article>
{{/post}}
</div><!– #content –>
</div><!– #primary –>
[/code]
Pagination
As for the pagination, Ghost documentation says that we need to create a folder in /content/themes/twentythirteen called partials and put in the same name of the template as we are trying to override. Well, I did that and created /content/themes/twentythirteen/partials/pagination.hbs and put this in:
[code lang=”js”]
<nav role="navigation" class="navigation paging-navigation">
<div class="nav-links">
{{#if prev}}
<div class="nav-next"><a href="{{pageUrl prev}}">Newer posts <span class="meta-nav">→</span></a></div>
{{/if}}
{{#if next}}
<div class="nav-previous"><a href="{{pageUrl next}}"><span class="meta-nav">←</span> Older posts</a></div>
{{/if}}
</div><!– .nav-links –>
</nav>
[/code]
But, unfortunately, this is not working at the moment. Ghost developers told us that proper documentation will be online these days, so I will wait and update this tutorial accordingly.
Conclusion
Ghost platform is really great even in this early stage. Making of Ghost Theme is not that difficult, even for non Node.js developer (like me), as it is very similar to WordPress. I really hope that Ghost will succeed and make it to the top of blogging platforms.
Great article! It’s exciting to see a community of Ghost developers spring up so quickly. I just wanted to let you know that we’ve started a new project on GitHub called, “Linen.” It’s an open-source Ghost theming framework. It goes beyond the basics that you’ll find in Casper and demonstrates some more advanced features of Handlebars and Ghost. Please look it over if you like. Thanks!
http://github.com/themespectre/Linen
Thanks,
I went to see the Linen and I like it. I had problems with overriding pagination helper template, any ideas what did I do wrong above?
As I looked in Ghost code, and above should work…
Sorry it’s taken so long to reply…
This is a known bug with Ghost. The pagination helper cannot currently be overridden as stated in the docs, and an issue has been raised in GitHub.
Pingback: An Introduction To The Ghost Blogging Platform | WiredTree Blog
One of the main reasons to take a decision about a CMS has always been, for me, the ease to propose a “custom theming” to customers.
Thank you for this post which cleared the topic.
Comments are closed.