The Cove Blog

How to create two (or more) blogs from a single Ghost installation

Guides • 6 min read

Using Ghost's routes file, it's easy to group posts into collections.

How to create two (or more) blogs from a single Ghost installation

For Cove's marketing website (this site you're on!), I wanted to use a single Ghost installation to power three different "sites":

  • the marketing site, which explains the product
  • a blog containing Ghost-related articles
  • an area for self-serve help and support documentation
  • a second blog of product updates

I decided having a single Ghost site would be the best option, using it as a centralised place to contain all posts and pages together. I didn't want to set up four different sites and have to handle domain names, installing sites, and duplicating design/styling.

Using Ghost routes it's reasonably easy to serve four different “sites” from the same installation.

The desired setup

  • cove.chat would be the main product homepage
  • Pages like cove.chat/page/ would let me add pages to the marketing site
  • The blog root would be cove.chat/blog/, with post URLs like cove.chat/blog/post-title/
  • The help docs would be at cove.chat/help/, with post URLs like cove.chat/help/post-title/
  • A simple Changelog page listing quick product updates would be at cove.chat/changelog/

Updating routes.yaml

To get the desired split of content between the three collections of posts (and to push posts down a level away from the homepage), I edited the routes.yaml file.

To work on this file, you need to download the current version from the Labs section of your Ghost admin and open it in a text editor.

Using Ghost's documentation plus some trial and error, this is how the file ended up:

routes:
  /:
    data: page.home
    template: home

collections:
  /help/:
    permalink: /help/{slug}/
    filter: tag:hash-help+tag:-hash-changelog
    template: index-help
  /changelog/:
    permalink: /changelog/{slug}/
    filter: tag:hash-changelog+tag:-hash-help
    template: index-changelog
  /blog/:
    permalink: /blog/{slug}/
    filter: tag:-hash-help+tag:-hash-changelog
    template: index

taxonomies:
  tag: /tag/{slug}/
  author: /author/{slug}/

The homepage is a page I created with a URL of /home/. Using the data attribute, I can tell Ghost to bring in the data from that page. I specified to use the template home.hbs for this page.

To split posts between the blog, help docs and changelog, I used the collections section of the file. What this does is tell Ghost to use the URLs /help/, /changelog/ and /blog/ as the bases for each collection and pull in different posts for each plus use different templates for the post list (index) view.

The filter specifies which posts to bring in to each area of the site. All I have to do is tag any help posts with the internal tag #help and any changelog posts with #changelog; every other post is shown in the blog.

This system uses basic Ghost filtering. tag:hash-changelog+tag:-hash-help means “pull in all posts with the tag hash-changelog but not posts tagged with hash-help” (note the - before hash-help). I used internal tags for these collections, which start with the # character. Internal tags are never shown in Ghost themes and can be used to organise posts behind the scenes.

