こんにちは!日々Wordpressと格闘している Millmiです^^
今回は、見出しをもとにリンク付きの目次を自動生成するコードのご案内です。
2020-11-21
phpバージョン変更で一部にエラーが出たため phpコードを一部修正しています m(__)m
SEO的にも、閲覧者の利便性にも、ページ内リンクって大切。
今まで、jQueryで作った目次を使ったり、特急の時は有名どころの目次プラグインにお世話になったりしていましたが、、、
ふと気が付きました。。。
jQueryの目次、ちゃんと動いてはいるけど、ソースに出ないしSEOとしてはどうなんだろう??
ずーっと更新されてないプラグイン。いつまで使える? 大丈夫???
という事で、サイトのリニューアルに合わせて、プラグインなしphpで動く目次コードを作っちゃいました。これで、しばらくはいけるかな~(*’▽’)ww
目次の作り方
この上にあるのが、以下のコードで作った当サイトの目次です^^v
functions.php に直接貼ってもいいのですが、管理のしやすさを考えると別ファイルにしてfunctions.php に読込せるのがお勧めです。(別ファイル化はいつか、、投稿するかもw)
直接貼る場合は、1行目を削除してくださいm(__)m
phpコード(コピペOK)
2020-11-21 phpコード修正済
<?php // ← functions.phpに直接貼る場合は、この行を削除!!
function my_add_content( $content ) {
if ( is_single() && in_the_loop() && is_main_query() ) {
$pattern = '/<h[2-5]>(.*?)</h[2-5]>/i'; //← h2~h5 に対応させる
preg_match_all( $pattern, $content, $matches, PREG_SET_ORDER );
if( count( $matches ) > 1 ){
$toc = '<ol class="postin-list">'. PHP_EOL;
$hierarchy = NULL;
$i = 0;
foreach( $matches as $element ){
$i++;
$id = 'toc' . $i;
$chapter = preg_replace( '/<(.+?)>(.+?)</(.+?)>/', '<$1 id="' . $id . '">$2</$3>', $element[0] );
$content = preg_replace( $pattern, $chapter, $content, 1);
if( strpos( $element[0], '<h2' ) === 0 ){$level = 0;}
elseif( strpos( $element[0], '<h3' ) === 0 ){$level = 1;}
elseif( strpos( $element[0], '<h4' ) === 0 ){$level = 2;}
elseif( strpos( $element[0], '<h5' ) === 0 ){$level = 3;}
$hclass = $level + 2;
if( $hierarchy === $level ){ $toc .= '</li>'. PHP_EOL; $hierarchy = $level; }
elseif( $hierarchy < $level ){ $toc .= PHP_EOL .'<ol class="toc-h'. $hclass .'">'. PHP_EOL; $hierarchy = $level; }
elseif( $hierarchy > $level ){
$closing = str_repeat('</li>'. PHP_EOL .'</ol>', $hierarchy - $level );
$toc .= $closing . PHP_EOL .'</li>'. PHP_EOL; $hierarchy = $level; }
elseif( $i == 1 ){ $hierarchy = 0; }
$title = $element[1];
$toc .= '<li><a href="#' . $id . '">' . $title . '</a>';
}
$toc .= str_repeat('</li>'. PHP_EOL .'</ol>', $level + 1);
$index = '<nav class="postin-nav toc"><p class="postin-tti">このページの目次</p>
<input type="checkbox" id="toc-ch" name="toc-ch" class="postin-ch" checked><label for="toc-ch" class="postin-label"></label>'. PHP_EOL . $toc . '</nav>'. PHP_EOL;
$h2 = '/<h2.*?>/i';
if (preg_match($h2, $content, $h2s)) {
$content = preg_replace($h2, $index . $h2s[0], $content, 1);
}
}
}
return $content; }
add_filter( 'the_content', 'my_add_content' );
さらっとご説明
7行目 | 見出し2個以上で表示 ⇒ 表示されにくくするなら数字を増やします | ||||||||
12~33行目 | 繰返しであれこれ処理 | ||||||||
|
|||||||||
34~37行目 | [ラッパー&見出し] を含む最終的な書き出し設定 | ||||||||
|
|||||||||
39~42行目 | 表示位置 (最初の<h2> の上) |
開閉不要の場合は 37行目のピンク部分
<input type="checkbox" id="toc-ch" name="toc-ch" class="postin-ch" checked><label for="toc-ch" class="postin-label"></label>
を削除します。
スタイルシート
本体部分
※ 当サイトでは 行頭アイコンにFontAwesomeを使用していますが、以下のソースでは、使いやすいよう »(»)にしてあります。
.postin-nav {
position: relative;
overflow: hidden;
font-size: 14px;
padding: 0;
margin: 1rem 4%;
border: solid 1px #ccc;
border-radius: 1rem; }
.postin-tti {
background: #f6f6f6;
font-weight: bold;
line-height: 2.2em;
padding: 0 7em 0 1rem;
margin: 0;
border-radius: 1rem 1rem 0 0; }
.postin-nav ol {
list-style: none; margin: 5px 0; }
.postin-nav ol.postin-list {
border-radius: 0 0 1rem 1rem; }
.postin-nav li {
position: relative;
line-height: 1.4;
padding: 5px 0.5em 3px 1.8em;
margin: 0; }
.postin-list > li {
order-top: dotted 1px #bbb; }
.postin-list > li li {
border-top: 0; }
.postin-nav li:before {
position: absolute; top: 2px; left: 1rem;
content: "»";
color: #ccc;
padding-right: 7px; }
CSSでの開閉
※開閉不要なら以下は必要ありません^^
input.postin-ch {
position: absolute; top: 0; right: 0;
z-index: 1;
opacity: 0; }
label.postin-label {
position: absolute; top: 0; right: 7px;
display: block;
width: 100%;
z-index: 100;
font-size: 1em; line-height: 2.2; text-align: right;
margin: 0;
cursor: pointer; }
label.postin-label:before {
content: "▲Close";
display: inline-block;
background: #343434;
color: #fff; font-weight: bold; line-height: 1.6;
padding: 0 7px;
border-radius: 10px; }
input.postin-ch + label.postin-label + ol.postin-list {
max-height: 40vh;
overflow-y: auto;
transition: transform 0.3s ease-out; }
input.postin-ch:checked + label.postin-label:before {
content: "▼Open"; }
input.postin-ch:checked + label.postin-label + ol.postin-list {
max-height: 0;
margin: 0; }
開閉方法を簡単にご説明
checkboxのチェックの有無で開閉させます。(チェック時は閉じる)
- checkbox ⇒「opacity: 0;」→ 透過させて見えないように
- label ⇒「width: 100%;」→ タイトル行クリックで反応
- ol.postin-list ⇒ max-height: 40vh; で高さ指定
※max-height で強引にtransitionさせているので、内容が少ない場合、開閉時に多少カク付きがでます _ _;;
コメント