在写文章的时候咱为了结构更清晰,通常会添加h2-h6
标签来展示段落标题,同时也提醒网络蜘蛛这些是内文小标题,是文章的重点。特别是当 WordPress 文章较长时,有一个自动索引的目录能有效帮助访客快速了解内容结构,会大大提高读者的阅读体验。
给 WordPress 文章添加自动目录的方法非常多,官方库里边也有很多相关的目录插件,比如知名的 LuckyWP Table of Contents、Heroic Table of Contents、Rich Table of Contents 等,它们主体功能差不多,文件越大的越贵的自然是功能更完善,小细节更好,但副作用也很明显,它们配置麻烦且会加重主机负担影响页面加载速度。
此前有段时间我特想给 WordPress 添加一个文章目录,后来因为更新较少就放下了。正好最近在瞎折腾,也看了不少教程,最后发现微言微语这一篇相当良心,该方案代码结构清晰注释多,操作步骤明了,作为技术小白的我一下就折腾成功了。为了给更多的人看到,特地把这篇纯代码实现 WordPress 多级文章目录索引转载过来,也算作是我的一个备忘录吧。
本方案代码量少,可自定义程度也比较高,我在原基础上稍微调整了下 CSS,具体的实现效果看本页,根据喜好你也可以修改 CSS 把目录嵌入进正文中展示,后面本站可能会那样做,届时再把 CSS 贴出来。其实,我的理想方案是把文章目录嵌入到边栏小工具中,并能在文章编辑时开关控制…这是后话了。
1. WordPress 构建文章多级目录索引
将以下这段代码加载进function.php
循环中,通过代码中注释可以知道文章目录是获取h2-h6
的标题,同时 h 标签的个数大于 2 才生效,也就是文章中要有 3 个及以上才展示,该数量可以自定义修改。
这段使用了两个函数:buildDirectory
和 article_index
。article_index 函数是一个 WordPress 的过滤器函数,用于在文章内容中自动生成目录。buildDirectory 函数则是用来构建目录的核心逻辑。
根据代码,article_index
函数首先使用正则表达式匹配文章内容中的标题,然后根据匹配到的标题内容和标题级别调用 buildDirectory
函数来构建目录。最后,将生成的目录插入到文章内容中,并返回处理后的内容。这段代码有个小 Bug,即当第一个 H 标签比后面的小时,目录可能无法正常加载…当然这也提醒我们:写作要规范~
// 构建文章多级目录索引
function buildDirectory($titleIndexArr, $titleContentArr, &$index, &$html)
{
$size = sizeof($titleIndexArr);
$flag = $index == 0;
$html .= $flag ? '<ol id="index-ol">' : '<ul id="index-ul">';
while ($index < $size) {
$title = trim(strip_tags($titleContentArr[$index])); // 标题内容
$h = $titleIndexArr[$index]; // 几级标题
$html .= '<li><a href="#title-' . $index . '" title="' . $title . '">' . $title . "</a></li>";
if ($index == $size - 1) { //最后一个
$index++;
break;
}
$next_h = $titleIndexArr[++$index]; // 下个标题是几级标题
if ($h < $next_h) { // 子标题递归
buildDirectory($titleIndexArr, $titleContentArr, $index, $html);
if ($index >= $size || $h > $titleIndexArr[$index]) {
break;
}
} else if ($h > $next_h) {
break;
}
}
$html .= $flag ? '</ol>' : '</ul>';
}
function article_index($content)
{
$html = '';
$matches = array();
// 当前设置 [2-6]即 h2 到 h6 可以自己修改下面正则
$r = '/<h([2-6])(.*?)>(.*?)<\/h[2-6]>/is';
// preg_match_all 函数用于执行一个全局正则表达式匹配。$r=正则,$content=文章内容,$matches=作为输出参数输出所有匹配结果
preg_match_all($r, $content, $matches);
$num_match = count($matches[0]);
// 用于文章页,同时 h 标签个数大于 2 个才生效
if ( is_single() && ($num_match > 2) ) {
foreach ($matches[1] as $key => $value) {
// strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签
$title = trim(strip_tags($matches[3][$key])); //文章标题
// 文章原标题添加锚点
$content = str_replace($matches[0][$key], '<h' . $value . ' id="title-' . $key . '"' . $matches[2][$key] . '>' . $title . '</h' . $value . '>', $content);
}
$titleIndexArr = $matches[1];
$titleContentArr = $matches[3];
$index = 0;
$html .= "\n".'<div id="article-index-show">目 录</div><div id="article-index"><div id="article-index-top"><strong>文章目录</strong><span id="article-index-hide">隐藏</span></div>';
buildDirectory($titleIndexArr, $titleContentArr, $index, $html);
$html .= '</div>'."\n";
}
return $html. $content;
}
add_filter('the_content', 'article_index');
2. WordPress 文章目录的 CSS 样式表
以下这段样式代码中包含了上述 WordPress 文章自动目录的一些样式定义,如索引框的位置、大小、背景颜色等。同时还包括了显示和隐藏文章目录的按钮样式。另外,这是我第一次用box-shadow: 0 0 5px rgba(0,0,0,.4);
这个参数,它能让内容产生阴影,可以给予页面更多灵活性,还挺好玩的~
#article-index {
position: fixed;
top: 50%;
transform: translateY(-50%);
left: 0;
width: auto;
max-height: 76%;
padding: 0 10px;
font-size: 14px;
border-radius: 0 6px 6px 0;
background-color: #fff;
box-shadow: 0 0 5px rgba(0, 0, 0, .4);
overflow: auto;
z-index: 99;
display: none;
}
#article-index-top {
position: sticky;
top: 0;
z-index: 92;
background: #fff;
}
#article-index strong {
display: block;
font-size: 16px;
padding: 10px 0 12px 5px;
}
#index-ol {
list-style: none;
font-size: 18px;
}
#index-ol ul {
font-size: 15px;
}
#index-ol li {
padding: 0;
margin-left: 18px;
line-height: 24px;
position: relative;
list-style-position: inherit;
word-break: break-all;
}
#index-ul {
list-style: revert-layer;
margin: 0;
padding: 4px 0px 6px 36px;
}
#index-ul li:before {
display: none;
}
#article-index-show {
position: fixed;
top: 50%;
transform: translateY(-50%);
left: 0;
display: block;
width: 50px;
height: 36px;
line-height: 36px;
text-align: center;
font-size: 14px;
/* border-radius: 0 36px 36px 0; */
color: #fff;
background-color: #cc3333;
cursor: pointer;
}
#article-index-hide {
position: absolute;
right: 0;
top: 5px;
display: block;
width: 32px;
height: 32px;
line-height: 32px;
text-align: center;
font-size: 12px;
border-radius: 100%;
background-color: #eeeeee;
cursor: pointer;
}
#article-index-hide:hover {
color: #fff;
background-color: #cc3333;
}
以上这个样式是我这里正在使用的效果,以下这段 CSS 是上面这段的变体,它让代码默认展开悬浮在正文旁边(细节还需要自己改一些),如图所示:
#article-index {
position: fixed;
top: 30%;
transform: translateY(-20%);
margin-left: -240px;
width: 224px;
max-height: 100%;
padding: 0 10px;
font-size: 14px;
border-radius: 6px;
background-color: #fff;
box-shadow: 0 0 5px rgba(0, 0, 0, .4);
overflow: auto;
z-index: 99;
display: block;
}
#article-index strong {
display: block;
font-size: 16px;
padding: 10px 0 16px 0;
}
#index-ol {
list-style: square;
text-wrap:
wrap;
}
#index-ol a {
color: #555;
}
#index-ol li {
list-style: none;
padding: 0;
margin-left: -50px;
line-height: 24px;
position: relative;
list-style-position: inherit;
word-break: break-all;
}
#index-ul {
list-style: circle;
margin: 0;
padding: 5px 0 5px 8px;
}
#index-ul li:before {
display: none;
}
#article-index-show {
position: fixed;
top: 31%;
transform: translateY(-50%);
margin-left: -240px;
display: block;
width: 200px;
height: 36px;
line-height: 36px;
text-align: center;
font-size: 14px;
border-radius: 36px 36px 36px 36px;
color: #fff;
background-color: #59f;
cursor: pointer;
}
#article-index-hide {
position: absolute;
right: 5px;
top: 5px;
display: block;
color: #fff;
width: 32px;
height: 32px;
line-height: 32px;
text-align: center;
font-size: 12px;
border-radius: 100%;
background-color: #59f;
cursor: pointer;
}
#article-index-hide:hover {
color: #fff;
background-color: #0088dd;
}
3. WordPress 文章自动目录所需要的 JS 代码
根据上面的主函数和 CSS,这里还需要一些 JavaScript 代码来实现点击显示和隐藏文章目录的功能。以下是一个简单的示例 JavaScript 代码,由 Devv AI 自动生成,用于显示和隐藏文章目录索引:
// 获取显示和隐藏按钮元素
const showButton = document.getElementById('article-index-show');
const hideButton = document.getElementById('article-index-hide');
const indexElement = document.getElementById('article-index');
// 点击显示按钮显示文章目录索引
showButton.addEventListener('click', function() {
indexElement.style.display = 'block';
});
// 点击隐藏按钮隐藏文章目录索引
hideButton.addEventListener('click', function() {
indexElement.style.display = 'none';
});
这段代码尚未经过测试,建议使用后面一段!请确保将此 JavaScript 代码添加到您的页面中,并根据需要调整元素 ID 以匹配您的实际代码。这样,您就可以实现点击按钮显示和隐藏文章目录索引的功能。
以下这段代码是本站正在使用的 JS 效果,把它加载到 jQuery 库后边就行,它能控制文章目录的开关和平滑滚动,可根据需要自行设定数值控制打开速度(毫秒)。
//文章目录展示切换
jQuery(document).ready(function(){
jQuery("#article-index-hide").click(function(){
jQuery("#article-index").hide(100);
jQuery("#article-index-show").show(200);
});
jQuery("#article-index-show").click(function(){
jQuery("#article-index").show(200);
jQuery("#article-index-show").hide(100);
});
});
//文章目录锚点点击平滑滚动
jQuery(document).on('click', '#article-index a[href^="#"]', function(e) {
var id = jQuery(this).attr('href');
var $id = jQuery(id);
if ($id.length === 0) {
return;
}
e.preventDefault();
var pos = $id.offset().top;
jQuery('body, html').animate({scrollTop: pos});
});
[…] 本站的文章目录功能是通过一段简单代码实现的,参考自“给 WordPress 文章添加自动目录(免插件)”这篇文章。原版的 CSS 和 JS 会在浏览器左侧固定一个按钮,访客点击后弹出文章目录。然而,通过观察发现,绝大多数人不会去点击这个按钮,而且它对页面整体美观造成了一定影响。尤其是在移动端,该按钮可能会遮挡部分文字,导致体验不佳。 […]