このサイトはHugo で構築しています。
ベースはRobust というテーマで、これをフォークしてrobust-iniwa というリポジトリで管理し、各サイトからは Git submodule として取り込んでいます。

この記事では、2026年9月8日に当サイトが取り込んでいる robust-iniwa のソースを基に、主なカスタマイズと、それを支えるサイト側(このリポジトリ)の構成についてまとめます。
コードはどんどん変わるので、最新はGitHub を見るのが早いです。この記事は雰囲気を掴む用です。

現在の構成

最初は「themes/robust 配下は触らず、/layouts/ に上書きファイルを置く」運用にしていましたが、姉妹サイト(diary.iniwach.com )と共通の改造が増えてきたので、テーマ自体をフォークして共有することにしました。

iniwach.com/
├── config/
│   ├── development/config.toml
│   └── production/config.toml
├── content/
├── static/
└── themes/
    └── robust-iniwa/      ← submodule (https://github.com/iniwa/hugo_theme_robust-iniwa)
        ├── archetypes/
        ├── assets/
        ├── layouts/
        └── static/js/

主な指針は次の通り。

  • テーマ全体に効くカスタマイズは themes/robust-iniwa/ に置き、両サイトで共有
  • サイト固有のもの(記事、画像、config.toml、static/robots.txt など)はサイトのリポジトリに置く
  • 設定は config/development/ と config/production/ で分割し、hugo server と本番ビルドで使い分ける

robust-iniwa 側では、上流(dim0627/hugo_theme_robust)に対してファイル単位で [mod] [new] [removed] のコメントマーカーを付けて差分を追えるようにしています。

サイドバーの構成

Author / Archives / Tags / Latests / Memos(設定時のみ) の順で並べています。
themes/robust-iniwa/layouts/baseof.html でこの順に partial を呼び出している形です。

Author欄

Twitter(X)、YouTube、Twitch、メールへのリンクを並べています。以前使っていた Font Awesome の CDN 読み込みは廃止し、現在はローカルのインライン SVG partial でアイコンを表示します。

config.toml の [params.author] を埋めるとそのまま反映されます。

1
2
3
4
5
6
7
8
9
[params.author]
thumbnail      = "images/profile/250202Author.png"
name           = "いにわ"
description    = "技術的な備忘録サイト。…"
twitter        = "https://twitter.com/iniwach"
twitter_handle = "@iniwach"
YouTube        = "https://www.youtube.com/@iniwach"
Twitch         = "https://www.twitch.tv/iniwach"
mail           = "GoogleフォームURL"

サイドバーのアイコン部分は themes/robust-iniwa/layouts/_partials/author.html で、ローカルの SVG アイコンとともに mail/Twitch/YouTube 等のエントリを表示しています。

月別アーカイブ・Tags

Taxonomy で、archive と tag の2つを定義。Categories は使わなくなったので消しました。

1
2
3
[taxonomies]
tag     = "tags"
archive = "archives"

各記事のフロントマターで下のように書けば、勝手に年月別アーカイブが生成されます。

archives:
  - 2025-02

サイドバー描画用に themes/robust-iniwa/layouts/_partials/archives.html を新規作成し、上流の taxonomy.html を流用する形にしています。

Latests

最新記事一覧。上流は10件固定だったので、Site.Params.latests_count で件数を可変にしました。未設定なら50件です。

[params]
latests_count = 50

Memos(自前ホスティングのメモ連携)

別途立てている Memos サーバーから最新メモを取ってきて、サイドバーに表示するようにしました。
Site.Params.memos_url を設定したときだけ partial が描画されます。

外部スクリプト(marked, DOMPurify)はバージョン固定 + SRI ハッシュ付きで読み込み、サニタイズしてから描画しています。
実際の読み込みタグは themes/robust-iniwa/layouts/_partials/memos.html にあります。バージョンと integrity は対で管理し、更新時には取得したファイルからハッシュを生成します。省略したハッシュをコピーするとブラウザが読み込みを拒否するため、ここではタグの例を省いています。

サイドバーの追従スクロール

PC 表示時はサイドバーが画面に追従するようにしています。
昔は custom.css に直書きしていましたが、今は themes/robust-iniwa/assets/css/layout.css に分離。スクロールバーは Webkit/IE/Firefox それぞれの方法で非表示にしています。

ヘッダーとフッター

スクロール連動でヘッダーを隠す

よく見るアレ。下スクロールでヘッダーが消え、上スクロールで再表示されます。
baseof.html 末尾に小さい JS、layout.css に .l-header.is-hidden の transform を仕込む構成です。

フッターとサイト内ナビゲーション

baseof.html の <footer> に /notice と /privacy へのリンクを追加。
それぞれ content/notice.md と content/privacy.md として用意しています。当サイト固有の layouts/baseof.html では、技術・ゲーム・運営者・お問い合わせへの導線と noindex の出力を追加しています。この上書きはテーマ更新時に元ファイルとの照合が必要です。

記事メタデータの取り扱い

更新日(Lastmod)の表示

summary.html と list.html の両方で、Date != Lastmod のときに更新アイコン付きで日付を出すようにしています。
日付アイコンもローカルの SVG を使います。記事の Lastmod は本文に変更があったときに更新します。

dateformat は Site.Params.dateformat で "2006/01/02" 形式に統一しています。

archetype

hugo new ○○.md で生成される雛形。サイトリポジトリ側の archetypes/default.md に置いてあります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
---
title: "{{ .TranslationBaseName | humanize | title }}"
description: ""
date: "{{ dateFormat "2006-01-02" .Date }}"
Lastmod: "{{ dateFormat "2006-01-02" .Date }}"
thumbnail: images/thumbnail/default_thumbnail.png
draft: true
toc: true
archives:
  - {{ dateFormat "2006-01" .Date }}
tags:
  - 
---

description は OGP 用に必須で入れる方針なので、空欄を最初から差し込んでいます。

OGP / Twitter Card / 構造化データ

当初は記事一覧ページにだけ手書きで OGP メタタグを追加していましたが、今はテーマ側で全ページ自動対応するようにしました。

themes/robust-iniwa/layouts/_partials/meta.html の主なポイント。

  • IsHome / IsPage / その他で OGP の中身を出し分け
  • description は frontmatter の description 優先、なければ Summary を160文字で truncate
  • 記事画像は Page Bundles に対応(Resources.GetMatch で記事フォルダ内の画像を解決)
  • data/ogp_manifest.json があれば事前生成された OGP 画像を優先し、画像の登録漏れはビルドエラーにする
  • manifest がない場合は、og_worker_url の Cloudflare Workers + Satori による動的生成、または記事画像へフォールバック
  • localhost / 127.0.0.1 の URL は Workers に渡せないので除外

動的生成へフォールバックする場合は、?title=...&bg=...&site=...&v=... で記事タイトルや背景画像、サイト名、Lastmod のキャッシュバスター を渡しています。

構造化データ(JSON-LD)

themes/robust-iniwa/layouts/_partials/single_json_ld.html で BlogPosting を出力。上流は NewsArticle でしたが、ブログ記事なら BlogPosting の方が適切です。
description / author / dateModified などひととおり整備しています。

アクセス解析・コメント・収益化

機能 どこに書く 状態
Google Analytics [services.googleAnalytics] 本番ビルド時のみ計測(DEV 環境では無効)
Disqus — 現在のテーマでは廃止
Umami [params.umami] website_id を入れたときだけ計測スクリプト挿入
Google AdSense [params] adsense_client_id hugo.IsProduction のときだけ <head> に挿入

[params.umami] の構造はこんな感じ。

[params.umami]
website_id = "xxxxxxxx-..."
script_url = "https://(自前ドメイン)/script.js"

AdSense の <script> タグは meta.html の中で Site.Params.adsense_client_id と hugo.IsProduction を確認し、さらにページの no_ads: true で出力を抑制しています。開発環境では出力しません。当サイトでは免責事項・プライバシーポリシー・移転案内と、404・タグ・月別一覧を対象外にしています。

ショートコード

themes/robust-iniwa/layouts/_shortcodes/ に下記を入れています。

accordion

<details> を使った折りたたみ。

ここをクリックで展開できます。
こういう最初は閉じていてクリックすると開くものをアコーディオンって言うらしいです。

{< accordion title="ここをクリックで展開" >}
ここに展開後の内容
{< /accordion >}

※実際はカッコは2つです。

img-view

画像をグリッドで並べる用。

{< img-view "a.jpg" "b.jpg" "c.jpg" >}
{< img-view 2 "wide1.jpg" "wide2.jpg" >}

先頭に数値を入れると列数を指定できる(デフォルト3列)ようにしてあります。WebP サムネを自動生成して <picture> で出すので、フルサイズ原本は別ロードされません。

tip

ホバー / フォーカスでツールチップを出す注釈。

これは {< tip "ここにポップアップ文" >}対象テキスト{< /tip >} です。

スタイルは assets/css/tip.css、開閉ロジックは static/js/tooltip.js。

外部リンク

新しいタブで開く + アフィリエイト sponsored 自動付与

themes/robust-iniwa/layouts/_markup/render-link.html で Markdown のリンクをカスタムレンダー。

  • http(s):// で始まるリンクは target="_blank" rel="noopener" を付与
  • Amazon・楽天・e☆イヤホン・A8・LinkSynergy 等のアフィリエイト系ドメインを含む場合は rel="sponsored noopener" に切り替え(Googleガイドライン準拠)
<a href="..." rel="sponsored noopener" target="_blank">...</a>

ドメイン一覧は配列で持っているので、必要に応じて足せます。

CSS の管理

昔は \layouts\partials\custom.css に全部詰めていましたが、テーマフォーク後にファイル分割しました。

  • assets/css/variables.css … カラー変数とサイズ。テーマバリアント切替もここ
  • assets/css/layout.css … ヘッダー・サイドバー・フッターと全体レイアウト
  • assets/css/content.css … 記事本文の見出し・段落・コードブロック・accordion など
  • assets/css/pagination.css … ページネーション
  • assets/css/grid.css … img-view のグリッド
  • assets/css/tip.css … ツールチップ
  • assets/css/memos-style.css … Memos サイドバー用

テーマバリアント

baseof.html の <body data-theme="..."> 属性に Site.Params.theme_variant を入れていて、variables.css で [data-theme="garden"] / [data-theme="tech"] ごとに変数値を上書きしています。
このサイトは tech、姉妹サイトの diary は garden です。

[params]
theme_variant = "tech"   # or "garden"

SyntaxHighlight・コードブロック

config.toml の [markup.highlight] で Hugo 内蔵の Chroma を使う設定にしています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[markup]
  [markup.highlight]
    anchorLineNos     = false
    codeFences        = true
    guessSyntax       = false
    lineNoStart       = 1
    lineNos           = false
    lineNumbersInTable = true
    noClasses         = true
    style             = 'monokai'
    tabWidth          = 4
    wrapperClass      = 'highlight'

記事内では Markdown 記法でそのまま書けます。

```text {linenos=true,hl_lines=[1,"3-4"],linenostart=1}
ここにコードを記入
ハイライト指定や行番号開始位置を渡せる
```

詳細はHugoのドキュメント へ。

robots.txt と sitemap.xml

現在は、下書き用のパスをクロール対象から外すために、enableRobotsTXT = false にして自前の static/robots.txt を使う構成にしました。

User-agent: *
Disallow: /_draft/

Sitemap: https://iniwach.com/sitemap.xml

タグ・アーカイブ等には noindex, follow を出力し、検索エンジンがそれを読めるよう robots.txt ではブロックしません。

sitemap からはタグ・アーカイブ・カテゴリ・下書き等を除外するため、themes/robust-iniwa/layouts/sitemap.xml で Permalink をフィルタする独自テンプレートに差し替え。

{{ range .Data.Pages }}
{{ if or (in .Permalink "/tags/") (in .Permalink "/categories/") (in .Permalink "/archives/") (in .Permalink "/_draft/")}}
{{ else }}
<url>
  <loc>{{ .Permalink }}</loc>
  ...
</url>
{{ end }}
{{ end }}

404ページ

上流の 404 はタイトルだけなので拡張。「トップへ戻る」リンクと最新記事5件を表示するようにしています。
themes/robust-iniwa/layouts/404.html 。

おわりに

最初は「themes 配下を触らない」運用でしたが、姉妹サイトとの共通化、上流との差分管理、デプロイ後のホットフィックスのしやすさ等を考えると、フォーク + submodule の方が圧倒的に楽でした。

hugo server で常にローカル確認しながら進められるのは引き続き気持ちいいです。AI を併用して書いていますが、上流との差分箇所には [mod] [new] [removed] のマーカーを残す運用にしているので、後から見返すときも比較的読みやすい状態を保てています。

更新履歴

  • 2026/09/08
    • 取り込み済みテーマのソースに合わせてパス、SVG、OGP、Disqusの説明を修正
    • 当サイト固有のナビゲーションと広告・検索対象の扱いを追記
  • 2025/02/06
    • コードブロック書式の追加
    • コンテンツの横幅についてを追加
    • RSSフィードの対応
  • 2025/02/07
    • Robots.txtについて追加
  • 2025/02/10
    • ogpタグについて追加
    • 記事一覧に更新日時の追加
  • 2025/07/17
    • リンクを新しいタブ開くを追加
    • custom.cssを修正
  • 2025/09/02
    • 画像のグリッド表示を追加
  • 2025/11/27
    • custom.cssを更新
    • ヘッダー追従の実装
  • 2025/12/05
    • テーマのサブモジュール化
  • 2026/04/28
    • 記事全体を現状の robust-iniwa の構成に合わせて全面リライト
    • OGP(Page Bundles・Satori Workers連携)、JSON-LD、Memos、Umami、AdSense、tip ショートコード、テーマバリアント、CSS分割、外部リンクの sponsored 付与、404 ページ拡張などを追加

関連記事

Hugoブログを運用してく上でちょっと便利な事達

参考にした記事

zzzmisa’s blog : HugoのテーマRobustのカスタマイズver3
syocky tech blog : Hugoテーマ「Robust」をカスタマイズする
親方の徒然なる日々 : HugoでFontAwesomeを使用してみた。
gkzz.dev : アコーディオンメニューをHugoで作った
テストウフ : Hugoのブログにページネーションを追加した
TelBouzu’s Blog : HugoのRobustでfaviconとかAdsenseの登録とか
OLD SUNSET DAYS : Hugoでrobots.txtとsitemap.xmlを作る
アロハル : HUGOでmeta descriptionなどのmetaタグを最適化する方法
k-kazがHugoで遊ぶサイト : Hugoで外部サイトを新しいタブで開きたい。
五里霧中 : GridレイアウトをCSSを利用したものに変更しました