← Files WixARCHIVED FILE

skills/wix-headless-templates/cms/seed/SEED.md

6.82 KB · Oct 8, 2026 · 12:02 UTC

↓ Download file

See the change to this file →

# CMS — seeding

Seed by **running `seed-cms.mjs` with a plan file** — don't hand-write the REST calls.
The script mints its own site token via the Wix CLI (logged-in session + `wix.config.json`
required), installs the Wix Data (CMS) app if needed, resolves every IMAGE value into Wix
Media in one parallel wave, and creates everything in order: per collection — create
(schema + permissions) → bulk-insert items → wire multi-references → verify persistence.

```bash
# from the project root (where wix.config.json lives):
node <SKILL_ROOT>/templates/cms/seed/seed-cms.mjs plan.json
```

`plan.json` is plain data — **it IS the site's content model**: the collections, their field
schemas, and the items the pages will render. Write it from the brief. Default to **one or
two content collections with ~3–6 items each** (the seed shows the shape; the owner adds the
rest in the dashboard). Give any collection that gets a detail page a `slug` TEXT field, and
every content item an image on an IMAGE field (a content site without images looks broken).

```json
{
  "collections": [
    {
      "id": "categories", "displayName": "Categories",
      "fields": [{ "key": "name", "type": "TEXT" }],
      "items": [{ "name": "Cakes" }, { "name": "Breads" }]
    },
    {
      "id": "recipes", "displayName": "Recipes",
      "fields": [
        { "key": "title", "type": "TEXT" },
        { "key": "slug", "type": "TEXT" },
        { "key": "summary", "type": "TEXT" },
        { "key": "body", "type": "RICH_TEXT" },
        { "key": "photo", "type": "IMAGE" },
        { "key": "publishDate", "type": "DATE" },
        { "key": "categories", "type": "MULTI_REFERENCE", "referencedCollectionId": "categories" }
      ],
      "items": [
        { "title": "Chocolate Layer Cake", "slug": "chocolate-layer-cake",
          "summary": "Three layers, one ganache.", "body": "<p>Cream the butter…</p>",
          "photo": "https://…", "publishDate": "2026-08-01", "categories": [0] },
        { "title": "Country Sourdough", "slug": "country-sourdough",
          "summary": "A 24-hour loaf.", "body": "<p>Feed the starter…</p>",
          "photo": "https://…", "publishDate": "2026-08-10", "categories": [1] },
        { "title": "Pavlova", "slug": "pavlova",
          "summary": "Crisp shell, soft heart.", "body": "<p>Whip the whites…</p>",
          "photo": "https://…", "publishDate": "2026-08-20", "categories": [0] }
      ]
    }
  ]
}
```

- `id` — the collection id the frontend binds to, verbatim (no namespace; Wix doesn't rename
  it). Item keys must match the field `key`s exactly — the script fails loud on a key the
  schema doesn't have (the API would silently drop it).
- Field `type` — `TEXT`, `NUMBER`, `BOOLEAN`, `DATE`, `DATETIME`, `TIME` (a `"hh:mm:ss.SSS"`
  string, stored as text), `URL`, `EMAIL`, `IMAGE`, `RICH_TEXT` (an HTML string, stored verbatim),
  `ARRAY_STRING` (tags: an array of strings), `REFERENCE`, `MULTI_REFERENCE`.
- `IMAGE` values — the default is `{ "prompt": "..." }` (AI-generated, ~1 Wix AI credit per
  image, account-billed): brand-contextual — subject, aesthetic/mood, palette, lighting —
  always ending "no text, no watermarks". At least one image in the set shows the real subject of the business — the actual product/space/service, not abstract decoration. For an asset the user actually supplied use
  `{ "path": "..." }` (a file on this machine — uploaded to Wix Media) or an https URL string
  (their own hosted URL; verify it with `curl -sI` → 200) — never a stock-photo or guessed URL. Images
  resolve in parallel and never block the seed; a failed image leaves that field unset (the
  item stays text-only).
- `DATE`/`DATETIME` values are ISO strings — the script wraps both as `{ "$date": iso }` (the
  form the app's reads and date filters are proven against; a `"YYYY-MM-DD"` string would be
  stored as text). A `TIME` value stays a string.
- References: **order collections so targets come first.** A `REFERENCE` value is the target
  item's index in its collection's `items` array; `MULTI_REFERENCE` is an array of indices
  (set at insert it would be silently dropped — the script wires these via
  `POST /wix-data/v2/bulk/items/insert-references`; at runtime the app does the same through
  `linkItems` / `unlinkItems` in `wix/cms/items.ts`).
- `permissions` — omit for the **public-read** default
  (`read: ANYONE`, writes `ADMIN`). Other shapes (per action: `ANYONE` › `SITE_MEMBER` ›
  `SITE_MEMBER_AUTHOR` › `ADMIN`):

  | preset | `read` / `insert` / `update` / `remove` | use |
  |---|---|---|
  | public-read (default) | `ANYONE` / `ADMIN` / `ADMIN` / `ADMIN` | admin content, anyone reads |
  | collaborative | `ANYONE` / `ANYONE` / `ANYONE` / `ANYONE` | visitor-written shared board (anonymous, unscoped) |
  | member-private | `SITE_MEMBER_AUTHOR` / `SITE_MEMBER` / `SITE_MEMBER_AUTHOR` / `SITE_MEMBER_AUTHOR` | per-user "my…" rows — **seed it EMPTY** (rows seeded here would be owned by the admin, invisible to members) |
  | member-shared-read-only | `SITE_MEMBER` / `ADMIN` / `ADMIN` / `ADMIN` | gated: any member reads, seed/admin writes |
  | public-wall | `ANYONE` / `SITE_MEMBER` / `SITE_MEMBER_AUTHOR` / `SITE_MEMBER_AUTHOR` | members post, everyone reads |

  `read` is the privacy decision — a public collection's `read` MUST be `ANYONE` or the
  visitor frontend reads **zero items with no error**.

**Seeding is additive — never delete or overwrite existing content** (an existing collection
is left as-is; its items are appended); ask first if a cleanup seems needed.

## Supplied content

The general rules are in `templates/shared/SUPPLIED-CONTENT.md`. For the CMS the user's data
defines the schema: each distinct table, sheet or file becomes a collection, its columns become
`fields` with a type read from the values (`TEXT`, `NUMBER`, `DATE`, `IMAGE` for image URLs,
`RICH_TEXT` for HTML), and its rows become `items`. Keep the user's column names as field keys. A
column whose values point at rows of another table becomes a `MULTI_REFERENCE`. When a column's
type is ambiguous, ask.

## Escape hatch — individual functions
`setupCms` composes exported steps — `installDataApp`, `createCollection`, `importImage`,
`bulkInsertItems`, `insertReferences`, `verifyItems`, plus `makeCtx()` — import them only
for a partial re-seed.

## Reference
Unexpected shape or an uncovered operation → read the live Wix API reference; every call the script
makes carries a `docs:` line with its reference page.
Endpoints used: `POST /wix-data/v2/collections` (Create Data Collection),
`POST /wix-data/v2/bulk/items/insert` (Bulk Insert Data Items),
`POST /wix-data/v2/bulk/items/insert-references` (Bulk Insert Data Item References),
`POST /wix-data/v2/items/query` (Query Data Items — the verify step),
`POST /site-media/v1/files/import` (Import File),
`POST /apps-installer-service/v1/app-instance/install` (Install App).

SHA-256: 80d5c4a5e02bf0723bca4817091a5b54038f7200465889cfb939dc11ab7a643e