こんにちは、パレイド技術部です。
前回の続きで、WordPressへの画像アップロード機能を拡張します。
本記事はローカル LLM による自動執筆パイプラインで生成されました。現段階ではクラウド AI(Claude 等)の補助や人間の編集が介在していますが、pareido.jp では最終的に AI が自律的にコンテンツを制作できる仕組みの構築を目指しています。
Markdown 上での画像の取り扱い
Markdown 形式では、画像のリンクは  のように記述します。
運用上は、記事の Markdown ファイルに直接画像ファイルをドロップしたり、スクリーンショットをコピペして使うことが多いでしょう。
VS Code はデフォルトでは Markdown の画像プレビューが表示されませんが、拡張機能を入れると便利です。pareido.jp では Markdown Preview Enhanced を利用しています。
ここで問題になるのが、Markdown 上の画像パスはローカルのファイルパスを指しているため、そのまま WordPress にアップロードしても画像が表示されないということです。ローカルパスの画像を WordPress のメディアライブラリにアップロードし、Markdown 内のパスを URL に差し替える処理が必要になります。
実装の方針
WordPress では、画像は全てメディアライブラリの管理対象になります。WordPress REST API の /wp/v2/media エンドポイントに画像ファイルを POST すれば、メディアライブラリに登録され、公開 URL が返ってきます。
今回の同期ツールでは、以下の流れで画像を処理します。
- Markdown 内の画像リンク
を正規表現で検出 - パスが
httpで始まるもの(既にアップロード済み)はスキップ - ローカルファイルを指しているものだけ WP にアップロード
- Markdown 内のパスをアップロード後の URL に差し替え
- アップロード済みの元ファイルを退避フォルダに移動
実装のイメージは下記のようになります。
import re, requests
def upload_local_images(markdown_text, wp_api_url, auth):
"""Markdown 内のローカル画像を WP にアップロードし URL に差し替える"""
def replace_image(match):
alt, path = match.group(1), match.group(2)
if path.startswith("http"):
return match.group(0) # 既に URL ならスキップ
with open(path, "rb") as f:
resp = requests.post(
f"{wp_api_url}/media",
auth=auth,
files={"file": f},
)
url = resp.json()["source_url"]
return f""
return re.sub(r"!\[([^\]]*)\]\(([^)]+)\)", replace_image, markdown_text)
ファイル名の衝突対策
WordPress のメディアライブラリでは、同名のファイルをアップロードすると自動でサフィックスが付与されます(image.png → image-1.png)。しかし、スクリーンショットのファイル名は スクリーンショット 2026-03-02 12.34.56.png のような形式で、別の記事でも似た名前になりがちです。
そこで、アップロード時にファイル名を {post_id}_{連番}_{タイムスタンプ}_{元のファイル名} 形式にリネームしています。こうすることで、どの記事の何番目の画像かがファイル名から判別でき、メディアライブラリの管理も楽になります。
アップロード済み画像の退避
一度アップロードした後は、画像ファイルが再アップロードされないよう _uploaded/ フォルダに移動する処理を加えました。
blog/articles/
├── 2026-02-02_my-article.md
├── screenshot.png ← 同期前
├── _uploaded/
│ └── 2183_01_20260202_screenshot.png ← 同期後に自動移動
これは、運用上はスクリーンショットをコピペして使うことが多く、ローカルに画像を保管しておく必要性が低いことを考慮した設計です。画像をローカルでマスター管理している場合は、移動ではなくコピーにするなど、用途に合わせて実装を変えた方が良いでしょう。
新規記事の画像は2回目の同期で
一点注意があります。画像のアップロードには WordPress 側の post_id が必要です(ファイル名に含めるため)。しかし、新規記事の初回同期では、記事の作成と同時に画像をアップロードする必要があり、まだ post_id が確定していません。
現在の実装では、初回同期で記事本体を先に作成して post_id を取得し、画像は 2回目の同期でアップロード される設計にしています。実運用上は記事の「枠」を取ってから徐々にドラフトの精度を上げていくため、画像の張り込みは最終段になるためこの仕様にしています。
まとめ
WordPress の編集体験に不満を感じつつも、長年の資産やプラグインの豊富さから離れるのは現実的ではありません。そこで、普段使い慣れた Markdown エディタで執筆し、ツールで WordPress と同期する仕組みを作ることにしました。
今回は画像の同期に焦点を当て、ローカル画像の検出 → アップロード → URL 差し替え → 退避という一連の流れを実装しました。実際に Claude Code を使って変換ツールを実装し、見出し・リスト・コードブロック・ブログカードなど主要なブロックの往復変換ができるところまで確認しています。画像の扱いや Cocoon 固有ブロックの対応など課題は残りますが、日常的な記事更新のワークフローとしては十分実用的な手応えがあります。
次回以降、実装の詳細や実際の運用で見えてきた課題について掘り下げていく予定です。



