まえがき

WordPressで運用していたこのページですが、夏休みの自由研究ということで、この度Hugoを利用して再構築することにしました。

理由としては、

  • WordPressは重いから
  • WordPressの更新が面倒だから

あたりでしょうか。

Hugoで生成すると、全部のページが単なるHTMLになるので、重いという問題はなくなります。 また、WordPressの更新に悩まされることもなくなります。

一方で、

  • ページをビルドしないといけない
  • ビルド結果をサイトにアップしないといけない

といったあたりは手間が増えることになります。

移行概要

自分で管理しているVPSにWordPressを入れていたので、WordPressのプラグインではなく、データベース(MySQL)から直接データを取得して、全部の投稿を1つずつのファイルにすることにします。

また、URLについては、WordPressの設定により、

/archives/%post_id%

となっており、これはそのまま活かすよう、記事IDをファイル名にすることにします。 記事数もそこそこあるので、記事は年ごとのディレクトリを作って、その中に入れるようにします。

今後作成する記事については記事ID=YYYYMMDDとすればいいのかな、例えば

2026/20260722.md

みたいな感じに。

Copilotが書いてくれた移行ツールの仕様は以下のような感じ。

データ移行ツール仕様

方針

  • URLは維持する
  • HTML本文は維持する
  • 画像URLは維持する
  • WordPressの記事IDをファイル名に利用する
  • コメントは無視する

入力・出力

WordPress の MySQL データベースを直接参照する。

利用するテーブルは以下の通り。

  • wp_posts
  • wp_terms
  • wp_term_taxonomy
  • wp_term_relationships

各記事は以下のファイルに出力する。

content/posts/YYYY/ID.md

例:

content/posts/2025/799.md

投稿日の年ごとにディレクトリを分ける。

content/posts/
├── 2004/
├── 2005/
├── ...
├── 2024/
├── 2025/
└── 2026/

ファイル名には、WordPressの記事IDをそのまま利用する。

799.md
800.md
801.md

対象記事

以下の条件を満たす記事のみ変換対象とする。

post_type = 'post'
post_status = 'publish'

Front Matter

出力例:

---
title: "Ubuntu24.04でSkinny.phpが警告を出すことへの対処"
date: 2025-02-26 00:00:00
categories:
  - "コンピュータ"
---

対応表:

Hugo WordPress
title post_title
date post_date
categories category taxonomy

本文の変換

本文は Markdown へ変換しない。

基本的に WordPress の HTML をそのまま出力する。

Gutenberg コメントのみ削除する。

例:

<!-- wp:paragraph -->
<!-- /wp:paragraph -->

<!-- wp:code -->
<!-- /wp:code -->

以下のような HTML はそのまま保持する。

<p>本文</p>

<pre><code>...</code></pre>

...

<a href="...">

画像 URL は変更しない。

記事内の

```html
<img srcss/wp-content/uploads/...

はそのまま出力する。

画像ファイルは後で

static/wp-content/uploads

へコピーすることにする。

移行ツール

上記の仕様を元に生成したソースコードは以下の通り。

#!/usr/bin/env perl

use strict;
use warnings;
use utf8;

use DBI;
use File::Path qw(make_path);
use POSIX qw(strftime);

my $dbh = DBI->connect(
    'DBI:mysql:database=DBNAME;host=localhost',
    'USER',
    'PASS',
    {
        RaiseError => 1,
        mysql_enable_utf8mb4 => 1,
    }
);

my $posts = $dbh->prepare(q{
    SELECT
        ID,
        post_title,
        post_content,
        post_date
    FROM wp_posts
    WHERE post_type = 'post'
      AND post_status = 'publish'
    ORDER BY ID
});

$posts->execute();

while (my $post = $posts->fetchrow_hashref) {

    my $id      = $post->{ID};
    my $title   = $post->{post_title};
    my $content = $post->{post_content};
    my $date    = $post->{post_date};

    my ($year) = $date =~ /^(\d{4})/;

    #
    # Gutenbergコメント除去
    #
    $content =~ s/<!--\s*wp:[^>]*-->//g;
    $content =~ s/<!--\s*\/wp:[^>]*-->//g;

    #
    # カテゴリ取得
    #
    my $cats = $dbh->selectcol_arrayref(q{
        SELECT t.name
        FROM wp_terms t
        JOIN wp_term_taxonomy tt
          ON tt.term_id = t.term_id
        JOIN wp_term_relationships tr
          ON tr.term_taxonomy_id = tt.term_taxonomy_id
        WHERE tr.object_id = ?
          AND tt.taxonomy = 'category'
        ORDER BY t.name
    }, undef, $id);

    my $dir = "content/posts/$year";

    make_path($dir);

    my $file = "$dir/$id.md";

    open(my $fh, '>:encoding(UTF-8)', $file)
        or die "$file: $!";

    print $fh "---\n";
    print $fh qq(title: "$title"\n);
    print $fh "date: $date\n";

    if (@$cats) {
        print $fh "categories:\n";
        for my $cat (@$cats) {
            print $fh qq(  - "$cat"\n);
        }
    }

    print $fh "---\n\n";
    print $fh $content;
    print $fh "\n";

    close $fh;

    print "wrote $file\n";
}

$dbh->disconnect;

WSL2でのビルドが遅い件

Windowsのデスクトップ上にファイルを並べて、WSL2からhugoを実行してみると、200弱の記事をビルドするのに27秒ほどかかりました。しかし、timeを測定したところ、実際にはほとんど待ち時間のようです。

Start building sites …
hugo v0.154.5+extended linux/amd64 BuildDate=2026-01-13T19:59:22Z VendorInfo=ubuntu:0.154.5-1


                  │ JA
──────────────────┼─────
 Pages            │ 278
 Paginator pages  │  70
 Non-page files   │   0
 Static files     │ 184
 Processed images │   0
 Aliases          │  13
 Cleaned          │   0

Total in 27718 ms

real    0m27.833s
user    0m1.395s
sys     0m2.702s

そこで、これはWSL2からWindowsのNTFSにアクセスするのが遅いのだろうと思い、Windows版のHugoコマンドをダウンロードしてWindows側でHugoを実行することにしました。

Start building sites …
hugo v0.164.0-ce2470e7012b5ab5fc4e10ebe4027e9f8d9e00dc windows/amd64 BuildDate=2026-07-06T16:39:30Z VendorInfo=gohugoio

WARN  deprecated: .Language.LanguageDirection was deprecated in Hugo v0.158.0 and will be removed in a future release. Use .Language.Direction instead.
WARN  deprecated: .Language.LanguageCode was deprecated in Hugo v0.158.0 and will be removed in a future release. Use .Language.Locale instead.

                  │ JA
──────────────────┼─────
 Pages            │ 278
 Paginator pages  │  70
 Non-page files   │   0
 Static files     │ 184
 Processed images │   0
 Aliases          │  13
 Cleaned          │   0

Total in 580 ms

27秒かかっていたものが0.6秒となりました。これで快適にビルドできますね。

ページの配置

サーバへページを配置するために、WSL2上でrsyncを使うことにしました。

これもWindowsネイティブのものの方が速いのでしょうけど、そこまで遅くもなかったので良しとします。