WordPressの無料テーマ「Cocoon」最高ですよね。Cocoonではプラグインを使わなくても記事の見出しから自動的に「目次」を生成・表示させる機能があります。素晴らしいですね。
さて、この目次ですが、長文となった記事を複数ページに分割したりすると、それらのページごとの目次が作られます。これはどうでしょうか。SEOの観点だったり、基本的な考え方のベースにページ単位で完結するというものがあったりするのでしょう。でも、分割されていても、記事が一つなら、目次もその記事全体分で一つという方が、しっくりくるという人もいるでしょう。また、2ページ目を読み進めている人が、1ページ目のあの箇所に戻りたいという人もいるでしょう。
今回はそうした人たちに向けて、複数ページに分割された記事で、全ページ分の目次を全ページに表示させる方法です(テーマはCocoonを前提にした説明です)。
functions.phpにコードを書きこむ
Cocoonにせっかく、目次表示の機能はあるのですが、今回は泣く泣く、表示しない設定にします。[Cocoon設定]の[目次]タブから、[目次を表示する]のチェックが外れていることを確認してください。
では、早速、複数ページに分割された記事で、全ページ分の目次を全ページに表示させる為のコードです。[外観]の[テーマエディター]から、functions.phpに下記のコードを書きこみます。記事中のhタグに応じて目次を作っていきます。ひとまず、h1~h6全てに対応します。本来h1タグは記事タイトル以外では使わないルールですが、WordPressではh1タグを使えない仕様にはなっていないので、対応しています。このコードの特徴は「$up_down」という配列にリストを作るためのタグ「ol」と「li」の組み合わせを11個用意して、連続するhタグの階層差に着目して呼び出します。それによってループの回数を減らし、タグの微調整はWordPressのタグ補正機能に委ねることにより、50行足らずのシンプルなコードを実現しています。
function toc_by_percredere($content){
if(is_singular()){
global $post;
$current_page_num = (get_query_var('page') == 0) ? 0 : get_query_var('page') - 1;
$htags = array();
$tag_num = array();
$p_link = get_permalink();
$pages = explode('<!--nextpage-->', $post->post_content);
$up_down = array("</li></ol></ol></ol></ol></ol></li>", "</li></ol></ol></ol></ol></li>", "</li></ol></ol></ol></li>", "</li></ol></ol></li>", "</li></ol></li>", "</li>", "<ol>", "<ol><ol>", "<ol><ol><ol>", "<ol><ol><ol><ol>", "<ol><ol><ol><ol><ol>");
for($p = 0; $p < count($pages); $p++){
preg_match_all('/(<h([1-6])>.+)<\/h[1-6]>/u', $pages[$p], $tag_each_page, PREG_SET_ORDER);
$htags[] = array_column($tag_each_page,1);
$tag_num = array_merge($tag_num, array_column($tag_each_page, 2));
}
if(!empty($tag_num)){
$tag_num[] = min($tag_num);
$htag_init = $tag_num[0] - min($tag_num) + 6;
}
$c = 0;
for($a = 0; $a < count($htags); $a++){
for($b = 0; $b < count($htags[$a]); $b++){
$htags_diff = $tag_num[$c + 1] - $tag_num[$c] + 5;
if($a == $current_page_num){
$for_toc .= preg_replace('/<h[1-6]>/u', "<li><a href='". "#". $b. "'>", $htags[$a][$b]). "</a>". $up_down[$htags_diff];
$content = preg_replace('/(<h[1-6])>/u','$1'. " id='". $b. "'>", $content, 1);
}else{
if($a == 0){
$for_toc .= preg_replace('/<h[1-6]>/u', "<li><a href='". $p_link. "#". $b. "'>", $htags[$a][$b]). "</a>". $up_down[$htags_diff];
}else{
$for_toc .= preg_replace('/<h[1-6]>/u', "<li><a href='". $p_link. ($a + 1). "/#". $b. "'>", $htags[$a][$b]). "</a>". $up_down[$htags_diff];
}
}
$c++;
}
}
if($current_page_num == 0){
$content = preg_replace('/(<h[1-6].+<\/h[1-6]>)/u', "<div class='toc'><div class='toc-title'>contents</div>". $up_down[$htag_init]. $for_toc. "</ol></div>". '$1', $content, 1);
}else{
$content = "<div class='toc'><div class='toc-title'>contents</div>". $up_down[$htag_init]. $for_toc. "</ol></div>". $content;
}
return $content;
}
}
add_filter('the_content','toc_by_percredere');
実際に貼付した画像が下記です。「以下に子テーマ用の関数を書く」の下に貼付してください。
目次のスタイルを整える
上記のコードだけで、目次は生成されますが、少しスタイルを整えたり、表示、非表示の切り替えができるようにします。この辺は皆さんのお好みでカスタマイズしてみてください。
style.cssにコードを書きこむ
目次表示の微調整と表示、非表示(open、close)切替の設定のコードです。[外観]の[テーマエディター]から、style.cssに下記のコードを書きこみます。
.toc{
margin:auto;
}
.toc-title::after {
content: '[close]';
margin-left: .5em;
cursor: pointer;
font-size: .8em;
}
.toc-title.active::after {
content: '[open]';
}
.article ol{
padding-left:15px;
}
javascript.jsにコードを書きこむ
最後に、目次の表示、非表示を動作させるコードです。[外観]の[テーマエディター]から、javascript.jsに下記のコードを書きこみます。
$('.toc-title').click(function(){
$(this).toggleClass("active").next().fadeToggle();
})
これで、スタイルも整って、表示、非表示もできる目次が自動で生成されます。
この記事はそんなに長文ではありませんが、複数ページに分割された記事で、全ページ分の目次が全ページに表示されることを確認する為、この下に改ページを入れます。また、1ページ目は目次を最初のhタグ(見出し)の直前に入れていますが、2ページ目以降はページの一番最初に目次を入れます。
それができているかを確認するため、あまり無いとは思いますが、2ページ目の開始を段落からにしています。
コメント
質問がしたく、コメントで申し訳ございません。
記事読ませていただきました。内容を参考にさせて頂きCOCOONを修正したのですが
こちら、目次の表示がデフォルトでCloseにする事は可能なのでしょうか??
私自身、能力が低く自分自身で修正/カスタマイズが出来ず、回答を頂けましたら幸いです。
お手数をお掛けしますが、ご確認お願い致します。
管理者の「Pくれーでれ」です。
コメントいただき、ありがとうございます。コメントの確認が大変遅れまして申し訳ございません。
目次の表示についてデフォルトで、閉じた状態にするには「style.cssにコードを書きこむ」のところに記載したコードを下記の通り、修正してください。
➀[open] と[close]を入れ替え
content: ‘[close]’; → content: ‘[open]’;
content: ‘[open]’; → content: ‘[close]’;
➁下記のコードを追加
.toc-content{
display: none;
}
以上で実現できると思います。お試しください。
こんにちは。
ブログ参考にさせていただいております。
ありがとうございます。
私も、もくじを一括表示させたいと思っており、
思い切って挑戦してみたのですが、、、
functions.php
に、添付したところ、
重大なエラーが、、、
という表示になってしまいました。
もともと、
functions.phpに記載してある内容の
下に添付するような形で
貼り付けさせていただいたのですが、
やり方が間違っておりますでしょうか?
この辺りのことは、
全く初心者なもので、、、
申し訳ございませんが、
お助け頂けましたら幸いです。
よろしくお願いいたします。
管理者の「Pくれーでれ」です。
コメントいただき、ありがとうございます。コメントの確認が大変遅れましたことをお詫びいたします。
下記についてご確認ください。
テーマは「cocoon」を使用しています。そのうえでfunctions.phpに実際貼付している画像を記事に追加しますので、貼付方法(貼付位置)をご確認ください。
初めまして。
まず私はExcel能力は仕事上必須ですから関数でもなんでも出来ますが、それ以外は初心者です。
私はwordplessでブログを10記事ほどやっと書き終えました。10記事総て関連性がありますので目次が必要でしたが設置方法がわかりません。
そんな時にPくれーでれさんのサイトに出くわし大喜びで読みました。
そして早速実践。
Pくれーでれさんの記事にこう書いてありました。
[外観]の[テーマエディター]から、functions.phpに下記のコードを書きこみます。
早速コピーして貼り付けました。
次に目次の微調整でしたので、その前に出来栄えを確認しようとしたしたが、いつもの画面に戻りません。
画面の写真を貼り付けられたら貼り付けるのですが…
何ヶ月もかけて書いたブログですので元に戻したいのですが、どうやれば良いのでしょうか?
この内容だけではどんな状況か不明だと思いますが…
画面には関数toc_by_percredere($ content){if(is_singular()){グローバル$ post;$ current_page_num =長いので止めますが…
非常に困っております。
何卒初心者の私にわかるような説明で宜しくお願い致します。
追って
ブログは非公開にしてあります。
管理者の「Pくれーでれ」です。
コメントいただき、ありがとうございます。コメントの確認が大変遅れましたことをお詫びいたします。
この関数は実際にcocoonのテーマにおいて、このサイトで使用して機能しています。
プラグインの使用状況など、その他の環境によるものか特定はできませんが、不具合が生じた場合、貼付した関数を削除いただきますようお願いいたします。
貼付した画面にも戻せないという状況ですと、こちらでも回復方法がわかりません。
以上の通りです。よろしくお願いいたします。
初めまして。
長文の記事を執筆するため、本記事を参考に目次をカスタマイズしてみました。
目次自体は機能したのですが、クリックすると新しいタブでページが開いてしまい、困っております。
本記事のように、同一ページ内ではスライドで移動、他ページではページが切り替わるように変更したいのですが、どのように設定すればよろしいでしょうか。
初心者で知識がなく、解決方法をご教示いただきたく存じます。
よろしくお願いいたします。
管理者の「Pくれーでれ」です。
コメントいただき、ありがとうございます。ご質問の件に関して、考えられるのは「内部リンクの設定」が「新しいタブで開く」となっているというものです。
テーマが「Cocoon」であれば、[Cocoon設定]の中の[本文]タブから「内部リンク設定」の「内部リンクの開き方」が「新しいタブで開く(_blank)」になっていると、その設定通りで新しいタブで開きます。これであればその設定を「変更しない」にすると解決すると思います。
ここに問題があることを願います。ご確認してみてください。