使用 GetSonids 标签(推荐,适用于子栏目)
这是最常用且最灵活的方法,它利用了 DedeCMS 的标签系统,可以在模板中直接调用,它的核心原理是先获取当前栏目的所有子栏目 ID(包括孙栏目等),然后再统计这些 ID 下的文章总数。

适用场景:在列表页或首页,显示某个顶级栏目及其所有子栏目的文章总数。
示例代码:
假设你的顶级栏目 ID 是 1(新闻中心”),你可以在模板中这样写:
{dede:channel type='top' typeid='1'}
<dl>
<dt><a href="[field:typeurl/]">[field:typename/]</a></dt>
<dd>
<!-- 使用 GetSonids 标签获取所有子栏目ID,并用逗号隔开 -->
{dede:getsonids typeid='1' noself='yes'}
[field:id function="GetSonIds(@me,0)"/],
{/dede:getsonids}
<!-- 获取上一步生成的所有子栏目ID,并统计文章数 -->
{dede:arclist sort='hot' channelid='1' subday='30' titlelen='42'
row='1' idlist=''}
总文章数:[field:total/]
{/dede:arclist}
</dd>
</dl>
{/dede:channel}
代码解释:

{dede:channel type='top' typeid='1'}: 调用顶级栏目,这里指定了栏目ID为1。{dede:getsonids typeid='1' noself='yes'}: 这个标签本身不输出内容,它的作用是在底层生成一个包含所有子栏目ID的变量,格式如2,3,4,。[field:id function="GetSonIds(@me,0)"/]: 这是调用一个自定义函数GetSonIds,它会递归获取指定ID的所有子栏目ID。@me是当前栏目ID(这里是1),0表示不包含自己,它会生成一个ID字符串,如2,3,4,。{dede:arclist ... idlist='...'}:arclist标签有一个idlist属性,可以指定只查询这些ID栏目下的文章,我们将上一步生成的ID字符串赋给它。[field:total/]: 这是arclist标签的一个特殊字段,表示idlist中所有栏目的文章总数。
更简洁的写法(推荐):
DedeCMS 的 arclist 标签本身支持 typeid 属性接受一个由逗号隔开的ID字符串,所以可以更简洁:
{dede:channel type='top' typeid='1'}
<h2>[field:typename/]</h2>
<p>
{dede:getsonids typeid='1' noself='yes'}
[field:id function="GetSonIds(@me,0)"/],
{/dede:getsonids}
<!-- 直接使用生成的ID列表 -->
{dede:arclist row='0' idlist=''}
本栏目及其子栏目共有 [field:total/] 篇文章。
{/dede:arclist}
</p>
{/dede:channel}
注意:这里 idlist 是空的,它会自动使用 {dede:getsonids} 在底层生成的变量。
使用 SQL 查询标签(最灵活,适用于所有情况)
如果方法一不能满足你的需求,或者你想进行更复杂的统计(比如按特定条件筛选),可以直接使用 DedeCMS 的 dede:sql 标签执行原生 SQL 查询。
适用场景:需要精确控制查询条件,或者统计方法一无法覆盖到的复杂情况。
示例1:统计单个栏目及其所有子栏目的文章数
假设顶级栏目ID为 1。
{dede:sql sql="
SELECT COUNT(*) as total
FROM `#@__archives`
WHERE typeid IN (
SELECT id FROM `#@__arctype`
WHERE reid = 1 OR topid = 1
)
"}
本栏目及其子栏目共有 [field:total/] 篇文章。
{/dede:sql}
SQL 语句解释:
SELECT COUNT(*) as total FROM dede_archives: 统计dede_archives(文章表) 中的记录数,并将结果命名为total。WHERE typeid IN (...): 只统计typeid(栏目ID) 在括号列表中的文章。SELECT id FROM dede_arctype WHERE reid = 1 OR topid = 1: 这是一个子查询,它从dede_arctype(栏目表) 中找出所有父级ID (reid) 是1或者顶级ID (topid) 是1的栏目ID,这样就获取了栏目1的所有直接和间接子栏目。
示例2:统计所有顶级栏目及其子栏目的文章数
这个需求更常见,比如在首页做一个网站地图。
<ul>
{dede:channel type='top'}
<li>
<strong>[field:typename/]</strong>
<!-- 对每个顶级栏目,执行一次SQL查询 -->
{dede:sql sql="
SELECT COUNT(*) as total
FROM `#@__archives`
WHERE typeid IN (
SELECT id FROM `#@__arctype` WHERE reid = ~typeid~
)
"}
([field:total/])
{/dede:sql}
<!-- 递归调用自身,显示子栏目 -->
{dede:channel type='son' noself='yes'}
- [field:typename/]
{/dede:channel}
</li>
{/dede:channel}
</ul>
注意:这里的 ~typeid~ 是一个占位符,DedeCMS 会自动将其替换为当前循环的栏目的 typeid 值。
使用自定义函数(性能最高,适合高级用户)
如果你的网站对性能要求极高,并且这个功能在多个地方被频繁调用,可以考虑创建一个自定义函数,然后在模板中调用,这需要你修改 PHP 文件。
步骤:
-
创建函数文件: 在
/include/extend.func.php文件中(如果不存在则创建一个)添加以下函数:/** * 统计指定栏目及其所有子栏目的文章数量 * @param int $typeid 栏目ID * @return int 文章总数 */ function GetTotalArticles($typeid = 0) { if ($typeid == 0) return 0; global $dsql; // 获取所有子栏目ID $sonids = GetSonIds($typeid, 0); $idstring = empty($sonids) ? $typeid : $typeid . ',' . $sonids; // 执行查询 $query = "SELECT COUNT(*) FROM `#@__archives` WHERE typeid IN ($idstring)"; $total = $dsql->GetOne($query); return $total['COUNT(*)']; } -
在模板中调用: 在任何需要的地方,通过
[field:function]标签调用。{dede:channel type='top' typeid='1'} [field:typename/]:[field:function='GetTotalArticles(@me)'/] 篇文章 {/dede:channel}或者
当前栏目 [field:typename/] 的文章数是:[field:function='GetTotalArticles(@me)'/]
优点:
- 性能最好:函数直接执行数据库查询,没有模板解析的额外开销。
- 代码复用:定义一次,处处可用。
- 逻辑清晰:将数据库操作与模板分离。
缺点:
- 需要修改 PHP 文件,对新手有一定门槛。
总结与建议
| 方法 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|
GetSonids |
纯模板实现,无需修改代码,灵活性好 | 在循环内使用时,效率不如方法三 | 大多数日常需求,如列表页、首页的栏目统计。 |
dede:sql |
灵活性最强,可处理复杂查询 | SQL 语句相对复杂,可读性稍差 | 需要特殊筛选条件或方法一无法满足时。 |
| 自定义函数 | 性能最高,代码复用性好 | 需要修改PHP文件,不适合新手 | 对性能要求极高的网站,或该功能被高频调用时。 |
对于绝大多数用户,方法一 是最简单、最直接、最安全的选择,如果遇到性能瓶颈或特殊需求,再考虑 方法二 或 方法三。
