Using Ghost tags for organization, layout, and more

How should you use Ghost tags to organize your content?

A ghost standing at a chalk board that reads "Ghost 101"
It's time for Ghost school!

While WordPress has both tags and categories, Ghost has only tags. In this post, I'll dig into how to use tags on your Ghost site, and why you might want some strategy in terms of how you apply those tags.

The basics

If you're totally new to Ghost, you probably want to start with this documentation:

Tags
Ghost has a flexible tagging system, which can be used to organize your content both in Ghost Admin and on your website for your visitors. Tags can quickly be added from the Post settings menu, with a menu to select existing tags, or you can add new tags from here.

I don't want to bore you by repeating all of it, so I'll assume you've read it, and just hit a few highlights.

Internal and public tags:

There are two major types of tags. Regular tags, and #internaltags. Internal tags start with a #. If you want your tag to be publicly displayed, you want a regular/public tag.

Regular tags:

  • Automatically have collections, available at /tag/tag-slug
  • Can be included in the search results in Ghost's built-in search
  • Are returned by the Content API.

#Internal tags:

  • Do not get a /tag/tag-slug route
  • Do not show up in built-in search results
  • Are not returned by the Content API

Primary and other tags

The first tag in the list of tags is the primary tag. You can change what tag is primary on a given post just by dragging and dropping the tags to reorder them.

Some themes treat the primary_tag differently from other tags.

Getting a page with all posts with a tag

Let's say you have podcasts and blogs. You can get a page that collects all the posts tagged blog and all the posts tagged podcast by visiting: /tag/blog/ and /tag/podcast/. (Posts tagged both will appear in both places.) This is the fast and easy way to get a webpage with all posts about a specific topic, and it may be all your need. But if you need something more complex, read on for the routing section!

Routing with tags

You can use tags to determine the URL of the post and what pages the posts are collected on. This is easiest for the primary tag. (The approaches below require uploading an edited routes.yaml.)

For example (partial routes.yaml file below):

collections:
  /blog/:
    permalink: /blog/{slug}/
    template: blog
    filter: primary_tag:blog
  /podcast/:
    permalink: /podcast/{slug}/
    template: podcast
    filter: primary_tag:podcast

Example from: https://ghost.org/docs/themes/routing/#filtering-collections

In this example, all the posts with the blog primary tag will be available at /blog/ , and all the posts with the podcast primary tag will be available at /podcast/. Another way to accomplish almost the same thing would be to skip the routes file and just use the addresses /tag/blog/ and /tag/podcast/, which gets all posts with those tags, not just the primary tags.

