Web制作忘備録

【WP】目次を自作で作る

トップ MEMORANDAM WORDPRESS

【WP】目次を自作で作る

WordPressでブログを書いて情報発信している会社は多いと思います。
いろんなブログを見に行ってる時に、記事ページはやっぱり目次があったほうが見やすいなと思いました。
プラグインでもいいんですが、サイトによっては重くなったりするし、コンフリクトのリスクもあります。
phpなんとなくわかるんだったら、書いた方が軽いので色々検索して合体させました。

プラグインの場合

有名どころはEasy Table of Contentsです。
入れるだけで文字くを作ってくれます。
サクッとやりたい方はこれをインストールして有効にしてください。

自作の場合

function.phpにコードを書いて動かします、function.phpを触ると危ないからバックアップを!
といった記載をよく見ますが、個人的には思っていません。
どこを触ったか覚えていればいいんです。

どんな仕組み?

ざっくり言うと、「記事内のコードを見て、h2とh3があればアンカーを作って表示する」
と言うプログラムです。
the_content内のタグをpreg_matchで検索、h2とh3があれば、それをアンカータグにして、かつそれぞれに対応するidを振ってくれます。
h2の数で発動管理もできますし、囲むタグも自分で指定できます。
注意点としては、記事内のh2とh3にクラスがついていると発動しないところです。

function.php

    
function my_add_content( $content ) {
    if ( is_single() ) {
        
        $pattern = '/<h[2-3]>(.*?)<\/h[2-3]>/i';     // 属性を持たないh2・h3要素を正規表現で表すパターン
        preg_match_all( $pattern, $content, $matches, PREG_SET_ORDER );         // 本文の中から、すべてのh2・h3要素を検索

        // ページ内のh2h3要素が3つ以上の場合に目次を出力
        if( count( $matches ) > 1 ){

            $toc = '<div class="toc_wrap"><h2 class="twt">目次</h2><ol class="olw">';
            $hierarchy = NULL;
            $i = 0;

            // 本文内のh2h3要素を上から順番にループで処理
            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 class="oli">';
                    $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 ){
                $toc .= '</li></ol>';
            }elseif( $level == 1 ){
                $toc .= '</li></ol></li></ol>';
            }

            $toc .= '</div>';


//ナビを出す場所の指定(1個目のh2の下に出す)
            $h2 = '/^<h2.*?>.+?<\/h2>$/im';//H2見出しのパターン
            if ( preg_match_all( $h2, $content, $h2s )) {
                if ( $h2s[0] ) {
                    if ( $h2s[0][0] ) {//1番目のH2見出し手前に挿入
                        $content  = str_replace($h2s[0][0], $toc.$h2s[0][0], $content);
                    }
                }
            }
        }
    }
    return $content;
}
add_filter( 'the_content', 'my_add_content' );

コピペでいけると思います。
細かい説明は参考引用のリンクから見に行ってください!

参考引用:コード全体
参考引用2:出す場所の指定