WordPressの目次をプラグイン無しで自動生成する【コピペOK】

著者:牧野健人

「WordPressサイトに目次の自動生成を導入したいけど、プラグインは増やしたくない」「使っているプラグインに不具合や望ましくない挙動がある」などとお考えの方に向けて、プラグイン無しでの実装方法を解説します。

コードはコピペOKなので、ご活用ください。

牧野健人

記事の著者牧野健人

株式会社リラクス 代表取締役。CRO・SEOを専門とし、デザイン・実装のスキルも活かしながら、クライアントの成果向上のための取組に尽力。
慶應義塾大学卒業後、行政機関を経て、デジタルマーケティングエージェンシーのアイレップにて運用型広告のクリエイティブプランニングに従事。2019年にリラクスを創業。

お問い合わせはフォームよりお願いいたします。

WordPressの目次をプラグイン無しで自動生成する

本コラムで解説する目次の自動生成の仕様は下記の通りです。

以下で、具体的なPHPのコードを提示した上でその使い方を解説します。

PHP

function generate_table_of_contents($headings) {
    $table_of_contents = '<div class="toc__container"><p class="toc__title">目次</p><ol class="toc__list">';
    $current_h2_item = '';
    $has_h3 = false;

    foreach ($headings as $heading) {
        if ($heading['tag'] == 'h2') {
            if ($current_h2_item !== '') {
                if ($has_h3) {
                    $table_of_contents .= '</ol>';
                }
                $table_of_contents .= '</li>';
            }
            $current_h2_item = '<li class="toc__item toc__item--h2"><a href="#' . $heading['id'] . '" class="toc__link">' . $heading['text'] . '</a>';
            $has_h3 = false;
            $table_of_contents .= $current_h2_item;
        } else {
            if (!$has_h3) {
                $table_of_contents .= '<ol class="toc__sublist">';
                $has_h3 = true;
            }
            $table_of_contents .= '<li class="toc__item toc__item--h3"><a href="#' . $heading['id'] . '" class="toc__link">' . $heading['text'] . '</a></li>';
        }
    }

    if ($current_h2_item !== '') {
        if ($has_h3) {
            $table_of_contents .= '</ol>';
        }
        $table_of_contents .= '</li>';
    }
    $table_of_contents .= '</ol></div>';

    return $table_of_contents;
}

function insert_table_of_contents($content) {
    if (is_single()) {
        $heading_pattern = '/<(h2|h3)(.*?)>(.*?)<\/(h2|h3)>/is';
        $matches = array();
        $heading_count = preg_match_all($heading_pattern, $content, $matches, PREG_SET_ORDER);

        if ($heading_count >= 2) {
            $headings = array();

            $heading_counter = 0;
            foreach ($matches as $match) {
                $headings[] = array(
                    'tag' => $match[1],
                    'attributes' => $match[2],
                    'text' => $match[3],
                    'id' => 'heading-' . $heading_counter
                );
                $heading_counter++;
            }

            $content = preg_replace_callback($heading_pattern, function ($match) use ($headings) {
                static $index = 0;
                $id = $headings[$index]['id'];
                $index++;
                return sprintf('<%1$s%2$s><span id="%3$s">%4$s</span></%1$s>', $match[1], $match[2], $id, $match[3]);
            }, $content);

            $table_of_contents = generate_table_of_contents($headings);

            $first_h2_position = strpos($content, '<h2>');
            if ($first_h2_position !== false) {
                $content = substr_replace($content, $table_of_contents, $first_h2_position, 0);
            }
        }
    }

    return $content;
}

add_filter('the_content', 'insert_table_of_contents');

コードの使い方

上述のPHPはWordPressのテーマフォルダ内にあるfunctions.phpに記載してください。

また、38行目と43行目は記述を差し替えることで設定を変更できますので、以下でそれぞれ解説します。

38行目:if (is_single())

目次生成を有効化するページのタイプを指定する箇所で、上述のコードではsingle(投稿ページ)を記載しています。

例えば特定のカスタム投稿タイプを指定したい場合は、if ( is_singular('投稿タイプ名') ) と書き換えてください。

また、URLを基準に条件を指定したい場合は、例えば/blog/であれば下記のように記述できます。

$url = $_SERVER['REQUEST_URI'];
if(strpos($url,'/blog/')!== false) {...}

43行目:if ($heading_count >= 2)

ページ内にいくつ以上のh2があれば目次を生成するかを指定しています。

仮に一つしか無いのであれば目次を配置する必要性が無いので、上述のコードでは2以上(>= 2)で設定しています。

2の部分を他の数値に差し替えることで、任意の最小数を設定可能です。

WebサイトのCV数を増やしたいなら無料相談 / お問い合わせ