WordPressをAstroに移行した話 — Python × Claude Codeで全自動化

目次

なぜ移行したか

一瞬Next.jsを試したこともあったけど…大半をWordPressで運用してきた。いくつかの理由で静的サイトジェネレーターへの移行を決めた。

  • 表示速度: WordPressはページ表示のたびにPHPとDBが動く。記事が増えるほど重くなる
  • セキュリティ: プラグインの脆弱性アップデートに追われるのが地味にストレス
  • Markdown で書きたい: エディタの中でMarkdownで完結したい。Gutenbergブロックエディタは自分には合わなかった

移行先にAstroを選んだのは、コンテンツ中心のサイトに最適化されていて、Markdownをそのまま扱えるから。ビルドも速く、472記事あっても数秒で完了する。

サーバー代/ランニングコストについては、結局実サーバーはもっていないといけないからなんとも言えない。

移行の全体像

やることをざっくりまとめるとこう。

WordPress XMLエクスポート
  ↓ convert_wp.py(HTML → Markdown変換)
  ↓ restore_pochipp.py(アフィリエイトカード復元)
  ↓ restore_internal_links.py(内部リンク修復)
  ↓ download_images.py(画像ダウンロード)
  ↓ optimize_images.py(WebP変換・リサイズ)
  ↓ fix_alt.py(alt属性の補完)
  ↓ generate_descriptions.py(metaディスクリプション自動生成)

Astroブログ完成

各ステップを独立したPythonスクリプトにした。一気にやると問題の切り分けが難しくなるので、1ステップずつ実行して確認できるようにしている。

ステップ別の解説

1. WordPress XML → Markdown変換

WordPressの「エクスポート」機能でXMLファイルを取得し、Pythonの markdownify でHTMLをMarkdownに変換する。

ここで最初にハマったのが XMLの不正な制御文字。WordPressのエクスポートXMLには、XML 1.0で許可されていない制御文字(\x00\x08 など)が混入していることがある。パーサーが落ちるので、パース前に除去する処理を入れた。

frontmatterには title, slug, date, categories, tags, image を設定。カテゴリとタグはWordPressの分類をそのまま引き継いだ。

2. アフィリエイトカード(pochipp)の復元

WordPressでは pochipp プラグインでAmazonの商品リンクを管理していた。これはショートコードで埋め込まれているので、単純なHTML→Markdown変換では消えてしまう。

pochippのデータはXML内のカスタム投稿タイプとして保存されているので、そこからJSON形式の商品データ(商品名・価格・画像URL・Amazonリンク)を抽出して、HTMLカードとして記事に挿入した。

3. 内部リンクの修復

472記事あると、記事間の相互リンクもかなりの数になる。WordPressの旧URLを新しいスラッグに変換する必要がある。

厄介だったのは、WordPress側のURL形式が統一されていなかったこと。

  • https://tako3.ch/slug/ — スラッグ直指定
  • https://tako3.ch/12345 — 投稿ID
  • https://tako3.ch/category/slug/ — カテゴリ付き

これら全パターンに対応するため、3段階のマッピングを構築した。さらに、独立した行に書かれたリンクはリンクカード風のHTMLに変換し、文中のインラインリンクはURLだけ置換するようにした。

4. 画像のダウンロードと最適化

画像はWordPressサーバーから一括ダウンロード。472記事分なので数も多く、10並列でダウンロードして処理時間を短縮した。403エラー対策としてUser-Agentも設定している。

ダウンロード後はPillowで JPG/PNG → WebP に変換。品質80・長辺1600px以内にリサイズすることで、画質を保ちつつファイルサイズを大幅に削減できた。スマートフォンで撮った写真のEXIF回転情報も考慮している。

5. alt属性とdescriptionの自動生成

画像のalt属性が空のものが大量にあったので、ファイル名から自動生成するスクリプトを作った。DSC_0001.jpg のようなカメラ生成のファイル名は記事タイトルで補完する、といった工夫をしている。

metaディスクリプションも同様に、記事本文の最初の段落から120文字以内で自動抽出した。見出しやHTMLタグはスキップして、実際のテキストだけを拾うようにしている。

Astroブログの構成

移行後のブログはシンプルな構成にした。

  • Astro 5 + Content Collections(glob loader)
  • ページ: トップ、記事詳細、カテゴリ一覧/絞り込み、タグ一覧/絞り込み、RSS
  • デザイン: CSS変数ベース、ダークモード対応、Zen Kaku Gothic Antique
  • 依存パッケージ: 最小限(astro, rss, sitemap, rehype-slug, フォントのみ)

フレームワークやCSSライブラリは入れず、Astroの標準機能だけで組んでいる。記事ページにはJSON-LD(BlogPosting)も入れてSEOに配慮した。

Claude Codeをどう使ったか

今回の移行では Claude Code をフル活用した。具体的にはこんな使い方をしている。

移行スクリプトの作成

Pythonの移行スクリプト群は、基本的にClaude Codeと対話しながら作った。「WordPressのXMLをパースしてMarkdownに変換して」という指示から始めて、実際にスクリプトを実行→エラーや不具合を報告→修正、というサイクルを回した。

特にpochippの復元や内部リンク変換のような、WordPress固有のデータ構造を扱う部分では、XMLの実データを見せながら「このデータ構造をこう変換したい」と伝えることで、的確なスクリプトが出てきた。

Astroサイトの構築

ブログのレイアウト、コンポーネント、ページルーティングもClaude Codeで構築した。Content Collectionsの設定、動的ルーティング、ページネーション、関連記事の表示ロジックなど、Astroの機能を活用した部分はほぼClaude Codeに任せている。

デバッグと微調整

「ビルドしたらこのエラーが出た」「この記事のリンクカードが崩れている」といった問題も、エラーメッセージや該当ファイルを見せるだけで修正できた。472記事あると手動チェックは現実的でないので、スクリプトで一括検証→問題箇所だけ修正、という流れが効率的だった。

使ってみた所感

Claude Codeの強みは ファイルを直接読み書きできること。「このファイルを読んで」「こう修正して」がシームレスにできるので、移行作業のような大量のファイルを扱うタスクとの相性が非常に良い。

一方で、472記事全部を一度にコンテキストに入れるのは無理なので、スクリプトで一括処理→サンプルで確認→問題があれば修正、という進め方が大事だった。

移行してみて

良かったこと

  • ビルド速度: 472記事で数秒。記事を書いてすぐプレビューできる
  • ホスティング費用: 静的サイトなのでほぼゼロ
  • Markdownで完結: エディタで記事を書いてgit pushするだけ
  • カスタマイズの自由度: テンプレートエンジンを介さず、HTMLを直接書ける感覚

注意点

  • 移行スクリプトの作り込み: WordPressの記事データは思った以上に多様。ショートコード、カスタム投稿タイプ、プラグイン固有のデータなど、一筋縄ではいかない部分が多かった
  • 画像パスの整合性: WordPressの画像URLは年月ディレクトリで管理されているので、ローカルパスとの対応を正確に取る必要がある
  • リダイレクト: 旧URLからのリダイレクト設定は別途必要。SEO的に重要

まとめ

WordPressブログをAstroに移行した。移行スクリプトをPythonで書いて自動化し、Claude Codeで開発を加速させることで、手作業では現実的でない規模の移行を実現できた。

WordPressに不満はなかったけど、Markdownベースの運用に切り替えたことで、記事を書くハードルが下がった実感がある。移行を検討している人の参考になれば。