Hugo 页面集合分组方法 GroupByParamDate:按自定义日期参数分组页面
【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo
PAGES.GroupByParamDate是 Hugo 中用于将页面集合按照页面 Front Matter 中自定义日期参数进行分组的方法,分组结果默认按日期降序排列,且分组键会根据当前站点的语言与地区进行本地化格式化。它特别适合"自定义事件日期""活动日程""纪念日"等不以页面内置date、publishdate为准,而是以业务自定义日期字段为分组依据的场景。读完本文你将掌握该方法完整的签名与返回值、布局字符串(layout string)语法、升降序控制、组内页面再排序技巧,以及其底层实现与测试行为。
方法签名与返回值
- 签名:
PAGES.GroupByParamDate PARAM LAYOUT [SORT] - 返回类型:
page.PagesGroup - 说明:按照给定的页面参数(
PARAM)中的日期值,以指定的时间布局(LAYOUT)将页面集合分组,分组默认按降序(descending)排列。
其中:
PARAM:Front Matter 中自定义参数的名称(支持点号嵌套路径,例如custom_object.date);LAYOUT:与time.Format相同的布局字符串,用于决定分组键的展示粒度(如只到年、到年月、到年月日);SORT(可选):分组排序方向,asc表示升序,desc表示降序,见 group-sort-order.md。
返回的PagesGroup是一个PageGroup列表,每个PageGroup包含两个字段:Key(分组键,any类型)和Pages(该组内的页面集合)。相关类型定义与注释位于 resources/page/pagegroup.go:
// PageGroup represents a group of pages, grouped by the key. // The key is typically a year or similar. type PageGroup struct { // The key, typically a year or similar. Key any // The Pages in this group. Pages }基础用法:按自定义日期参数分组
假设站点中的若干页面在 Front Matter 中定义了自定义日期参数(例如eventDate),并希望以"年 + 月"为单位分组展示。以下模板代码取自原文档,可直接放入列表页模板中使用:
{{ range .Pages.GroupByParamDate "eventDate" "January 2006" }} <p>{{ .Key }}</p> <ul> {{ range .Pages }} <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li> {{ end }} </ul> {{ end }}执行逻辑为:
- 遍历
.Pages,读取每页 Front Matter 中的eventDate参数; - 按布局
"January 2006"将日期格式化为分组键(例如April 2012); - 默认按日期降序返回分组,组内页面同样按该参数日期排序(降序)。
控制分组排序方向
通过可选的第三个参数指定分组排序方向。以下示例将分组按日期升序排列:
{{ range .Pages.GroupByParamDate "eventDate" "January 2006" "asc" }} <p>{{ .Key }}</p> <ul> {{ range .Pages }} <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li> {{ end }} </ul> {{ end }}原文档强调:组内的页面也会按参数日期排序,方向与分组排序方向一致(升序或降序)。这一点在测试TestGroupByParamDateInReverseOrder中有明确印证(见 resources/page/pagegroup_test.go):调用pages.GroupByParamDate("custom_date", "2006-01", "asc")后,期望分组键依次为2012-01、2012-03、2012-04,且组内页面同样按日期升序排列。
组内页面重新排序
如果希望组内页面不按日期、而是按其他属性(如标题)排序,可在组内调用任意页面排序方法。例如按标题排序:
{{ range .Pages.GroupByParamDate "eventDate" "January 2006" }} <p>{{ .Key }}</p> <ul> {{ range .Pages.ByTitle }} <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> {{ end }} </ul> {{ end }}其他常用的组内排序方法还包括ByDate、ByPublishDate、ByExpiryDate、ByLastmod、ByWeight、ByLength等,相关文档见 methods/pages 目录。
Layout string 布局字符串
GroupByParamDate的LAYOUT参数与time.Format函数的布局字符串格式完全一致,均基于 Go 的参考时间(reference time):
Mon Jan 2 15:04:05 MST 2006常用布局组件如下(完整表格见 time-layout-string.md):
| 含义 | 合法组件 |
|---|---|
| 年份 | "2006" "06" |
| 月份 | "Jan" "January" "01" "1" |
| 星期 | "Mon" "Monday" |
| 月内日期 | "2" "_2" "02" |
| 年内日期 | "__2" "002" |
| 小时 | "15" "3" "03" |
| 分钟 | "4" "04" |
| 秒 | "5" "05" |
| 上午/下午标记 | "PM" |
| 时区偏移 | "-0700" "-07:00" "-07" "-070000" "-07:00:00" |
需要注意的几点(来自公共片段文档):
PST、CET这类字符串是时区缩写而非时区;-07:00、+01:00这类字符串是时区偏移而非时区。真正的时区是地理区域,例如缩写PST/PDT对应的时区是America/Los_Angeles;- 若希望时区偏移在 UTC 时输出
Z而非偏移量,可将布局中的符号替换为Z(如"Z0700" "Z07:00" "Z07"等)。
分组结果键(.Key)会根据当前渲染站点的语言与地区进行本地化(localized for language and region),因此同一布局字符串在不同语言站点下会输出本地化的月份、星期名称。
参数值类型与底层实现原理
GroupByParamDate的底层实现位于 resources/page/pagegroup.go。核心流程分为两阶段:
第一阶段:读取参数并排序(sorter)
sorter := func(pages Pages) Pages { var r Pages for _, p := range pages { param := resource.GetParam(p, key) var t time.Time if param != nil { var ok bool if t, ok = param.(time.Time); !ok { // Probably a string. Try to convert it to time.Time. t = cast.ToTime(param) } } dates[p] = t r = append(r, p) } pdate := func(p1, p2 Page) bool { return dates[p1].Unix() < dates[p2].Unix() } pageBy(pdate).Sort(r) return r }从源码可以看出:
- 参数值首先尝试直接断言为
time.Time类型; - 若失败,则通过
cast.ToTime尝试将字符串转换为time.Time(对应历史 issue #3983 的修复,测试见 TestGroupByParamDateWithStringParams); - 每个页面的日期值会被缓存到
datesmap 中,随后按Unix()时间戳进行排序。
第二阶段:按布局字符串分组(groupByDateField)
func (p Pages) groupByDateField(format string, sorter func(p Pages) Pages, getDate func(p Page) time.Time, order ...string) (PagesGroup, error) { sp := sorter(p) if !(len(order) > 0 && (strings.ToLower(order[0]) == "asc" || ...)) { sp = sp.Reverse() } ... currentSite := firstPage.Site().Current() formatter := langs.GetTimeFormatter(currentSite.Language()) formatted := formatter.Format(date, format) ... }要点如下:
- 排序方向判断:只有显式传入
asc(或源码中同样支持的rev、reverse变体)时才保持升序,否则一律降序; - 本地化实现:分组格式化使用
langs.GetTimeFormatter(currentSite.Language()),即当前渲染站点的语言格式化器——这印证了文档中"分组键针对语言与地区本地化"的说明; - 页面集合可能混有多种语言,因此这里取第一个页面所属 Site 的当前语言作为格式化语言(见源码注释 "Pages may be a mix of multiple languages...")。
空集合行为:当页面集合为空时,方法直接返回nil, nil,不会报错。测试 TestGroupByParamDateWithEmptyPages 验证了这一行为。
嵌套参数支持:PARAM支持点号嵌套路径,例如custom_object.date、custom_object.string_date,分别对应测试 TestGroupByParamDateNested 与 TestGroupByParamDateNestedWithStringParams。
与相关分组方法的对比
GroupByParamDate属于 Hugo 页面分组方法家族中的一员,理解它与近亲方法的差异有助于正确选型:
| 方法 | 分组依据 | 默认排序 | 说明 |
|---|---|---|---|
GroupByParamDate | 自定义参数中的日期 | 降序 | 本文主题,自定义日期参数 |
GroupByDate | 页面内置日期(默认date字段) | 降序 | 见 GroupByDate.md |
GroupByPublishDate | publishdate | 降序 | 见 GroupByPublishDate.md |
GroupByExpiryDate | expirydate | 降序 | 见 GroupByExpiryDate.md |
GroupByLastmod | lastmod | 降序 | 见 GroupByLastmod.md |
GroupByParam | 自定义参数(非日期) | 升序 | 见 GroupByParam.md |
从源码结构看,GroupByDate、GroupByPublishDate、GroupByExpiryDate、GroupByLastmod与GroupByParamDate都复用了同一个groupByDateField辅助函数,区别仅在于"取哪个日期字段"和"如何排序"(见 resources/page/pagegroup.go)。GroupByParamDate与GroupByParam的差异在于:前者将参数值按时间解析并格式化为分组键,后者则直接以参数原始值作为分组键。
常见使用场景与注意事项
典型场景:活动/会议站点的日程归档页,按自定义的eventDate分组展示"即将举办/历史活动";或者对带有自定义"发布日期"参数(如releaseDate)的产品文档进行按月归档。
注意事项:
- 确保 Front Matter 中的参数值可被解析为日期(
time.Time或可转换的字符串,如2012-04-06),否则该页面的日期值将是零值时间,可能被归入异常分组; - 若页面未定义该参数,源码中
param == nil时该页面会得到一个零值时间并参与排序(见 sorter 实现),需要结合自身数据评估影响; LAYOUT字符串决定了分组粒度与键的显示格式,例如"2006"只按年分组、"January 2006"按年月分组、"2006-01-02"按天分组;- 组内默认按参数日期排序,如需其他顺序请显式调用组内排序方法。
结语
GroupByParamDate为 Hugo 模板提供了"按自定义日期参数分组页面集合"的声明式能力:一行模板即可完成参数读取、时间解析、格式化分组、本地化与排序的全部工作。其底层实现(resources/page/pagegroup.go)清晰地展示了时间参数的类型兼容(time.Time与字符串)、语言本地化格式化以及统一的groupByDateField分组管线,配合 resources/page/pagegroup_test.go 中覆盖降序、升序、嵌套参数、字符串参数与空集合的完整测试用例,开发者可以在自己的 Hugo 站点中放心、准确地使用该方法构建按日期归档的内容展示。
延伸阅读
- 方法文档原文:GroupByParamDate.md
- 分组排序说明(asc/desc):group-sort-order.md
- 布局字符串参考:time-layout-string.md
- 同类分组方法:GroupByDate.md、GroupByParam.md
- 底层实现:resources/page/pagegroup.go
- 测试用例:resources/page/pagegroup_test.go
【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考