wordpressで目次(TOC)をプラグインなしで設置する方法

wordpressで目次(TOC)をプラグインなしで設置する方法

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 目次などで検索すると色々な方が目次の設置に関して書いた記事が見つかります。それらも参考にして目次の設置をしてみてください。