Hugo 站点集合 API 完全指南:Site.Sites 方法、hugo.Sites 函数与多维站点排序
2026/9/20 12:33:32 网站建设 项目流程
  • 开发工具
  • 前端
  • CLI

【免费下载链接】hugo

The world’s fastest framework for building websites.

项目地址:https://gitcode.com/gh_mirrors/hu/hugo
点击查看免费下载

本指南围绕 Hugo 中获取“全维度站点集合”的Sites方法展开,涵盖其返回值类型、三级排序规则、在 multilingual + multiversion 项目中的实战用法,以及 v0.156.0 起的弃用迁移路径。读完本文,你将能正确使用hugo.Sites/hugo.Sites.Default遍历语言、版本、角色三个维度上的全部站点,并理解其底层实现机制。

一、Sites 方法是什么

Sites是 Hugo 站点对象(Site)提供的一个方法,用于返回所有维度(language、version、role)上的全部站点集合。在模板中通过SITE.Sites调用,返回类型为page.Sites(见 Sites.md 的 front matter 定义:returnType: page.Sitessignatures: [SITE.Sites])。

在单个站点(site)的模板上下文里,Sites集合让开发者能够从当前语言/版本的视角,一次性访问整个站点矩阵——包括其他语言、其他版本、其他角色的站点。

注意:Sites是无参方法,直接{{ .Sites }}即可得到集合对象,通常配合range遍历使用。

二、重要变更:v0.156.0 起已弃用

该文档明确标注了弃用状态(deprecated 2026-02-18 in v0.156.0):

Use thehugo.Sitesfunction instead.

即从 v0.156.0 开始,模板中应改用全局函数hugo.Sites替代Site.Sites/Page.Sites。新函数对应的完整文档位于 hugo/Sites.md,标注为new-in 0.156.0

迁移对应关系:

旧写法(已弃用)新写法(推荐)
{{ .Site.Sites }}{{ hugo.Sites }}
{{ .Sites }}(页面上下文){{ hugo.Sites }}

从源码看,旧方法仍保留兼容但会触发弃用告警。在 hugolib/site.go 中:

// Returns all sites for all dimensions. // Deprecated: Use hugo.Sites instead. func (s *Site) Sites() page.Sites { s.h.printSiteSitesDeprecationInit.Do(func() { hugo.Deprecate(".Site.Sites and .Page.Sites", "Use hugo.Sites instead.", "v0.156.0") }) return slices.Collect(s.h.allSitesInterface(nil)) }

可以看到它通过printSiteSitesDeprecationInit只输出一次弃用提示,随后仍委托给底层的allSitesInterface完成实际遍历,因此功能语义与hugo.Sites完全一致,区别仅在告警与调用入口。

三、返回集合的排序规则

Sites返回的集合遵循层级排序(hierarchical sort):每个后续维度作为前一维度的 tie-breaker。该规则定义在共享文档 sites-collection.md 中,具体如下:

  1. Language(语言):按weight升序排序;若weight相同或未定义,回退到字典序(lexicographical order)。
  2. Version(版本):在语言排序之后,按weight升序;若并列,Hugo 默认采用语义版本降序(descending semantic sort)。
  3. Role(角色):最后按weight升序排序,最终回退到字典序。

也就是说,集合顺序 = 先按语言排,再按版本排,最后按角色排。理解这一顺序对依赖遍历顺序输出导航、语言切换器或版本选择器至关重要。

四、实战配置:多语言 + 多版本项目

以 hugo/Sites.md 中的完整配置为例,一个包含两种语言(de、en)和三个版本(v1.0.0、v2.0.0、v3.0.0)的项目配置如下:

defaultContentLanguage = 'en' defaultContentLanguageInSubdir = true defaultContentVersionInSubdir = true [languages.de] contentDir = 'content/de' direction = 'ltr' label = 'Deutsch' locale = 'de-DE' title = 'Projekt Dokumentation' weight = 1 [languages.en] contentDir = 'content/en' direction = 'ltr' label = 'English' locale = 'en-US' title = 'Project Documentation' weight = 2 [versions.'v1.0.0'] [versions.'v2.0.0'] [versions.'v3.0.0']

关键参数说明:

  • defaultContentLanguage = 'en':声明默认语言,决定hugo.Sites.Default落在哪个语言上(对应配置文档中的defaultContentLanguage项);
  • defaultContentLanguageInSubdir = true:默认语言内容也放在子目录(URL 中体现为/en/前缀);
  • defaultContentVersionInSubdir = true:默认版本内容也放在子目录(URL 中体现为/v3.0.0/前缀);
  • 每个[languages.xx]块定义一种语言:contentDir指定内容目录、weight控制排序权重、title/label/locale用于展示与本地化;
  • 每个[versions.'x.y.z']块声明一个版本维度;未显式配置 weight 时,版本并列,Hugo 按语义版本降序排列(即 v3.0.0 排最前)。

五、模板用法与输出示例

1. 遍历全部站点

