Create An URL Shortener in your Quartz Blog

Here's how to create a simple URL shortener for your Quartz blog. This guide will walk you through implementing a redirect feature using a custom Quartz plugin. This allows you to specify a redirectUrl in your markdown frontmatter, turning your blog page into a redirect to another site. It's pretty barebones (no click tracking, no UI to manage the redirects) but it does the job.

Crafting a Redirect Emitter Plugin

First, you need to create the core plugin responsible for generating the redirect pages. Create a new file at quartz/plugins/emitters/RedirectEmitter.ts with the following content:

import { QuartzEmitterPlugin, BuildCtx, ProcessedContent, StaticResources } from "../types";
import { FilePath } from "../../util/path";
import { promises as fs } from "fs";
import path from "path";

interface Options {
  enableRedirects?: boolean
}

const defaultOptions: Options = {
  enableRedirects: true
}

export const RedirectEmitter: QuartzEmitterPlugin<Options> = (opts?: Options) => ({
  name: "RedirectEmitter",

  getQuartzComponents(ctx: BuildCtx) {
    return [];
  },

  async emit(ctx: BuildCtx, content: ProcessedContent[], resources: StaticResources): Promise<FilePath[]> {
    const filePaths: FilePath[] = [];

    for (const [tree, file] of content) {
      const redirectUrl = file.data?.frontmatter?.redirectUrl;

      if (redirectUrl) {
        const targetUrl = redirectUrl.startsWith('http') ? redirectUrl : `/${redirectUrl.replace(/^\//, '')}`;

        const redirectHtml = `
<!DOCTYPE html>
<html lang="en-US">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="refresh" content="0;url=${targetUrl}">
    <script>
      window.location.replace("${targetUrl}");
    </script>
    <title>Redirecting...</title>
</head>
<body>
    <p>Redirecting to <a href="${targetUrl}">${targetUrl}</a>...</p>
</body>
</html>`;

        const outputPath = path.join(ctx.argv.output, file.data.slug! + ".html");
        await fs.mkdir(path.dirname(outputPath), { recursive: true });
        await fs.writeFile(outputPath, redirectHtml);
        const fp = file.data.slug! + ".html";

        filePaths.push(fp);
      }
    }

    return filePaths;
  },
});

This code defines a RedirectEmitter plugin. Let's break down what's happening:

Registering the Plugin

To enable the RedirectEmitter, you need to register it in your quartz.config.ts file. Open quartz.config.ts and modify the plugins array within the configuration block to include Plugin.RedirectEmitter({ enableRedirects: true }):

   Plugin.Assets(),
   Plugin.Static(),
   Plugin.NotFoundPage(),
   // The three above should already be present
   Plugin.RedirectEmitter({ enableRedirects: true }),

By adding Plugin.RedirectEmitter({ enableRedirects: true }), you're telling Quartz to use your new plugin during the build process. The enableRedirects: true option is currently the only configuration, and it's set to true by default in the plugin, but it's good practice to include it explicitly.

Excluding Redirect Pages from Recent Notes

If you leave it at that, it will work but then your redirect pages will appear in your recent notes list. Usually you don't want that. To exclude them, modify the RecentNotes.tsx component to filter out pages with the redirectUrl frontmatter property. Open quartz/components/RecentNotes.tsx and update the pages filtering logic:

    // Replace this line
    const pages = allFiles.filter(opts.filter).sort(opts.sort)
    // With the following
    const pages = allFiles
      .filter(opts.filter)
      .filter(page => !page.frontmatter?.redirectUrl) // Filter out pages with redirectUrl
      .sort(opts.sort)
    // rest of existing code
    const remaining = Math.max(0, pages.length - opts.limit)
    return (
       <div class={classNames(displayClass, "recent-notes")}>

This change adds .filter(page => !page.frontmatter?.redirectUrl) to the page filtering chain. This ensures that any page with a redirectUrl in its frontmatter will be excluded from the list of recent notes.

Exporting the Plugin

Finally, ensure your new plugin is exported so Quartz can find it. Open quartz/plugins/index.ts and add the following line to the exports:

// After this line
export * from "./emitters"
// Add
export { RedirectEmitter } from "./emitters/RedirectEmitter"

Using the Redirect Feature

Now, to use the redirect feature, simply add the redirectUrl property to the frontmatter of your markdown file. For example:

---
title: My Redirect Page
redirectUrl: https://example.com
---

This content will be ignored. You will be redirected.

When Quartz builds your site, it will generate an HTML file for this markdown page that immediately redirects to https://example.com. The original markdown content will be effectively bypassed, and the page will function as a URL shortener.

Refer to the Quartz official docs if you want to understand plugins in detail.