Seedファイルフォーマット

このページ

Seedファイルは、EmDashサイトを初期化するJSONドキュメントです。コレクション、フィールド、タクソノミー、メニュー、リダイレクト、ウィジェットエリア、サイト設定、およびオプションのサンプルコンテンツを定義します。

ルート構造

Seedファイルには次のトップレベルの構造があります:

{
	"$schema": "https://emdashcms.com/seed.schema.json",
	"version": "1",
	"meta": {},
	"settings": {},
	"collections": [],
	"taxonomies": [],
	"bylines": [],
	"menus": [],
	"redirects": [],
	"widgetAreas": [],
	"sections": [],
	"content": {}
}
フィールド必須説明
$schemastringいいえエディタ検証用のJSONスキーマURL
version"1"はいSeedフォーマットバージョン
metaobjectいいえSeedに関するメタデータ
settingsobjectいいえサイト設定
collectionsarrayいいえコレクション定義
taxonomiesarrayいいえタクソノミー定義
bylinesarrayいいえバイラインプロファイル定義
menusarrayいいえナビゲーションメニュー
redirectsarrayいいえリダイレクトルール
widgetAreasarrayいいえウィジェットエリア定義
sectionsarrayいいえ再利用可能なコンテンツブロック
contentobjectいいえサンプルコンテンツエントリ

Meta

metaオブジェクトには、Seedに関するオプションの説明的なメタデータが含まれます:

{
	"meta": {
		"name": "Blog Starter",
		"description": "A simple blog with posts, pages, and categories",
		"author": "EmDash"
	}
}

Settings

settingsオブジェクトには、サイト全体の設定値が含まれます:

{
	"settings": {
		"title": "My Site",
		"tagline": "A modern CMS",
		"postsPerPage": 10,
		"dateFormat": "MMMM d, yyyy"
	}
}

設定はsite:プレフィックス付きでoptionsテーブルに適用されます。セットアップウィザードは、Seedファイルからtitletaglineを事前入力し(提供されている場合)、ユーザーが初期設定中にそれらを上書きできるようにします。

Collections

各コレクション定義は、データベースにコンテンツタイプを作成します:

{
	"collections": [
		{
			"slug": "posts",
			"label": "Posts",
			"labelSingular": "Post",
			"description": "Blog posts",
			"icon": "file-text",
			"supports": ["drafts", "revisions"],
			"fields": [
				{
					"slug": "title",
					"label": "Title",
					"type": "string",
					"required": true
				},
				{
					"slug": "content",
					"label": "Content",
					"type": "portableText"
				},
				{
					"slug": "featured_image",
					"label": "Featured Image",
					"type": "image"
				}
			]
		}
	]
}

コレクションプロパティ

プロパティ必須説明
slugstringはいURL安全な識別子(小文字、アンダースコア)
labelstringはい複数形の表示名
labelSingularstringいいえ単数形の表示名
descriptionstringいいえ管理UI説明
iconstringいいえLucideアイコン名
supportsarrayいいえ機能:"drafts""revisions"
fieldsarrayはいフィールド定義

フィールドプロパティ

プロパティ必須説明
slugstringはいカラム名(小文字、アンダースコア)
labelstringはい表示名
typestringはいフィールドタイプ
requiredbooleanいいえ検証:フィールドには値が必要
uniquebooleanいいえ検証:値は一意である必要がある
defaultValueanyいいえ新しいエントリのデフォルト値
validationobjectいいえ追加の検証ルール
widgetstringいいえ管理UIウィジェットオーバーライド
optionsobjectいいえウィジェット固有の設定

フィールドタイプ

タイプ説明格納形式
string短いテキストTEXT
text長いテキスト(textarea)TEXT
number数値REAL
integer整数INTEGER
boolean真/偽INTEGER
date日付値TEXT (ISO 8601)
datetime日時TEXT (ISO 8601)
emailメールアドレスTEXT
urlURLTEXT
slugURL安全な文字列TEXT
portableTextリッチテキストコンテンツJSON
image画像参照JSON
fileファイル参照JSON
json任意のJSONJSON
reference別のエントリへの参照TEXT

Taxonomies

タクソノミーはコンテンツの分類システムです:

