Skip to content

🚀 A fully-featured and deeply tested Cloudinary Ghost storage adapter

Notifications You must be signed in to change notification settings

eexit/ghost-storage-cloudinary

Repository files navigation

Ghost Storage Cloudinary

npm version Test Maintainability Test Coverage

A fully featured and deeply tested Cloudinary Ghost storage adapter.

Features

  • Up to date with latest Ghost versions 🚀
  • Latest Cloudinary NodeJS SDK
  • Image upload, existence check & deletion (when Ghost will support it)
  • Ability to upload in dated sub-directories (alike first Ghost default Local storage adapter YYYY/MM)
  • Ability to upload images into a specific directory
  • Ability to tag images
  • Cool plugins!

Installation

Install using yarn

  • Go into Ghost root directory
  • Download the adapter:
yarn add ghost-storage-cloudinary
mv node_modules/ghost-storage-cloudinary content/adapters/storage/ghost-storage-cloudinary
  • Done, go configure

Install on Docker

Here's an example of using this adapter with a containerized Ghost:

FROM ghost:5-alpine as cloudinary
RUN apk add g++ make python3
RUN su-exec node yarn add ghost-storage-cloudinary

FROM ghost:5-alpine
COPY --chown=node:node --from=cloudinary $GHOST_INSTALL/node_modules $GHOST_INSTALL/node_modules
COPY --chown=node:node --from=cloudinary $GHOST_INSTALL/node_modules/ghost-storage-cloudinary $GHOST_INSTALL/content/adapters/storage/ghost-storage-cloudinary
# Here, we use the Ghost CLI to set some pre-defined values.
RUN set -ex; \
    su-exec node ghost config storage.active ghost-storage-cloudinary; \
    su-exec node ghost config storage.ghost-storage-cloudinary.upload.use_filename true; \
    su-exec node ghost config storage.ghost-storage-cloudinary.upload.unique_filename false; \
    su-exec node ghost config storage.ghost-storage-cloudinary.upload.overwrite false; \
    su-exec node ghost config storage.ghost-storage-cloudinary.fetch.quality auto; \
    su-exec node ghost config storage.ghost-storage-cloudinary.fetch.cdn_subdomain true;

Make sure to set the content path right in the Ghost config as well:

"paths": {
    "contentPath": "/var/lib/ghost/content/"
}

Configuration

Check out configuration.json.dist for a complete example.

  • Ensure to disable Ghost Image Optimisation
  • The optional useDatedFolder = false to upload images in dated sub-directories (alike default Ghost Local storage adapter)
  • The auth property is optional if you use the CLOUDINARY_URL environment variable authentification method
  • The optional upload property contains Cloudinary API upload options
  • The optional fetch property contains Cloudinary API image transformation options

Recommended configuration

  • upload.use_filename = true in order use the original image name
  • upload.unique_filename = false unlikely Ghost local storage adapter which auto-dedup an existing file name, Cloudinary will return the existing image URL instead of deduping the image
  • upload.overwrite = false goes along with previous option: returns existing image instead of overwriting it
  • upload.folder = "my-blog" allows to upload all your images into a specific directory instead of Cloudinary media library root
  • upload.tags = ["blog", "photography"] if you want to add some taxonomy to your uploaded images
  • fetch.quality = "auto" equals auto:good (see doc)
  • fetch.secure = false set to true if you want to serve images over SSL (not recommended for performances)
  • fetch.cdn_subdomain = true to really use the benefit of Cloudinary CDN

❤️ Don't forget to checkout the plugins!

Development

Run yarn install without the --production flag.

Runs the tests and generate coverage:

yarn coverage

Runs the linter:

yarn eslint

To enable debug logs, set the following environment variable:

DEBUG=ghost-storage-cloudinary:*

Integration testing:

docker build \
    --build-arg CLOUDINARY_URL=cloudinary://.... \
    --file Dockerfile.test \
    --tag test \
    .
docker run -itp 2368:2368 test

Go to http://localhost:2368.


Many thanks to @mmornati, @sethbrasile and all other contributors for their work. In the continuation of this project, don't hesitate to fork, contribute and add more features.