Self-hosted Ghost tips and tricks
Ghost is the platform this website is created on. Frankly, it's amazing. It works right out the box, and a little tinkering will get you a theme you're happy with. But sometimes we want different functionality in our pages, or we want to make the theme a little more 'me'.
Below are some of the things I've added to this site, and I'll update this page as and when I can.
Knowing where to put the code
This can be daunting to start with, so I'm going to show you the main locations you may need to paste or create some script or code snippets.
Code Injector

From the settings page, you want to find and click on Code Injection.

This page has two code blocks you can input code. The first is the Site Header
, while the second (predictably) is the Site Footer
. These are not really interchangeable, so make sure you pay attention to where the instructions tell you to put your code.
Also notice that the header and footer show that the code is injected into the {{ghost_head}}
or {{ghost_foot}}
respectively. This is good to know if you decide to inject code into the default.hbs
file instead, and I'll show you where that is now.
default.hbs
This file is located inside your theme's main folder (Casper, Editorial, whatever it may be). It is what tells your web pages to look the way they do. The top of the document would look something like this:

default.hbs
Remember the {{ghost_head}}
I mentioned above? There it is. Everything above that in the file is the header, and where the Code Injector puts anything you've written in it. This means that you also can use this file instead of the code injector, and if for any reason you put some code in but get duplication errors or anything else, you now know where to look to see what's what.
Similarly, if you scroll down to the bottom of the default.hbs
you'll see something like this:

default.hbs
As it says, the {{ghost_foot}}
should be the last thing before the closing </body>
tag, so you put the footer code just above it.
Other theme files
You may want some style choices to only appear on a particular type of page, like a post or an index. In those cases you'd add the code directly to those, whether it's the post.hbs
or home.hbs
etc.
Javascript and CSS files
Sometimes you will need to copy paste a javascript file into your theme so it can be referenced in a header or footer script. You may also want to know where your main css file is to make very specific, detailed tweaks to how something looks or reacts. These can both be found inside your /assets/main
folder in your theme:

A word on updating these files
Just saving any changes to these files won't automatically update what you see in your browser. The ghost service (whether it's a docker container or otherwise) needs to be restarted for these changes to take effect.
And with that out of the way, let's check out what we can do!
Opening all external links in another tab
Clicking a link inside your site, by default, will navigate you away from the page you're on and into the next site. This can be undesirable, so the following code will recognise whether a link is part of your domain or not, and depending on that will open external links in another tab.
Checking our content wrapper
Inside your theme folder you should have a file called post.hbs
. Open that, and find a handlebars {{ }}
line that says {{content}}
:

Take note of what the class is called. In my case, it's called content
, but for you it may be something like post-content
or something else entirely.
The Code
Locate your default.hbs
file inside your theme, and copy paste the following to just above {{ghost_foot}}
:
{{!-- Open external links in a new tab --}}
<script>
var links = document.querySelectorAll('.content a');
for (var i = 0, length = links.length; i < length; i++)
{
if (links[i].hostname != window.location.hostname)
{
links[i].target = '_blank';
links[i].rel = 'noopener';
}
}
</script>
('.content a')
is correct for youMake sure that the .querySelectorAll
class identifier matches the class we found above. This means if your class was post-content
then your snippet above would look like var links = document.querySelectorAll('.post-content a');
.
Safe the file, now when you reload your container, any external link should open in a new tab while keeping all internal links and anchors as they were.
Lightboxes for your images
This allows you to zoom into the images you put in your posts without leaving the page. As an example, click the image below:

Nifty. The way we do this is as follows:
- Click this link https://fslightbox.com/javascript/download and click the 'Download' button
- Extract the zip once it's downloaded
- Locate the
fslightbox.js
file, and copy paste it into theassets/main/js
folder of your Ghost theme's folder structure - Locate your
default.hbs
file, and copy paste the following so it sits just above{{ghost_foot}}
:
{{!-- Lightbox --}}
<script async src="{{asset "main/js/fslightbox.js"}}"></script>
<script>
const images = document.querySelectorAll('.kg-image-card img, .kg-gallery-card img');
// Lightbox function
images.forEach(function (image) {
var wrapper = document.createElement('a');
wrapper.setAttribute('data-no-swup', '');
wrapper.setAttribute('data-fslightbox', '');
wrapper.setAttribute('href', image.src);
wrapper.setAttribute('aria-label', 'Click for Lightbox');
image.parentNode.insertBefore(wrapper, image.parentNode.firstChild);
wrapper.appendChild(image);
});
refreshFsLightbox();
</script>
note that the location of thefslightbox.js
file must be accurate. If you have simply put the file into the/assets/main
folder, then you would change the handlebars above to be"{{asset "main/fslightbox.js"}}"
Now you can save your default.hbs
and restart the container.
Some notes:
If it doesn't work, right click inside your browser and click inspect
to see if there are any errors that come up.
For instance, I already had images
defined (where it says const images =
and images.forEach
) in a different script. I got around this by simply defining them as something else, in my case imageslb
(L.B. so I remembered that it was specifically for LightBox, but it can be anything you want).
You may also experience an error saying Uncaught ReferenceError: refreshFsLightbox is not defined at (index):[numbers]
. I'm not totally sure why, but it doesn't seem to impede the functionality of the lightbox.
If there's anything you've been trying to do on your site that you'd like me to put here, let me know in the comments below.
Have some feedback or something to add? Comments are welcome!
Please note comments should be respectful, and may be moderated