{
	"taxonomies": [
		{
			"name": "category",
			"label": "Categories",
			"labelSingular": "Category",
			"hierarchical": true,
			"collections": ["posts"],
			"terms": [
				{ "slug": "news", "label": "News" },
				{ "slug": "tutorials", "label": "Tutorials" },
				{
					"slug": "advanced",
					"label": "Advanced Tutorials",
					"parent": "tutorials"
				}
			]
		},
		{
			"name": "tag",
			"label": "Tags",
			"labelSingular": "Tag",
			"hierarchical": false,
			"collections": ["posts"]
		}
	]
}

タクソノミープロパティ

プロパティ必須説明
namestringはい一意の識別子
labelstringはい複数形の表示名
labelSingularstringいいえ単数形の表示名
hierarchicalbooleanはいネストされたタームを許可(カテゴリ)またはフラット(タグ)
collectionsarrayはいこのタクソノミーが適用されるコレクション
termsarrayいいえ事前定義されたターム

タームプロパティ

プロパティ必須説明
slugstringはいURL安全な識別子
labelstringはい表示名
descriptionstringいいえターム説明
parentstringいいえ親タームスラッグ(階層のみ)

menus配列は、管理画面から編集可能なナビゲーションメニューを定義します:

{
	"menus": [
		{
			"name": "primary",
			"label": "Primary Navigation",
			"items": [
				{ "type": "custom", "label": "Home", "url": "/" },
				{ "type": "page", "ref": "about" },
				{ "type": "custom", "label": "Blog", "url": "/posts" },
				{
					"type": "custom",
					"label": "External",
					"url": "https://example.com",
					"target": "_blank"
				}
			]
		}
	]
}

メニューアイテムタイプ

タイプ説明必須フィールド
customカスタムURLurl
pageページエントリへのリンクref
post投稿エントリへのリンクref
taxonomyタクソノミーアーカイブへのリンクrefcollection
collectionコレクションアーカイブへのリンクcollection

メニューアイテムプロパティ

プロパティ説明
typestringアイテムタイプ(上記参照)
labelstring表示テキスト(ページ/投稿refの場合は自動生成)
urlstringカスタムURL(customタイプの場合)
refstringSeed内のコンテンツID(page/postタイプの場合)
collectionstringコレクションスラッグ
targetstring新しいウィンドウの場合は"_blank"
titleAttrstringHTMLタイトル属性
cssClassesstringカスタムCSSクラス
childrenarrayネストされたメニューアイテム

Bylines

バイラインプロファイルは所有権(author_id)とは別です。再利用可能なバイラインIDを一度定義し、コンテンツエントリから参照します。

{
	"bylines": [
		{
			"id": "editorial",
			"slug": "emdash-editorial",
			"displayName": "EmDash Editorial"
		},
		{
			"id": "guest",
			"slug": "guest-contributor",
			"displayName": "Guest Contributor",
			"isGuest": true
		}
	]
}
プロパティ必須説明
idstringはいcontent[].bylinesで使用されるSeedローカルID
slugstringはいURL安全なバイラインスラッグ
displayNamestringはいテンプレートとAPIに表示される名前
biostringいいえオプションのプロファイル略歴
websiteUrlstringいいえオプションのウェブサイトURL
isGuestbooleanいいえバイラインをゲストプロファイルとしてマーク

Redirects

redirects配列は、移行後にレガシーURLを保持するリダイレクトルールを定義します:

{
	"redirects": [
		{ "source": "/old-about", "destination": "/about" },
		{ "source": "/legacy-feed", "destination": "/rss.xml", "type": 308 },
		{
			"source": "/category/news",
			"destination": "/categories/news",
			"groupName": "migration"
		}
	]
}

リダイレクトプロパティ

