文章分类 listCategories 函数隐藏未启用条目
近期给博客更新主题功能时,在边栏显示文章分类环节遇到了个小困扰。我使用的是官方默认主题提供的 listCategories(); 函数,它能正常输出所有分类,但由于我的“强迫症”原因,提前预留了 100 个分类,目的是防止后续标签占用数据表而导致分类 ID 隔断不连续,但这就出现了一个明显问题:该函数会把未启用的分类也一并列出。
函数效果

改进思路
查阅官方文档和网上的解决方案后,发现多数思路是将所有分类压入数组,再通过重组数组元素剔除未使用的分类。但这个方案并不适合我的主题,我将主题诸多功能都集成在 functions.php 中,文件内已有大量代码,若新增分类处理逻辑以及多级菜单的生成,会进一步降低代码可读性不便于后续维护,所以我的核心诉求很明确:在不改动核心源码、精简情况下进行改进。
处理方式
在调用 listCategories(); 前,使用 ob_start(); 捕获内容至缓冲区,再通过ob_get_clean(); 将缓冲区内容取出并赋值给变量。
这里必须注意:要将 listCategories(); 的 showCount 参数开启,这是后续匹配空分类的关键依据。
PHP
- ob_start();
- \Widget\Metas\Category\Rows::alloc()->listCategories([
- 'wrapClass' => 'widget-categories',
- 'showCount' => true,
- 'countTemplate' => '<span class="count">%d</span>'
- ]);
- $base = ob_get_clean();
空分类的核心特征是 count 标签内的数值为 0,我是通过两段正则,分别实现“删除空分类列表项”和“清理空分类对应的子菜单”:
PHP
- // 删除空分类
- do {
- $cache = $base;
- $base = preg_replace('#<li[^>]*>(?:(?!<li).)*?<([a-zA-Z0-9]+)\s+class="count">0</\1>(?:(?!<li).)*?</li>\s*#is', '', $base);
- } while ( $cache !== $base );
- // 整个分类均为空,则删除整个子菜单
- $base = preg_replace('#<ul\b[^>]*>(?:\s| |<!--.*?-->)*</ul>\s*#is', '', $base );
正则说明:
- 第一段正则中:
(?:(?!<li).)*?是负向预查,确保只匹配当前 li 标签内的内容,不跨层级匹配子元素。 - 第二段正则用于清理空 ul 容器,如果该子分类所有的 li 均移除,则删除空 ul 子菜单。
总结与拓展思路
本次优化的核心优势在于,没有改动主题核心源码和 listCategories(); 函数本身,仅通过“缓冲区捕获 + 正则过滤”的组合,就解决了未启用分类显示的问题。当然也可以在前端通过 jQuery / Zepto 等框架交给客户端处理。
不过,对于我所需要简单的分类列表结构,本次的正则方案已经足够高效。如果你的博客分类存在多层级嵌套、结构复杂的情况,建议尝试DOMDocument 解析方案,稳定性会更有保障。
https://www.uevan.com/listcategories-hide-inactive-items
maple's sky
CC BY-NC 4.0