下面的模板(来自官方文档示例)遍历所有站点,为每个站点的首页生成链接,同时显示站点标题和版本名:

<ul> {{ range hugo.Sites }} <li><a href="{{ .Home.RelPermalink }}">{{ .Title }} {{ .Version.Name }}</a></li> {{ end }} </ul>

配合上文配置,输出结果为(注意顺序符合排序规则:德语 weight 更小故排前,版本按语义降序 v3.0.0 → v1.0.0):

<ul> <li><a href="/v3.0.0/de/">Projekt Dokumentation v3.0.0</a></li> <li><a href="/v2.0.0/de/">Projekt Dokumentation v2.0.0</a></li> <li><a href="/v1.0.0/de/">Projekt Dokumentation v1.0.0</a></li> <li><a href="/v3.0.0/en/">Project Documentation v3.0.0</a></li> <li><a href="/v2.0.0/en/">Project Documentation v2.0.0</a></li> <li><a href="/v1.0.0/en/">Project Documentation v1.0.0</a></li> </ul>

2. 定位默认站点

hugo.Sites.Default返回默认站点——即默认语言(defaultContentLanguage)、默认版本、默认角色交汇处的站点,与其在集合中的位置无关

{{ with hugo.Sites.Default }} <a href="{{ .Home.RelPermalink }}">{{ .Title }}</a> {{ end }}

对于上文配置,该模板渲染出英文 v3.0.0 站点的首页链接。尽管三个德语站点因weight更小排在最前,但defaultContentLanguage = 'en'决定了默认站点是英文站点。注意Default需要用with包裹以处理空值场景。

3. 旧 API 写法(v0.156.0 前)

在升级前,等价的旧写法是{{ range .Site.Sites }}/{{ .Site.Sites.Default }}。由于新函数与旧方法共享底层实现,迁移时只需机械替换调用入口即可,输出结果完全一致。

六、源码实现解析

1. 全局函数入口

hugo.SiteshugoSitesSitesProvider提供,定义于 hugolib/hugo_sites.go:

// hugoSitesSitesProvider is a wrapper that implements page.SitesProvider. // This avoids naming conflict with HugoSites.Sites field. type hugoSitesSitesProvider struct { h *HugoSites } func (sp hugoSitesSitesProvider) Sites() page.Sites { return slices.Collect(sp.h.allSitesInterface(nil)) }

注释点明了设计动机:该包装类型实现了page.SitesProvider接口,避免与HugoSites.Sites字段命名冲突。

2. 核心遍历逻辑

新旧两种入口最终都汇聚到allSitesInterface(hugolib/hugo_sites.go):

func (h *HugoSites) allSitesInterface(include func(s page.Site) bool) iter.Seq[page.Site] { if include == nil { include = func(s page.Site) bool { return true } } return func(yield func(s page.Site) bool) { for _, v := range h.sitesVersionsRoles { for _, r := range v { for _, s := range r { if !include(s) { continue } // Site() returns a wrapped version of the site that only exposes the page.Site interface. if !yield(s.Site()) { return } } } } } }

从该实现可以推断出:

  • 站点的组织结构是嵌套的sitesVersionsRoles(语言 → 版本 → 角色)三维矩阵,allSitesInterface以三重循环展开它,这与文档中“所有维度(language/version/role)”的描述一一对应;
  • 返回给模板的每个元素通过s.Site()包装,只暴露page.Site接口,保证模板层无法触碰内部实现;
  • 函数签名支持传入include过滤函数,为内部按维度筛选站点预留了能力(传入nil时返回全部站点)。

3. 站点包装层

resources/page包中,siteWrapper.Sites()(resources/page/site.go)直接透传给内部站点对象:

func (s *siteWrapper) Sites() Sites { return s.s.Sites() }

page层面(如 resources/page/page.go 的nopHugoSitesProvider)也实现了同名方法,说明Sitespage.Site接口体系中的标准成员。

七、相关 API 与使用建议

  • Site.IsDefault:判断当前站点是否为全维度默认站点(源码位于 hugolib/site.go,即“Returns whether this site is the default across all dimensions”),常与Sites搭配实现“仅在默认站点输出”的逻辑;
  • Site.Home:获取站点首页页面对象,Sites遍历中常用.Home.RelPermalink生成链接;
  • Site.Version:获取站点所属版本信息,多版本站点中用于展示版本名;
  • Site.Language:获取语言信息,多语言切换器中常与Sites联用。

升级建议:若你的模板仍在使用{{ .Site.Sites }}{{ .Sites }},请尽快迁移到hugo.Sites(v0.156.0+),以避免弃用告警并在未来版本中保持兼容;多语言、多版本站点矩阵的排序、默认站点判定规则在新旧 API 间完全一致,可直接替换无需调整业务逻辑。

  • 开发工具
  • 前端
  • CLI

【免费下载链接】hugo

The world’s fastest framework for building websites.

项目地址:https://gitcode.com/gh_mirrors/hu/hugo
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询