Add a portfolio to your Ghost blog
Tags: ghost
Published: 2020-12-12 10:41:32

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](https://ghost.org/) 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*:

![add-portfolio](https://dev-to-uploads.s3.amazonaws.com/i/s55rzm86ulyo7yitsrfh.png)
 
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.

![lab](https://dev-to-uploads.s3.amazonaws.com/i/77huxl46cbxc6r8j0z7f.png)

By default, your `routes.yaml` should look like that:
```yaml
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:
```yaml
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`:

```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:
```yaml
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:
```json
[
  {
    "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!