WordPressでプラグインなしで目次を自動生成する方法



ワードプレスで目次を自動作成する方法

ワードプレスで記事内に目次を作りたい。と思ったとき、

個人的には
「functions.php」と「style.css」を編集して目次を自動で生成してくるショートコードを作るというのが現状ベストかなと思っています。

以下、もう少し解説を。



ワードプレスで効率良く目次を作りたい

ワードプレスで目次を作る3つの方法

この記事にもありますが、目次と言うのは冒頭にあるあれですね。

記事の概要が一目でわかるし、見出しをクリックすればそこにジャンプできる。つまりリンク機能がある。

目次に必ずしもリンク機能が備わっていないといけないわけではありませんが、やはり記事の冒頭に見出しへのリンクがついた目次は便利です。

で、この目次を作る方法は主に3つあります。

  • 自分で毎回手入力で作る
  • プラグインを使う
  • テーマを編集して作る


です。


目次を毎回手作りすること

ただ目次を作るだけなら手打ちでもいいわけです。
つまり毎回記事内に目次のHTMLを記述する。

でもこれは面倒ですね。

まずHTMLで記述すること自体が慣れてない人にはハードルが高い。

仮に慣れても、今度は見出しを見ながら毎回目次に見出しのタイトルを打つといった二度手間が必要になる。

よって多くの人は手入力ではなくもっと効率的な方法がないかと模索するわけです。


「プラグイン」か「コードの編集」か?

このような経緯で、目次を自動生成してくれるプラグインを探すに至ります。

しかしながら、
プラグインは基本的にワードプレスの動作を重くしますし互換性やセキュリティなど管理することが増えるため個人的にはできるだけ使いたくない。

そのため、
テーマを直接編集して目次を自動で生成できるようにしようという考えに行きつきます。

ただ、ここで思うのが、
全ての記事に自動で目次が生成するようなコードでは嫌だとういこと。

なぜなら、今後記事を書く上で、目次が欲しいときもあれば欲しくないときもあるかもしれません。

つまり、
目次を自動で生成することもできるし、目次なしにもできるような状況にしたい。

このような経緯から、
目次を自動生成するショートコードを作ろうという結論に至るわけです。



目次を自動生成するショートコードの作り方

作業内容としては、「functions.php」「style.css」を編集します。

テーマを編集するので、バックアップをとったり子テーマでの編集をおすすめします。

以下のコードは「マメポップ」さんの記事を参考に、ちょこちょこ改良したものです。


「functions.php」の編集

//以下、目次の自動作成ショートコードの記述です
//もし「functions.php」に他に何も書いていないなら、冒頭に「<?php」を付け足す。
class Toc_Shortcode {
 
	private $add_script = false;
	private $atts = array();
 
	public function __construct() {
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
		add_shortcode( 'toc', array( $this, 'shortcode_content' ) );
		add_action( 'wp_footer', array( $this, 'add_script' ) );
	}
 
	function enqueue_scripts() {
		if ( !wp_script_is( 'jquery', 'done' ) ) {
			wp_enqueue_script( 'jquery' );
		}
	}
 
