WordPressで文中に目次を自動生成する方法|プラグイン不要で実装可能
目次
この記事では、WordPressの自動で目次(Table of Contents)を生成する方法を解説します。クラシックエディタでもそのまま貼り付けて使えるように、PHPやJavaScript、CSSも含めたサンプルです。
1 実装のポイント
- 記事の見出し(h2・h3)を自動で検出して目次を生成
- ショートコードやプラグインを使わず、functions.phpとJavaScriptで実装可能
- CSSでスタイルを調整し、テーマごとに見た目を最適化
2 functions.php にコードを追加
// ------------------------------
// 記事本文に階層付き番号+折りたたみボタン付き目次を挿入
// ------------------------------
function insert_collapsible_numbered_toc($content) {
if (is_singular() && in_the_loop() && is_main_query()) {
// ショートコード [no-toc] があれば目次を生成しない
if (has_shortcode($content, 'no-toc')) {
return $content;
}
preg_match_all('/<h([2-3])>(.*?)<\/h[2-3]>/i', $content, $matches, PREG_SET_ORDER);
if (!empty($matches)) {
$toc = '<div class="toc-container">';
$toc .= '<div class="mokuji-wrapper">';
$toc .= '<span class="mokuji"><strong>目次</strong></span>';
$toc .= '<button type="button" class="toc-toggle">[非表示]</button>';
$toc .= '</div>';
$toc .= '<ul style="clear:both;">';
$h2_count = 0;
$h3_count = 0;
foreach ($matches as $match) {
$level = $match[1];
$text = strip_tags($match[2]);
$anchor = sanitize_title($text);
if ($level == 2) { $h2_count++; $h3_count = 0; $num = $h2_count; }
elseif ($level == 3) { $h3_count++; $num = $h2_count . '.' . $h3_count; }
$toc .= '<li class="toc-level-' . $level . '"><a href="#' . $anchor . '">' . $num . ' ' . $text . '</a></li>';
$content = str_replace($match[0], '<h' . $level . ' id="' . $anchor . '">' . $num . ' ' . $text . '</h' . $level . '>', $content);
}
$toc .= '</ul></div>';
$content = $toc . $content;
}
}
return $content;
}
add_filter('the_content', 'insert_collapsible_numbered_toc');
// 目次折りたたみスクリプトを読み込む
function enqueue_toc_script() {
wp_enqueue_script(
'auto-toc',
get_stylesheet_directory_uri() . '/js/auto-toc.js',
array(), // 依存なし
'1.0',
true // フッターで読み込む
);
}
add_action('wp_enqueue_scripts', 'enqueue_toc_script');
// [no-toc] ショートコード(目次非表示用)
function shortcode_no_toc($atts, $content = null) {
return ''; // 実際には何も表示せず、コメントとして残す
}
add_shortcode('no-toc', 'shortcode_no_toc');
補足:
- 見出しが存在する投稿でのみ目次が自動挿入されます。
- 目次の順序は本文の見出し順に従います。
- h2 と h3 が対象。必要に応じて h4 なども対象に追加可能です。
3 目次を非表示にしたい場合
特定のページや投稿で目次を表示したくない場合は、本文中にショートコード [no-toc] を挿入してください。このショートコードを入れると、そのページでは自動生成される目次は表示されません。
- ショートコードは本文のどこに入れても構いません(先頭でも最後でもOK)
- ショートコード自体は何も表示されず、コメントとして残るだけです
記事内で表示する場合:
[no-toc]
4 javascript にコードを追加
ファイル名:auto-toc.js
保存先:wp-content/themes/child-theme/js/auto-toc.js
document.addEventListener('DOMContentLoaded', function() {
// 目次折りたたみボタン
const toggleBtn = document.querySelector('.toc-container .toc-toggle');
const tocList = document.querySelector('.toc-container ul');
if (toggleBtn && tocList) {
toggleBtn.addEventListener('click', function() {
// 現在の表示状態を取得
const isHidden = window.getComputedStyle(tocList).display === 'none';
if (isHidden) {
tocList.style.display = 'block';
toggleBtn.textContent = '[非表示]';
} else {
tocList.style.display = 'none';
toggleBtn.textContent = '[表示]';
}
});
}
// スムーズスクロール
const header = document.querySelector('.site-header') || document.querySelector('header'); // 固定ヘッダー
const headerHeight = header ? header.offsetHeight : 0;
document.querySelectorAll('.toc-container a').forEach(function(anchor) {
anchor.addEventListener('click', function(e) {
e.preventDefault(); // デフォルトジャンプを防ぐ
const target = document.querySelector(this.getAttribute('href'));
if(target){
const targetPosition = target.getBoundingClientRect().top + window.pageYOffset - headerHeight - 10;
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
}
});
});
});
4.1 ディレクトリ構造
- child-theme/
- style.css
- functions.php
- footer.php
- header.php
- js/
- auto-toc.js
- images/
- logo.png
5 汎用CSS
/* -------------------------
* 投稿本文に目次を挿入するフィルター
---------------------------- */
/* 目次全体のコンテナ */
.toc-container {
display: inline-block; /* コンテンツ幅に合わせる */
background: #edf6ff; /* 背景色 */
border: 1px solid #999; /* 枠線 */
padding: 10px; /* 内側余白 */
margin-bottom: 20px; /* 下余白 */
max-width: 100%; /* 親幅を超えない */
box-sizing: border-box; /* paddingとborderを幅に含める */
font-size: 80%; /* 文字サイズを少し小さめ */
}
/* タイトル+非表示ボタンのラッパー */
.mokuji-wrapper {
display: inline-flex; /* 横並びにする */
justify-content: center; /* 横方向中央揃え */
align-items: center; /* 縦方向中央揃え */
gap: 10px; /* タイトルとボタンの間隔 */
margin-bottom: 10px; /* 下余白 */
width: 100%; /* 親幅いっぱいで中央揃え */
}
/* 「目次」タイトル */
.mokuji {
font-weight: bold; /* 太字 */
font-size: 1.2em; /* 少し大きめ */
}
/* 折りたたみボタン([非表示]) */
.toc-toggle {
cursor: pointer; /* マウスオーバーで指アイコン */
color: #666; /* グレー文字 */
text-decoration: none; /* 下線なし */
background: none; /* 背景なし */
border: none; /* 枠なし */
padding: 0; /* 余白なし */
font-size: 1.1em; /* 少し大きめ */
}
/* 目次リスト全体 */
.toc-container ul {
display: none; /* 目次リスト全体を初期は非表示 */
list-style: none; /* デフォルトリストマーカーを消す */
padding-left: 0; /* 左余白を削除 */
margin: 0; /* 外側余白を削除 */
line-height: 1.0; /* 行間調整(必要に応じて) */
}
/* リスト項目 */
.toc-container li {
margin-left: 0; /* 左余白リセット */
line-height: 1.5; /* 行間を少し広めに */
}
/* 階層ごとのインデント */
.toc-level-2 {
padding-left: 0; /* h2 は左揃え */
}
.toc-level-3 {
padding-left: 20px; /* h3 は少し右にずらす */
}
/* リンクの基本スタイル */
.toc-container a {
text-decoration: none; /* 下線なし */
color: #666; /* グレー文字 */
}
/* リンクのホバー時 */
.toc-container a:hover {
text-decoration: underline; /* 下線表示 */
color: #444; /* 少し濃いグレー */
}
補足:
デフォルトは非表示になっています。
display: none;を消すと表示がデフォルトになります。
.toc-container ul {
display: none; /* 目次リスト全体を初期は非表示 */
}
6 完成イメージ
左がTable of Contents Plusプラグインで作成されたもの
右がコードで自動作成されたもの

7 代用プラグイン
- Table of Contents Plus:同様に投稿本文に目次を自動生成
- Easy Table of Contents:ショートコードで柔軟に目次を挿入可能
8 まとめ
- functions.phpにコードを追加するだけで、投稿本文中に目次を自動生成可能
- JavaScriptでスムーズスクロールも実装できる
- CSSでテーマに合わせて目次のデザインを変更可能
- 目次を表示したくない場合はショートコード
[no-toc]を挿入すれば目次は非表示


