【Hexo】ギャラリープラグインを作ってみた

2025-07-08

今さらブログを書いたところで生成AIにパクられて検索に食われるだけなのでオワコン気味ではあるが、 ギャラリーページみたいに画像を列挙して一覧表示させたかったのでHexoのプラグインを作ってみた。

サンプル:ギャラリー

環境:Hexo 7.3.0

Hexoプラグインの作り方

Hexoのプラグインはいろいろ公開されているが、探すのも大変なので自分で作ってみることに。

プラグイン

プラグインの作り方がどこに書いてあるのか分からなかったので hexo-generator-taghexo-generator-archiveを参考に試した (後々APIの「拡張」に説明が書かれているのを知った)。

  • 単純なプラグインの場合、scritsディレクトリ内にJavaScriptのファイルを置く
  • ページを生成するにはジェネレータで、hexo.extend.generator.register('gallery', function(locals) {...})で登録する
    • コールバック関数から返すオブジェクトにpath, data, layoutの各キーに値を格納
    • 複数のページを生成する場合には配列にして返す
    • 引数localsにいろいろ入っていて、locals.postsが全てのポスト内容
    • this.configでコンフィグ
    • ページネーションさせるにはhexo-paginationを使用する

各ポストにはタイトルやパスの他に、Front Matterの内容も格納されている。 ここではギャラリーに載せたい記事のFront Matterにgallery: 画像のパスで指定:

---
title: ブログ記事のタイトル
gallery: 画像のパス (例:/assets/foo.png)
---

本文

して、その記事を列挙させることにした:

// scripts/hexo-generator-gallery.js
'use strict'

const pagination = require('hexo-pagination')

hexo.extend.generator.register('gallery', function(locals) {
const config = this.config
const galleryDir = config.gallery_dir || 'gallery/'
const orderBy = config.gallery_generator?.order_by || '-date'

const galleryPosts = locals.posts
.filter(post => post.gallery)
.sort(orderBy)

if (galleryPosts.length === 0)
return

// HTMLのヘッダ用に、タイトルを多言語対応しておく
const __ = this.theme.i18n.__()
const title = __('gallery') || 'Gallery'

// 単一のページで済ます場合:
// return {
// path: `${galleryDir}index.html`,
// data: {
// title,
// posts: galleryPosts,
// },
// layout: ['gallery', 'index'],
// }

// ページネーション対応
const perPage = config.gallery_generator?.per_page || 50
const pages = pagination(galleryDir, galleryPosts, {
perPage,
layout: ['gallery', 'index'],
format: `${galleryDir}%d/`,
data: { title },
})
return pages
})
  • filterpost.galleryとしてるので、Front Matterに指定した記事だけが列挙される
  • HTMLのヘッダの<title>data.titleで設定されるようになってるが、自分の使用しているテーマでは自動的には多言語対応されないので、ジェネレータ内で対応しておく
    • $/themes/xxxx/layout/_partial/head.ejsでヘッダの出力で、<title>もそこで設定されていた
  • ページネーション、簡単に使えて便利

コンフィグ

一応設定をいじれるように、コンフィグの値を参照するようにした:

# $/_config.yml

gallery_dir: blog/gallery/

# Gallery Generator
gallery_generator:
per_page: 50
order_by: -date

レイアウト追加

生成するページのlayout'gallery'と指定したので、それにあうレイアウトのテンプレートファイルを追加する:

<!-- $/themes/xxxx/layout/gallery.ejs -->
<%
var title = __('gallery');
%>

<!-- Page Header -->
<!-- Set your background image for this header in the theme's configuration: index_cover -->
<header class="intro-header" style="background-image: url('<%- theme.index_cover %>')">
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="site-heading">
<h1><%- title %></h1>
</div>
</div>
</div>
</div>
</header>

<!-- Main Content -->
<div class="gallery-container">
<div class="card-container">
<% page.posts.forEach(function(post){ %>
<div class="card" data-hover="<%- post.title %>">
<a href="<%- config.root %><%- post.path %>">
<img src="<%- post.gallery %>" alt="<%- post.title %>" title="<%- post.title %>" loading="lazy">
</a>
</div>
<% }); %>
</div>

<%- partial('_partial/pagination') %>
</div>
  • HTMLの内容はテーマに合うように、同じディレクトリ内のarchive.ejsなどを参考に書き換えること
  • page.posts に各記事が入ってくる
    • post.galleryにFront Matterに記述した内容が入っているので、例えば<img src>に使用する

辞書追加

ギャラリーページのタイトルを多言語対応するために辞書に追加:

# $/themes/xxxx/languages/ja.yml
gallery: ギャラリー

メニューに追加

使用しているテーマにもよると思うが、メニューに追加するにはテーマのコンフィグに追加:

# $/themes/xxxx/_config.yml

menu:
...
Gallery: /blog/gallery # <- gallery_dirと合わせる

センスのいいギャラリーページ

Googleの画像検索結果やPinterestみたいなカッコいいページにしたいが、デザインセンス皆無なのでなんともいえない。

  • レスポンシブ:PCではカードで3~4列程度、スマホではSNSアプリっぽく各画像を正方形で横幅いっぱいにしたい:flexboxとメディアクエリを使う
    • flex-growを指定すると最後の行が割り切れない場合に横に拡大されてしまうのを回避したい
  • マウスホバーで記事タイトルを表示:<div data-hover="タイトル">と指定しておき、.card::before{content:attr(data-hover); opacity:0}.card:hover::before{opacity:1;}とする

できはともかく、画像がたくさん並ぶとなんかいろいろやってきたんだなって感じでよい。