プロパティ必須説明
sourcestringはいソースパス(/で始まる必要があります)
destinationstringはい宛先パス(/で始まる必要があります)
typenumberいいえHTTPステータス:301302307、または308
enabledbooleanいいえリダイレクトがアクティブかどうか(デフォルト:true
groupNamestringいいえ管理フィルタリング/検索用のオプションのグループ化ラベル

Widget Areas

widgetAreas配列は、設定可能なコンテンツ領域を定義します:

{
	"widgetAreas": [
		{
			"name": "sidebar",
			"label": "Main Sidebar",
			"description": "Appears on blog posts and pages",
			"widgets": [
				{
					"type": "component",
					"title": "Recent Posts",
					"componentId": "core:recent-posts",
					"props": { "count": 5 }
				},
				{
					"type": "menu",
					"title": "Quick Links",
					"menuName": "footer"
				},
				{
					"type": "content",
					"title": "About",
					"content": [
						{
							"_type": "block",
							"style": "normal",
							"children": [{ "_type": "span", "text": "Welcome to our site!" }]
						}
					]
				}
			]
		}
	]
}

ウィジェットタイプ

タイプ説明必須フィールド
contentリッチテキストコンテンツcontent(Portable Text)
menuメニューをレンダリングmenuName
component登録されたコンポーネントcomponentId

組み込みコンポーネント

コンポーネントID説明
core:recent-posts最近の投稿のリスト
core:categoriesカテゴリリスト
core:tagsタグクラウド
core:search検索フォーム
core:archives月別アーカイブ

Sections

セクションは、エディタが/sectionスラッシュコマンドを介してPortable Textフィールドに挿入する再利用可能なコンテンツブロックです:

{
	"sections": [
		{
			"slug": "hero-centered",
			"title": "Centered Hero",
			"description": "Full-width hero with centered heading and CTA button",
			"keywords": ["hero", "banner", "header", "landing"],
			"content": [
				{
					"_type": "block",
					"style": "h1",
					"children": [{ "_type": "span", "text": "Welcome to Our Site" }]
				},
				{
					"_type": "block",
					"children": [
						{ "_type": "span", "text": "Your compelling tagline goes here." }
					]
				}
			]
		}
	]
}

セクションプロパティ

プロパティ必須説明
slugstringはいURL安全な識別子
titlestringはいセクションピッカーに表示される表示名
descriptionstringいいえこのセクションを使用するタイミングを説明
keywordsarrayいいえセクションを見つけるための検索用語
contentarrayはいPortable Textブロック
sourcestringいいえ"theme"(Seedのデフォルト)または"import"

Seedファイルからのセクションはsource: "theme"とマークされ、管理UIから削除できません。エディタは独自のセクション(source: "user")を作成でき、コンテンツの編集時に任意のセクションタイプを挿入できます。

Content

contentオブジェクトには、コレクション別に整理されたサンプルコンテンツエントリが含まれます:

{
	"content": {
		"posts": [
			{
				"id": "hello-world",
				"slug": "hello-world",
				"status": "published",
				"bylines": [
					{ "byline": "editorial" },
					{ "byline": "guest", "roleLabel": "Guest essay" }
				],
				"data": {
					"title": "Hello World",
					"content": [
						{
							"_type": "block",
							"style": "normal",
							"children": [{ "_type": "span", "text": "Welcome!" }]
						}
					],
					"excerpt": "Your first post."
				},
				"taxonomies": {
					"category": ["news"],
					"tag": ["welcome", "first-post"]
				}
			}
		],
		"pages": [
			{
				"id": "about",
				"slug": "about",
				"status": "published",
				"data": {
					"title": "About Us",
					"content": [
						{
							"_type": "block",
							"style": "normal",
							"children": [{ "_type": "span", "text": "About page content." }]
						}
					]
				}
			}
		]
	}
}

コンテンツエントリプロパティ

プロパティ必須説明
idstringはい参照用のSeedローカルID
slugstringはいURLスラッグ
statusstringいいえ"published"または"draft"(デフォルト:"published"
dataobjectはいフィールド値
bylinesarrayいいえ順序付けられたバイラインクレジット(byline、オプションroleLabel
taxonomiesobjectいいえタクソノミー名によるターム割り当て

Content References

$ref:プレフィックスを使用して他のコンテンツエントリを参照します:

{
	"data": {
		"related_posts": ["$ref:another-post", "$ref:third-post"]
	}
}

$ref:プレフィックスは、シード中にSeed IDをデータベースIDに解決します。

Media References

URLから画像を含める:

{
	"data": {
		"featured_image": {
			"$media": {
				"url": "https://images.unsplash.com/photo-xxx",
				"alt": "Description of the image",
				"filename": "hero.jpg",
				"caption": "Photo by Someone"
			}
		}
	}
}

.emdash/media/からローカル画像を含める:

{
	"data": {
		"featured_image": {
			"$media": {
				"file": "hero.jpg",
				"alt": "Description of the image"
			}
		}
	}
}

メディアプロパティ

プロパティ必須説明
urlstringはい*ダウンロードするリモートURL
filestringはい*.emdash/media/内のローカルファイル名
altstringいいえアクセシビリティ用の代替テキスト
filenamestringいいえファイル名を上書き
captionstringいいえメディアキャプション

*urlまたはfileのいずれかが必要です。両方は不可。

Applying Seeds Programmatically

CLIツールまたはスクリプト用のSeed APIを使用します:

import { applySeed, validateSeed } from "emdash/seed";
import seedData from "./.emdash/seed.json";

// 最初に検証
const validation = validateSeed(seedData);
if (!validation.valid) {
	console.error(validation.errors);
	process.exit(1);
}

// Seedを適用
const result = await applySeed(db, seedData, {
	includeContent: true,
	onConflict: "skip",
	storage: myStorage,
	baseUrl: "http://localhost:4321",
});

console.log(result);
// {
//   collections: { created: 2, skipped: 0 },
//   fields: { created: 8, skipped: 0 },
//   taxonomies: { created: 2, terms: 5 },
//   bylines: { created: 2, skipped: 0 },
//   menus: { created: 1, items: 4 },
//   redirects: { created: 3, skipped: 0 },
//   widgetAreas: { created: 1, widgets: 3 },
//   settings: { applied: 3 },
//   content: { created: 3, skipped: 0 },
//   media: { created: 2, skipped: 0 }
// }

Applyオプション

オプションデフォルト説明
includeContentbooleanfalseサンプルコンテンツエントリを作成
onConflictstring"skip""skip""update"、または"error"
mediaBasePathstringローカルメディアファイルのベースパス
storageStorageメディアアップロード用のストレージアダプタ
baseUrlstringメディアURLのベースURL

Idempotency

シードは複数回安全に実行できます。エンティティタイプ別の競合動作:

エンティティ動作
Collectionスラッグが存在する場合はスキップ
Fieldcollection + スラッグが存在する場合はスキップ
タクソノミー定義名前が存在する場合はスキップ
タクソノミーターム名前 + スラッグが存在する場合はスキップ
バイラインプロファイルスラッグが存在する場合はスキップ
メニュー名前が存在する場合はスキップ
メニューアイテムすべて置換(メニューは再作成されます)
リダイレクトソースが存在する場合はスキップ
ウィジェットエリア名前が存在する場合はスキップ
ウィジェットすべて置換(エリアは再作成されます)
セクションスラッグが存在する場合はスキップ
設定更新(設定は変更されることを意図しています)
コンテンツコレクション内にスラッグが存在する場合はスキップ

Validation

Seedファイルは適用前に検証されます:

import { validateSeed } from "emdash/seed";

const { valid, errors, warnings } = validateSeed(seedData);

if (!valid) {
	errors.forEach((e) => console.error(e));
}

warnings.forEach((w) => console.warn(w));

検証は次のことを確認します:

  • 必須フィールドが存在する
  • スラッグがそのタイプに対して有効である(コレクションとフィールドのスラッグは小文字、数字、アンダースコアを許可します。他のスラッグはハイフンも許可します)
  • フィールドタイプが有効である
  • 参照が既存のコンテンツを指している
  • 階層タームの親が存在する
  • リダイレクトパスが安全なローカルURLである
  • リダイレクトソースが一意である
  • コレクション内に重複するスラッグがない

CLI Commands

.emdash/seed.jsonpackage.json#emdash.seed、またはseed/seed.jsonのSeedファイルは、ビルドにインライン化され、データベースが空の場合の最初のリクエストで適用されます。既存のサイトのスキーマ(およびオプションでそのコンテンツ)をSeedファイルとしてエクスポートするには:

# 新しいプロジェクトではまだ.emdash/が存在しない可能性があるため`mkdir -p`
mkdir -p .emdash

# 現在のスキーマをSeedファイルとしてエクスポート
npx emdash export-seed > .emdash/seed.json

# コンテンツ付きでエクスポート
npx emdash export-seed --with-content > .emdash/seed.json

Next Steps