Creative Geek: IMHO

Web design & development, data visualization, UI/UX, pretty things, zombies and whatever else by Chienyi Cheri Hung

Creative Geek: IMHO

Web design & development, data visualization, UI/UX, pretty things, zombies and whatever else by Chienyi Cheri Hung

Building a Ghost Blog Theme - Part 1

UPDATED 11.23.2014 ()
I've always wanted to give Ghost blog a go. Blogging in Markdown just seems so much easier (and geekier). No more writing HTML, just writing.

However, before Ghost launched a hosting service, finding a way to host and spin up the Node.js-based platform was a bit too much trouble.

Not a problem anymore! So I recently started out by building my own theme, Islay. It's named after my favorite style of whisky. I took the Scotch's lovely smokey and layered flavors as my design inspiration.

The theme is built on the awesome Foundation 5 framework. Currently, I'm developing and compiling it using Mixture. This is a rapid work flow that I love. But, I still plan on creating a Grunt version for release in the future. A lot easier to share with peeps.

Lessons Learned: Template Building

Ghost uses Handlebar templates and comes with some built-in helpers for looping posts, pagination, tags etc. For more details on the theme components and requirements, check out their comprehensive documentation on creating your own theme.

Partials & Assets

Handlebar partials are supported by Ghost. Partials are great for making your code modular. To use this in your theme, create a folder partials/ in your theme folder. It can then be included from anywhere by using {{> partial_file_name }}.

Your theme should also have an assets folder that contains the css, javascript or any other assets. You can then use the handy helper {{asset}} to link to any of those files with ease. E.g. {{asset css/styles.css}}.

Customizing Pagination

Ghost has a built-in pagination. To replace it with your own, simply create a partial named pagination.hbs. Then include it like so {{pagination}}.

It's helpful to start from the default codes which you can find in the core/server/helpers/tpl/ folder of your local install.

pagination.hbs default

<nav class="pagination" role="navigation">  
    {{#if prev}}
        <a class="newer-posts" href="{{page_url prev}}">&larr; Newer Posts</a>
    {{/if}}
    <span class="page-number">Page {{page}} of {{pages}}</span>
    {{#if next}}
        <a class="older-posts" href="{{page_url next}}">Older Posts &rarr;</a>
    {{/if}}
</nav>  

As far as I know, there isn't a way to display a numerated pagination from Ghost. If anyone finds a way, let me know!

Ghost also has a built-in site navigation. I decided not to have one in my theme. The process for customization is the same as pagination. The file name is nav.hbs.

Customizing Tag Item

Ghost supports tags for posts and pages. Including {{tags}} in your templates, it loops through the associated tags and then generates an <a> for each tag, separated by commas as the default. You can't change the generated markup (why would you really?). But it can further customized by adding prefix, suffix, and separator attributes. There is no default prefix or suffix.

For example, since I styled each of my tag to look like labels and have no need for a separator, I simply used this {{tags separator=''}}.

Author Info Outside of Post Loop

I wanted to display my author information in the footer. That data is saved in back-end admin area like the blog information. So I thought it would be as easy as pulling that. But then I quickly realized that Ghost only enables author info to be pulled within a post/page loop.

Putting it in the loop is useful when you have multiple authors and/or wish to display author attribution per post. But I don't see a need to display my name repeatedly in my personal blog. (Google Authorship you say? Just add a <link rel="author" href="your_googleplus_url"/> in the <head> instead).

A work around is to literally wrap author tag in a post loop to fetch the information. The first part of the if/else is for when you are on a single post or page. When on an index page, it'll fetch the information from the first post in the loop. (Meh, it's a work around.) Like so:

{{#if post}}
    {{#post}}
        <div class="author-image left">
        <img src="{{author.image}}" alt="   
        {{author.name}}"></div>
        <p class="author-bio">{{author.bio}}</p>
    {{/post}}
{{else}}
    {{#foreach posts}}
    {{#if @first}}
        <div class="author-image left">
        <img src="{{author.image}}" alt="   
        {{author.name}}"></div>
        <p class="author-bio">{{author.bio}}</p>
    {{/if}}
    {{/foreach}}
{{/if}}

Showing Partial Post Content Instead of Excerpt

On the index pages, I wanted to show a truncated post rather than an excerpt, which is the default in the example Casper theme.

It's a minor difference between these two Ghost built-in features. {{excerpt words="80"}} shows the first 80 words without html. It's also possible to limit by characters instead. {{content words="80"}} shows 80 words of HTML. It's smart enough to not truncate ending html tags. Nicer presentation than a chunk of text for my taste.

Currently, Ghost doesn't have a native way to write customized excerpt.

Social Social Social

To add user commenting, I used Disqus, the free plug-and-play third-party service. Ghost leaves out commenting as a built-in feature. This isn't terribly missed. Services like Disqus is easy enough. (Though I wish I could customize the look of Disqus comment embeds.)

To enable easier sharing and site analytics, I simply created partials with AddThis and Google Analytics embed codes. Included them in the templates and done! Simple.

Cover Images

Post Cover Image

With Ghost 0.5.2, it comes the ability to assign cover image to a post à la Wordpress feature image.

I added template support for it in my Islay 0.1.5 release. If there is a cover image assigned, it will be printed after published date and before all content.

To print the post cover image, use helper {{image}} in your templates. There may be more support with cover image helpers later. For now, {{image}} inside a post loop simply returns the image's path. You will need to wrap it in an <img> tag. Like this line that I added in post.hbs:

{{#if image }}
<div class="feature-image"><img src="{{image}}"></div>  
{{/if}}

The conditional is just good practice to avoid printing empty tags if no cover image exists.

Blog Cover Image

Ghost supports setting a Blog Cover image via its Admin menu. To fetch and display, use @blog.cover which also outputs the image's url path.

There is no way to run the handlebar helper in my theme scss file. The way is to add a <style> block in the <head> after styles.css.

{{#if @blog.cover}}
 <style tyle="text/css">
  body { 
      background: url('{{@blog.cover}}') top center repeat; 
  }
</style>  
{{/if}}

Ghost vs Wordpress

Just for comparison's sake and since I do a fair amount of Wordpress theme development — I found it to be a much faster and less painful process than creating a new Wordpress theme.

After setting up Ghost locally, the development process is really straightforward. If you are familiar with Handlebar, it should be a piece of cake. There are not a lot of code to dig through or modify.

I plan on writing a part 2 that talks about integrating Foundation 5, customized sass functions, and javascript fun. No idea when I'll get to it.