Anatomy of a Ghost Blog Theme
Ghost is an open source blogging platform that was built by writers for writers. Designed to allow you to focus on your content and not which plugin to use, Ghost is very no frills. You won’t find jQuery navigation bars or sliders. What you will find is an easy to use blogging system that puts your content first.
Ghost also uses Markdown to format your posts, again making it simple for non-developers to update their blog. Many people want to blog but are intimidated by the scope of a product like WordPress. If you want to get up and running relatively quick with a blog, Ghost could be for you.
The simple design also makes it easy to incorporate your favorite frameworks and libraries. Want to use Foundation or Bootstrap components? How about jQuery or Masonry? The scaled down design of Ghost makes it effortless to use third party tools in your custom themes.
Installation
Installation of Ghost is simple if you have Node.js installed on your system. Even if you don’t know Node.js you should have no problem installing on your platform of choice. If you don’t have Node.js installed, you can get it here. After installing Node, head on over to Ghost to download.
I want to take a moment to highlight the challenges the use of Node.js poses. Since Node is essentially server-side JavaScript, you are limited in the hosts you can use Ghost on. You will need a virtual server to run Ghost with standard hosting, an expensive proposition if you just want to start a simple blog. The most economical options are the free tier of Amazon Web services, Digital Ocean, or Ghost Pro. Amazon is free but will require the configuration of a server. Digital Ocean is five dollars a month and offers full control, again requiring configuration of a server. The Ghost Pro option, ten dollars a month, is completely managed by the Ghost team and is the easiest to get up and running.
First steps
Create a folder called Ghost and extract the zip file into it. Open the Node command prompt and navigate to the directory where you extracted the file. Run this command to install Ghost:
npm install --production
After installation, go to the Ghost folder and open config.js
file and change the following line to the URL of your site:
url: 'http://my-ghost-blog.com',
If you do not have a domain name you can use your IP address. You can also change the host and port although this is not necessary to get Ghost working. After you change these settings, type the following command:
npm start
This will work only if you are in the Ghost folder. Ghost will start up and let you know what domain/IP address and port it is listening on (should be the same as what you set in config.js
).
Creating a theme
Out of the box, Ghost comes with the basic Casper theme. Casper is designed to be a starting point for your own themes. Ultimately you will want to design your own themes. The only limit on what you can build is the way that Ghost handles the data that makes up your blog posts.
Navigate to your the \content\themes
folder in your Ghost folder. In there you will see a folder for the Casper theme. Creating a custom theme is as easy as creating a folder with the name of your theme. Inside your theme folder create a post.hbs and index.hbs file and you have a theme, although it is not very useful at this point. Lets take a deeper look at the files that make up a theme.
package.json
{
"name": "Theme",
"version" : "1.0"
}
The package.json file will eventually be required by Ghost. It basically tells Ghost the name and version for your theme.
default.hbs
<!DOCTYPE html>
<html>
<head>
{{! Document Settings }}
<meta http-equiv="Content-type" content="text/html" charset="UTF-8" />
{{! Page Meta }}
<title>{{meta_title}}</title>
<meta name="description" content="{{meta_description}}" />
<meta name="HandheldFriendly" content="True" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{{! Stylesheets }}
<link rel="stylesheet" type="text/css" href="/assets/css/pig.css" />
<link href='http://fonts.googleapis.com/css?family=Changa+One' rel='stylesheet' type='text/css'>
{{! Ghost outputs important style and meta data with this tag }}
{{ghost_head}}
</head>
<body class="{{body_class}}">
<div class="pagewrapper">
{{>header}}
<div>
{{{body}}}
</div>
{{> footer}}
{{! Ghost outputs important scripts and data with this tag }}
{{ghost_foot}}
</div>
{{! Javascript files here }}
</body>
</html>
Even though you only need a post.hbs and index.hbs file in a folder to have a theme, the glue that holds the theme together is default.hbs. This file is the main template for all pages, and all pages will load as part of default.hbs. The .hbs is a file extension used with the Handlebars template engine.
{{! Document Settings }}
Normally tags within double curly brackets are Handlebars tags. In this case the exclamation point makes this a comment.
<title>{{meta_title}}</title>
A Handlebars tag in action, this time supplying the title of the page.
{{ghost_head}},{{ghost_foot}}
This is a special Ghost tag for outputting styles, meta data, and scripts.
<body class="{{body_class}}">
This is used to output classes based on what content is being loaded.
{{>header}}, {{> footer}}
Used to output partial files, Handlebars will look for these in the partials directory.
{{{body}}}
The most important tag on the page, this is where content will be loaded. Also note the triple curly braces. This tells Handlebars not to escape HTML and display as intended.
index.hbs
{{!< default}}
{{#foreach posts}}
<article class="mbox">
<div class="i-title">
<h2><a href="{{{url}}}">{{title}}</a></h2>
<time>
{{date format='DD MMM YYYYY'}}
</time>
</div>
<div class="list-post">
<div class="i-pic">
<p>{{content words="0"}}</p>
</div>
<div class="i-blurb">
<p>{{excerpt}} ... <a href="{{{url}}}">Read More</a></p>
</div>
</div>
</article>
{{/foreach}}
index.hbs is first page that displays when you load a Ghost page and it’s the only page that receives data for all posts. That means that index.hbs is the only page you can have a list of posts on without hacking together a solution in JavaScript.
{{!< default}}
The above indicates to Handlebars that this page will load into default.hbs, into the {{{body}}} tag from default.hbs.
{{#foreach posts}}, {{/foreach}}
This is the Handlebars block helper that displays a list of posts. Content between tags will repeat for each post.
{{{url}}}, {{title}},{{date format='DD MMM YYYYY'}}
Handlebars tags for URL, title, and date of post.
{{content words=”0″}}, {{excerpt}}
These are special tags to output a small snippet of a post for the post listing. Normally you would use just one of these but I used both as a hack to include a picture in a post listing. The “content words” tag will output pictures but excerpt will not. Content words will output any amount of words you specify. When you choose 0, it only outputs the picture attached to the post. The “excerpt” tag is used to add a separate text area to a post, allowing you to style the picture and text independently.
post.hbs
{{!< default}}
{{#post}}
<article class="art-box">
<div class="p-title">
<h1><a href="/">← Go back</a></h1>
<h1>{{title}}</h1>
</div>
<div class="p-content">
{{{content}}}
</div>
{{#if author}}
<div class="p-writer">
<p>Written by {{author}}</p>
</div>
{{/if}}
</article>
{{/post}}
Page that displays when you click on a post, this page has access only to the contents of a single post.
{{#post}}, {{/post}}
This tells Handlebars that the page has access to a single post.
{{#if author}},{{/if}}
This checks to see if the post has an author profile; if so, it displays with the post.
header.hbs
<div class="head-wrap" {{#if @blog.cover}}style="background: url({{@blog.cover}});"{{/if}}>
{{#if @blog.logo}}
<div class="h-logo">
<a class="h-logo-style" href="{{@blog.url}}">
<img src="{{@blog.logo}}" alt="{{@blog.title}}">
</a>
</div>
{{/if}}
<div class="h-title">
<h1 class="h-title-style">
<a title="{{@blog.title}}" href='{{@blog.url}}'>{{{@blog.title}}}
</a>
</h1>
</div>
<div class="h-description">
<h2 class="h-description-style">{{@blog.description}}</h2>
</div>
</div>
Found in the partials directory, this is the file loaded from the {{>header}} tag in default.hbs.
<div class="head-wrap"
{{#if @blog.cover}}style="background: url({{@blog.cover}});"{{/if}}>
This tag checks if a blog cover has been uploaded and if so it sets it as the background.
{{#if @blog.logo}}, {{/if}}
This is used to output the blog logo if it has been uploaded.
<img src="{{@blog.logo}}" alt="{{@blog.title}}"
This displays the blog logo.
<a title="{{@blog.title}}" href='{{@blog.url}}'>{{{@blog.title}}}
Displays the blog title as a link.
<h2 class="h-description-style">{{@blog.description}}</h2>
Displays the blog description.
footer.hbs
<div class="foot-box">
<div class="f-social">
<a href="http://www.facebook.com/sharer.php?u={{url absolute="true"}}" target="_blank">
<img src="/assets/images/facebook.png">
</a>
<a href="https://plus.google.com/share?url={{url absolute="true"}}" target="_blank">
<img src="/assets/images/google_plus.png">
</a>
<a href="http://twitter.com/share?text={{@blog.title}}&url={{url absolute="true"}}" target="_blank">
<img src="/assets/images/twitter.png">
</a>
</div>
<div class="f-cp">
<p>© {{date format='YYYY'}} <a href="{{@blog.url}}">{{@blog.title}}</a></p>
</div>
<div class="f-ghst">
<p>Runs on <a href="http://ghost.org" target="_blank">Ghost</a></p>
</div>
</div>
Also found in the partials directory, this file loads from the {{> footer}} tag in default.hbs. No Handlebars tags you haven’t seen yet, this footer contains social media icons for sharing.
Styling the theme
As I mentioned, Ghost is very barebones. I was originally going to use Bootstrap to style pages but I decided to use a small grid system I built with Sass.
@media screen and (max-width: 600px) {
.mbox .list-post .i-pic {
position: relative;
min-height: 1px;
padding-left: 0px;
padding-right: 0px;
float: left;
width: 100%;
background-color: #f2e7e7;
border-bottom: 3px solid #090a0a;
}
.mbox .list-post .i-pic img {
width: 100%;
height: 100%;
}
}
@media screen and (min-width: 601px) {
.mbox .list-post .i-pic {
position: relative;
min-height: 1px;
padding-left: 0px;
padding-right: 0px;
float: left;
width: 33.33333%;
left: 33.33333%;
background-color: #f2e7e7;
border-bottom: 3px solid #090a0a;
}
}
In this small snippet from my .css file, I only included two breakpoints for this article, but in a real world application we would include many more. As you can see, all of the columns scale to 100% once the screen shrinks to 600 pixels.
Conclusion
I’ve only scratched the surface of what can be done with Ghost. If you are looking to start a blog and have the resources, I would suggest you give Ghost a try. Remember it’s built for writers by writers!