WordPressの記事から見出しを自動で探し出し、リンク付きの「目次」ナビゲーションを設置するためのスクリプトを紹介します。
jQueryも一切使っていないです。
プラグインを使いたくない!って方は是非参考にしてみてください。
1. 見出しタグやブログのHTML構造を確認する
まずは準備として、現在使用しているテーマのHTMLソースの構造を把握しておきましょう。
目次にしたい見出しは何番のHタグを使っているのか
まずは見出しタグから確認していきましょう。
例えば下の画像のように、記事のタイトルがH1タグで、 大見出しはH2タグ、中見出しは全てH3タグで書いてあるパターンなどがあると思います。
ほとんどこんな感じかと思いますが、たまに大見出しも全部h1タグだったりするので確認しておきましょう。
今回は このパターンを例にしたスクリプトを紹介していきます。
記事を囲っているdivタグなどのID名またはクラス名を確認する
見出しを探し出す対象範囲を限定するため、記事全体を包むラッパーのID名などを使用するので確認しておいてください。
記事全体でなくとも、見出しが使われ始める本文の導入部以降が何かのタグで包まれている場合、それを使うこともできます。
IDまたはクラスが付いている要素か、もしくはそのページで1回しか使われていないタグ(articleなど)で記事部分が包まれている必要があります。
今回のコードでは、.post_content
というクラス名のタグで記事が囲まれていると想定したものとします。
2. 1つ目のH2タグの直前に目次用のdivタグを設置する
目次を設置するためのdivタグを先に挿入しておきましょう。
PHP側で先に挿入しておく方法と、JavaScriptで生成する方法の2パターンを紹介しておきます。
どちらでもいいと思いますが、管理画面から見出しの生成をするかどうかを切り替えれるようにしたい場合や、アドセンスも同時に挿入したい場合などはPHPで挿入しておいた方が楽かなと思います。
PHPでdivタグを先に挿入しておく方法
'the_content'
アクションフィルターにて、preg_match()
でH2タグを探し、divタグを挿入します。
functions.php
に以下のコードを記述してください。
1つ目「見出し2」の直前にdivタグを挿入するコード
function add_index_to_content( $content ) {
$index_wrap = '<div class="index_wrap"><span>目次</span></div>';
$tag = '/<h2.*?>/i';
if ( preg_match( $tag, $content, $tags )) {
$content = preg_replace($tag, $index_wrap.$tags[0], $content, 1);
}
return $content;
add_filter( 'the_content', 'add_index_to_content' );
JavaScriptでdivタグを生成する方法
h2タグの直前にdivタグを生成して挿入するスクリプト
let indexWrap = document.createElement("div"); //見出し用のdiv
let postContent = document.querySelector('.post_content'); //記事本文が書かれているラッパー
let firstH2 = "";
if (postContent) {
firstH2 = postContent.querySelector('h2'); //一つ目のH2タグを取得
}
if (firstH2) {
indexWrap.classList.add('index_wrap');
indexWrap.innerHTML = '<span>目次</span>';
firstH2.parentNode.insertBefore(indexWrap, firstH2);
}
3. 目次の生成スクリプト
さて、では目次を生成するスクリプトを紹介していきます。
どの深さまで目次を生成したいかによってコードが変わってくるのですが、今回は以下の2パターンを例にしたコードのみ紹介しておきます。
- H2タグのみを目次に表示する
- H2とH3タグを目次に表示する
「H2タグだけを目次に表示する」場合のスクリプト
見出し生成スクリプト(※ ES6記法です)
let indexWrap = document.querySelector('.index_wrap'); //functions.phpでH2タグの前に挿入したdivタグ
if ( indexWrap ) {
let postContent = document.querySelector('.post_content'); //記事本文を囲んでいるラッパー
let hTags = postContent.querySelectorAll('h2'); //記事内のH2タグを全て取得
if (hTags.length > 0) {
let indexList = document.createElement("ul");
let listSrc = "";
for (let i = 0; i < hTags.length; i++) {
let theHeading = hTags[i];
theHeading.setAttribute('id', "index_id" + i); //リンクで飛べるようにIDをつける
listSrc += '<li><a href="#index_id' + i + '">' + theHeading.textContent + '</a></li>';
}
indexList.innerHTML = listSrc;
indexWrap.appendChild(indexList);
}
}
「H2タグとH3タグを目次に表示する」場合のスクリプト
見出し生成スクリプト(※ ES6記法です)
const indexWrap = document.querySelector('.index_wrap'); //H2タグの前に挿入したdivタグ
if ( indexWrap ) {
let postContent = document.querySelector('.post_content'); //記事本文が書かれているラッパー
let hTags = postContent.querySelectorAll('h2, h3'); //記事内のH2とH3タグを全て取得
if (hTags.length > 0) {
let indexList = document.createElement("ul");
let listSrc = "";
let h3List = ""; //h3タグを取得しておくための変数
for (let i = 0; i < hTags.length; i++) {
let theHeading = hTags[i];
theHeading.setAttribute('id', "index_id" + i); //リンクで飛べるようにIDをつける
if (theHeading.tagName === 'H2') {
if (h3List !== "") {
//h3リストが生成されていれば
listSrc += '<ul>' + h3List + '</ul>';
h3List = "";
}
listSrc += '</li><li><a href="#index_id' + i + '">' + theHeading.textContent + '</a>';
} else if (theHeading.tagName === 'H3') {
h3List += '<li><a href="#index_id' + i + '">' + theHeading.textContent + '</a></li>';
}
}
if (h3List !== "") {
//最後のリストがh3だった場合
listSrc += '<ul>' + h3List + '</ul></li>';
} else {
listSrc += '</li>';
}
indexList.innerHTML = listSrc;
indexWrap.appendChild(indexList);
}
}
H2タグだけを表示する場合よりかなりコードが長くなっています。
H3タグが続けば H3だけのリストを生成していき、次にH2タグが来た時にまとめて連結しています。
このような手法で、H4、H5と、見出しに表示したい見出しの深さだけコードを追加していきましょう。
4. リンク先への移動をアニメーションさせたい場合
特に何もしなければ、リンク先への移動は瞬間移動してしまいますが、これをアニメーションさせるともっといい感じになります。
スムーススクロールってやつですね。
そのスムーススクロールを実装する方法も別の記事で紹介していますので、ぜひ参考にしてみてください。