WordPressサイトでPHPを使用して独自の目次を作成する方法
『WordPress PHP 目次』などと調べても、検索にヒットした内容だと、ショートコードなどで他の記事を読み込んだりしたときに『the_content()』が弊害になって『add_filter('the_content' ...』で目次を挿入する形だと都合が悪かったので、 『add_filter('the_content' ...』ではhタグのid付与だけ処理を行い、目次の挿入は別の処理に分けて行い意図せず目次が複数表示されてしまう現象を回避しました。
今回は下記のような目次を作成できます。
それではWordPressに実装していこうと思います。まずはfunctions.phpに読み込むための記述をしていきます。
// 目次パーツ追加(※設置するディレクトリを指定してください。)
require_once('class-toc.php');
次に、『class-toc.php』の中身を作成していきます。
function custom_toc() {
$index_adder = new Toc_Adder();
$index_adder->generate_toc();
}
class Toc_Adder {
private $index_content = '';
public function __construct() {
add_filter('the_content', array($this, 'add_index'));
}
public function add_index($content) {
if (is_single()) {
$pattern = '/<h[2-6][^>]*>(.+?)<\/h[2-6]>/s';
preg_match_all($pattern, $content, $elements, PREG_SET_ORDER);
if (count($elements) >= 1) {
$i = 0;
$id = 'chapter-';
foreach ($elements as $element) {
$id .= $i + 1;
$regex = '/' . preg_quote($element[0], '/') . '/su';
$replace_title = preg_replace('/<(h[2-6])(.*?)>(.+?)<\/(h[2-6])>/s', '<$1$2 id="' . $id . '">$3</$4>', $element[0], 1);
$content = preg_replace($regex, $replace_title, $content, 1);
$i++;
$id = 'chapter-';
}
return $content;
} else {
return $content;
}
}
}
public function generate_toc() {
ob_start();
the_content();
$content = ob_get_clean();
if (is_single()) {
$pattern = '/<h[2-6][^>]*>(.+?)<\/h[2-6]>/s';
preg_match_all($pattern, $content, $elements, PREG_SET_ORDER);
}
if (count($elements) >= 1) {
$i = 0;
$id = 'chapter-';
$toc = '';
$currentlevel = 0;
foreach ($elements as $element) {
$id .= $i + 1;
$regex = '/' . preg_quote($element[0], '/') . '/su';
$replace_title = preg_replace('/<(h[2-6])(.*?)>(.+?)<\/(h[2-6])>/s', '<$1$2 id="' . $id . '">$3</$4>', $element[0], 1);
$content = preg_replace($regex, $replace_title, $content, 1);
if (strpos($element[0], '<h2') !== false) {
$level = 1;
$item_class = 'heading-2';
} elseif (strpos($element[0], '<h3') !== false) {
$level = 2;
$item_class = 'heading-3';
} elseif (strpos($element[0], '<h4') !== false) {
$level = 3;
$item_class = 'heading-4';
} elseif (strpos($element[0], '<h5') !== false) {
$level = 4;
$item_class = 'heading-5';
} elseif (strpos($element[0], '<h6') !== false) {
$level = 5;
$item_class = 'heading-6';
}
while ($currentlevel < $level) {
if (0 === $currentlevel) {
$toc .= '<ol class="index__list">';
} else {
$toc .= '<ol class="index__list_child">';
}
$currentlevel++;
}
while ($currentlevel > $level) {
$toc .= '</li></ol>';
$currentlevel--;
}
$toc .= '<li class="index__item"><a href="#' . $id . '" class="index__link ' . $item_class . '">' . $element[1] . '</a>';
$i++;
$id = 'chapter-';
}
while ($currentlevel > 0) {
$toc .= '</li></ol>';
$currentlevel--;
}
$this->index_content = '<div class="toc-design"><div class="toc_title"><span class="toc_title_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3.8 17.2h-3c-.5 0-.8.4-.8.8v3c0 .4.3.8.8.8h3c.4 0 .8-.3.8-.8v-3c-.1-.4-.4-.8-.8-.8zm0-15h-3c-.5 0-.8.4-.8.8v3c0 .4.3.8.8.8h3c.4 0 .8-.3.8-.8V3c-.1-.4-.4-.8-.8-.8zm0 7.6h-3c-.5 0-.8.3-.8.7v3c0 .4.3.8.8.8h3c.4 0 .8-.3.8-.8v-3c-.1-.4-.4-.7-.8-.7zM23.2 18h-15c-.4 0-.8.3-.8.8v1.5c0 .4.3.8.8.8h15c.4 0 .8-.3.8-.8v-1.5c0-.5-.3-.8-.8-.8zm0-15h-15c-.4 0-.7.3-.7.8v1.5c0 .4.3.7.7.7h15c.5 0 .8-.3.8-.8V3.8c0-.5-.3-.8-.8-.8zm0 7.5h-15c-.4 0-.8.3-.8.8v1.5c0 .4.3.8.8.8h15c.4 0 .8-.3.8-.8v-1.5c0-.5-.3-.8-.8-.8z" /></svg></span><span class="toc_title_text">目次</span><span class="toc_title_open_btn" id="toc_open_btn">表示</span></div><div class="toc_list">' . $toc . '</div></div><script>window.addEventListener("DOMContentLoaded",()=>{CustomTOCEvent()});const CustomTOCEvent=()=>{let t=document.querySelector(".toc-design");if(!t)return!1;let e=t.querySelector("#toc_open_btn");e.addEventListener("click",n=>{n.preventDefault(),t.classList.toggle("show"),t.classList.contains("show")?e.textContent="非表示":e.textContent="表示"})};</script>';
$this->insert_toc();
}
}
public function insert_toc() {
ob_start();
echo $this->index_content;
echo ob_get_clean();
}
}
最後に呼び出したいsingleページの任意の位置で
<?php custom_toc(); ?>
と記述することで呼び出すことができます。