ワードプレスでプラグインなしに目次を自動挿入する方法

自動的に目次を自動挿入する方法の解説ページのアイキャッチ

このページではプラグインなしにワードプレスで目次を自動で挿入する方法について解説します。紹介する方法を実施すれば、こんな感じでページの先頭に目次を自動で挿入することができます。

目次の表示例

このページではこの挿入する方法だけでなく、プログラムの解説や目次を自動挿入する仕組み、簡単なプログラムのカスタマイズ方法についても解説しますので、これらの解説も参考にして自分でカスタマイズやプログラムを作成するときテクニックなどを参考にしていただければと思います。

目次を自動で挿入する方法

では早速目次を自動で挿入する方法について解説します。コピペだけで目次を自動挿入することが可能です。

プログラムを functions.php にコピペする

まずテーマフォルダの直下にある functions.php に下記のプログラムをコピペします。

functions.php
/**
 * Summary
 *  見出しに id を自動挿入
 *
 * @param string $the_content 記事の本文.
 **/
function add_auto_id( $the_content ) {

	/* idを付加する見出しレベルを設定 */
	$start = 1;
	$end   = 6;

	/* 見出しのパターンを作成 */
	$pattern = '/^<h([' . $start . '-' . $end . ']).*?>.+?<\/h[' . $start . '-' . $end . ']>$/im';

	/*
		$headingsにページ内の見出し要素を格納
		$headings[0]:マッチした文字列
		$headings[1]:見出しレベル(h3なら"3")
	*/
	if ( ! preg_match_all( $pattern, $the_content, $headings ) ) {
		/* 見出しがない場合は終了 */
		return $the_content;
	}

	/* idが設定されているかどうかを判断するためのパターン */
	$id_pattern = '/^<h([' . $start . '-' . $end . ']).+?id\s*=\s*\"(.+?)\".*>(.+?)<\/h[' . $start . '-' . $end . ']>$/im';

	/* 見出しごとにidが設定されていない見出しにidを付加 */
	$num_count = count( $headings[0] );
	for ( $i = 0; $i < $num_count; $i++ ) {

		/* 見出しにidが設定されているかどうかの判断. 見出しにidが設定されている場合のみマッチ */
		if ( ! preg_match( $id_pattern, $headings[0][ $i ], $dummy ) ) {

			/* idが設定されていない見出しの場合に行う処理. idを付加した文字列(<hX id=autoid-Y)を作成 */
			$id_str = '<h' . $headings[1][ $i ] . ' id="autoid-' . $i . '"';

			/* id_str(<hX id=autoid-Y)で元々の見出しの"<hX"部分に置換 */
			$replaced_heading =
				str_replace( '<h' . $headings[1][ $i ], $id_str, $headings[0][ $i ] );

			/* id付加後の見出しで元々のコンテンツ内の見出しを置換 */
			$the_content =
				str_replace( $headings[0][ $i ], $replaced_heading, $the_content );
		}
	}

	return $the_content;
}

/* the_contentフックに関数をフック */
add_filter( 'the_content', 'add_auto_id', 9 );
/* 見出しにid属性を自動挿入 End */


/**
 * Summary
 *  目次を自動挿入
 *
 * @param string $the_content 記事の本文.
 **/
