Writing About Custom Post & Tag Paths with Ghost
This post covers how to customise tag and post paths with the Ghost blogging platform.
The background required is a working installation of Ghost 0.4.2, a basic understanding of JavaScript and a decent text editor, say Sublime 3.
Motivation
Firstly, why? It’s not an especially useful trick, but as I host my blog at andy.stanton.is/writing I wanted to have blog posts like
writing/about/custom-post-tag-paths-with-ghost
and tags like
writing/on-the-subject-of/video
Although there are alternative approaches (for example url rewriting with nginx or Apache), a secondary motivation is that I’ve been experimenting with NodeJS lately and wanted to dissect a production JavaScript codebase to see what makes it tick, or even whether I could make head or tail of it at all.
SPOILER ALERT: I could.
Before we start
Stop your Ghost blog and back it up. Please note this guide is provided as is and I accept no liability if your blog stops working.
I will use my blog’s example of changing the tag path from /tag
to /on-the-subject-of
and prefixing the path of blog posts with /about
.
Tags
We’ll start with tags. The files that we will modify are:
- core/server/config/url.js
- core/server/routes/frontend.js
- core/server/controllers/frontend.js
- core/server/helpers/index.js
Update core/server/config/url.js
This module contains the code that Ghost uses to construct the path for a particular item (post, tag, page etc). We are interested in this because we want to change links to tags from being created as tag/some_tag
to on-the-subject-of/some_tag
.
Within the function urlFor(context, data, absolute)
locate the block:
Modify the existing tag path from
to your new desired tag path, e.g.
Update core/server/routes/frontend.js
This module is responsible for the routing of requests to the blog to the correct controller. This means that when someone hits your blog with the path /rss
or /tag/tag_name
, then the rss feed or the posts corresponding to that tag will get returned.
We’re going to modify it so that our paths containing our replacement for the word tag are now responsible for invoking the appropriate tag controllers.
Locate the section where the tags are mapped to controllers:
Replace tag
with your preferred path e.g. on-the-subject-of
.
Update core/server/controllers/frontend.js
This module contains the frontend controller configuration for Ghost. We need to modify this because Ghost performs some of its url construction here for the rss and paginated views of tags. This is important because otherwise you end up with writing/tag/coding/page/2
rather than writing/on-the-subject-of/coding/page/2
.
There’s a lot of replacing to do here, but unfortunately there is no blanket approach - this has to be done by hand.
Within the function function tagUrl(tag, page)
change the constructed url from:
to
Next find the rss controller function: 'rss': function (req, res, next)
and update the if condition that begins if (isNaN(pageParam) || pageParam < 1 ||
from:
to
Then within this condition, replace:
with
Slightly further down replace:
with
and
with
Update core/server/helpers/index.js
The Core Helpers module appears to be dedicated to utility methods for developers creating themes. We’re going to update a function used to retrieve the current page url in the context of a tag.
Within the page_url function: coreHelpers.page_url = function (context, block)
, change:
to
That’s tags done! You can test it out at this point by starting up your blog and verifying that links to tags are now mapped to your new path.
Posts
Posts are a little different to tags as we’re introducing a new section of the url path rather than replacing an existing one, but we will be revisiting some of the files we touched in the previous section.
Make sure you stop Ghost again before you continue with this step.
The files we will be modifying for posts are:
- core/server/config/url.js
- core/server/routes/frontend.js
- core/server/controllers/frontend.js
Update core/server/config/url.js
We updated this file for the tags earlier. This time we want to change links to posts from being created as some_post
to about/some_post
.
Within the function urlPathForPost(post, permalinks)
, update the base path from being the empty string by changing
to your new desired post path, e.g.
Update core/server/routes/frontend.js
This file got updated earlier too. We want to change it in a similar way and make sure the posts controller is invoked for requests addressed to about/*
.
At the very bottom, find the line:
Add your custom post path before the /* as follows:
Update core/server/controllers/frontend.js
We updated this earlier. This time we need to modify it because Ghost can only process posts based on the url format it understands, but since we’ve changed the url format we need to help Ghost out.
Within the ‘single’ entry of the frontendControllers object: 'single': function (req, res, next) {
Modify the path variable, removing the custom post path. You can do this by replacing occurrences of your path with the empty string e.g.
becomes
You can now verify the change has succeeded by firing up Ghost and verifying that links to posts are mapped to your new path. And that’s it!
Conclusions
This experiment was a fun way to have a look around the Ghost source and gain a bit of experience navigating a JavaScript codebase. It would be nice to make this more than a hack and make it customisable from the core Ghost configuration, but that’s a project for another day!