Introduction

View my gallery for an example

I'm lazy. I wanted to create a photo gallery solution for Ghost that involved little ongoing effort to maintain, little effort to modify with changes to the gallery, and (hopefully) little intervention as the Ghost code base evolves. My solution lets you upload a photo (e.g. over sftp or ssh) to a monitored directory and automatically generate a thumbnail and HTML. If you remove a photo, the thumbnail and HTML are removed from the gallery. Captions are based off of the file name of the image.

We use the handy incron utility to monintor file system changes in a target directory. If you've never used incron, it's similar to cron, but triggers on file system changes rather than at a set interval. Incron then calls a simple bash script which uses imagemagick to create thumbnails and echos html to the end of a file. I'm using fancybox3 for the lightbox modal, but you can sub in any system you prefer.

Right now this thing is very simple. This initial design will only work with flat gallery structure (e.g. no nested galleries), but can be scalled relatively easily. Reordering the gallery needs to be done manually, either by editing the html file directly after upload, or removing pictures and reuploading them in the order you would like them to appear.

Why Another Solution?

Ghost 2.1 now includes photo galleries. They are great! Thanks you awesome Ghost developers =) However, they are limited to 9 photos and designed more for story telling within a post. I was looking more for a gallery landing page.

AttilaTheDud has a great solution for Ghost that uses Nginx to generate thumbnails. Go check it out! I wanted a more automated solution for the HTML and I figured I could generate thumbnails just once at the same time.

Install Packages

This solution uses two packages to automate photo gallery generation on upload of new photos to the server. Incron is a nifty little utility that runs a command upon changes to the file system. Everyone's favorite imagemagick will automatically generate thumbnails. Everything else should be built into your Linux distro.

Debian \ Ubuntu

sudo apt install incron
sudo apt install imagemagick

REHL \ CentOS

sudo yum install incron
sudo yum install imagemagick

Setup File Structure

Under the image directory of ghost (e.g. /var/www/ghost/content/images) create a gallery directory and two new subdirectories, 'core' to hold the script that runs our gallery and 't' for the thumbnails. Feel free to change these directories to anything you would like, but make sure to update the bash script and incrontab as needed:

cd /var/www/ghost/content/images
mkdir -p gallery/core gallery/t

Create a new bash script

The most up-to-date version of this script may be found on github

In the core directory we're going to create a new script that incron will call when files are added or removed from our gallery directory. This example uses nano as the editor.

nano /var/www/ghost/content/images/gallery/core/auto_gallery

And copy and paste this script into the newly created file. This script assumes the script is always located in a subdirectory called 'core' below the monitored directory. We will define the monitored directory in incron and pass it to the script with an argument.

#!/bin/bash
# Automate thumbnail and html management for a simple one directory photo gallery
# upon changes in a monitored directory.


# Create variables from arguments passed by incron
path=$1
file=$2
event=$3


# Thumbnail and HTML Creation tasks upon addition of a file to directory
if [ $event = IN_CREATE ]
then
    # Create square thumbnails in subdirectory /t 
    # Size is 300x300 and the ^, -gravity, and -extent blocks make a square crop
    convert "$path/$file" -thumbnail 300x300^ -gravity center -extent 300x300 -quality 60 "$path/t/$file"
    # Append html to the gallery webpage
    echo "<a data-fancybox='gallery' data-caption='$file' href='/content/images/gallery/$file'><img src='/content/images/gallery/t/$file' alt='$file' /></a>" >> $path/core/gallery.html
fi

# Remove thumbnail and HTML when file is deleted from directory
if [ $event = IN_DELETE ]
then 
    # Delete thumbnail file
    rm -f "$path/t/$file"
    # Remove link in html
    sed -i "/$file/d" $path/core/gallery.html
fi

Write out the file from your editor (Ctrl+O for nano) and exit (Ctrl+X for nano). And finally, make that new script executable.

sudo chmod 755 /var/www/ghost/content/images/gallery/core/auto_gallery

Setup Incron

We previously installed incron, but by default no users are allowed to call incron. Edit the access table at incron.allow to allow root or other users to initiate incron tasks.

First open incron.allow

sudo nano /etc/incron.allow

Then add any user(s) you would like. One user name per line. Root is used in this example.

root

Write out the file from your editor and exit. Now that we've given a user permission, we need to open up the incron table to add a new task.

incrontab -e

And copy and paste the following into incrontab. Please remember to update the directory location as neccessary!

/var/www/ghost/content/images/gallery IN_CREATE,IN_DELETE [email protected]/core/auto_gallery [email protected] $# $%

The first section of that line tells incron which directory to monitor. The second tells incron when to do something, e.g. when a new file appears in the directory or is removed from the directory. The final section invokes the auto_gallery shell script and sends three arguments, [email protected] (the monitored directory path), $# (the file that triggered the event), and $% (the actual event triggered).

Create Ghost Gallery Page

We're almost done! Create a new story in Ghost and a new HTML block with the following content:

<div id="gallery"></div>

Under the settings section, you may wish to turn this page into a permanent post.

This example uses the fancybox3 to build a simple lightbox gallery, but feel free to use whatever you prefer. To enable fancybox, we need to inject some CSS and JS into this specific page.

If you would like to use the default fancybox styling, the simpliest way to add the CSS is to use their CDN hosted file. In the Code Injection section, insert the following into the header:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.4.1/jquery.fancybox.min.css" />

For the JS, the simpliest way to add it is to again, use their CDN. We also need a way to inject the HTML for each item in the gallery into this page (generated in /core/gallery.html). In the Code Injection section, insert the following into the footer:

<script type="text/javascript">
$(document).ready(function(e) {
    $('#gallery').load('/content/images/gallery/core/gallery.html',function(){});
});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.4.1/jquery.fancybox.min.js"></script>

The first script uses jQuery to insert the gallery HTML into div#gallery on the gallery page. The second script calls fancybox from the Cloudflare CDN.

If you do not have jQuery already running in your Ghost Blog (unlikely), also inject the following into the footer BEFORE you call fancybox's JS. Do not duplicate jQuery on your site!

<script src="//code.jquery.com/jquery-3.3.1.min.js"></script>

Style your new gallery

Below is some styling to get you started. I use the '.page-photos' CSS selector to override some default styles I want applied to my other pages.

/* Photo Gallery
/* ---------------------------------------------------------- */

.page-photos .post-content {
    max-width: 100%;
}

#gallery {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 300px));
    grid-gap: 1.5rem;
    justify-content: center;
    align-items: center;
}

#gallery a {
    display: inline;
    padding: 1rem;
    box-shadow: none;
    transition: all 500ms ease;
    border: 1px solid #fff;
    background: rgba(255,255,255,.5);
}

#gallery a:hover {
    opacity: 0.8;
    transform: scale(0.95);
}

#gallery a img {
    margin: 0;
    padding: 0;
    width: 100%;
}

Implementation

Change the file name of an image you want to include in the photo gallery to the caption you would like to appear with the image. If you include single ' or double " quotes in the file name, it's likely to break stuff, so please avoid using them in the file name. You can always go back and manually add the quotation marks in the HTML if needed or change the code above to sanitize your file names.

Know that everything is setup, drop your image file into the monitored folder at /var/www/ghost/content/images/gallery and wait for the magic =) If your photos page does not automatically update, your browswer is likely caching the old version. An easy way to fix this is by appending a random number to the jQuery string you added in the footer of your gallery page, like this:

$('#gallery').load('/content/images/gallery/core/gallery.html?v=3',function(){});