Wordpressの記事を静的サイトジェネレータZolaへ移行する


ブログをWordpressからZola(Rust製の静的サイトジェネレータ)へ移行して数か月、自作テーマは依然として作成途中であるが、とりあえず今のところ問題もなさそうなので、重い腰を上げて旧ブログの記事を移行することにした。

具体的な工程としては以下
1. WordPressの記事をSSG用のテキストファイルへ出力
2. 記事ファイルの整理
3. フロントマターをZola用のものに修正
4. リンクなど記事内の情報の修正(これは今回の記事では扱わない)

前提

移行前の環境

ブログプラットフォームでおなじみのWordPress
ブログから大規模サイトまで作れる CMS | WordPress.org 日本語

多言語用にサブディレクトリ型のマルチサイトを使用

本記事の工程でも多言語、マルチサイト用の余計な工程ががかかってる。シングルサイトならもっと楽。

移行先の環境

静的サイトジェネレーターZolaで生成
Zola

今回はZolaだが、移行の手順の流れや考え方自体は他でも使えるのではないかと思う。

手順1: WordPressからSSG向けの形式への出力

Zola用のツールがあるとは思えなかったので、ほかにメジャーなSSGであるところのHUGO用のツールを探す。

見つかったのがこちら
SchumacherFM/wordpress-to-hugo-exporter: Hugo is static site generator written in golang. Wordpress is a tool for remote access to your server ;-) ❗️Contributions welcome!

プラグインのインストール

SSHでサーバーに入り、以下のようにプラグインを入れる

$ cd /path/to/wordpress/wp-content/plugins/
$ sudo wget https://github.com/SchumacherFM/wordpress-to-hugo-exporter/archive/2.0.0.zip
$ sudo unzip 2.0.0.zip

自分のケースではsudoが必要だったが共有してるタイプのレンタルサーバーならHOMEディレクトリ以下にあると思うので、sudoしなくてもいい。

次にWordPress上の画面で対応

プラグインを有効化し...

エクスポート

少し待つとダウンロードが始まる

中身の確認

なぜか一部のマークダウンがAtomにディレクトリ扱いされて読めないというイレギュラーがあったが、VSCodeでは開けたのでそのまま続行する。
Atom最近使ってなかったから更新されてなくてバグってたのかもしれない。

Hugoならこれで終わりかもしれないが、今回は別のSSGなので、ここからが本番。

手順2: フォーマットの修正

正直今回のケースでは記事が少ないので手動修正のほうが早かったのだけれど、せっかく記事にするなら役に立つ記事にしたいというのと、bashを学ぶちょうどいい機会ということもあって、極力bashで一括でやれるようにした

ファイルの移動

出力時のディレクトリの構造としてはこんなかんじ

  • hugo-export
    • about
      • index.md
    • posts
      • yyyy-mm-dd-slug1.md
      • yyyy-mm-dd-slug2.md
      • etc
    • wp-content
    • config.yaml

posts内のファイル名は投稿日-スラッグ.mdという形式だった

aboutが固定ページで、ほかの投稿はpost配下に日付-スラッグという形式で入っている模様。

補足: config.yamlと固定ページについて

config.yamlはサイトの設定だが今回は移行先のブログはすでにあるので使わない
また、固定ページは1件しかなかったのと内容を更新するつもりだったので後述の自動処理では扱っていない。

