WP GFMでTable Of Contentsに対応してみた

WordPresでMarkdown使うWP GFMを作ってて今回TOCを使えるようにしてみた。

JetpackプラグインでMarkdownが使える

WordPress.comでMarkdown記法が使えるようになった機能Jetpackプラグインで取り込まれたので、もう開発しなくていいかなと思っていたけど部分的に使えないようなのでひとまずWP GFMを継続中。(WP GFMでは[markdown]で囲った部分だけがMarkdown記法になるので他の記述やプラグインと共存が容易)

さて、QiitaでMarkdownで書いた記事に目次が表示されるようになって便利やなーと思ってた、さらにAmazonJSの説明ページがどんどん長くなって読みづらくなってきたのでTOCをつけてみようと思った。

PHP-Markdown + TOC

実装方法を検索したところjtopjianさんが、PHP-Markdownの拡張でTOC対応していた(php-markdown-extra)ので参考にさせてもらった。

PHP-Markdownにはdocument_gamut、block_gamut、span_gamutと3段階のシーケンスがあって、この修正ではまず見出しの変換を改良して<h2 id="xxx"/> のようにidをつけ、document_gamutでhタグを検索して目次を作成して追加するという処理になっている。

しかし[TOC]という文言を他の場所で使うとdocument_gamutの処理で置換の対象になってしまいよからぬことが起きたので、まずspan_gamutで[TOC]が単体で書かれている箇所にマークをつけ、document_gamutでそのマークを変換するようにした。

TOCの記法

TOCの記法、表示についてはRedmineのWiki記法を参考にした。

[TOC]は左寄せ、[>TOC]は右寄せになる。CSSスタイルも参考にした。

見出しのIDについて

これはjtopjianさんの実装によるものだが見出しを## Header {#headerId} と書いた場合に headerId をidとして使うようになっている。それ以外の場合は post-{id}-md-{n}nが連番でつくようにしている。

このブログだと連番が1から始まっていないが、調べるとこれはヘッダのmetaタグのdescriptionを記事本文を使って出力しているからだったつまりthe_contentが2回呼ばれていて、2回目のthe_contentで連番のnが続きになっている。the_contentごとにリセットすることも考えたがidが重複しないこと優先し、値は動的に変わってもいたしかたないと考えることにした。他のページからアンカーへリンクを貼りたい場合は {#headerId}を使ってIDを静的に指定すれば良い。

実行結果

このページでも使ってみているけど、AmazonJSの説明ページは全体を把握しやすくなったと思う。