HighLab

【Javascript】WordPressの記事で目次を自動生成

  • 公開日:
  • 更新日:
  • 文字数:3227文字

はじめに

WordPressの記事に目次をプラグインなしで作成する方法をご紹介。毎回記事に目次をつける作業をしていたら、1,2つの記事なら問題ないですが、それが10,20の記事に目次をつける作業となると、かなり面倒です。
その面倒な目次を自動生成します。

前提・環境

  • WordPress OK
  • Javascriptの貼り付けができる

HTMLのコード(記事)を書く


<div class="article">
    <h2>タイトル</h2>
    <p>テキストテキスト</p>
    <h3>サブタイトル</h3>
    <p>テキストテキスト</p>
    <h2>タイトル2</h2>
    <p>テキストテキスト</p>
</div>

<div class="mokuji">
<h2>目次</h2>
<div id="mokuji-list"></div>
</div>

mokuji-listというIDにarticle内部のh2,h3の目次を追加します。

Javascriptのコード

// 設定
    const TOC_INSERT_SELECTOR = '#mokuji-list';              // [セレクター指定] 目次を挿入する要素 querySelector用
    const HEADING_SELECTOR    = '.article h2,.article h3'; // [セレクター指定] 収集する見出し要素 querySelectorAll用
    const LINK_CLASS_NAME     = 'mokuji-a';           // [クラス名] 目次用aタグに追加するクラス名     .無し
    const ID_NAME             = 'heading';           // [ID名]    目次に追加するID名のプレフィックス #無し
    const tocInsertElement    = document.querySelector(TOC_INSERT_SELECTOR);
    const headingElements     = document.querySelectorAll(HEADING_SELECTOR);
    const layer = [];
    let id = 0;
    const uid   = () =>`${ID_NAME}${id++}`;
    let oldRank = -1;
    try {
        const createLink = (el) => {
            let li = document.createElement('li');
            let a  = document.createElement('a');
            el.id  = el.id || uid();
            a.href = `#${el.id}`;
            a.innerText = el.innerText;
            a.className = LINK_CLASS_NAME;
            li.appendChild(a);
            return li;
        };
        const findParentElement = (layer, rank, diff) => {
            do {
                rank += diff;
                if (layer[rank]) return layer[rank];
            } while (0 < rank && rank < 7);
            return false;
        };
        const appendToc = (el, toc) => {
            el.appendChild(toc.cloneNode(true));
        };
        headingElements.forEach( (el) => {
            let rank   = Number(el.tagName.substring(1));
            let parent = findParentElement(layer, rank, -1);
            if (oldRank > rank) layer.length = rank + 1;
            if (!layer[rank]) {
                layer[rank] = document.createElement('ol');
                if (parent.lastChild) parent.lastChild.appendChild(layer[rank]);
            }
            layer[rank].appendChild(createLink(el));
            oldRank = rank;
        });
        if (layer.length) appendToc(tocInsertElement, findParentElement(layer, 0, 1));
    } catch (e) {
        //error 
    }

内部スクロールを導入

内部スクロールを入れたら完了です。あとは、CSSを独自に追加していただければOKです。

$(document).on("click", 'a[href^="#"]', function(){
    var speed = 600;
    var href= $(this).attr("href");
    var target = $(href == "#" || href == "" ? 'html' : href);
    var position = target.offset().top - 10;
    $('body,html').animate({scrollTop:position}, speed, 'swing');
    return false;
});

参考文献