EmDash のインポートシステムはプラガブルなソースアーキテクチャを使用します。各ソースは特定のプラットフォームからのプローブ、分析、コンテンツ取得の方法を知っています。
インポートソース
| ソース ID | プラットフォーム | プローブ | OAuth | フルインポート |
|---|---|---|---|---|
wxr | WordPress エクスポートファイル | No | No | Yes |
wordpress-com | WordPress.com | Yes | Yes | Yes |
wordpress-rest | セルフホスト WordPress | Yes | No | プローブのみ |
WXR ファイルアップロード
最も完全なインポート方法です。WordPress eXtended RSS (WXR) エクスポートファイルを管理ダッシュボードに直接アップロードします。
機能:
- すべての投稿タイプ(カスタムを含む)
- すべてのメタフィールド
- 下書きと非公開投稿
- 完全なタクソノミー階層
- メディア添付ファイルメタデータ
WXR ファイルの取得方法:
- WordPress 管理画面で ツール → エクスポート に移動
- すべてのコンテンツ または特定の投稿タイプを選択
- エクスポートファイルをダウンロード をクリック
.xmlファイルを EmDash にアップロード
WordPress.com OAuth
WordPress.com でホストされたサイトの場合、OAuth で接続して手動ファイルエクスポートなしでインポートできます。
- WordPress.com サイト URL を入力
- Connect with WordPress.com をクリック
- WordPress.com ポップアップで EmDash を認証
- インポートするコンテンツを選択
含まれるもの:
- 公開済みと下書きコンテンツ
- 非公開投稿(認証付き)
- API 経由のメディアファイル
- REST API に公開されたカスタムフィールド
WordPress REST API プローブ
URL を入力すると、EmDash はサイトをプローブして WordPress を検出し、利用可能なコンテンツを表示します。
Detected: WordPress 6.4
├── Posts: 127 (published)
├── Pages: 12 (published)
└── Media: 89 files
Note: Drafts and private content require authentication
or a full WXR export.
REST プローブは情報提供用です。完全なインポートには WXR ファイルのアップロードまたは OAuth 接続(WordPress.com の場合)を提案します。
インポートフロー
すべてのソースは同じフローに従います。
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 接続 │────▶│ 分析 │────▶│ 準備 │────▶│ 実行 │
│ (プローブ/ │ │ (スキーマ │ │ (スキーマ │ │ (コンテンツ │
│ アップロード)│ │ チェック) │ │ 作成) │ │ インポート) │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
ステップ 1: 接続
URL を入力してプローブするか、ファイルを直接アップロードします。
URL プローブ は登録されたすべてのソースを並列実行します。最も高い確信度のマッチが次のアクションを決定します。
- WordPress.com サイト → OAuth 接続を提案
- セルフホスト WordPress → エクスポート手順を表示
- 不明 → ファイルアップロードを提案
ステップ 2: 分析
ソースがコンテンツを解析し、スキーマの互換性をチェックします。
Post Types:
├── post (127) → posts [新規コレクション]
├── page (12) → pages [既存、互換性あり]
├── product (45) → products [3フィールド追加]
└── revision (234) → [スキップ - 内部タイプ]
Required Schema Changes:
├── Create collection: posts
├── Add fields to pages: featured_image
└── Create collection: products
各投稿タイプのステータス:
| ステータス | 意味 |
|---|---|
| Ready | 互換性のあるフィールドを持つコレクションが存在 |
| New collection | 自動的に作成されます |
| Add fields | コレクションが存在し、不足フィールドが追加されます |
| Incompatible | フィールドタイプの競合(手動修正が必要) |
ステップ 3: スキーマの準備
Create Schema & Import をクリックして:
- SchemaRegistry 経由で新しいコレクションを作成
- 正しいカラム型で不足フィールドを追加
- インデックス付きのコンテンツテーブルをセットアップ
ステップ 4: インポート実行
コンテンツは順次インポートされます:
- Gutenberg/HTML を Portable Text に変換
- WordPress ステータスを EmDash ステータスにマッピング
- WordPress 著者を所有権(
authorId)とプレゼンテーション署名にマッピング - タクソノミーの作成とリンク
- 再利用可能ブロック(
wp_block)をセクションとしてインポート - 進行状況をリアルタイムで表示
著者インポートの動作:
- 著者マッピングが EmDash ユーザーを指す場合、所有権はそのユーザーに設定され、同じユーザーの紐付き署名が作成/再利用されます。
- ユーザーマッピングがない場合、WordPress の著者アイデンティティからゲスト署名が作成/再利用されます。
- インポートされたエントリは順序付き署名クレジットを取得し、最初のクレジットが
primaryBylineIdとして設定されます。
ステップ 5: メディアインポート(任意)
コンテンツの後に、任意でメディアをインポートします。
-
分析 — タイプ別の添付ファイル数を表示
Media found: ├── Images: 75 files ├── Video: 10 files └── Other: 4 files -
ダウンロード — WordPress URL から進行状況付きでストリーミング
Importing media... ├── 45 of 89 (50%) ├── Current: vacation-photo.jpg └── Status: Uploading -
URL の書き換え — コンテンツが新しい URL で自動的に更新
メディアインポートは重複排除にコンテンツハッシュ(xxHash64)を使用します。複数の投稿で使用された同じ画像は 1 回だけ保存されます。
ソースインターフェース
インポートソースは標準インターフェースを実装します:
interface ImportSource {
/** 一意の識別子 */
id: string;
/** 表示名 */
name: string;
/** URL のプローブ(任意) */
probe?(url: string): Promise<SourceProbeResult | null>;
/** このソースからコンテンツを分析 */
analyze(input: SourceInput, context: ImportContext): Promise<ImportAnalysis>;
/** コンテンツアイテムをストリーミング */
fetchContent(input: SourceInput, options: FetchOptions): AsyncGenerator<NormalizedItem>;
}
入力タイプ
ソースは異なる入力タイプを受け付けます:
// ファイルアップロード(WXR)
{ type: "file", file: File }
// トークン付き URL(REST API)
{ type: "url", url: string, token?: string }
// OAuth 接続(WordPress.com)
{ type: "oauth", url: string, accessToken: string }
正規化された出力
すべてのソースは同じ正規化されたフォーマットを生成します:
interface NormalizedItem {
sourceId: string | number;
postType: string;
status: "publish" | "draft" | "pending" | "private" | "future";
slug: string;
title: string;
content: PortableTextBlock[];
excerpt?: string;
date: Date;
author?: string;
authors?: string[];
categories?: string[];
tags?: string[];
meta?: Record<string, unknown>;
featuredImage?: string;
}
API エンドポイント
インポートシステムは以下のエンドポイントを公開します:
URL のプローブ
POST /_emdash/api/import/probe
Content-Type: application/json
{ "url": "https://example.com" }
検出されたプラットフォームと推奨アクションを返します。
WXR の分析
POST /_emdash/api/import/wordpress/analyze
Content-Type: multipart/form-data
file: [WordPress export .xml]
スキーマ互換性付きの投稿タイプ分析を返します。
スキーマの準備
POST /_emdash/api/import/wordpress/prepare
Content-Type: application/json
{
"postTypes": [
{ "name": "post", "collection": "posts", "enabled": true }
]
}
コレクションとフィールドを作成します。
インポートの実行
POST /_emdash/api/import/wordpress/execute
Content-Type: multipart/form-data
file: [WordPress export .xml]
config: { "postTypeMappings": { "post": { "collection": "posts" } } }
指定されたコレクションにコンテンツをインポートします。
メディアのインポート
POST /_emdash/api/import/wordpress/media
Content-Type: application/json
{
"attachments": [{ "id": 123, "url": "https://..." }],
"stream": true
}
ダウンロード/アップロード中に NDJSON 進行状況更新をストリーミングします。
URL の書き換え
POST /_emdash/api/import/wordpress/rewrite-urls
Content-Type: application/json
{
"urlMap": { "https://old.com/image.jpg": "/_emdash/media/abc123" }
}
新しいメディア URL で Portable Text コンテンツを更新します。
エラー処理
回復可能なエラー
- ネットワークタイムアウト — バックオフ付きでリトライ
- 単一アイテムのパース失敗 — ログ記録、スキップ、インポート継続
- メディアダウンロード失敗 — 手動処理用にマーク
致命的なエラー
- 無効なファイル形式 — エラーメッセージでインポート停止
- データベース接続切断 — インポート一時停止、再開可能
- ストレージクォータ超過 — インポート停止、使用量を表示
エラーレポート
インポート後:
Import Complete
✓ 125 posts imported
✓ 12 pages imported
✓ 85 media references recorded
⚠ 2 items had warnings:
- Post "Special Characters ñ" - title encoding fixed
- Page "About" - duplicate slug renamed to "about-1"
✗ 1 item failed:
- Post ID 456 - content parsing error (saved as draft)
失敗したアイテムはレビュー用に元のコンテンツを _importError に含めて下書きとして保存されます。
カスタムソースの構築
他のプラットフォーム用のソースを作成:
import type { ImportSource } from "emdash/import";
export const mySource: ImportSource = {
id: "my-platform",
name: "My Platform",
description: "Import from My Platform",
icon: "globe",
canProbe: true,
async probe(url) {
// URL がプラットフォームに一致するか確認
const response = await fetch(`${url}/api/info`);
if (!response.ok) return null;
return {
sourceId: "my-platform",
confidence: "definite",
detected: { platform: "my-platform" },
// ...
};
},
async analyze(input, context) {
// コンテンツの解析と分析
// ImportAnalysis を返す
},
async *fetchContent(input, options) {
// 各コンテンツピースに対して NormalizedItem を yield
for (const item of items) {
yield {
sourceId: item.id,
postType: "post",
title: item.title,
content: convertToPortableText(item.body),
// ...
};
}
},
};
EmDash 設定にソースを登録:
import { mySource } from "./src/import/custom-source";
export default defineConfig({
integrations: [
emdash({
import: {
sources: [mySource],
},
}),
],
});
次のステップ
- WordPress からの移行 — 完全な WordPress 移行ガイド
- プラグインの移植 — WordPress プラグインを EmDash に移植