function add_my_toc( $the_content ) {
	/* 投稿ページ以外の場合はすぐに終了 */
	if ( ! is_single() ) {
		return $the_content;
	}

	/* ここから見出しへの id 付加(idがない見出しのみに対して) */

	/*
		目次に設定する見出しを設定する
		下記で指定した$startから$endの見出しを目次に表示する
		例えば見出し h2 と h3 のみを目次に表示するのであれば、
		$start = 2;, $end = 3 に設定する
	*/
	$start = 2;
	$end   = 6;

	/* $startと$endの設定がおかしい場合はすぐに関数終了 */
	if ( $start > $end ) {
		return $the_content;
	}

	/* 見出しにid属性を付加 */
	$the_content = add_auto_id( $the_content, $start, $end );

	/* id が設定されているかどうかを判断するためのパターン */
	$toc_pattern = '/^<h([' . $start . '-' . $end . ']).+?id\s*=\s*\"(.+?)\".*>(.+?)<\/h[' . $start . '-' . $end . ']>$/im';

	/*
		$toc_headingsにページ内の見出し要素を格納
		$toc_headings[0]:マッチした文字列
		$toc_headings[1]:見出しレベル(h3なら"3")
		$toc_headings[2]:id設定値
		$toc_headings[3]:見出し文
	*/
	if ( ! preg_match_all( $toc_pattern, $the_content, $toc_headings ) ) {
		/* 目次に表示する見出しがない場合は終了 */
		return $the_content;
	}

	/* 目次の作成ここから */

	/* 目次をdivで作成 */
	$toc = "<div class=\"mytoc_body\">\n";

	/* 目次の上部の見出しを作成 */
	$toc = $toc . "<p class=\"mytoc_heading\">目次</p>\n";

	/* 見出しを箇条書きで書き出し */
	$toc       = $toc . "<nav class=\"mytoc_nav\">\n";
	$toc       = $toc . "<ul>\n";
	$num_count = count( $toc_headings[0] );
	for ( $i = 0; $i < $num_count; $i++ ) {

		/* 見出しを内部リンク付きで箇条書きの項目として書き出し */
		$toc = $toc . '<li><a href="#' . $toc_headings[2][ $i ] . '">' . $toc_headings[3][ $i ] . "</a></li>\n";
	}

	$toc = $toc . "</ul>\n</nav>\n</div>\n";

	/* 最初の見出しの上に目次を追加 */
	$the_content = str_replace( $toc_headings[0][0], $toc . $toc_headings[0][0], $the_content );

	/* 目次の作成ここまで */

	/* 置換後のコンテンツを返却 */
	return $the_content;
}

/* the_content フックに関数をフック */
add_filter( 'the_content', 'add_my_toc', 10 );
/* 目次を自動挿入 End */

これだけで目次は表示されます。

目次の表示例(スタイルシートなし)

スタイル設定を style.css にコピペする

目次は確かに挿入されていますが、見た目がイマイチですね。これは CSS ファイルでスタイル設定すれば改善することが可能です。テーマフォルダ直下にある sytle.css に下記をコピペします。

style.css
.mytoc_body{
	margin-right : 50px;
	margin-left : 50px;
	padding : 0px;
	border : solid 3px #FFA0A0;
	background : #FFF0F0;
	box-shadow :0px 0px 5px silver;
}

.mytoc_heading{
	margin : 0px;
	padding : 5px;
	font-weight : 700;
	color : #FFFFFF;
	text-align : center;
	background : #FFA0A0;
	font-size : 1.5em;
}
.mytoc_nav{
	font-size : 1.3em;
}
.mytoc_nav a{
	padding : 10px;
	text-decoration: none;
	color : #444444;
}

.mytoc_nav a:hover {
	text-decoration: underline;
}

.mytoc_nav ul{
	font-size : 1.0em;
	padding-right :1em;
}
これによって目次は下のように表示されるようになります。ちょっと見た目が良くなりましたね!

目次の表示例

もちろん CSS を変更すれば、さらにあなた好みに見た目をカスタマイズすることが可能です。

目次を自動で挿入する仕組み

それではどうやって目次を自動挿入しているか、その仕組みについて解説していきたいと思います。

目次を自動挿入するための全体的な流れ

まずウェブページにおける目次とは基本的に下記のようなものになると思います。

  • 記事内の見出しの一覧が表示される
  • 一覧の見出しをクリックするとその見出しに飛べる

ポイントの一つは「見出しをクリックするとその見出しに飛べる」という点です。つまりこれは、目次から見出しに対してページ内リンクを貼っているということになります。ですが、ページ内リンクを貼るためには見出しに id 属性が設定されている必要があります。

ですので、まずページ内の見出しに id 属性を設定する必要があります。

もしページ内リンクの貼り方をご存知ない方がおられましたら、まずは下記ページでページ内リンクについて理解していただけると、今後の説明の理解も進むと思います。

ページ内リンクの作成方法解説ページのアイキャッチ20秒で完成!ページ内リンクの作成方法を解説

また、ページ内リンクを貼られた見出しの一覧を表示するためには、記事内の見出し文とその id 属性を取得する必要があります。

さらに、取得した id 属性に対してページ内リンクを貼った見出し文を一覧として表示する必要があります。

