WordPressからHugoへブログを移行したものの、WordPress時代のURL /2023/02/12/9136/ のような形式で外部からリンクされているページが大量にある。Hugo側のURLは /p/{slug}/ という全く別の構造なので、そのままだと旧URLが全て404になってしまう。
Hugoの aliases 機能とWordPressのSQLダンプを組み合わせることで、nginx設定を触らずにリダイレクトできたのでメモしておく。
WordPressのURL構造
WordPress(デフォルトのパーマリンク設定)では投稿のURLはこの形式になっている。
/YYYY/MM/DD/{投稿ID}/
2023年2月12日に公開された投稿ID 9136の記事なら /2023/02/12/9136/ になる。この情報は全て wp_posts テーブルに入っている。
wp_postsから取り出すカラム
SQLダンプの wp_posts テーブルのカラム定義はこんな感じ。
CREATE TABLE `tblog_wp_posts` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`post_author` bigint(20) unsigned NOT NULL DEFAULT '0',
`post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_content` longtext NOT NULL,
`post_title` mediumtext NOT NULL,
`post_excerpt` mediumtext NOT NULL,
`post_status` varchar(20) NOT NULL DEFAULT 'publish',
...
`post_name` varchar(200) NOT NULL DEFAULT '',
...
`post_type` varchar(20) NOT NULL DEFAULT 'post',
...
);
旧URLの復元とHugo記事への紐付けに使うのはこの4つ。
| カラム | 役割 | 例 |
|---|---|---|
ID |
投稿ID。旧URLのパスの一部 | 9136 |
post_date |
投稿日時。旧URLの年月日部分 | 2023-02-12 22:11:10 |
post_name |
スラッグ。Hugo側の記事とマッチさせるキー | xremapを利用して特殊なショートカットをマッピング |
post_type |
投稿タイプ。post のみ対象 |
post |
post_status が publish または draft のものだけフィルタする。
旧URLの組み立て
post_date からYYYY・MM・DDを抽出して ID と組み合わせるだけ。
year = post_date[0:4] # "2023"
month = post_date[5:7] # "02"
day = post_date[8:10] # "12"
post_id = "9136"
old_url = f"/{year}/{month}/{day}/{post_id}/"
# → /2023/02/12/9136/
Hugo記事とのマッチング
Hugo側の記事ファイルには front matter に slug が設定されている。
---
title: "xremapを利用して特殊なショートカットをマッピングしてみる"
slug: "xremapを利用して特殊なショートカットをマッピング"
---
SQLダンプの post_name カラムがWordPress側のスラッグに相当する。WordPress→Hugo変換時に post_name をそのまま slug として使っているので、この値でマッチングできる。
post_name が空の投稿(下書きなど)は変換時に post-{ID} というスラッグを割り当てているので、同じルールでフォールバックする。
slug = post_name if post_name else f"post-{post_id}"
Hugoのaliases
Hugo には front matter に aliases を指定すると、そのパスにリダイレクト用のHTMLを自動生成してくれる機能がある。これが便利。
---
title: "xremapを利用して特殊なショートカットをマッピングしてみる"
date: 2023-02-12 22:11:10
slug: "xremapを利用して特殊なショートカットをマッピング"
aliases:
- /2023/02/12/9136/
categories:
- Tech
---
この設定だけでHugoのビルド時に /2023/02/12/9136/index.html が生成される。中身はmeta refreshによるリダイレクトHTMLで、アクセスすると /p/xremapを利用して特殊なショートカットをマッピング/ に自動遷移する。
nginxやApacheのrewrite設定は一切不要で、Hugo単体で完結する。GitHub PagesやCloudflare Pagesのような静的ホスティングでもそのまま動く。
スクリプトで一括処理
1,300件以上あるので手作業は無理。Pythonスクリプトで一括処理した。
処理の流れはシンプルで、
- SQLダンプの
INSERT INTO文をパースして各投稿のID,post_date,post_nameを取得 post_name(スラッグ)をキーにしてcontent/post/内のMarkdownファイルを特定- front matter に
aliases: ["/YYYY/MM/DD/{ID}/"]を挿入
front matter の編集では、既存の aliases があればマージし、なければ slug: 行の直後に挿入するようにしている。
実行結果。
WordPress投稿数: 1327
Markdownファイル数: 1327
更新: 1326
マッチなし: 1
1,327件中1,326件で追加できた。マッチしなかった1件はスラッグの重複回避処理で名前が変わっていたケースなので、実質的には全件対応できている。
あとはHugoをビルドし直せば旧URLからのリダイレクトが有効になる。サーバー側の設定変更なしでここまでできるのはありがたい。