	public function shortcode_content( $atts ) {
		$this->atts = shortcode_atts( array(
			'id' => '',
			'class' => 'toc',
			'title' => '<span class="icon-info"></span> 【目次】 ',
			'toggle' => 'true',
			'opentext' => 'open',
			'closetext' => 'close',
			'showcount' => 2,
			'depth' => 0,
			'toplevel' => 2,
			'targetclass' => 'entry-content',
			'offset' => '',
			'duration' => 'normal'
		), $atts );
 
		$content = get_the_content();
 
		$headers = array();
		preg_match_all( '/<([hH][1-6]).*?>(.*?)<\/[hH][1-6].*?>/u', $content, $headers );
		$header_count = count( $headers[0] );
		$counter = 0;
		$counters = array( 0, 0, 0, 0, 0, 0 );
		$current_depth = 0;
		$prev_depth = 0;
		$top_level = intval( $this->atts['toplevel'] );
		if ( $top_level < 1 ) $top_level = 1;
		if ( $top_level > 6 ) $top_level = 6;
		$this->atts['toplevel'] = $top_level;
 
		// 表示する階層数
		$max_depth = ( ( $this->atts['depth'] == 0 ) ? 6 : intval( $this->atts['depth'] ) );
 
		$toc_list = '';
		for ( $i = 0; $i < $header_count; $i++ ) {
			$depth = 0;
			switch ( strtolower( $headers[1][$i] ) ) {
				case 'h1': $depth = 1 - $top_level + 1; break;
				case 'h2': $depth = 2 - $top_level + 1; break;
				case 'h3': $depth = 3 - $top_level + 1; break;
				case 'h4': $depth = 4 - $top_level + 1; break;
				case 'h5': $depth = 5 - $top_level + 1; break;
				case 'h6': $depth = 6 - $top_level + 1; break;
			}
			if ( $depth >= 1 && $depth <= $max_depth ) {
				if ( $current_depth == $depth ) {
					$toc_list .= '</li>';
				}
				while ( $current_depth > $depth ) {
					$toc_list .= '</li></ul>';
					$current_depth--;
					$counters[$current_depth] = 0;
				}
				if ( $current_depth != $prev_depth ) {
					$toc_list .= '</li>';
				}
				if ( $current_depth < $depth ) {
					$toc_list .= '<ul' . ( ( $current_depth == 0 ) ? ' class="toc-list"' : '' ) . '>';
					$current_depth++;
				}
				$counters[$current_depth - 1]++;
				$number = $counters[0];
				for ( $j = 1; $j < $current_depth; $j++ ) {
					$number .= '.' . $counters[$j];
				}
				$counter++;
				$toc_list .= '<li><a href="#toc' . ($i + 1) . '"><span class="contentstable-number">' . $number . '</span> ' . $headers[2][$i] . '</a>';
				$prev_depth = $depth;
			}
		}
		while ( $current_depth >= 1 ) {
			$toc_list .= '</li></ul>';
			$current_depth--;
		}
 
		$html = '';
		if ( $counter >= $this->atts['showcount'] ) {
			$this->add_script = true;
 
			$toggle = '';
			if ( strtolower( $this->atts['toggle'] ) == 'true' ) {
				$toggle = ' <span class="toc-toggle">[<a class="internal" href="javascript:void(0);">' . $this->atts['closetext'] . '</a>]</span>';
			}
 
			$html .= '<div' . ( $this->atts['id'] != '' ? ' id="' . $this->atts['id'] . '"' : '' ) . ' class="' . $this->atts['class'] . '">';
			$html .= '<p class="toc-title">' . $this->atts['title'] . $toggle . '</p>';
			$html .= $toc_list;
			$html .= '</div>' . "\n";
		}
 
		return $html;
	}
 
	public function add_script() {
		if ( !$this->add_script ) {
			return false;
		}
 
		$class = $this->atts['class'];
		$offset = is_numeric( $this->atts['offset'] ) ? (int)$this->atts['offset'] : - 1;
		$duration = is_numeric( $this->atts['duration'] ) ? (int)$this->atts['duration'] : '"' . $this->atts['duration'] . '"';
		$targetclass = trim( $this->atts['targetclass'] );
		if ( $targetclass == '' ) {
			$targetclass = get_post_type();
		}
		$targetclass = ".$targetclass :header";
		$opentext = $this->atts['opentext'];
		$closetext = $this->atts['closetext'];
		?>
<script type="text/javascript">
(function ($) {
  var offset = <?php echo $offset; ?>;
  var idCounter = 0;
  $("<?php echo $targetclass; ?>").each(function () {
    idCounter++;
    this.id = "toc" + idCounter;
  });
  $(".<?php echo $class; ?> a[href^='#']").click(function () {
    var href = $(this).attr("href");
    var target = $(href === "#" || href === "" ? "html" : href);
    var h = (offset === -1 ? $("#wpadminbar").height() + $(".navbar-fixed-top").height() : offset);
    var position = target.offset().top - h - 4;
    $("html, body").animate({scrollTop: position}, <?php echo $duration; ?>, "swing");
    return false;
  });
  $(".toc-toggle a").click(function () {
    var tocList = $(".toc-list");
    if (tocList.is(":hidden")) {
      tocList.show();
      $(this).text("<?php echo $closetext; ?>");
    } else {
      tocList.hide();
      $(this).text("<?php echo $opentext; ?>");
    }
  });
})(jQuery);
</script>
		<?php
	}
 
}
 