したがって、目次の自動挿入は下記の3手順で実施することになり、上記のプログラムでもこの手順に従った処理を行なっています。

  • 見出しに id 属性を設定
  • 記事内の id 属性と見出し文を取得
  • 内部リンクを貼った見出しの一覧を出力

この3つをどのような処理で実現しているかをここから解説していきます。

見出しに id 属性を設定

見出しへの id 属性の設定は、上のプログラムの add_auto_id 関数で行なっています。

この add_auto_id 関数がどのようなものであるか、どうやって id を設定しているかは下のページで解説していますので、詳しく知りたい方はこちらを見ていただければと思います。

見出しにidを自動設定する方法の解説ページのアイキャッチワードプレスで見出しに自動的に id 属性を付ける方法

この add_auto_id 関数を下記で the_content 関数(記事の本文を出力する関数)にフックしていますので、the_content 関数実行前に add_auto_id が実行されて記事出力前に見出しに id を付加することができます。

add_filter( 'the_content', 'add_auto_id', 9 );

例えば記事の一番初めの見出しが下記のようなものであった場合、

<h2">見出し1</h2>

下記のように見出し要素が置き換わり、id 属性が付加された見出し要素が作成されたことになります。

<h2 id="auto-id=1">見出し1</h2>

記事内から id 属性と見出し文を取得

add_auto_id 関数により記事内の見出しに id が設定されますので、次は実際に目次を作成していきます。目次の作成を行なっているのは add_my_toc 関数です。

まずページ内リンクを貼るために各見出しの id 属性を、見出し一覧を作るために各見出しの見出し文を記事内から取得しています。

ここで用いるのも add_auto_id でも用いた preg_match_all 関数です。指定するパターンとしては下記の $toc_pattern を用います。

// id が設定されているかどうかを判断するためのパターン
$toc_pattern = '/^<h(['.$start.'-'.$end.']).+?id\s*=\s*\"(.+?)\".*>(.+?)<\/h['.$start.'-'.$end.']>$/im';

これを用いて preg_match_all 関数を実行することで、第三引数の $toc_headings にマッチした文字列等が格納されます。

$toc_ pattern には括弧で括っている部分が3つあり、それぞれが下記のように $toc_headings  に格納されます。

$toc_headings[0]:マッチした文字列
$toc_headings[1]:見出しレベル(h3なら"3")
$toc_headings[2]:id設定値
$toc_headings[3]:見出し文

内部リンクを貼った見出しの一覧を出力

目次を作成するための情報は揃ったので、ここから実際に目次を HTML として作成していきます。目次は単に箇条書きとして記事内の見出し一覧(ページ内リンクつき)を表示しているだけです。

実際に HTML を作成しているのは下記の部分になります。

/* 目次をdivで作成 */
$toc = "<div class=\"mytoc_body\">\n";

/* 目次の上部の見出しを作成 */
$toc = $toc . "<p class=\"mytoc_heading\">目次</p>\n";

/* 見出しを箇条書きで書き出し */
$toc       = $toc . "<nav class=\"mytoc_nav\">\n";
$toc       = $toc . "<ul>\n";
$num_count = count( $toc_headings[0] );
for ( $i = 0; $i < $num_count; $i++ ) {

	/* 見出しを内部リンク付きで箇条書きの項目として書き出し */
	$toc = $toc . '<li><a href="#' . $toc_headings[2][ $i ] . '">' . $toc_headings[3][ $i ] . "</a></li>\n";
}

$toc = $toc . "</ul>\n</nav>\n</div>\n";

$toc 変数は目次の HTML を格納する変数です。見出し毎に、この $toc 変数と <li> 〜 </li> で囲ったページ内リンクつきの各見出し文との連結を行うことで見出しを箇条書きとした HTML を作成しています。

最後に作成した HTML を記事内の一番上の見出しに挿入するために、「記事内の一番上の見出し要素」を「作成した HTML」+「記事内の一番上の見出し要素」に文字列置換を行なっています。

/* 最初の見出しの上に目次を追加 */
$the_content = str_replace( $toc_headings[0][0], $toc . $toc_headings[0][0], $the_content );

関数のフック

これらを行う add_my_toc 関数を add_auto_id 関数同様に 下記で the_content 関数にフックさせています。

add_filter( 'the_content', 'add_my_toc', 10 );

これにより the_content 関数が実行されるタイミングでこの add_my_toc 関数が実行され、自動的に目次が挿入されるようになります。

