文章目录对于长篇幅的文章非常有必要,合理使用文章目录功能,可以帮助访客快速了解文章的内容结构。

4个不错的WordPress文章目录插件

Easy Table of Contents

一个用户友好、功能突出的Wordpress文章目录插件,可让您将目录插入到文章、页面和自定义文章类型中。

插件特色

  • 通过解析标题的内容,自动为您的文章、页面和自定义文章类型生成目录。
  • 支持<!--nextpage-->标签。
  • 支持Rank Math插件。
  • 可以在经典编辑器、Gutenberg、Divi、Elementor、WPBakery页面生成器和Visual Composer页面编辑器使用。
  • (可选)启用页面和/或文章。支持自定义文章类型,只要其内容与the_content()模板标签一起输出即可。
  • (可选)自动将目录插入页面,可以根据启用的文章类型进行选择。
  • 提供许多易于理解的选项来配置何时何地插入目录。
  • 许多选项可用于配置插入目录的显示方式,其中包括几个内置主题。如果提供的主题不能满足您的需求,则可以通过为边框,背景和链接颜色选择自己的颜色来创建自己的主题。
  • 多种反缩进形式可供选择;无、十进制、数字和罗马数字。
  • 选择显示或不显示目录。这意味着优先级较低的标题将嵌套在优先级较高的标题下。
  • 用户可以选择隐藏目录。您完全控制此功能。可以将其禁用,并且可以选择默认情况下将其隐藏。
  • 支持平滑滚动。
  • 每个文章可选择性地启用或禁用目录。
  • 选择用于生成目录的标题。也可以每篇文章进行设置。
  • 轻松地在全局范围和单个文章的基础上排除标题。
  • 如果您不希望在文章内容中插入目录,则可以使用提供的小工具并将目录放在主题的侧边栏中。
  • 这些小工具支持粘贴在页面上,因此在向下滚动页面时始终可见。注意:这是一个高级选项,因为每个主题都是不同的,您可能需要主题开发人员的支持才能了解在设置中使用正确的项目选择器以启用此功能。
  • 小工具会自动突出显示页面上当前可见的部分。高亮颜色是可配置的。
  • 开发人员友好,提供许多动作挂钩和过滤器。

Easy Table of Contents 下载地址:https://wordpress.org/plugins/easy-table-of-contents/

LuckyWP Table of Contents

为您的文章、页面或自定义文章类型创建SEO友好的文章目录。