new Toc_Shortcode();
//以上、目次の自動作成ショートコードの記述でした。


「style.css」の編集

/* 以下、目次自動生成のデザインです。 */
.toc {
    width: auto;
    display: table;
    margin: 15px 0px 15px 0px;
    padding: 10px 10px 10px 10px;
    color: #333;
    word-break: break-all;
    word-wrap: break-word;
    border: #ccc double 1px;
    background-color: #ffebff;
}
.toc .toc-title {
    margin: 0;
    padding: 0;
    text-align: center;
    font-weight: bold;
}
.toc .toc-toggle {
    font-weight: normal;
    font-size: 90%;
    text-decoration:none;
}
.toc ul{
    list-style: none;
    margin-left:-25px;
}
.toc .toc-list {
    margin: 0;
    margin-left:0px;
    padding: 0;
}
/* 以上、目次自動生成のデザインでした。 */



まとめ

目次があると記事の概要が一目でわかるし、見出しをクリックすればそこにジャンプできて便利です。

目次の作り方はいろいろあります。
中には自動で目次を作成してくれる機能を持ったテーマもあるでしょう。

そういったテーマでない場合。
自分で効率よく目次を作りたい場合。

プラグインもいいですが、よりシンプルにと思うと

「functions.php」と「style.css」を編集して目次を自動で生成してくるショートコードを作るというのが現状ベストかなと思っています。

「functions.php」と「style.css」に先述のコードを記述します。

そして、各投稿記事の冒頭(目次を入れたい場所ならどこでもOK)に、

[toc]

と入力します。

そうすると目次が自動生成されます。



その他の記事

インターネットで正しい情報を得るテクニック
【目次】 ・インターネットで正しい情報を得るテクニック ・「自分で調べる力」と「調べた情報を見極める力」 ・まとめ ・その他...
WordPressでメディアをカテゴリー分けしたい~Enhanced Media Library~
WordPressでメディアをカテゴリー分けしたい WordPress(ワードプレス)を使っていると、画像を使うことがあるわけ...
Google Analyticsで自分のスマホのアクセスを除外する
WordPressでウェブサイトを運営したりブログを書いたりしていると、アクセス解析としてGoogle Analyticsを導入することは多...
STINGER8 更新日を非表示にする
WordPressのテーマであるSTINGER8(スティンガー8)のカスタマイズをします。 STINGER8は記事のページに投稿日と更...
STINGER8 フォントサイズを変更する
WordPressのテーマであるSTINGER8(スティンガー8)のカスタマイズをします。 ※ちなみにこのサイトのテーマは現在STINGE...
WordPressでプラグインなしで目次を自動生成する方法
ワードプレスで目次を自動作成する方法 ワードプレスで記事内に目次を作りたい。と思ったとき、 個人的には 「functi...
カエレバのリンクが長いのでショートコードで短く記述(プラグインなし)
カエレバの商品リンクを短くする方法 ブログでアフィリエイトをする際に使っている人が多いと思われるカエレバ。 ただ、普通に...



参考資料

『ワードプレスにプラグインなしで目次を追加する方法』(マメポップ)2019年2月24日検索