まくまくHugoノート
セクションページでいろいろな方法でページソートする
2022-05-20

.Pages のデフォルトソート順序

Hugo のセクションページのテンプレート内で .Pages 変数を参照すると、子セクションや子ページの一覧を取得できますが、その一覧はデフォルトで次のような情報をもとにソートされています(参考: Lists of Content in Hugo - Order Content)。

  1. Weight
    • ページのフロントマターで weight: 1 のように書いておくと、ページに重み付けできる。小さな値の weight を持っているページの方が先に表示される。weight を持たないページ(あるいは weight: 0 のページ)は、いかなる weight を持つページよりも後ろに表示される。
  2. Date
    • ページのフロントマターで、date: "2022-05-20" のように記述しておくと、そのページの作成日として認識される。より新しいページが先に表示される。
  3. LinkTitle / Title
    • ページのタイトルで昇順ソートされる。フロントマターに linkTitle が指定されていればその値でソートされ、なければ title の値でソートされる。
  4. FilePath
    • .md ファイルのフルパスで昇順ソートされる。

具体的のどのような実装になっているかは、下記 Hugo ソースコードの DefaultPageSort 関数あたりを見ると分かります。

ソート方法をカスタマイズする

.Pages 変数でページの一覧を取得するときに、.Pages.ByTitle のように指定すると、タイトルでソートすることを明示できます。 他にもいろいろな参照方法があります。

参照方法 意味
.Pages.ByWeight フロントマターの weight の小さい順。ただし、weight: 0 は指定なしとみなされる
.Pages.ByTitle タイトル (title) 順
.Pages.ByLinkTitle タイトル (linkTitle) 順。linkTitle がない場合は title を参照する
.Pages.ByDate 日付 (date) が新しい順
.Pages.ByPublishDate 日付 (publishdate) が新しい順
.Pages.ByExpiryDate 日付 (expirydate) が新しい順
.Pages.ByLastmod 日付 (lastmod) が新しい順
.Pages.ByLength 本文が短い順
.Pages.ByParam "rating" フロントマターの独自フィールドの値でソート(この場合は rating
.Pages.ByParam "author.last_name" 上の応用(入れ子になった独自フィールド)

逆順にしたいときは、後ろに .Reverse を付けます。 例えば次のようにすると、タイトルで降順ソートされます。

.Pages.ByTitle.Reverse

次のようなセクションテンプレートを用意すれば、各種ソート条件でどのように表示されるかをテストできます。

layouts/_default/section.html(抜粋)

<ul>
  {{ range .Pages.ByTitle.Reverse }}
  <li><a href={{ .RelPermalink }}>{{ .Weight }} / {{ .Date.Format "2006-01-02" }} / {{ .LinkTitle }}</a></li>
  {{ end }}
</ul>

応用: 複数の条件でソートする

前述の通り、.Pages はデフォルトで Weight → Date → LinkTitle → FilePath の優先度でソートされるのですが、これをカスタマイズして Weight → LinkTitle の順でソートしたい場合はちょっとややこしいです。

.Pages.ByWeight.ByTitle

としてしまうと、Weight 順にソートされた結果がタイトル順で再度ソートされるだけでうまくいきません(.ByWeight の意味がなくなってしまいます)。 段階的にソートするには、まずグループ機能で同じ Weight を持つページを取り出し、そのグループ内でタイトル順ソートする必要があります。 次のパーシャルテンプレートは、渡された .Pages を Weight → LinkTitle の順でソートする関数です。

layouts/partials/functions/sort-pages.html

{{- $pages := . }}
{{- $pagesWithWeight := where $pages "Weight" "<>" 0 }}
{{- $pagesWithoutWeight := where $pages "Weight" "==" 0 }}
{{- $ret := slice }}

{{- range $pagesWithWeight.GroupBy "Weight" }}
  {{- $ret = $ret | append .Pages.ByLinkTitle }}
{{- end }}
{{- $ret = $ret | append $pagesWithoutWeight.ByLinkTitle }}

{{- return $ret }}

あとは、セクションテンプレートなどから次のように使用します。

layouts/_default/section.html(抜粋)

<ul>
  {{ range partial "functions/sort-pages" .Pages }}
    <li><a href={{ .RelPermalink }}>{{ .LinkTitle }}</a></li>
  {{ end }}
</ul>
2022-05-20