Using primary_tag has the advantage that each post has no more than one primary tag. (Be sure to think about where posts with no primary tag will end up!) That simplifies the process of tagging a post. You either tag is as blog or podcast, and no post can have two primary tags. [If you think you're going to be inconsistent about tagging, consider using filter: 'primary_tag:-podcast' and filter: primary_tag: podcast instead, so that every post ends up at one of two routes, instead of some posts ending up without routing.

It's possible to create collections that use non-primary tags, but it can get fussy fast, and you have to be careful not to put a post on two routes or zero routes. Here's how I have this site set up:

collections:
  /blog/:
    permalink: /blog/{slug}/
    template: index
    filter: tags:-[cathy-sarisky-portfolio,launch-diary]
    order: published_at desc

  /portfolio/:
    permalink: /portfolio/{slug}/
    template: portfolio-index
    filter: tags:[cathy-sarisky-portfolio]
    order: published_at desc

  /launch-diary/:
    permalink: /launch-diary/{slug}/
    template: tag
    filter: tags:[launch-diary]
    data: tag.launch-diary

Partial routes file for https://www.spectralwebservices.com/. This file causes blog posts to appear at /blog/post-title, my portfolio posts to appear at /portfolio/post-title, and launch diary posts to appear at /launch-diary/post-title.

You can use #internal tags in filters, using the notation hash-internal for a tag with the slug of #internal.

If you want more flexible groupings, check out channels instead.

Including tags in URLs

The primary tag can be included within the URL, by setting the permalink.

collections:
  /:
    permalink: /{primary_tag}/{slug}/    

What should I tag?

How exactly you’ll want to tag depends a LOT on your theme, but here are some generalities:

  • Put the most important tag first. That’s the primary tag, and some themes treat it special. After that, order doesn’t matter.
  • Start ‘secret’/internal tags with #. Don’t start other tags with #. Tags without # can be brought onto a page automagically just by doing /tag/tagslug. That doesn’t work for #internaltags.
  • Tags are probably most useful when they have multiple posts in them, but NOT when they’re applied to every post. (DO tag posts  #blog  and  #podcast and  #recipe if you have three content types and need to separate them. DO NOT tag everything #blog if you only have a blog.)
  • Unlike the body of the post, the tag is searchable. So if you wanted to make it possible to search for Joan Rivers but not all of your posts about her have her name in the title, a tag could be a good workaround.

How do themes use tags?

There's no single answer to this question! Tags are super userful in lots of different ways. But here are a few examples!

  • Headline (and also paid themes like Tripoli) use tags to create sections in their news site layouts on the homepage. Be sure to read the theme documentation. Headline will take the most commonly used tags if you don't set your tags list in settings > Design and Branding. Tripoli won't show any news sections if you don't set your tags list in settings > Design & Branding.
  • Many themes use tags to determine what posts to show next in a Related Posts section. You can read my write-up on making related posts work better if you'd like to learn more.

Making tags do more

OK, so tags are great for organizing content. They're also really awesome for effectively adding an unlimited number of settings to posts. (No custom fields? Use tags instead!) Before you do this, be sure to check how your theme is pulling related posts, because a bunch of style related tags can swamp out the content-related tags, if you're using a related block that uses all the tags on the post.

Many (but perhaps not all) themes will add extra classes to the body of the post that includes the tag, like "tag-ghost-101" or "tag-hash-internal-tag". These can be super useful for selectively styling posts based on the tags they have, and can allow some pretty clever style changes, even if you're limited to code injection. Here are some examples.

Making posts with the dark-mode tag show up as dark-mode (code injection✔️):

<style>
body.tag-dark-mode {
        --background-color: #000!important;
    --color-primary-text: #ccc!important;
    --color-secondary-text: #999;
    --color-white: #000;
    --color-lighter-gray: #111;
    --color-light-gray: #222;
    --color-mid-gray: #ccc;
    --color-dark-gray: #ddd;
    --color-darker-gray: #eee;
    --color-black: #fff
}
</style>

Note: Selectors chosen for Ruby. You'll need to adapt.

When I blog about dark mode for Ghost, I want posts to show up in dark mode. So I'm tagging them with a dark-mode tag, and then I have this styling above in my theme's styles or in site-wide code injection. It's much easier to set up these styles once than to insert them into code injection for each individual post!

Changing how images display (code injection✔️)

My little cartoon ghosts don't like getting cropped, so I use a #contain tag to tell Ghost to leave them along. You can read about it here:

Help! Ghost is cropping my posts!
What to do if Ghost is cropping your images.

I've used a similar approach to change the colors of headings on some posts, to change what part of the image is included if it's going to be cropped, and more.

Bigger changes based on tags

I've also used tags to change what handlebars writes out for a given post page, or what posts are retrieved from the database in the first place. For example, on https://goldentoday.com/ , my client wanted an "Eye Candy" post to always appear in the featured section of her modded Tripoli theme. So that part of her home.hbs became:

{{#get 'posts' filter='tag:eye-candy' include='tags,authors' limit='1' }}
   {{#foreach posts}}
      {{> card cardSize='large' cardAlign='center' showExcerpt=true showCaption=true isEyeCandy=true}}
   {{/foreach}}
{{/get}}

No, this doesn't work with code injection. It requires edits to the theme files.

This code lets me get just the most recent "Eye Candy" post, and then calls the 'card' partial with the 'isEyeCandy' variable set, so that that partial can change the rendering a bit, to include the full size image as a clickable zoom-and-popout option.

Another client wanted to totally control what posts appeared in the top section of his modded Tripoli. So I'm pulling the left, right, and center column content onto the page based on tags.

Using tags to enable different styling, without a million custom templates.

Here's one more clever tags trick. The Fragile Sea wanted to be able to change header colors, to match the image used on each page. So we added a number of 'style' tags that he can use as needed (only a few shown).

These tags let him tweak the layout of each post separately, without requiring a custom post template for each possible combination.

As hinted in the section above, you can also use tags to add or suppress extra behavior. For example, loading the table of contents javascript only happens on pages that don't have a #no-toc tag. Tags can also be used to add or suppress comments sections. Just change the bit with the comments section like so, and put on a has-comments tag:

{{#has tag="#has-comments"}}
 {{comments}}
 {{/has}}

Or here's an example from Foxwizard.com, where he needed to be able to turn on or off a sign-up form, depending on the post, and whether it should be above or below the content varied from post to post:

{{#has tag="#subscribe-box-top"}}
{{> subscribe-for-about}}
{{/has}}

{{> one-post}} {{!-- this is a partial that renders the post body --}}

{{#has tag="#subscribe-box-below"}}
{{> subscribe-for-about}}
{{/has}}

That's all for today! Thanks for reading!

💡
Want more? This post has a sequel! "How to fake a tags hierarchy"

Hey, before you go... If your finances allow you to keep this tea-drinking ghost and the freelancer behind her supplied with our hot beverage of choice, we'd both appreciate it!


Your turn!

How do you use tags?

p.s. Yes, as a matter of fact, I did tag this post both "Getting started" and "Advanced topics". Maybe it should have been two posts instead!