これが日本語と英語と2組ある(英語は英語勉強したい気分の時にしか
にある

まずはこれを移行先の構造に合わせ以下のようなレイアウトに移動したい

  • content
    • post
      • slug1
        • index.md
        • index.en.md
      • slug2
        • index.md
        • index.en.md

一括処理用にBashを書く

最終的に出来たのがこれ

ROOT=${PWD} # hugo-exportの親ディレクトリで実行することを想定。
SRC="$ROOT/hugo-export/posts" # 移動元のディレクトリ
DST="$ROOT/content/posts" # 移動先のディレクトリ

cd $SRC
for $FILE in *.md
do 
    LEN=$((${#FILE} - 14)) # スラッグ未設定の場合は日付だけだったので、判別する。
    if [[ $LEN -eq 0 ]]; then
        AFTER="$DST/${FILE:0:-3}" # 日付だけの場合は仕方がないのでとりあえずそのまま移行する。
    else 
        AFTER="$DST/${FILE:11:-3}" # スラッグがある記事については日付を取り除く。
    fi
    mkdir $AFTER

    echo "$FILE to $AFTER"

    cp "$FILE" "$AFTER/index.md" # 英語記事を移動するときはここだけ変える
done

これでだいたい移動ができた。

誤算だったのは下書きで、slugがファイル名にもフロントマターにも反映されていなかった。原因が下書きだからかスラッグが未入力だったからか?
とはいえブログを移行して数か月という状況で、旧ブログに残っていた下書きの必要はなさそうなので、気にせず続行する。

フロントマターの修正

Hugo-exporterはその名の通りHUGO用なので、Zolaとはフロントマター(ワードプレスで言うところの記事名とかスラッグとか、要は本文以外の情報が書いてるとこ)の書式が違う。
具体的に言うとHugo exporterの出力形式だとフロントマターはYAMLだが、ZolaはTOMLというのを使っているらしい。

出力時が以下

---
title: タイトル
author: ワードプレスのユーザー名
type: post
date: 2019-06-24T12:01:46+00:00
draft: true (公開済みの記事はこの行自体がない)
url: /ja/slug/
featured_image: /path/to/image
categories:
  - 未分類
tags:
  - tag1
  - tag2

---
移行MD形式の本文
<!--more-->

移行先に合わせた修正後のフォーマットが以下
※移行ついでにいらない情報削除したりスラッグの構造を変えつつ旧パーマリンクにエイリアスをつくって以前のurlでも飛べるようにとかしてるんで同じ内容というわけではない。

+++
title = "タイトル"
date = 2019-06-24T12:01:46+00:00
slug = "slug"
aliases =  "/ja/slug/"
categories = [
    "未分類"
    ]
tags = [
    "tag1",
    "tag2",
]

+++
本文

YAMLをTOMLに移行するだけならツールがありそうだが、今回はあくまでもMarkdonファイルの一部に埋め込まているという微妙な状態なので、こちらもBashで何とかしてみる

Bash

使ったのが以下

#!/bin/bash
ROOT=${PWD} # 前回の処理の続きで実行することを想定してる
SRC="$ROOT/content/posts" # 記事別のディレクトリの親フォルダ
DIRS="$SRC/*"   # 記事別のディレクトリ
for DIR in $DIRS # 記事別のディレクトリに対するくりかえし処理
do               
    FILES="$DIR/*.md" 
    for FILE in $FILES  # 記事別のディレクトリ内の各記事ファイルに対する繰り返し処理
    do                  # 言語別の記事がなければこのループじゃなくてもいい
        sed -r -i  -e "s/^---$/+++/g" $FILE # sed コマンドで区切り文字の置き換え
        sed -r -i  -e  '1,/^\+\+\+$/ { s/^title: (.*)$/title = "\1"/;
            s/^date: (.*)$/date = \1/;
            s/^draft: (.*)$/draft = \1/;
            /^author:/d;
            /^type:/d;
            /^featured_image:/d;
            s/^url: \/(.*)\/([0-9a-z]+)\/$/slug = "\2"\naliases = \["\/\1\/\2\/",\]/;
            s/^categories:$/\[taxonomies\]\ncategories = \[/;
            s/^tags:$/\]\ntags = \[/;
            s/^  - (.*)$/"\1",/;
            s/^$/\]/;
        }' $FILE # 一つの文字列中で入れ子にした関係上、コメントがはさめないので詳細は後述
    done
done

$SRC/*/*.mdで孫ファイル一覧をそのまま取得できるので実はループを二重にする必要がなかったことは後から知った。

二つ目のsedコマンドの処理についてについて解説

sedコマンドでの文字列の置き換えだが、条件がややこしくなったのでこちらで解説

といってもこういう認識で書いて実際に実行してそれっぽく動いているというだけなので、あっているかは自信がない

1,/^\+\+\+$/ {複数の処理}:
{}内の処理を 1行目から次の+++までの範囲に行う。

s/^title: (.*)$/title = "\1"/;:
:=に置き換え、タイトル名を"でかこう

s/^date: (.*)$/date = \1/;s/^draft: (.*)$/draft = \1/;:
datedraft:=に差し替え

/^author:/d;/^type:/d;/^featured_image:/d;:
authortypefeatured_imageを削除

s/^url: \/(.*)\/([0-9a-z]+)\/$/slug = "\2"\naliases = \["\/\1\/\2\/",\]/;:
urlを最後のスラッグのみ切り出し、slugに設定。
もとのurlでもそのまま飛べるようaliasesとして設定

s/^categories:$/\[taxonomies\]\ncategories = \[/; s/^tags:$/\]\ntags = \[/; s/^ - (.*)$/"\1",/; s/^$/\]/;:
カテゴリとタグをtoml形式に直す処理

リンクなど本文の内容の修正

以下の事情により簡単な置換が難しそうであったため、今回は保留

  • 内部リンク用のアドレスが複数ある 言語別のアドレスがあることにくわえ、今回の移行のその前に1度ドメインを移行していたことによる内部リンクのドメインの混在 そもそも移行前のサイトの時点でリンクが切れまくっていたらしい。今度ははちゃんと直そう、そのうち
  • リンクの形式がマークダウン化されているものとhtmlのままのが混在している。 これはおそらくGutenbergWP Githuber MDなど, ワードプレスで編集に使っていたエディタによる違いかと思う。

そのうちちまちま手動で治すことにする

結果

  • いろいろ手こずったけどなんとか移行ができた。
  • なんやかんやで一度ファイルににしてしまえば、あとはBash等の置き換えでで一括で書き換えられるのは便利 今後の移行も楽そう(さすがにいい加減落ち着くとは思うが)