The Markdown parser in Ghost does not parse LaTeX\LaTeX, but you can parse it separately using other tools and post them on your Ghost blog.

In this tutorial, I'll show you how to use KaTeX\KaTeX with Ghost. KaTeX\KaTeX is a fast typesetting library that helps you print TeX\TeX on the web.

Easy way

The easiest way to publish LaTeX\LaTeX in Ghost is to use the Append Editor. Paste your Markdown in the Append Editor, open the menu in the top right, then under Share, click Copy rendered HTML. Then paste the HTML in an HTML card in Ghost.

Then copy the following link into the header or footer of your website or post as a code injection:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css"
  integrity="sha384-AfEj0r4/OFrOo5t7NnNe46zW/tFgW6x/bCJG8FqQCEo3+Aro6EYUG4+cU+KJWu/X"
  crossorigin="anonymous"
/>

The latest links are available on GitHub.

The Hard Way

Set up

  1. Install Node.js
  2. Create a package.json with this content:
{
  "name": "compiler-for-ghost",
  "version": "1.0.0",
  "description": "Compile Markdown to HTML for Ghost",
  "main": "src/compiler.js",
  "dependencies": {
    "rehype-highlight": "^4.0.0",
    "rehype-katex": "^3.0.0",
    "rehype-raw": "^4.0.2",
    "rehype-react": "^6.0.0",
    "rehype-stringify": "^8.0.0",
    "remark-emoji": "^2.1.0",
    "remark-external-links": "^6.1.0",
    "remark-footnotes": "^1.0.0",
    "remark-math": "^2.0.1",
    "remark-parse": "^8.0.2",
    "remark-rehype": "^7.0.0",
    "remark-slug": "^6.0.0",
    "remark-toc": "^7.0.0",
    "unified": "^9.0.0"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
  1. Run sudo npm install -g npm-check-updates.
  2. Run ncu -u.
  3. Run npm install.

Create a Compiler

Create a compilers.js file with the following content:

'use strict';
const unified = require('unified');
const parse = require('remark-parse');
const remark2rehype = require('remark-rehype');

const math = require('remark-math');
const rehypeKatex = require('rehype-katex');
const highlight = require('rehype-highlight');
const emoji = require('remark-emoji');
const externalLinks = require('remark-external-links');
const toc = require('remark-toc');
const footnotes = require('remark-footnotes');
const slug = require('remark-slug');
const raw = require('rehype-raw');
const stringify = require('rehype-stringify');

const processor = unified()
  .use(parse, { commonmark: true })
  .use(slug)
  .use(toc, { maxDepth: 2 })
  .use(externalLinks, { rel: ['noopener'] })
  .use(footnotes, { inlineNotes: true })
  .use(remark2rehype, { allowDangerousHtml: true })
  .use(raw)
  .use(math)
  .use(rehypeKatex)
  .use(highlight, { ignoreMissing: true })
  .use(emoji)
  .use(stringify);

Command Line Approach

To run the compiler without specifying your .md and .html files within compiler.js, add this code to the bottom of compiler.js:

/**
 * stdin = './path/to/BlogPost.md';
 * stdout = './path/to/BlogPost.html';
 * node compiler.js < ./path/to/BlogPost.md > ./path/to/BlogPost.html
 */
process.stdin.pipe(stream(processor)).pipe(process.stdout);

To compile your Markdown to HTML, run this command:

node compiler.js < ./path/to/BlogPost.md > ./path/to/BlogPost.html

:::warning
This approach will overwrite your ./path/to/BlogPost.html file if it already exists.
:::

File System Approach

To specify the .md and .html files within compiler.js, add this code to the bottom of compiler.js:

const fs = require('fs');
const fileIn = './path/to/BlogPost.md';
const fileOut = './path/to/BlogPost.html';
const text = fs.readFileSync(fileIn, { encoding: 'utf-8' });
const html = processor.processSync(text);
fs.writeFileSync(fileOut, html, { encoding: 'utf-8' });

To compile your Markdown to HTML, run this command:

node compiler

:::warning
This approach will overwrite your ./path/to/BlogPost.html file if it already exists.
:::

Stylesheets

Finally, add the KaTeX\KaTeX stylesheets to your Ghost blog as a code injection to the header. You can add it globally if you need to use it often, or to the code injection for each individual post. You can find the latest links to the CDN on GitHub:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css"
  integrity="sha384-zB1R0rpPzHqg7Kpt0Aljp8JPLqbXI3bhnPWROx27a9N0Ll6ZP/+DiW/UqRcLbRjq"
  crossorigin="anonymous"
/>

Examples

Further Resources

Give back

The techniques described in this tutorial depend heavily on free and open-source plugins developed by the Unifiedjs Collective. If you think their plugins are useful, please support their work on Open Collective.