Installing Markdown/Showdown Extensions in Ghost

Ghost uses Showdown to convert markdown to HTML (although, currently it uses its own fork). Showdown supports extensions which allow developers to extend its capabilities and add new features.

Installing a Showdown extension requires building Ghost from source. You can find the details on this here.

Markdown to HTML

The basic flow from Markdown you type to HTML you see in your posts is:

  1. Type Markdown
  2. {ghost}/core/client/app/helpers/gh-format-markdown.js uses Showdown to convert the markdown to HTML client-side
  3. HTML is shown in the preview pane to the right
  4. Press "Save Draft"/"Update Post" button
  5. {ghost}/core/server/models/post.js uses Showdown to convert the markdown to HTML server-side
  6. HTML is saved to the database
  7. When a user views your post, the saved HTML is presented to them

As you can see, the Makdown is converted to HTML twice: once client-side for the preview and again server-side to save to the database.

Install Extension

The extension's JavaScript is used only by the admin tool, but it used both client-side (for the preview) and server-side (to save to the database). The extension's CSS is used client-side by both the admin tool and your blog.

Client-Side

To install client-side, I create Showdown extensions folder like so: {ghost}/core/client/app/showdown-extensions/extension-name/. Put all extension files in this directory.

Now we need to tell the client-side Showdown instance used by the admin tool to generate the preview to use our extension:

{ghost}/core/client/app/helpers/gh-format-markdown.js

import extensionName from 'ghost-admin/showdown-extensions/extension-name/extension.js';

let showdown = new Showdown.converter({
  extensions: [
    'ghostimagepreview', 'ghostgfm', 'footnotes', 'highlight',
    extensionName // add your extension to the list
  ]
});

If your extension requires CSS to display properly, we need to make sure that CSS is available to both the admin tool pages for the preview and your blog pages for the posts.

Include your CSS in the admin tool's main CSS file like so:

{ghost}/core/client/app/styles/app.css

/* add your css files to the end of the file */
@import "../showdown-extensions/extension-name/extension.css";

Add your CSS to your theme. First put your CSS files in your theme's asset folder {ghost}/content/themes/casper/assets/css/extension.css. Then, include the CSS file in your theme's header:

{ghost}/content/themes/casper/default.hbs

{{! Styles'n'Scripts }}
<head>
  ...
  <link rel="stylesheet" type="text/css" href="{{asset "css/extension.css"}}" />
  ...
</head>

Server-Side

Similar to client-side, create a folder to hold your extension like so: {ghost}/core/server/showdown-extensions/extension-name/. Put your extension files in this directory. Note: CSS files are not needed nor used server-side.

Now we need to tell the server-side Showdown instance used to generate the HTML that is saved to the database (and then displayed to the user) to use our extension:

{ghost}/core/server/models/post.js

var extensionName = require('../showdown-extensions/extension-name/extension.js');

var converter = new Showdown.converter({
  extensions: [
    'ghostgfm', 'footnotes', 'highlight',
    extensionName // add your extension to the list
  ]
}),

Final Steps

Do a re-build with grunt prod after making all of your changes. This will build all the CSS and JavaScript assets sent to the browser. Also make sure to clear your browsers cache or do a hard refresh so you get the latest assets. Note that you will have to edit and save all your existing posts to generate the HTML with the extension applied.