作ったものとか » Hugo テーマ

Hugo テーマ 9. Pagefind でサイト内検索機能を付ける

2026-06-07 15:27:06 Hugo
最終更新日から %s 以上が経過しています。
内容が古くなっている可能性があるのでご注意ください。

静的なインデックスを使った検索 UI を提供する Pagefind 組み込んでみます。

Pagefind は HTML の内容からインデックスを作成し、それを使ったサイト内検索機能を提供してくれます。

インデックスの作成は Node.js もしくは Python を使って行い、検索 UI は HTML や JS, CSS としてサイト内に組み込みます。

利用までの基本的な流れ

Note

まずは、Hugo 関係なく、HTML で構成された静的サイトに組み込む流れを簡単に紹介します。

hugo build

HTML ファイルを生成しておきます。

Note

テーマとしては、この際に生成される HTML に対して、Pagefind 向けのインデックスに関する指定や検索 UI の定義を生成することになります。

npx -y pagefind --site public

public/pagefind にインデックスファイルや検索 UI 用の JS, CSS が生成されます。


基本的な手順は以上です。

ただし、これだけでは、当然ながらサイト上には検索 UI は出てきません。

検索 UI の追加

Pagefind Component UI #Quick Start に記載があります。

検索対象の指定、除外の指定

Configuring what content is indexed にある内容を押さえておけば、そこそこ満足できる結果が出てきます。

HTML 要素の属性に特定の内容を記載することで、検索インデックスの作成対象を指定したり、逆に除外したりすることができます。

テーマ側の対応

ここからは、主に検索 UI やインデックス対象を、テーマ側の観点でサイトに盛り込んでいきます。

このサイト向けのテーマ derty では…

検索 UI

search.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{{ "<!-- SEARCH -->" | safeHTML }}

{{- if $.Site.Params.derty.pagefind -}}
<div class="search">
  <pagefind-modal-trigger shortcut="/"></pagefind-modal-trigger>
  <pagefind-modal reset-on-close="true"></pagefind-modal>
</div>
{{- end }}

{{ "<!-- SEARCH -->" | safeHTML }}

meta.html

こちらは部分的に記載。

1
2
3
4
5
{{ if $.Site.Params.derty.pagefind -}}
<!-- Pagefind -->
<link href="/pagefind/pagefind-component-ui.css" rel="stylesheet">
<script src="/pagefind/pagefind-component-ui.js" type="module"></script>
{{- end }}

プロジェクト側の設定で $.Site.Params.derty.pagefind に falsy でない値 (go-template / if ) が指定されている場合に有効になるようにしています。

テーマとしてはプロジェクトの設定に以下を記載することができることをドキュメントとして伝える必要が出てきます。

[params]
  [params.derty]
    pagefind = true

スタイル

スタイルについてはこれまでコードを掲載していない&細かすぎてあまり伝えるものでもないため、引き続き掲載は控えます。

Pagefind 側が生成する CSS の詳細度が高いため、derty としては !import へ無理やり適用させるようにしています。
あまりお行儀はよくないと思いますが…

テンプレート (レイアウト定義)

baseof.html

部分的に掲載。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
      <div class="main">
        <div class="toc-area">
          {{ .TableOfContents }}
        </div>
        <div class="main-area" {{- if and $.Site.Params.derty.pagefind (.IsPage) }} data-pagefind-body{{ end -}}>
          {{ block "main" . }}{{ end }}
        </div>
        <div class="side-area">
          {{ partial "search.html" . }}
          {{ partial "profile.html" . }}
          {{ partial "latest.html" . }}
          {{ partial "tags.html" . }}
        </div>
      </div>

$.Site.Params.derty.pagefind の条件に加えて、baseof.html での処理対象が page (コンテンツ) の場合に、その main-area 以下を検索インデックスの作成対象としています。

page.html

baseof.html で IsPage な場合に data-pagefind-body を指定しているためコンテンツページの内容そのままインデックスの作成対象としてよいかと思いきや、
このテーマ derty では記事の冒頭と末尾に追加の情報を出しており、それが検索の結果に混在してしまっていたため、個別に除外することにしました。

部分的に掲載。 期限切れについての除外設定。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  {{/* 表示期限切れの警告 */}}
  {{/* あらかじめプロジェクトの [params.derty] 内に以下の if で使っているパラメーターを設定しておく */}}
  {{ if and .Site.Params.derty.outdatedUnit .Site.Params.derty.outdatedLimit }}
    {{/* 最終的な表示は js にまかせる */}}
    <div class="may_be_outdated"
      derty-outdated-since="{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" }}"
      derty-outdated-limit="{{ .Site.Params.derty.outdatedLimit }}"
      derty-outdated-limit-unit="{{ .Site.Params.derty.outdatedUnit }}"
      {{- if $.Site.Params.derty.pagefind }} data-pagefind-ignore="all"{{ end -}}>
        {{ .Site.Params.derty.outdatedMessageHTML | default  "最終更新日から %s 以上が経過しています。<br/>内容が古くなっている可能性があるのでご注意ください。" | safeHTML }}
    </div>
  {{ end }}