【WordPress】目次自動作成スクリプト改良版【javascript少な目】
以前,「【WordPress】目次を自動生成するには」という目次自動生成スクリプトを紹介したことがあった.
今回,「A タグの href に javascript:void(0); とか入れんな」という突っ込みを PageSpeed Insights 様から受けたので対応するためにプログラムを改良した.
折角なので公開する.
WordPress の目次自動作成プログラム
WordPress で記事に自動的に目次を作成するプログラムである.
目次を一々作らなくても見出しから自動的に作ってくれるので,自分で作ることを考えるととても楽が出来る.
functions.php に入れるだけなので実装も簡単だ.
目次の「閉じる」「開く」を CSS だけで動作するように改良
元々のプログラムでは「閉じる」「開く」を javascript で実装していた.
その「閉じる」「開く」ボタンが A タグで作成されていて,href に javascript:void(0); と書かれていたのだ.
そのため,PageSpeed Insights で警告を受けた.
この部分はアコーディオン表示なので「CSS のみでアコーディオン表示する」を参考にしながら,この部分を javascript を使わないように書き替えた.
PHP と javascript のソースコード
これを functions.php に挿入すればよい.
class Toc_Shortcode {
private $add_script = false;
private $atts = array();
public function __construct() {
add_shortcode('toc', array( $this, 'shortcode_content' ) );
add_action('wp_footer', array( $this, 'add_script' ), 999999 );
add_filter('the_content', array( $this, 'change_content' ), 9 );
}
function change_content( $content ) {
return "<div id=\"toc_content\">{$content}</div>";
}
public function shortcode_content( $atts ) {
global $post;
if ( ! isset( $post ) )
return '';
$this->atts = shortcode_atts( array(
'id' => '',
'class' => 'toc',
'title' => '目次',
'showcount' => 2,
'depth' => 0,
'toplevel' => 2,
), $atts );
$content = $post->post_content;
$headers = array();
preg_match_all( '/<([hH][1-6]).*?>(.*?)<\/[hH][1-6].*?>/us', $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>';
}
while ( $current_depth < $depth ) {
$class = $current_depth == 0 ? ' class="toc-list"' : '';
$toc_list .= "<ul{$class}>";
$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 = <<<EOD
<style>
.toc input {
display: none;
}
.toc {
max-height: inherit;
overflow-y: visible;
}
.toc .toc-toggle {
text-align: center;
display: block;
}
.toc .toc-list {
max-height: inherit;
overflow-y: visible;
visibility: visible;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
-ms-transition: all 0.5s;
-o-transition: all 0.5s;
transition: all 0.5s;
}
.toc .clickarea {
padding: 6px;
}
.toc input[type="checkbox"]:checked ~ .toc-list {
max-height: 0;
overflow-y: hidden;
visibility: hidden;
opacity: 1;
}
.toc .clickarea:before {
content: "[閉じる]";
}
.toc input[type="checkbox"]:checked ~ * .clickarea:before {
content: "[開く]";
}
</style>
EOD;
if ( $counter >= $this->atts['showcount'] ) {
$this->add_script = true;
$toggle = ' <input type="checkbox" id="tocclose"/><label for="tocclose" class="toc-toggle"><span class="toc-title">' . $this->atts['title'] . '</span><span class="clickarea"></span></label>';
$html .= '<div' . ( $this->atts['id'] != '' ? ' id="' . $this->atts['id'] . '"' : '' ) . ' class="' . $this->atts['class'] . '">';
$html .= $toggle . $toc_list;
$html .= '</div>' . "\n";
}
return $html;
}
public function add_script() {
if ( ! $this->add_script ) {
return false;
}
?>
<script>
let xoToc = () => {
const entryContent = document.getElementById('toc_content');
if (!entryContent) {
return false;
}
/*
* ヘッダータグに ID を付与
*/
const headers = entryContent.querySelectorAll('h1, h2, h3, h4, h5, h6');
for (let i = 0; i < headers.length; i++) {
headers[i].setAttribute('id', 'toc' + (i + 1));
var cls = headers[i].getAttribute('class');
if (cls == null) { cls = ''; }
headers[i].setAttribute('class', cls + ' anchor');
}
};
xoToc();
</script>
<?php
}
}
new Toc_Shortcode();
スタイルシートのコード
これは同じなので以前作った「【WordPress】目次を自動生成するには」のページを参考にどうぞ.
ご質問等ありましたら,お手数ですが弊社の個人情報保護方針をお読み頂いた上でフォームからお願い致します.
※このページと無関係な内容のセールスはご遠慮ください.