wordpressで目次を設置するとなるとプラグインを使うのが一番手っ取り早いです。
また、最近ではテーマ自体の機能で目次を作れるものもあったりするので、わざわざfunctions.php
にコードを書いて…なんてことをしようと思う人がいるのかどうか…
ただ、特にプラグインに関してはアップデートが中々行われないようになってセキュリティ的にどうなのってなってしまうことも考えられるので、可能であれば、ある程度自分でコードを書いて設置した方がいいのかなとも思っています。
というわけで、自分で目次を設置したいという方に向けて、わたしがこのブログでどのように目次を設置したのかを紹介していきます。
目次を記事本文中に表示
今回、目次を設定するにあたり、以下の条件で作成にあたりました。
- h2h32種類の見出しのみを目次にする
- 記事本文中の最初のh2タグの前に目次を挿入する
- h2h3の各タグにidを付与する
- 投稿ページのみに設置する
大まかに上記3点を条件に作成しました。
h2・h3の抽出
まず、本文中の<h2>
<h3>
タグを抽出していきます。
$tag = '{<h([2-3]).*?>(.*?)</h[2-3]>}';
上記の正規表現パターンを使用してpreg_match_all()
で各hタグを配列に格納します。
foreachを使ってループ処理
先ほどのpreg_match_all()
にて取得した配列には以下の内容が格納されています。
<h>~</h>
の全部- h〇の丸の数字(2もしくは3)
- hタグ内のテキスト
これらの3つの情報をforeach()
を使って処理していきます。
function index_insert($content){
if(is_single()){
$toc_li = '';
$tag = '{<h([2-3]).*?>(.*?)</h[2-3]>}';
preg_match_all($tag,$content,$index,PREG_SET_ORDER);
if(!empty($index)){
$h2_i = 1;
$h3_i = 1;
foreach($index as $val){
$title = $val[2];
$current = intval($val[1]);
if($current == 2){
$headline_id = 'headline'.$current.'-'.$h2_i;
$toc_li .= <<<EOF
<li><a href="#{$headline_id}">{$title}</a></li>
EOF
;
$grant_id = '<h2'.' id="'.$headline_id.'">'.$title.'</h2>';
if($h2_i == 1){
$search = $grant_id;
}
$content = str_replace($val[0],$grant_id,$content);
$h2_i++;
}elseif($current == 3){
$headline_id = 'headline'.$current.'-'.$h3_i;
$toc_li .= <<<EOF
<li class="h-child"><a href="#{$headline_id}">{$title}</a></li>
EOF
;
$grant_id = '<h3'.' id="'.$headline_id.'">'.$title.'</h3>';
$content = str_replace($val[0],$grant_id,$content);
$h3_i++;
}
}
$toc_html = <<<EOF
<details open>
<summary>
<span class="summary-inner"><span class="icon"></span>目次</span>
</summary>
<ul class="toc-list">
{$toc_li}
</ul>
</details>
EOF
;
$replace = $toc_html.$search;
$content = str_replace($search,$replace,$content);
}
}
return $content;
}
add_filter('the_content','index_insert');
上記ソースが全体像ですが、部分ごとに説明していきます。ある程度分かる方やすぐに目次を設置したい方はfunctions.php
へコピペして各自調整してください。
$h2_i = 1;
$h3_i = 1;
この部分ですが、これは各hタグへidを付与するための準備です。
<h2 id="headline2-1"></h2>
<h2 id="headline2-2"></h2>
といった具合に数字を割り振るためのものです。次にhタグ内のテキストとh〇の丸の数字を取得します。
$title = $val[2];
$current = intval($val[1]);
実はここで少しハマりました…
$current
に格納した数字で<h2>
なのか<h3>
なのかを判別して、それぞれに処理をしようとしたのですが、思うようにいきませんでした。
$current = $val[1];
当初、このようにしていたのですが、if()
の条件分岐で望む結果にならなかったのです。
if($current == 2){
}elseif($current == 3){
}
このように条件分岐していたのですが、すべて<h2>
と判断されてしまいました。結果的にintval()
を使って整数型に変換することで問題は解決しました。
$headline_id = 'headline'.$current.'-'.$h2_i;
$toc_li .= <<<EOF
<li><a href="#{$headline_id}">{$title}</a></li>
EOF
;
$grant_id = '<h2'.' id="'.$headline_id.'">'.$title.'</h2>';
$headline_id
にid名を格納して$grant_id
でidを付与したhタグを格納します。
$toc_li
には目次表示用のhtmlを格納しています。
次に本文中のhタグをid付与されたhタグに置き換えます。
if($h2_i == 1){
$search = $grant_id;
}
$content = str_replace($val[0],$grant_id,$content);
str_replace()
で本文中のhタグを置き換えているのですが、その前のif()
で何をしているかというと、最終的に出来上がった目次を本文一番最初の<h2>
タグの前へ挿入するために$search
に一番最初のh2タグを格納しています。
一番最初のh2タグの前に目次を設置
記事本文中にある一番最初の<h2>
タグの前に目次を挿入します。
$toc_html = <<<EOF
<details open>
<summary>
<span class="summary-inner"><span class="icon"></span>目次</span>
</summary>
<ul class="toc-list">
{$toc_li}
</ul>
</details>
EOF
;
$replace = $toc_html.$search;
$content = str_replace($search,$replace,$content);
$toc_html
に目次全体のhtmlを格納し、先ほどの$search
と結合させます。そして、結合させた目次とhタグを本文中一番最初の<h2>
タグと置き換えています。
ザックリとした流れですが、このような形で目次を本文中に挿入しています。
ちなみに、<h3>
タグの処理の際、<li>
にclassを付与して表示するときにインデント(字下げ)できるようにしています。
wordpress 目次などで検索すると色々な方が目次の設置に関して書いた記事が見つかります。それらも参考にして目次の設置をしてみてください。