Here at H+S headquarters, we're pretty into the Ghost blogging platform. It's a lot like Wordpress, except without everything that sucks about Wordpress. It's a Node app, isn't bloated with widgets, is more secure, smarter, prettier, and so on. If you're a dev looking to get a quick clean CMS running, Ghost is pretty much a no-brainer.

While the platform has been around for a while, the community is still in its infancy as humanity lags behind the curve, with 80% of all sites victim of hacking being Wordpress-based. As such, we consider it our duty to share knowledge where possible to expedite the growth of independent blogging.

This is no means a "getting started with Ghost" post - Ghost's own documentation covers that quite well. Instead, we'd like to share the source for some of the widgets we've developed over the years to help your theme along.

Basics of Ghost Theme Development

There are actually two stacks we should be conscious of when building Ghost themes: the core Ghost stack, and our theme's stack (yes, they are different... kind of).

Ghost is built on the following core stack:

  • NodeJS
  • ExpressJS
  • Handlebars
  • Grunt

Common to both Ghost's core stack and a Ghost theme stack is Handlebars. Handlebars is a templating system which adds logic to otherwise-static HTML pages. If you're not quite familiar with Handlebars, check out our quick tutorial on how to get the gist of things As long as you're familiar with Express and Handlebars, you'll be good to go. You could very well

Everything we're doing today happens at the theme level, which is your presentation layer that can be swapped at any given time. Running on your own installation, the path should look something like:

/var/www/ghost/content/themes/myTheme/

This is where our development will be taking place.

The Widgets

A "widget" is simply a Handlebars partial saved in your theme. Unlike your traditional monolithic Blog CMS (such as Wordpress), Ghost's widgets must be added to your theme programmatically (I would argue that this is not a bad thing).

1. Recent Posts Widget

This is a fairly common widget which displays X number of posts ranked by most recent.

