WordPressの記事ページにプラグインなしで目次を自動生成する方法

記事の長さがファーストビューで収まらず、見出しが複数ある場合に閲覧性などをよくする際に目次が欲しくなりますが、毎度作るとなると内部リンクを作成したりするのが面倒で作らずに記事を公開してしまうことが多いのですが、最近Claudeなどを利用して、ブログの改善をしているときに、目次を自動生成する方法があるのでは?となり、実装できたので、備忘録踏まえて記事にまとめました。

本記事に掲載しているコードの使用はWordPressのバックアップなど注意を払った上で自己責任でお願いします。

目次

テーマファイルに含まれる「function.php」に処理を追記して自動処理させる

自動処理で目次を表示させる方法はテーマファイル内の「function.php」に記事をsingle表示の時に記事内の見出しタグ(h2〜h6)を抽出、その中の文字列を抽出しつつ、idを追加して目次を生成する処理と、目次用のスタイルを出力する処理を追加します。

スタイルについてはstyle.cssなどに追記しても対応できます。

※自動処理のコードを「function.php」に追加する場合はテーマファイルのバックアップやエラー発生時にブログが見えなくなるなどする場合があるので細心の注意が必要です。

自動処理の「function.php」に追加するコードサンプル

下記のようなコードを「function.php」追記することで目次を最初の見出しの直前に追加することができます。


// 見出し作成処理
function add_toc_to_content($content) {
    // 投稿ページ以外では実行しない
    if (!is_singular('post')) {
        return $content;
    }

    // 見出しを検索する正規表現パターン
    $pattern = '/<h([2-6]).*?>(.*?)<\/h[2-6]>/';
    preg_match_all($pattern, $content, $matches, PREG_SET_ORDER);

    // 見出しが2つ未満の場合は目次を作成しない
    if (count($matches) < 2) {
        return $content;
    }

    // 目次のHTML生成
    $toc = '<div class="post-toc">';
    $toc .= '<h4>目次</h4>';
    $toc .= '<ul class="toc-list">';

    foreach ($matches as $match) {
        $level = $match[1]; // 見出しレベル(2-6)
        $title = strip_tags($match[2]); // 見出しテキスト
        $anchor = sanitize_title($title); // アンカーリンク用のスラッグ生成

        // 見出しに id 属性を追加
        $replacement = sprintf(
            '<h%1$s id="%2$s">%3$s</h%1$s>',
            $level,
            $anchor,
            $title
        );
        $content = str_replace($match[0], $replacement, $content);

        // インデント用のクラスを追加
        $indent_class = 'toc-h' . $level;
        $toc .= sprintf(
            '<li class="%s"><a href="#%s">%s</a></li>',
            $indent_class,
            $anchor,
            $title
        );
    }

    $toc .= '</ul></div>';

    // 最初の見出しの前に目次を挿入
    $first_heading_pos = strpos($content, '<h');
    if ($first_heading_pos !== false) {
        $content = substr_replace($content, $toc, $first_heading_pos, 0);
    }

    return $content;
}
add_filter('the_content', 'add_toc_to_content');

// 目次のスタイルを追加
function add_toc_styles() {
    ?>
    <style>
        .post-toc {
            background: #f9f9f9;
            border: 1px solid #ddd;
            padding: 20px;
            margin-bottom: 30px;
            border-radius: 4px;
        }
        .post-toc h4 {
            margin-top: 0;
            margin-bottom: 15px;
        }
        .toc-list {
            margin: 0;
            padding: 0;
            list-style: none;
        }
        .toc-list li {
            margin-bottom: 8px;
            line-height: 1.4;
        }
        .toc-list a {
            color: #333;
            text-decoration: none;
        }
        .toc-list a:hover {
            color: #0066cc;
            text-decoration: underline;
        }
        .toc-h2 { margin-left: 0; }
        .toc-h3 { margin-left: 20px; }
        .toc-h4 { margin-left: 40px; }
        .toc-h5 { margin-left: 60px; }
        .toc-h6 { margin-left: 80px; }
    </style>
    <?php
}
add_action('wp_head', 'add_toc_styles');

「function.php」に追加するメリット・デメリット

最大のメリットは記事データ自体に目次の情報が含まれないところで、記事内容を変更するなどした際も目次の修正が必要ないので、目次に対する手間を省くことができます。

また、JavaScriptを用いて生成する場合と比べ、SEO対策としてもメリットが享受できる可能性があります。

逆にデメリットはテーマファイルを更新する際にfunction.phpを上書きしてしまうと消えてしまうところ。そのため作成する際はテーマファイルのバックアップをすることが大切です。

また、サーバー側のPHPのバージョン更新などで関数や記述方法の変更が必要になる場合があります。

まとめ

ずっと億劫になり、やっていなかった目次の追加が自動で、しかもプラグインを必要とせず追加できる方法がわかり、実装できたのが収穫でした。

今回は、ブログの収益性やSEO対策を踏まえ、色々AIなどと試行錯誤する中で便利な機能としてできたもののひとつで、最近、関連記事リンク一覧を、WordPress Popular postの内容を閲覧して表示するなど、色々改善を行なっているので、こういった記事の需要がわかれば、また記事を書いていこうと考えています。