wp_import.py実装解説(前編):原稿を分解して整える

はじめに

ここまでで原稿フォーマットを決め、CLAUDE.mdの責務分離も決めました。次は実際に、HTML+YAML原稿をWordPressに送り込むスクリプトの中身です。

wp_import.pyは私のブログ運用の中心スクリプトで、役割は「原稿を受け取って、各APIに渡す形式に整えて、投稿リクエストを送る」の三つです。前編ではこのうち原稿を整える部分を、後編でAPIに送る部分を扱います。

全体の処理フロー

スクリプトの全体像は四段階に分かれます。

前編で扱うのは1から3まで。各段階で必ず入力と出力の形を固定することを最優先に設計しています。途中で状態が増えると、後段のデバッグが急に難しくなるためです。

1. HTMLとYAMLの分解

原稿ファイルは冒頭にYAMLブロック(---で囲まれた領域)、その後にHTML本文という構造で書いています。これを分解する処理は、ライブラリに任せます。Python標準のPyYAMLと、python-frontmatterの組み合わせで完結します。

import frontmatter

with open(path, 'r', encoding='utf-8') as f:
    post = frontmatter.load(f)

meta = post.metadata   # YAMLが辞書として取れる
body = post.content    # HTML本文が文字列として取れる

このわずか3行が全体の出発点です。自前でパーサーを書かなかった理由は、YAMLは見た目より仕様が複雑だからです。インデント、複数行文字列、エスケープ、コメントの扱いを正しく実装するのは無理なコストでした。

分解した直後に必須項目のバリデーションを入れます。タイトル・スラッグ・カテゴリ・公開日のうち一つでも欠けていたら、ここで止めて原稿に戻ります。後段に進んでから気付くと、画像アップロードまで終わってからのロールバックが必要になるためです。

失敗は早く、安く起こす」というのが、変換レイヤー全体の方針です。

2. 画像参照をCDNパスに置換

原稿執筆中は、画像参照をローカルパスで書いています。WordPressに投稿するときは、これをCDN上のURLに書き換える必要があります。

書き換えのロジックは単純です。<img src="./images/foo.png">のような相対パスを正規表現で拾って、画像をWordPressのメディアライブラリにアップロードし、返ってきたURLで置換します。

ここで決めた設計判断が二つあります。

判断1:アップロード結果はキャッシュする

同じ画像を毎回アップロードしないように、ファイルのハッシュ値とアップロード先URLをローカルのJSONに記録しています。原稿を修正してwp_import.pyを再実行しても、変更されていない画像はアップロードをスキップします。

判断2:alt属性が空ならエラーで止める

altが空のimg要素を見つけたら、警告ではなくエラーとして処理を止めます。「あとで直す」ことが現実には起きないからです。altが書かれていなければ原稿に戻れ、というルールにしておくと、運用一年後の画像群に空altが混ざらずに済みます。

3. JSON-LD構造化データの生成

記事の種類(Article / FAQPage / HowTo)に応じて、JSON-LDを自動生成して本文末尾に挿入します。

YAMLフロントマターに記事種別を指定しておけば、テンプレートを切り替えるだけです。

FAQPage型なら、フロントマターのfaq項目(質問と回答のペア)からJSON-LDを組み立てます。HowTo型なら、原稿中の見出し階層を解析して手順リストを抽出します。

ここで重要なのは、JSON-LDのバリデーションを生成直後に入れることです。Googleの構造化データテストツールが提供するスキーマ定義に照合して、必須項目の欠落がないか確認します。検証を後回しにすると、投稿してから「リッチリザルトに出ない」と気付いて、修正・再投稿のループに入ります。

設計時に却下した代替案

案:WordPressプラグインに構造化データを任せる

Yoast SEOやRank Mathといったプラグインに構造化データ生成を委ねる案は、最初に検討しました。

却下した理由は、プラグイン依存の脆さです。プラグインの仕様変更、有償化、開発停止のリスクを長期で抱えたくありませんでした。JSON-LDは仕様が公開されたWeb標準なので、自前で生成しておけば一生メンテできます。

案:画像はCDNに直接アップロード、WPメディアライブラリは使わない

WordPressのメディアライブラリをスキップして、CDN(CloudflareやS3)に直接アップロードする案も検討しました。

却下した理由は、WPの記事から見たときの管理しやすさです。WPメディアライブラリに登録しておかないと、後からWP管理画面で記事を編集するときに画像が「外部URL」扱いになってしまう。手作業の編集と自動投稿を併用する前提では、メディアライブラリ経由が現実的でした。

次回予告

後編は、ここまでで整えた原稿を実際にWordPressへ投稿する部分です。Rinkerショートコードの展開、WP REST APIへの投稿、エラー処理、そして再実行しても壊れない冪等性の確保まで。連携レイヤーの実装判断を解説します。


このシリーズで紹介する設計は、執筆時点の各ツールバージョンに基づきます。Claude Code、MCP、WordPress、各種APIは仕様変動が大きいため、最新ドキュメントとの照合をおすすめします。

広告