Something to note here is that I had to put the help and changelog sections above the blog section in the file to get every other post to go into the blog by default (I don't want to have to manually add a #blog tag to every blog post).

I left the taxonomies section of the file the same.

Now if users visit cove.chat/help/, they will see a section of only help posts, and at cove.chat/changelog/, there is a list of changelog posts. cove.chat/blog/ shows all other posts.

Different layouts

I mentioned briefly above about using different templates for each collection of posts. I wanted different designs for the blog, changelog and help docs, so I built out three slightly different "index" template files called index.hbs, index-changelog.hbs and index-help.hbs (these are all in the theme's root folder).

I also created different partials for each type of post; on the blog, I want a featured image, title and date, whereas the help docs only shows the post title.

index.hbs

{{!< default}}

{{> "site-nav"}}

<div class="container">

<h1 class="font-heading">Blog</h1>

<main class="main-content">
    {{#foreach posts}}
        {{> "post-card-blog"}}
    {{/foreach}}

    {{pagination}}
</main>

partials/post-card-blog.hbs

<article class="post-card--blog {{#unless feature_image}}no-image{{else}}{{/unless}}">

    {{#if feature_image}}
    <a class="b0" href="{{url}}">
        {{!-- This is a responsive image, it loads different sizes depending on device
        https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}}
        <img class="post-card-image mb1"
            srcset="{{img_url feature_image size="s"}} 300w,
                    {{img_url feature_image size="m"}} 600w,
                    {{img_url feature_image size="l"}} 1000w,
                    {{img_url feature_image size="xl"}} 2000w"
            sizes="(max-width: 1000px) 400px, 700px"
            src="{{img_url feature_image size="m"}}"
            alt="{{title}}"
        />
    </a>
    {{/if}}
    <div>
        <time datetime="{{date format="YYYY-MM-DD"}}">{{date format="D MMM YYYY"}}</time>
        &bull;
        {{#if tags}}
            {{#foreach tags}}
            <a href="{{url}}">{{name}}</a>
            {{/foreach}}
        {{/if}}

        <a href="{{url}}">
            <h1 class="mv1 lh1 font-special">{{title}}</h1>

            <section>
                {{excerpt words="44"}}
            </section>
        </a>
    </div>

</article>

index-changelog.hbs

{{!< default}}

{{> "site-nav"}}

<div class="container">

<h1 class="font-heading">Changelog</h1>

<main class="main-content">
    {{#foreach posts}}
        {{> "post-card-changelog"}}
    {{/foreach}}

    {{pagination}}
</main>

post-card-changelog.hbs

This is a super simple template that displays the full post in the list page. As these posts will be at most a couple of paragraphs, it makes sense to show the whole post.

<article class="post-card--changelog">

    <div>
        {{#if tags}}
            {{#foreach tags}}
            <span class="tag">{{name}}</span>
            {{/foreach}}
        {{/if}}
        &nbsp;
        <time datetime="{{date format="YYYY-MM-DD"}}">{{date format="D MMM YYYY"}}</time>
        <h1 class="mt0 mb0 changelog-title font-heading">{{title}}</h1>
        {{content}}
    </div>

</article>

index-help.hbs

The help docs page has custom lists of posts. I use tags (like Memberships and Billing) to categorise all posts within the help section and then simply add a header and a {{#get}} block to get the related posts. Only the title is shown for each post.

{{!< default}}

{{> "site-nav"}}

<div class="container">

<h1 class="font-heading">Support & Help</h1>

<main class="main-content">
    <div>
    <h2 class="font-heading mb0">Setup & installation</h2>
    <p class="fssmall color--grey mt0">How to get started with Cove and install it in your Ghost site.</p>
    {{#get "posts" filter="tags:setup"}}
        {{#foreach posts}}
            {{> "post-card-help"}}
        {{/foreach}}
    {{/get}}
    </div>

    <div class="mt3">
    <h2 class="font-heading mb0">Memberships in Ghost</h2>
    <p class="fssmall color--grey mt0">How to get Members set up in Ghost.</p>
    {{#get "posts" filter="tags:memberships"}}
        {{#foreach posts}}
            {{> "post-card-help"}}
        {{/foreach}}
    {{/get}}
    </div>

    <div class="mt3">
    <h2 class="font-heading mb0">Managing members</h2>
    <p class="fssmall color--grey mt0">How to manage members in Cove.</p>
    {{#get "posts" filter="tags:members"}}
        {{#foreach posts}}
            {{> "post-card-help"}}
        {{/foreach}}
    {{/get}}
    </div>

    <div class="mt3">
    <h2 class="font-heading mb0">Comments</h2>
    <p class="fssmall color--grey mt0">How to manage and moderate your comments in Cove.</p>
    {{#get "posts" filter="tags:comments"}}
        {{#foreach posts}}
            {{> "post-card-help"}}
        {{/foreach}}
    {{/get}}
    </div>

    <div class="mt3">
    <h2 class="font-heading mb0">Billing</h2>
    <p class="fssmall color--grey mt0">Information about pricing and the billing system.</p>
    {{#get "posts" filter="tags:billing"}}
        {{#foreach posts}}
            {{> "post-card-help"}}
        {{/foreach}}
    {{/get}}
    </div>
</main>

post-card-help.hbs

<div>
    <a class="post-card-title" href="{{url}}">
        {{title}}
    </a>
</div>

And there you have it! Cove.chat is now split into four “sites”, powered by different collections of posts and a custom homepage template.

The Cove Newsletter

Subscribe to helpful tips about using Ghost and its membership features.

You've successfully subscribed to Cove!