WordPress 記事に自動的に目次を追加したい

Table of Contents

このブログの記事に他のブログでよく見かける目次機能をつけたい。

プラグインのTable Of Contents Plus(TOC+)というのをインストールすると簡単にできるようだけど、せっかくなので自分で追加してみる。

手順

前提としては、記事内で使っている見出しは h2 h3 のみで、特にCSSクラスやIDなどは指定してない。
ということで、JavaScriptを使って以下の手順で作ってみる。

  1. 記事内の見出し取得
  2. 取得した見出しが有れば、アンカーリンク用のidを追加(無ければここで処理終了)
  3. 取得した見出しから目次用の配列データ作成
  4. 目次用の配列データから、目次のDOMを作成
  5. 目次のDOMをタイトルのしたに挿入する

とりあえずsingle.phpに以下のJavaScriptを書いてみた。

/**
 * 目次自動追加
 */
window.addEventListener('DOMContentLoaded', () => {
  // 記事のコンテンツ
  const entryContent = document.querySelector('#contents .entry-content');

  // コンテンツ内の見出し h2, h3
  const headlines = entryContent.querySelectorAll('h2, h3');

  // 見出しがある場合
  if(headlines.length > 1) {
    // 目次情報用配列
    const tocData = []; //toc - table of content(目次)の略

    // 各見出しにアンカーリンク用のidをつける
    headlines.forEach((headline, index) => {
      // idを生成
      const anchor_id = 'anchor' + (index + 1);

      // idをhtmlに追加
      headline.setAttribute('id', anchor_id);

      // 目次用に各見出しの[タグ,テキスト,id]を配列に格納
      tocData[index] = [headline.tagName.toLowerCase(), headline.textContent, anchor_id];
    });

    // 目次のエリアとリストを作成
    const tocWrapper = document.createElement('div');
    tocWrapper.insertAdjacentHTML('afterbegin', '<div class="toc_ttl">目次</div>');

    const tocList = document.createElement('ul');
    tocWrapper.appendChild(tocList);

    // CSSクラス追加(装飾用)
    tocWrapper.classList.add('toc_wrapper');
    tocList.classList.add('toc_list');

    // リスト格納用変数
    let listHtml = '';

    // 目次リスト作成
    tocData.forEach((data) => {
      listHtml += `<li class="tag_${data[0]}"><a href="#${data[2]}">${data[1]}</a></li>`;
    });
    tocList.insertAdjacentHTML('afterbegin', listHtml);

    // 記事タイトルの下に追加
    const entryTitle = document.querySelector('#contents .entry-title');

    entryTitle.insertAdjacentElement('afterend', tocWrapper);
  }
});

一応ちゃんと表示された。↓

あとはCSSで装飾すれば完了。

改善したいところ

1点いまいちなところがある。

DOMの構造的にh2とh3が同じリストのレベルであること。
それぞれ違うCSSクラスを追加してあるので、見た目上はインデントを付けたりして、一応分けることは可能。

でも、ちょっとスッキリしない感じ。
とりあえず今回はここまでとして、またそのうち改善することとしよう。

ページの先頭へ