<!-- recent posts -->
{{#get "posts" limit="3" filter="primary_tag:-#hidden"}}
  <div class="widget">
    <h4 class="title">Recent</h4>
    <div class="content recent-post">
      {{#foreach posts}}
        <div class="recent-single-post">
          <a href="{{url}}" class="post-title">{{title}}</a>
          <div class="date">{{date format="MMMM DD, YYYY"}}</div>
        </div>
      {{/foreach}}
    </div>
  </div>
{{/get}}
<!-- end widget -->
recentposts.hbs

{{#get}} will fetch posts, tags, or users within the given specifications. The tag does nothing on it's own; it simply allows us to work within the context of getting these items, such as how we use {{#foreach posts}} afterwards.

The filter is actually quite powerful, and perhaps a bit under-documented. In this case we're only fetching posts who have a visible main tag: you might want to do something like this if you sometimes use 'posts' to make announcements.

{{#foreach posts}} loops through our 3 posts and will create the result DOM structure the number of times it loops.

Similar to the above, but only returns posts which share the same main tag:

<!-- related posts -->
<div class="widget">
  <h4 class="title">Related</h4>
  <div class="content recent-post">
    {{#get "posts" limit="3" filter="id:-{{id}}+tag:{{primary_tag.slug}}"}}
      {{#foreach posts}}
        <div class="recent-single-post">
          <a href="{{url}}" class="post-title">{{title}}</a>
          <div class="date">{{date format="MMMM DD"}}</div>
        </div>
      {{/foreach}}
    {{/get}}
  </div>
</div>
<!-- end widget -->
relatedposts.hbs

3. Authors Widget

A surprisingly uncommon widget, we've actually yet to see this on another blog yet. This will list all contributors to your blog with their avatar, and link back to their author page:

<!-- authors widget -->
<div class="widget contributors">
  <h3 class="title">Contributors</h3>
  <div class="recent-post">
    {{#get "users"}}
      {{#foreach users}}
        <div class="single-author {{slug}}">
          {{#unless profile_image}}
            <a href="{{url}}"><i class="fas fa-user"></i></a>
          {{/unless}}
          {{#if profile_image}}
            <a href="{{url}}"><img src="{{img_url profile_image}}" alt="Author image" class="avi"></a>
          {{/if}}
          <div class="info">
            <a href="{{url}}" class="single-author-name">{{name}}</a>
            <span class="role"></span>
          </div>
        </div>
      {{/foreach}}
    {{/get}}
  </div>
</div>
<!-- end widget -->
authors.hbs

4. About the Current Author Widget

This widget only exists within the context of pages/posts which have an explicit author. Also supports the use case of multiple authors.

<!-- about the author -->
{{#foreach authors}}
  <div class="about-author clearfix widget">
    <h4 class="title">Author</h4>
    {{#if profile_image}}
      <a href="{{url}}"><img src="{{profile_image}}" alt="Author image" class="avatar pull-left"></a>
    {{else}}
      <a href="{{url}}"><img src="{{asset "images/defaultimage.jpg"}}" alt="Author image" class="avatar pull-left"></a>
    {{/if}}
    <div class="details">
      <div class="author">
        <a href="{{url}}">{{name}}</a>
      </div>
      <div class="meta-info">
        {{#if location}}
          <span class="location"><i class="fal fa-home"></i>{{location}}</span>
        {{/if}}
        {{#if website}}
          <span class="website"><a href="{{website}}" targer="_BLANK"><i class="fal fa-globe"></i>{{t "Website"}}</a></span>
        {{/if}}
        {{#if twitter}}
          <span class="twitter"><a href="{{twitter_url}}"><i class="fab fa-twitter"></i>{{twitter}}</a></span>
        {{/if}}
        {{#if facebook}}
          <span class="facebook"><a href="{{facebook_url}}"><i class="fab fa-facebook"></i></a></span>
        {{/if}}
      </div>
    </div>
    {{#if bio}}
      <div class="bio">
        {{{bio}}}
      </div>
    {{/if}}
  </div>
{{/foreach}}
<!-- end widget -->
authorcard.hbs

5. About all the Authors Widget

A combination of the above two, this widget displays a blurb and information about all authors who contribute to your publication.

<!-- all authors -->
{{#get "users" limit="all" include="count.posts" order="count.posts desc" }}
  {{#foreach users}}
    <div class="about-author clearfix" style="background: url({{cover_img}}) center center; background-color: rgba(255, 255, 255, 0.9); background-blend-mode: overlay;">
      {{#if profile_image}}
        <a href="{{url}}"><img src="{{profile_image}}" alt="Author image" class="avatar pull-left"></a>
      {{else}}
        <a href="{{url}}"><img src="{{asset "images/default-user-image.jpg"}}" alt="Author image" class="avatar pull-left"></a>
      {{/if}}
      <div class="details">
        <div class="author">
          <a href="{{url}}">{{name}}</a>
        </div>
        <div class="meta-info">
          <span class="post-count"><i class="fal fa-pencil"></i><a href="{{url}}">{{plural count.posts empty=(t "0 Post") singular=(t "% Post") plural=(t "% Posts")}}</a></span>
          {{#if location}}
            <span class="location"><i class="fal fa-home"></i>{{location}}</span>
          {{/if}}
          {{#if website}}
            <span class="website"><i class="fal fa-globe"></i><a href="{{website}}" targer="_BLANK">{{website}}</a></span>
          {{/if}}
          {{#if twitter}}
            <span class="twitter"><i class="fab fa-twitter"></i><a href="{{twitter_url}}">{{twitter}}</a></span>
          {{/if}}
          {{#if facebook}}
            <span class="facebook"><a href="{{facebook_url}}"><i class="fab fa-facebook"></i></a></span>
          {{/if}}
        </div>
      </div>
      {{#if bio}}
        <p class="bio">
          {{{bio}}}
        </p>
      {{/if}}
    </div>
  {{/foreach}}
{{/get}}
<!-- end widget -->
allauthors.hbs

Obviously you can customize your widgets as you see fit to include or exclude the information you're looking for. Hopefully these snippets serve as a useful reference for some common use cases to help your blog be as baller as possible.