插件特色

  • 自动插入目录(配置文章类型和位置)。
  • SEO友好:目录代码已可供Google在结果页上用于代码段。
  • 通过简码、Gutenberg块或小工具插入。
  • 经典编辑器工具栏上显示插入按钮。
  • “通用区块”中包含文章目录区块。
  • 设置显示目录的最小标题数。
  • 设置目录标题的深度。
  • 按级别或文字跳过标题。
  • 分层或线性视图。
  • 计数项目:十进制或罗马数字顺序或嵌套。
  • 可自定义的外观:宽度、浮动、标题字体大小和粗细、项目字体大小、颜色。
  • 配色方案(深色,浅色,白色,透明,从主题继承)以及覆盖颜色的功能。
  • 切换显示/隐藏(可选)
  • 可自定义标签。
  • 平滑滚动(可选)。
  • 设置偏移顶部以平滑滚动。
  • <!–noindex–>标记包装目录(可选)。
  • URL中的漂亮哈希值(如example.com/faq/#how_do_this)。
  • RTL支持。
  • 可用文章的设置覆盖全局设置。
  • 与WordPress主题和插件高度兼容。

LuckyWP Table of Contents 下载地址:https://wordpress.org/plugins/luckywp-table-of-contents/

Table of Contents Plus

一个功能强大但用户友好的文章目录插件,可以为长页面(和自定义文章类型)自动创建特定于上下文的索引或目录(TOC)。该插件不仅仅是目录插件,还可以列出整个网站上的页面和/或分类的站点地图。

目录是从头开始构建的,并且考虑到了Wikipedia,默认情况下,目录出现在页面的第一个标题之前。这使作者可以插入可以概述或介绍页面其余部分的导入内容。它还使用了独特的编号方案,不会因跨主题的CSS差异而丢失。

该插件是内容丰富站点的绝佳伴侣。也就是说,博客作者在编写较长的结构化文章时也具有相同的好处。

插件包括一个管理选项面板,您可以在其中自定义设置(例如显示位置),定义显示索引之前的最小标题数,其他外观等。对于高级用户,请扩展高级选项以进一步调整其行为–例如:排除不希望的导航级别,例如h5和h6;禁用包含的CSS文件的输出;调整顶部偏移量等等。使用简码,您可以覆盖默认行为,例如特定页面上的排除选项,甚至完全隐藏目录。

希望在侧边栏中包含文章目录?转到外观>小工具,然后将TOC +拖到所需的侧边栏即可。

支持自定义文章类型,但是,仅当自定义文章类型使用the_content()输出文章内容时,自动插入才有效。每种文章类型都会出现在选项面板中,因此请启用所需的文章类型。

Table of Contents Plus 下载地址:https://wordpress.org/plugins/table-of-contents-plus/

GutenTOC – Advance Table of Content for Gutenberg

GutenTOC是只能在Gutenberg编辑器下使用的SEO友好的文章目录插件,可让您自动创建文章目录。

插件特色

  • 通过插入Advance Table of Content 块自动生成文章目录。
  • 自动生成锚链接,但是您可以根据需要进行自定义。
  • SEO友好的目录和锚点列表,它将很好地显示在搜索结果页面(SERP)中。
  • 您可以更改切换显示或隐藏。
  • 反项目符号格式为无、小数、数字、图标。
  • 单击锚点时平滑滚动。

GutenTOC 下载地址:https://wordpress.org/plugins/gutentoc-advance-table-of-content/


手工–纯JS实现WordPress简单文章目录功能

导语

文章目录这种东西本应是每个(WordPress)站点都有的功能,尤其是阅读长文章的时,在用户触手可及的地方提供一个目录,既可以方便用户快捷跳转,又可以快速了解文章概要,是一件一举两得的事情。然而现实情况却不尽人意,大部分CMS只关注文章本身,而把其他部分交给主题和用户来定制,导致这些”其他部分”一直没有一个统一的标准,主题和插件实现的五花八门。加之中外审美的巨大差异,找一个和自己主题搭配且好用的文章目录方案,确实是一件十分困难的事情。

相信折腾到最后,大部分人都会选择使用带文章目录功能的主题,或是文章目录插件。我自己找了一圈,发现大部分插件不是审美严重不同(违和感极强),就是价格昂贵,十分划不来,并且我个人也不喜欢使用不必要插件。

最终,我决定使用纯JavaScript实现一个文章目录功能。这样既不会影响后续更新,也免去了使用不搭配的插件带来的一系列烦恼,实现效果可以参考右侧侧边栏

设计思路

在页面加载时通过JavaScript提取页面中的标题信息,随后创建并插入文章目录。

大致分为三个步骤

  1. 判断是否为文章页面
  2. 获取标题信息
  3. 生成文章目录

文章标题的结构

通常情况下我们使用h1-6标签显示标题,h1标签显示文章标题,因此我们在正文使用的标签就从h2开始。一般标题分级不会太多,h2、h3、h4再往后就几乎不用了。观察维基百科的目录结构,一般是显示三级,但我们通常不会写那么长的大型文章,分二级显示就足够了。也就是说,我们只需要获取文章页面的h2、h3标签

获取标题信息

大部分WordPress主题的文章主体部分都是在一个div里的,div里包含着各种文章元素,标题h2 h3、段落p、图片img等等,不过这个div的class是什么由开发者决定。按下你浏览器的F12键,打开审查元素,可以很轻松的发现它。

判断是否为文章页面

由于WordPress的限制,我们在不修改模板/使用插件的前提下插入JS代码只能插入到整个网站。不过解决方法也很简单,只要检索页面中有没有文章主体的div即可判断出当前页面是不是文章页面,进而自适应生成目录。

let articleContent = document.getElementsByClassName('entry-inner');
if (articleContent.length !== 1) {
    return null;
}

寻找并记录标题

遍历这个容器的所有元素,找出二级标题h2和三级标题h3即可。为了实现目录层次,我们使用一个数组来记录一个二级标题下的所有三级标题。为了实现跳转功能,我们为每个标题标签分配唯一id

let catalog = [];
let header = {};
let elements = articleContent[0].childNodes;
// 遍历所有元素
for (let i = 0; i < elements.length; i++) {
    if (elements[i].nodeName === 'H2') {
        // 为二级标题分配ID以供锚点跳转,下同
        elements[i].id = 'h2-' + catalog.length;
        // 记录此二级标题和其所有的三级子标题
        header = {
            name: elements[i].innerText,
            childHeaders: []
        };
        catalog.push(header);
    } else if (elements[i].nodeName === 'H3') {
        elements[i].id = 'h2-' + (catalog.length - 1) + '-h3-' + header.childHeaders.length;
        // 记录此三级标题到二级标题下
        header.childHeaders.push(elements[i].innerText);
    }
}

生成文章目录

有了目录信息,并且在上一步已经为标签添加了ID,只需要简单的拼接即可实现自动生成文章目录

let catalog = '<div style="text-align: center; margin-top: 10px;">文章目录</div>';
for (let i = 0; i < catalogData.length; i++) {
    let target = '#h2-' + i; // 跳转目标
    let index = (i + 1) + '. '; // 标题索引
    let name = catalogData[i].name; // 标题
    catalog += '<a href="' + target + '">' + index + name + '</a><br/>';
    for (let i2 = 0; i2 < catalogData[i].childHeaders.length; i2++) {
        target = '#h2-' + i + '-h3-' + i2;
        index = (i + 1) + '.' + (i2 + 1) + '. ';
        name = catalogData[i].childHeaders[i2];
        catalog += '  <a href="' + target + '">' + index + name + '</a><br/>'
    }
}

完整代码

使用时记得根据你的实际情况修改dynamic-wrapperentry-inner两处,目录的样式随意发挥。

为了平滑跳转,可以为htmlbody设置 scroll-behavior: smooth

已添加详细注释,方便修改使用

<script>
    /*
    Author: Azure99
    WebSite: https://www.rainng.com/
    GitHub: https://github.com/Azure99
     */

    let catalogData = getArticleCatalog();
    // 自适应文章目录
    if (catalogData != null) {
        // dynamic-wrapper换成你的目录容器
        let wrapper = document.getElementById('dynamic-wrapper');
        wrapper.innerHTML = generateCatalog(catalogData);
    }

    // 获取本页面的文章目录信息
    function getArticleCatalog() {
        // entry-inner换成你使用主题的文章容器
        let articleContent = document.getElementsByClassName('entry-inner');
        if (articleContent.length !== 1) {
            return null;
        }

        let catalog = [];
        let header = {};

        let elements = articleContent[0].childNodes;
        // 遍历所有元素
        for (let i = 0; i < elements.length; i++) {
            if (elements[i].nodeName === 'H2') {
                // 为二级标题分配ID以供锚点跳转,下同
                elements[i].id = 'h2-' + catalog.length;
                // 记录此二级标题和其所有的三级子标题
                header = {
                    name: elements[i].innerText,
                    childHeaders: []
                };
                catalog.push(header);

            } else if (elements[i].nodeName === 'H3') {
                elements[i].id = 'h2-' + (catalog.length - 1) + '-h3-' + header.childHeaders.length;
                // 记录此三级标题到二级标题下
                header.childHeaders.push(elements[i].innerText);
            }
        }

        return catalog;
    }

    // 根据目录信息生成文章目录代码
    function generateCatalog(catalogData) {
        let catalog = '<div style="text-align: center; margin-top: 10px;">文章目录</div>';

        for (let i = 0; i < catalogData.length; i++) {
            let target = '#h2-' + i; // 跳转目标
            let index = (i + 1) + '. '; // 标题索引
            let name = catalogData[i].name; // 标题
            catalog += '<a href="' + target + '">' + index + name + '</a><br/>';

            for (let i2 = 0; i2 < catalogData[i].childHeaders.length; i2++) {
                target = '#h2-' + i + '-h3-' + i2;
                index = (i + 1) + '.' + (i2 + 1) + '. ';
                name = catalogData[i].childHeaders[i2];
                catalog += '  <a href="' + target + '">' + index + name + '</a><br/>'
            }
        }

        return catalog;
    }
</script>