Easily Zip Ghost Themes with Python

Previous iterations of this site used the Ghost blogging platform which utilized a custom theme. In order to upload it to the Ghost application a zipped folder of the theme is required. To save mouse clicks and keyboard strokes, I wrote a Python script to zip the theme files and save out a .zip file with the version included in the filename.

For Ghost, the theme version is set in the package.json and package-lock.json files for it to be recognized in the Ghost admin. The Python script below gets the version value from package.json and includes it in the zipped file name.

The Python script is placed in the directory to be zipped and some variables are set:

  • BASE_NAME – base name of the output zip file with the output name being [BASE_NAME]-[VERSION].zip
  • OUTDIR – local output directory name for the resulting zip file
  • REMOVE_DIRS and REMOVE_FILES – lists of directories and files, respectively, to exclude in the resulting zip file

Then, running this file compiles the files in the current directory and all subdirectories with the exceptions listed in REMOVE_DIRS and REMOVE_FILES and places an named zip file in the directory specified in OUTDIR.

import os
import glob
import zipfile
import json

BASE_NAME = 'my_zip_file'
OUTDIR = 'Zipped'
REMOVE_DIRS = ['Zipped','.vscode','.git']
REMOVE_FILES = ['VERSION','zip.py','routes.yaml']

with open('package.json') as f:
    packagejson = json.load(f)
    version = packagejson['version']

theme_files = set(glob.glob('*'))
theme_files = theme_files - set(REMOVE_DIRS) - set(REMOVE_FILES)

if not os.path.exists(OUTDIR):

zip = zipfile.ZipFile(
    os.path.join(OUTDIR, f'{BASE_NAME}-{version}.zip'),

def zipdir(directory):
    for root, dirs, files in os.walk(directory):
        for file in files:
            zip.write(os.path.join(root, file))
        for dir in dirs:

for file in theme_files:
    if os.path.isdir(file):