When building a personal blog, you don't have to re-invent the wheel and implement everything from scratch. Many people tend to use a CMS in order to focus more on the blog's content instead of having to focus on building the barebones of the blog (taxonomies, pagination, SEO, etc) from scratch.

There are many solutions available like WordPress, Drupal, Ghost, etc. Each one has its own pros and cons, but for me I've always been a fan of Ghost when it comes to managing blog content.

One special thing about Ghost is that it focuses mainly on content publishing. But does that mean that it can't be used for other types of content? Not at all. Thanks to its flexible routing system, it allows you to also build powerful custom site structures.

Here's how you can customize the default routes to add your personal portfolio to a ghost blog.

Understanding collections and channels

In ghost, you can create your own specific channels in order to change the organization of your content and what URLs they live on. It's important to note that a post can be only in one collection. That's why it's necessary to properly setup your filters to insure that.

But what if you want a post to be accessible from multiple routes? Like for example when you want  a project to be displayed on your general portfolio and on a page where you only have mobile projects? Well, that's where channels come to the rescue. A channel is a collection of content matching a specific filter. Unlike collections, they don't influence the post's URL which is why it's possible to have a post present on multiple channels.

Enough theory for now... Once we see an example in action, you'll have a better idea about the difference between collections and channels.

Adding the portfolio projects

The first thing to do is to create a tag called "Portfolio" (the name doesn't really matter, so you can choose any other name you want). This will be the primary tag assigned to all of our portfolio projects. Just like with any other post, you can assign as many tags to the project. The important thing is to have the same primary tag for all the projects you add (It's the Portfolio tag in this case).

A project is just like any other post, except that it has the tag Portfolio:

Once you add a couple of projects, you'll notice that they will appear on your home page alongside the other posts. But ideally, we'd want our portfolio to be separate from the blog.  

Separating the portfolio from the blog

The first step now is to download your routes file. To do that, go to the Labs section in your dashboard and press on "Download current routes.yaml" at the very bottom.

By default, your routes.yaml should look like that:

routes:

collections:
  /:
    permalink: /{slug}/
    template: index

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

What we need to do now is to filter out the portfolio items from the home page and move them to their own directory. In addition to that, we'll use the template page of the tag in order to display a header and a small description about the portfolio. The updated routes.yaml looks like this:

routes:

collections:
  /:
    permalink: /{slug}/
    filter: primary_tag:-portfolio
    template: index
  /portfolio/:
    permalink: /portfolio/{slug}/
    filter: primary_tag:portfolio
    template: tag
    data: tag.portfolio

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

So what happened here?

  1. The filter property under home is telling it to get all the posts except the ones that have a primary tag of portfolio (notice the minus sign before portfolio)
  2. The filter under /portfolio/ tells it to get only the ones with the primary tag of portfolio.

By using these two filters, we ensure that anything with portfolio as a primary tag will belong only to the portfolio collection. A few more thing to note:

  • The permalink of the portfolio collection is /portfolio/{slug}/ which means that all the posts that belong to this collection will have a URL of this form
  • The template we're using is tag which tells the theme to use the tag.hbs template when building the portfolio page. You can even create a custom template and use it for your portfolio page by specifying it here.
  • Since the tag template needs the data of a tag to display properly, we are passing the portfolio tag's data by specifying the data property of the collection.

Using channels to create specialized profiles

Let's say you want to show someone all the mobile apps you built previously by sending them the link portfolio/mobile/. You could follow the same process as before and create that as a collection, but as we mentioned before a post can live in one collection only. Which means that by doing this, they won't appear in your primary portfolio page anymore.

In cases like that, it's better to use channels. You can think of channels as a set of permanent search results. It allows you to have a filtered slice of content from your site, without modifying the content itself.

Here's an example of how you can do that inside your routes.yaml:

routes:
  /portfolio/mobile/:
    controller: channel
    filter: tag:portfolio+tag:mobile
  /portfolio/desktop/:
    controller: channel
    filter: tag:portfolio+tag:desktop
  /portfolio/web/:
    controller: channel
    filter: tag:portfolio+tag:websites

collections:
  /:
    permalink: /{slug}/
    filter: primary_tag:-portfolio
    template: index
  /portfolio/:
    permalink: /portfolio/{slug}/
    filter: primary_tag:portfolio
    template: tag
    data: tag.portfolio

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

All the new modifications are inside routes. What happens now is that all the posts matching the specific filter you set on a certain route will appear inside that route while still appearing inside their own collection too.

There are tons of filters you can use; here's an example of the possible combinations you can have:

filter: tag:x+tag:y # must have both "x" and "y" tags (+ = AND)
filter: tag:x,tag:y # can have either "x" or "y" tags (, = OR)
filter: tag:-x+tag:y # must have tag "y" but not tag "x" (- = NOT)
filter: tag:[x,y,z] # must have either "x", "y", or "z" tags ([] = IN)
filter: tag:-[x,y,z] # must not have any one of "x", "y", or "z" tags (-[] = NOT IN)
filter: author:steve+tag:x # must be written by "steve" and have tag "x"

Setting the new routes.yaml

By now, we have our updated routes.yaml, and all we need to do is set it on our website. To do that, you go to the lab section on the dashboard and you go to the same place where you downloaded the initial file. From there, you can press the Upload routes YAML button and select the updated file to upload.

Adding redirects

One more thing you can do is to set a redirect from /tag/portfolio to portfolio directly because they are now the exact same page (same layout, data and content). To do that, download your initial redirects file from the lab. If you haven't worked with it before, it should be an empty file.

Now add the redirect you want to it. In our case it becomes:

[
  {
    "from": "/tag/portfolio/",
    "to":"/portfolio/",
    "permanent":true
  }
]

Then re-upload it like you did for the routes.yaml file.

That's all! Thank you for reading and have a nice day!