add_filter 関数の第三引数は優先度を表しており、同じ関数にフックされた関数は、この数字が小さいものから実行されます(優先度は省略された場合 10 が設定されます)。

今回紹介した add_my_toc 関数は、見出し要素に id 属性が付加されていることを前提とした作りとなっていますので、必ず add_auto_id 関数よりも後に実行されるように優先度を add_auto_id よりも大きい数字にしてください。

以上が目次を自動挿入する仕組みとなります。

スポンサーリンク

目次のカスタマイズ

続いて最初にのせたプログラム・CSS を変更して目次をカスタマイズを行う方法について解説します。

目次に表示数する見出しレベルを変更する

目次に表示する見出しレベルを変更するためには下記を変更すれば良いです。

$start = 2;
$end = 4;

見出しレベルが $start の見出しから $end の見出しが目次に表示されるようになります。

目次にネストをつける

見出しレベルに応じて目次にネストを付けるとさらに見やすくページ構成がわかりやすい目次にすることができます。

目次にネストを付けるためには、プログラムの下記部分を

/* 目次の作成ここから */
〜略〜
/* 目次の作成ここまで */

下記で置き換えれば良いです。

	/* 目次の作成ここから */

	/* ネスト管理用の変数 */
	$now_nest = $start;

	/* 目次自体の見出しを作成 */
	$toc = "<div class=\"mytoc_body\">\n";
	$toc = $toc . "<p class=\"mytoc_heading\">目次</p>\n";

	/* 見出しを箇条書きで書き出し */
	$toc       = $toc . "<nav class=\"mytoc_nav\">\n";
	$toc       = $toc . "<ul>\n";
	$num_space = 0;
	$num_count = count( $toc_headings[0] );
	for ( $i = 0; $i < $num_count; $i++ ) {

		/* 目次に書き出しする箇条書きのネストを計算 */
		$nest      = $toc_headings[1][ $i ];
		$diff_nest = $nest - $now_nest;

		if ( $diff_nest > 0 ) {

			/* 現在よりもネストを深くする場合 */
			for ( $j = 0; $j < $diff_nest - 1; $j++ ) {

				/* ネストを深くするためにタグ <ul> を付加 */
				$toc = $toc . "<ul>\n";
				$toc = $toc . "<li class=\"mytoc-li-none\">\n";

				$now_nest++;

			}

			/* ネストを深くするためにタグ <ul> <li> を付加 */
			$now_nest++;
			$toc = $toc . "<ul>\n";
			$toc = $toc . '<li class="mytoc-li-' . $now_nest . "\">\n";

		} elseif ( $diff_nest < 0 ) {
			if ( $i > 0 ) {
				/* 前の箇条書き <li> を閉じるための </li> */
				$toc = $toc . "</li>\n";
			}

			/* 現在よりもネストを浅くする場合 */
			for ( $j = 0; $j < -$diff_nest; $j++ ) {

				$now_nest--;

				/* ネストを浅くするためにタグ </ul> </li> を付加 */
				$toc = $toc . "</ul>\n";
				$toc = $toc . "</li>\n";

			}
			/* 箇条書きタグ追加 */
			$toc = $toc . '<li class="mytoc-li-' . $now_nest . "\">\n";
		} else {
			if ( $i > 0 ) {
				/* 前の箇条書き <li> を閉じるための </li> */
				$toc = $toc . "</li>\n";
			}
			/* 箇条書きタグ追加 */
			$toc = $toc . '<li class="mytoc-li-' . $now_nest . "\">\n";
		}
		/* 見出しを箇条書きとして書き出し */
		$toc =
			$toc . '<a href="#' . $toc_headings[2][ $i ] . '">' . $toc_headings[3][ $i ] . "</a>\n";
	}

	/* 最後の箇条書きを閉じる </li> */
	$toc = $toc . "</li>\n";

	/* 深くなったネストを浅くする */
	for ( $j = 0; $j < $now_nest - $start; $j++ ) {
		$toc = $toc . "</ul>\n";
		$toc = $toc . "</li>\n";
	}

	$toc = $toc . "</ul>\n</nav>\n</div>\n";

	/* 最初の見出しの上に目次を追加 */
	$the_content =
		str_replace( $toc_headings[0][0], $toc . $toc_headings[0][0], $the_content );

	/* 目次の作成ここまで */

