今回はWordPressを使用したサイトでプラグインを一切使わずに開け閉め可能、且つスムーススクロール導入の目次を作成して自動で記事内に挿入する方法を紹介します。
この記事のphp、js、cssのコードを使えば以下のような目次が完成します。上級者向けの技術ですが、プラグインを使用したくない場合は挑戦してみて下さい。

目次作成の準備
まずは準備するものを紹介します。
- jQuery
- function.php
- jsファイル
- cssファイル
準備するものは上記のみです。
WordPressを使用している場合は、大抵の人が準備済だと思うので該当するファイルで作業して下さい。
jQueryの基本的な読み込み方は以下を参照下さい。
ただWordPressではデフォルトでjQueryが入っています。しかし少し癖があります。WordPressでjQueryを扱うには「$」の記述を全て「jQuery」にして書いていかなくてはいけません。しかもデフォルトで組み込まれているバージョンに依存してしまいます。あまりいい事は無いのでheader.phpの「wp_head」の前に以下の記述を入れてデフォルトのjQueryを読み込まないようにしてから、上記の記事でjQueryの基本的な読み込み方をして下さい。
<?php
wp_deregister_script('jquery'); //wp_headの前に書く
?>
今回は、この方法でjQueryを読み込んだ場合のやり方となっています。(デフォルトの状態で作っていく場合は$をjQueryに変えていって下さい。)
function.phpに目次の機能を追記する
準備が完了したら、function.phpに目次の機能を追加します。
以下のコードで目次の機能を追加出来ます。環境/用途によって書き換えていって下さい。次で重要部分の解説をします。
// 目次機能
function my_add_content( $content ) {
if ( is_single() ) {
//h3を追加したい場合は<h[2]-h[3]>(.*?)<\/h[2]-h[3]>にすればOK
$pattern = '/<h[2]>(.*?)<\/h[2]>/I';
preg_match_all( $pattern, $content, $matches, PREG_SET_ORDER );
if( count( $matches ) > 3 ){
//ここのHTMLを編集して見た目を変えてく。もちろんclass/idもOK。
$toc = '<dl class="toc" id="tocMenu"><dt><i class="fas fa-list"></i> 目次</dt><dd class="toc_list">';
$hierarchy = NULL;
$i = 0;
foreach( $matches as $element ){
$i++;
$id = 'chapter-' . $i;
$chapter = preg_replace( '/<(.+?)>(.+?)<\/(.+?)>/', '<$1 id ="' . $id . '">$2</$3>', $element[0] );
$content = preg_replace( $pattern, $chapter, $content, 1);
if( strpos( $element[0], '<h2' ) === 0 ){
$level = 0;
}else{
$level = 1;
}
if( $hierarchy === $level ){
$toc .= '</li>';
}elseif( $hierarchy < $level ){
$toc .= '<ol>';
$hierarchy = 1;
}elseif( $hierarchy > $level ){
$toc .= '</li></ol></li>';
$hierarchy = 0;
}elseif( $i == 1 ){
$hierarchy = 0;
}
$title = $element[1];
$toc .= '<li><a href="#' . $id . '">' . $title . '</a>';
}
if( $level == 0 ){
//ここにHTMLの閉じタグを入れる。もちろんいくらでもHTMLは追加可能。
$toc .= '</li><div class="close"><i class="fas fa-times"></i></div></dd></dl>';
}elseif( $level == 1 ){
$toc .= '</li></ol></li><div class="close">閉じるボタン</div></dd></dl>';
}
$h2 = '/<h2.*?>/i';
if ( preg_match( $h2, $content, $h2s )) {
$content = preg_replace($h2, $toc.$h2s[0], $content, 1);
}
}
}
return $content;
}
add_filter( 'the_content', 'my_add_content' );
4行目でsingle.phpを使用してるページを選択しています。要するに投稿のみに反映します。
5行目でh2タグを変数に入れています。最終的にh3も含めたい場合はここの記述を<h[2]-h[3]></h[2]-h[3]>とすればOKです。
8行目では目次として表示させるHTMLを作り出しています。閉じタグと中に入る実際の要素は41行目〜45行目のコードで作成しているので閉じタグは不要です。9行目では、3つ以上h2があった場合に実行との処理が入っています。すなわちh2が3つ以上のページに目次は付きます。
12行目〜22行目あたりではchapterとのidをh2に付けてくれたり、ループ処理を行ったりしています。特に弄る部分はありませんのでこのままでOKです。
24行目〜34行目まではh2とh3の連続/不連続の場合の条件分枝を書いています。これも弄る必要はないです。
38行目では、アンカーリンクを作成しています。
41行目〜45行目では、8行目で書いたHTMLタグを閉じていきます。もちろん追加のHTMLも書いていけます。今回の場合はアイコンや閉じるボタンなどを追加しています。
47行目では記事中の最初のh2タグの直前に目次を挿入する指示をしています。
57行目では、the_content(投稿)に機能させる事を意味します。
このphpコードがHTMLで吐き出されると以下のようになります。
<dl class="toc" id="tocMenu"><dt><i class="fas fa-list"></i> 目次</dt>
<dd class="toc_list">
<li><a href="#chapter-1">見出し</a></li>
<li><a href="#chapter-2">見出し</a></li>
<li><a href="#chapter-3">見出し</a></li>
<li><a href="#chapter-4">見出し</a></li>
<li><a href="#chapter-5">見出し</a></li>
<li><a href="#chapter-6">見出し</a></li>
<div class="close"><i class="fas fa-times"></i></div>
</dd>
</dl>
これだけで目次の機能は完成です。全ての投稿でh2があるページに目次が反映されます。
ただし見た目は残念ですし、リンクを押すとカクッとページが飛んだようになります。これをスムーズな動きにして且つ見た目も整えていきましょう。
jsで目次の動きを調整する
次はjsファイルにて目次の動きに関しての記述をしていきます。
JavaScript(jQuery)ではアンカーリンクのスムーススクロール化、目次のアコーディオン化、TOPに戻るボタンの追加を行います。
コードは以下のようになっています。WordPressのデフォルトjQueryを使用している場合は「$」を「jQuery」にすれば多分いけます。
// アンカーリンクをスムーススクロールに
$(function(){
$('a[href^="#"]').click(function(){
let speed = 500;
let href= $(this).attr("href");
let target = $(href == "#" || href == "" ? 'html' : href);
let position = target.offset().top - 100;
$("html, body").animate({scrollTop:position}, speed, "swing");
return false;
});
});
// アコーディオン
$(function(){
$("#tocMenu dt").on("click", function() {
$(this).next().slideToggle();
}).next().hide();
$('.close').click(function() {
$(this).parent().prev().toggleClass('selected');
$(this).parent().slideToggle();
});
});
// TOPに戻る
$(document).ready(function() {
var pagetop = $('.pagetop');
$(window).scroll(function () {
if ($(this).scrollTop() > 150) {
pagetop.fadeIn();
} else {
pagetop.fadeOut();
}
});
pagetop.click(function () {
$('body, html').animate({ scrollTop: 0 }, 500);
return false;
});
$(document).ready(function(){
$(window).scroll(function() {
if($(this).scrollTop() > 150) {
$(".pagetop").removeClass("d-none");
}
});
});
});
技術的な詳しい解説は以下の各々の記事を参照下さい。
アンカーリンクのスムーススクロール化
スムーススクロールの実装の仕方(jsバージョン)
アコーディオンの作り方(CSSのみ。jQueryの場合は上記のコード)
CSSで見た目を整える
最後に目次の見た目を整えます。ここまで全てコピペでやってきた場合は、以下のCSSをコピペすればある程度整います。HTMLを変更している場合は、その部分を変更して下さい。
.toc {
margin-bottom: 1.5em;
}
.toc_list {
padding: 1em;
margin-bottom: 2em;
background: #eee;
}
.toc_list li {
padding: .5em 0;
}
.toc_list ol {
padding-left: 1em;
}
#tocMenu dt {
border: #999 1px solid;
cursor: pointer;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
}
#tocMenu dd {
background:#f2f2f2;
border:#999 1px solid;
list-style: none;
display:none;
}
#tocMenu dd li a {
text-decoration: none;
}
.pagetop {
font-size: 3em;
position: fixed;
right: 20px;
bottom: 20px;
}
.close {
display: flex;
justify-content: flex-end;
cursor: pointer;
}
.d-none {
display: none;
}
最後のdisplay:none;はTOPへ戻るボタン用です。
そして最後にTOPへ戻るボタンを表示させるためにfooter.phpの最後に以下のHTMLを追加します。
<p class="pagetop d-none"><a href="#wrap"><i class="fas fa-angle-up"></i></a></p>
これで目次の完成です。
以上が「プラグイン無しで目次を作り投稿内に自動挿入する方法!!【完全版】」でした。
ここまで大掛かりな作業をやる時は必ずテスト環境で試してみて下さい。どうしても出来ない場合はTable of Contents Plusなどのプラグインを使用するか、1ページずつHTMLで書いていって下さい。