I recently put up a blog for my wife. I was looking for something that was easy for her to use, and easy enough to for me to customize for her needs. I landed on Ghost (GitHub) because of its simplicity. For her, it's been great for many reasons. For me, it's turned out to be a near-ideal balance between customisable and not needing to customization at all. For the customizations I did need to make, getting them to an easily maintainable state has been a fun learning experience.

To make it fit, it needed a few relatively minor customizations; A couple really minor stylesheet tweaks, a basic menu to for static pages, and comments for posts. Ghost is a young, actively developed platform, so it will continue to change (maybe drastically) with every release. I don't want to spend a lot of time re-integrating my changes whenever Ghost sees a release, so I needed my tweaks to be done in a way that I can reproduce with minimal effort, or toss if Ghost integrates the feature natively.

New Features: Comments and Menu

The menu addition was a simple unordered list under the cover image on the index page, styled to match Casper's other elements. The comments use Disqus, which employs JavaScript to dump an iframe into the page to provide comments as a service. These features both needed chunks of markup, which would be annoying to re-integrate over and over every time Ghost and Casper are updated. To make updating easy, I used partials (partial templates) for my markup additions, needing only a one line change in the Casper templates to actually include the feature.

After adding the menu and comments handlebars templates into the partials directory, adding them into the right Casper templates is easy (diff):

diff --git a/index.hbs b/index.hbs
index 80cf642..e8d18d4 100644
--- a/index.hbs
+++ b/index.hbs
@@ -16,10 +16,12 @@
 <a class="scroll-down icon-arrow-left" href="#content" data-offset="-45"><span class="hidden">Scroll Down</span></a>

+{{> "menu"}}
 {{! The main content area on the homepage }}
 <main id="content" class="content" role="main">

Because this is a one-liner, it's trivially easy to re-add my changes later if a later update of Ghost or Casper can't cleanly merge with the customization above.

Stylesheet Customizations

Ghost's excellent default theme (called Casper) is pretty much perfect out of the box. Since there isn't support for comments or menus in Ghost (and implicitly Casper), styles for those elements need to be integrated within Casper. This can be done maintainably by keeping CSS customizations to a minimum, and in a stand-alone file. By keeping the stylesheet is in a separate file, upstream changes to Ghost or Casper can be updated without worrying about conflicting changes in the stylesheets.

The only downside to this approach is that the reader's browser has to download one additional file. This won't be a noticeable problem for a blog on this scale.

I called my custom stylesheet custom.css, for which I added a reference at the top of the default template (diff):

--- a/default.hbs
+++ b/default.hbs
@@ -16,6 +16,7 @@

     {{! Styles'n'Scripts }}
     <link rel="stylesheet" type="text/css" href="{{asset "css/screen.css"}}" />
+    <link rel="stylesheet" type="text/css" href="{{asset "css/custom.css"}}" />
     <link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Merriweather:300,700,700italic,300italic|Open+Sans:700,400" />

     {{! Ghost outputs important style and meta data with this tag }}

This one-liner is so simple it should merge into future updates, but is trivially easy to re-add later if there are major upstream changes.


My previous approach was based on several examples published on the web, which directly integrated changes into the theme templates. These changes used to take me the better part of an hour to re-integrate when updating Ghost. This time around using the above approach, I was able to update the Ghost installation in just a few minutes. Overall, that's a decent time saver while still feeling like my wife's blogging platform is top-notch.