この変更により目次の見た目は下記のように変わります。

ネストにスタイル設定していない時の目次

見出しレベルに応じて箇条書きの項目タグ <li> に下記のクラスを設定しています(Xは見出しレベル)。

<li class="mytoc-li-X">

ですのでこのクラスに応じてスタイル設定すれば、ネストに応じた見た目を設定することができます。

例えば style.css に下記を追記すれば、

.mytoc_nav ul{
	padding-left :0.5em;
}

.mytoc-li-2{
	list-style-type: none;
	font-size : 1.0em;
	line-height: 1.5;
	padding-bottom : 0.5em;
	padding-top : 0.5em;
	border-bottom: dashed 1px silver;
}
.mytoc-li-2::before{
	content: "■";
	color : #FF4040;
}

.mytoc-li-3{
	list-style-type: none;
	font-size : 0.9em;
}
.mytoc-li-3::before{
	content: "●";
	font-size:0.8em;
	color : #FF4040;
}

.mytoc-li-4{
	list-style-type: none;
	font-size : 0.9em;
}
.mytoc-li-4::before{
	content: "+";
	color : #FF4040;
}

.mytoc-li-5{
	list-style-type: none;
	font-size : 0.9em;
}
.mytoc-li-5::before{
	content: ">";
	color : #FF4040;
}

.mytoc-li-6{
	list-style-type: none;
	font-size : 0.9em;
}
.mytoc-li-6::before{
	content: ">>";
	color : #FF4040;
}

.mytoc-li-none{
	font-size : 0.9em;
	list-style-type: none;
}

目次の見た目は下のようになります。

ネストに対してスタイル設定してした時の目次

目次の見た目を変更する

目次を表示する部分の HTML は下記のようになっています。

下の図のように各要素に対して class を設定していますので、プログラムを変更して要素を変更したり、この class のスタイル設定を変更することでさまざまな見た目の目次にすることができます。

目次を構成する要素

また目次を作成している部分のプログラムを変更すればこの要素の構造自体も変更することが可能です。

例えば目次にプログラムの下記部分を消して、

$toc = $toc."<p class=\"mytoc_heading\">目次</p>\n";

その部分に下記を追記し、

$toc = $toc."<label class=\"mytoc_label\" for=\"mytoc_check_button\">目次</label>";
$toc = $toc."<input id=\"mytoc_check_button\" class=\"mytoc_check\" type=\"checkbox\">";

さらに style.css の下記部分を消して、

.mytoc_nav{
	font-size : 1.3em;
}

代わりに下記を追記すれば

.mytoc_check {
	display : none;
}

.mytoc_nav{
	opacity : 0;
	height: 0;
	overflow: hidden;
	transition: 0.5s;
	padding: 0px;
	margin : 0px;
	font-size : 1.3em;
}

.mytoc_check:checked + .mytoc_nav{
	height: auto;
	opacity: 1;
}

.mytoc_label{
	display : block;
	padding : 5px;
	font-weight : bold;
	color : #FFFFFF;
	text-align : center;
	background : #FFA0A0;
	font-size : 1.5em;
	cursor :pointer;
}

「目次」部分をクリックすることで目次の表示・非表示を切り替えられるようになります。アコーディオンとか言うやつですね。

アコーディオンを利用した目次表示

こんな感じでプログラムと style.css を変更すればどんどん目次の見た目を変更することが可能ですので、あなたのセンスでどんどんカスタマイズしていただければと思います。

参考サイト

スタイルシートの設定については下記のサルワカさんのページを参考にさせていただきました。センスの良いスタイル設定方法が解説されていますのでいつも参考にさせていただいています。

コピペで使えるリストデザイン34選:CSSで箇条書きをおしゃれに

まとめ

今回はプラグインなしにワードプレスで目次を自動挿入する方法について解説しました。

目次は下記のようにプログラムを作成することで自動挿入することが可能です。

  • 見出しに id 属性を設定
  • 記事内の id 属性と見出し文を取得
  • 内部リンクを貼った見出しの一覧を出力

preg_match_all 関数や str_replace 関数を使いこなせるとワードプレスのカスタマイズでできることが増えますので、ぜひこの機会に使い方をマスターしておくと良いと思います!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

ワードプレスの処理時間は約 0.168 秒です