WordPressの記事に目次を付けるというとプラグインを使うのが一般的だ。
が、できればプラグインなしで、WordPressの記事に目次を付けたい。
プラグインなしでWordPressの記事に目次を付けるには
WordPressの記事の見出しを目次として利用したい。
で、目次の部分をクリックすると、その内容にリンクするようにしたいわけ。
で、あちこち調べてみると、ありました。
目次を付けるためにカスタマイズするファイル
- 目次のコードは子テーマのfunctions.php に記載する。
- スタイルシートは子テーマのスタイルシートに記載。
- ショートコードはSimplicity2の場合、投稿記事の一番初めのH2見出しの前にウィジットが設定できるので、ウィジットを使い最初のH2見出しの前に目次が入るようにした。
ウィジットに記載するショートコード
1.Simplicity2の〔外観〕→ウィジット→「投稿本文中」のウィジットの中に、〔クラッシックテキスト〕を設置。
2.〔クラッシックテキスト〕の中に以下のショートコードを記載する。
[toc title="目次" depth="2"
]
functions.php に記載する目次のコード
参考サイトの記載コードと同じ。
でも、一応コードは乗せておく。
/**
* 目次ショートコードです。
*
* @version 1.1.0
*/
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 ) {
global $post;
if ( ! isset( $post ) )
return '';
$this->atts = shortcode_atts( array(
'id' => '',
'class' => 'toc',
'title' => '目次',
'toggle' => true,
'opentext' => '開く',
'closetext' => '閉じる',
'close' => false,
'showcount' => 2,
'depth' => 0,
'toplevel' => 2,
'targetclass' => 'entry-content',
'offset' => '',
'duration' => 'normal'
), $atts );
$this->atts['toggle'] = ( false !== $this->atts['toggle'] && 'false' !== $this->atts['toggle'] ) ? true : false;
$this->atts['close'] = ( false !== $this->atts['close'] && 'false' !== $this->atts['close'] ) ? true : false;
$content = $post->post_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 ) {
$class = $current_depth == 0 ? ' class="toc-list"' : '';
$style = $current_depth == 0 && $this->atts['close'] ? ' style="display: none;"' : '';
$toc_list .= "<ul{$class}{$style}>";
$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 ( $this->atts['toggle'] ) {
$toggle = ' <span class="toc-toggle">[<a class="internal" href="javascript:void(0);">' . ( $this->atts['close'] ? $this->atts['opentext'] : $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 = $(this).parents(".<?php echo $class; ?>").children(".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();
スタイルシートの記載
これまた、参考サイトのスタイルシートをそのまま利用する。
.toc {
width: auto;
display: table;
margin: 0 0 10px;
padding: 10px;
color: #333;
word-break: break-all;
word-wrap: break-word;
border: #ccc solid 1px;
border-radius: 3px;
background-color: #fafafa;
}
.toc .toc-title {
margin: 0;
padding: 0;
text-align: center;
font-weight: bold;
}
.toc .toc-toggle {
font-weight: normal;
font-size: 90%;
}
.toc ul {
list-style: none;
}
.toc .toc-list {
margin: 0;
padding: 0;
}
参考サイト
参考サイトというより、上のコードを作ってくれた人のサイト。
今回、まったく、コードをいじっていないので。
おいらの能力じゃ、いじるのが難しかった。
下のリンクから、参考サイトへどうぞ。
コードが何を示しているかの説明もある。
コメント