@wix/agent-skills 1.23.0 → 1.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +2 -1
- package/skills/wix-app/SKILL.md +4 -1
- package/skills/wix-app/references/BUSINESS_MANAGER_THEME.md +108 -0
- package/skills/wix-app/references/BUSINESS_MANAGER_TOKENS.md +81 -0
- package/skills/wix-app/references/DASHBOARD_MODAL.md +41 -0
- package/skills/wix-app/references/DASHBOARD_PAGE.md +2 -0
- package/skills/wix-app/references/DASHBOARD_PLUGIN.md +19 -4
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +64 -50
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +5 -4
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +8 -7
- package/skills/wix-app/references/dashboard-page/DYNAMIC_PARAMETERS.md +21 -38
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +4 -3
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +28 -25
- package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +8 -2
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +12 -14
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +4 -3
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +66 -9
- package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +25 -0
- package/skills/wix-app/references/editor-react-component/OVERFLOW.md +146 -0
- package/skills/wix-app/references/editor-react-component/PARTS.md +6 -0
- package/skills/wix-app/scripts/scan-a11y-eslint.cjs +25 -1
- package/skills/wix-headless/SKILL.md +0 -1
- package/skills/wix-headless/references/CAPABILITIES.md +3 -3
- package/skills/wix-headless/references/DISCOVERY.md +1 -1
- package/skills/wix-headless/references/SDK_HANDOFF.md +1 -1
- package/skills/wix-headless/references/SEED.md +1 -1
- package/skills/wix-headless/references/SETUP.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +1 -1
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-experiences.md +2 -2
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +3 -14
- package/skills/wix-headless/scripts/bootstrap.mjs +156 -0
- package/skills/{wix-headless-fast → wix-headless-kit}/SKILL.md +83 -64
- package/skills/{wix-headless-fast → wix-headless-kit}/cold-start/bootstrap.mjs +2 -2
- package/skills/{wix-headless-fast → wix-headless-kit}/cold-start/cold-start.md +26 -35
- package/skills/wix-headless-kit/guides/capabilities.md +76 -0
- package/skills/wix-headless-kit/guides/feedback.md +98 -0
- package/skills/{wix-headless-fast → wix-headless-kit}/guides/migration.md +20 -9
- package/skills/{wix-headless-fast → wix-headless-kit}/install/AGENTS.md +5 -2
- package/skills/{wix-headless-fast → wix-headless-kit}/install/attach.mjs +5 -2
- package/skills/wix-headless-kit/install/bootstrap.mjs +156 -0
- package/skills/{wix-headless-fast → wix-headless-kit}/install/check.mjs +2 -2
- package/skills/wix-headless-kit/install/context.mjs +169 -0
- package/skills/{wix-headless-fast → wix-headless-kit}/install/deploy.mjs +17 -4
- package/skills/{wix-headless-fast → wix-headless-kit}/install/setup.mjs +89 -55
- package/skills/{wix-headless-fast → wix-headless-kit}/install/templates.mjs +1 -1
- package/skills/wix-manage/SKILL.md +2 -8
- package/skills/wix-manage/references/cms/cms-dashboard-navigation.md +2 -2
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +263 -31
- package/skills/wix-manage/references/cms/cms-publishing-flow.md +15 -15
- package/skills/wix-manage/references/cms/cms-schema-management.md +58 -7
- package/skills/wix-manage/references/sites/query-sites.md +1 -8
- package/skills/wix-auth/SKILL.md +0 -12
- package/skills/wix-auth/references/device-flow.md +0 -140
- package/skills/wix-headless-fast/install/context.mjs +0 -126
- package/skills/wix-manage/references/cms/cms-data-operations-extended.md +0 -263
- package/skills/wix-manage/references/cms/cms-references-and-relationships.md +0 -162
- /package/skills/{wix-headless-fast → wix-headless-kit}/guides/existing-site.md +0 -0
- /package/skills/{wix-headless-fast → wix-headless-kit}/guides/reference-mode.md +0 -0
- /package/skills/{wix-headless-fast → wix-headless-kit}/install/agents-md.mjs +0 -0
- /package/skills/{wix-headless-fast → wix-headless-kit}/install/lock.mjs +0 -0
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# Device Flow
|
|
2
|
-
|
|
3
|
-
Implements the OAuth 2.0 Device Authorization Grant (RFC 8628). The user approves in a browser while the agent polls for tokens.
|
|
4
|
-
|
|
5
|
-
Produces two kinds of token:
|
|
6
|
-
- **Account token** — works for account-level APIs (e.g. list sites). Expires in ~4 hours.
|
|
7
|
-
- **Site token** — required for any site-specific API (contacts, products, bookings, …). Derived on demand from the account `refreshToken` + a `siteId`. Expires in ~15 minutes.
|
|
8
|
-
|
|
9
|
-
## Constants
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
BASE_URL = https://manage.wix.com
|
|
13
|
-
CLIENT_ID = 6f95cec8-3e98-48b9-b4e5-1fb92fcd9973
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Required headers on every request:
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
X-XSRF-TOKEN: nocheck
|
|
20
|
-
Cookie: XSRF-TOKEN=nocheck
|
|
21
|
-
User-Agent: wix-cli
|
|
22
|
-
Content-Type: application/json (on POST requests)
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Step 1 — Request a device code
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
GET /oauth2/device/code?clientId=CLIENT_ID
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Response:
|
|
32
|
-
|
|
33
|
-
```json
|
|
34
|
-
{ "deviceCode": "…", "userCode": "XXXXXXXX", "verificationUri": "https://users.wix.com/login/device-login", "expiresIn": 600 }
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Step 2 — Ask the user to authorize
|
|
38
|
-
|
|
39
|
-
Show the user this URL and code:
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
URL: {verificationUri}?color=developer&studio=true
|
|
43
|
-
Code: {userCode}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Make sure the user has copied or noted the code **before** opening the link — they'll need to enter it on the page. Present the URL as a clickable link that opens in a new tab if your interface supports it.
|
|
47
|
-
|
|
48
|
-
## Step 3 — Poll for the token
|
|
49
|
-
|
|
50
|
-
Every 3 seconds, POST:
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
POST /oauth2/token
|
|
54
|
-
{ "clientId": "CLIENT_ID", "grantType": "urn:ietf:params:oauth:grant-type:device_code", "scope": "offline_access", "deviceCode": "{deviceCode}" }
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
- While waiting: server returns `400` with `{ "error": "authorization_pending" }` or `{ "message": "Device code is not yet verified" }` — keep polling.
|
|
58
|
-
- On approval: `200` with `{ "access_token": "…", "refresh_token": "…", "expires_in": 14400 }`.
|
|
59
|
-
- Stop polling after `expiresIn` seconds total.
|
|
60
|
-
|
|
61
|
-
## Step 4 — Fetch user info
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
GET /_serverless/wix-cli-userinfo/userinfo
|
|
65
|
-
Authorization: Bearer {access_token}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Response: `{ "userId": "…", "email": "…" }`
|
|
69
|
-
|
|
70
|
-
## Step 5 — Persist
|
|
71
|
-
|
|
72
|
-
At this point you already hold all the values in memory — store them securely to whatever credential store your platform provides (file, secrets manager, environment variables, etc.), without asking the user to enter them manually. **Treat these as secrets: never print them in the conversation, never include them in logs, and never send them to any service other than the Wix APIs.**
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
accessToken string
|
|
76
|
-
refreshToken string
|
|
77
|
-
expiresIn number (seconds)
|
|
78
|
-
issuedAt number (Unix timestamp in seconds, recorded at the moment tokens were received)
|
|
79
|
-
userInfo { userId, email }
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Getting a valid token on subsequent calls
|
|
83
|
-
|
|
84
|
-
**Account token**
|
|
85
|
-
|
|
86
|
-
1. Load stored credentials. If missing → run the device flow above.
|
|
87
|
-
2. Check validity: `issuedAt + expiresIn - 600 > now` (10-min buffer).
|
|
88
|
-
3. If expired → refresh silently:
|
|
89
|
-
|
|
90
|
-
```
|
|
91
|
-
POST /oauth2/token
|
|
92
|
-
{ "clientId": "CLIENT_ID", "grantType": "refresh_token", "refreshToken": "{refreshToken}" }
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Same response shape as Step 3. Persist the new tokens with a fresh `issuedAt`.
|
|
96
|
-
|
|
97
|
-
4. If refresh returns `400 invalid_grant` → session revoked; run the device flow again.
|
|
98
|
-
|
|
99
|
-
**Site token**
|
|
100
|
-
|
|
101
|
-
The account token returns `403` on site-level endpoints. Derive a site token on demand:
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
POST /oauth2/token
|
|
105
|
-
{ "clientId": "CLIENT_ID", "grantType": "refresh_token", "refreshToken": "{refreshToken}", "siteId": "{siteId}" }
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Response: `{ "access_token": "…", "refresh_token": "…", "expires_in": 900 }`
|
|
109
|
-
|
|
110
|
-
Re-derive on each use rather than caching — it expires in 15 minutes.
|
|
111
|
-
|
|
112
|
-
## Examples
|
|
113
|
-
|
|
114
|
-
**List sites (account token)**
|
|
115
|
-
|
|
116
|
-
```
|
|
117
|
-
POST https://www.wixapis.com/site-list/v2/sites/query
|
|
118
|
-
Authorization: Bearer {accountToken}
|
|
119
|
-
{ "query": { "filter": { "namespace": { "$in": ["WIX", "HEADLESS"] } }, "cursorPaging": { "limit": 100 } } }
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Returns `{ sites: [{ id, displayName, namespace, … }] }` — the `id` is the `siteId` for site-scoped calls.
|
|
123
|
-
|
|
124
|
-
> Without the `namespace` filter, headless sites are silently excluded from results.
|
|
125
|
-
|
|
126
|
-
**List contacts (site token)**
|
|
127
|
-
|
|
128
|
-
```
|
|
129
|
-
POST https://www.wixapis.com/contacts/v4/contacts/query
|
|
130
|
-
Authorization: Bearer {siteToken}
|
|
131
|
-
{ "query": { "paging": { "limit": 10 } } }
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
Returns `{ contacts: […] }`.
|
|
135
|
-
|
|
136
|
-
---
|
|
137
|
-
|
|
138
|
-
For the full Wix REST API reference — endpoints, request/response shapes, and field details — see [https://www.wix.com/skills/docs](https://www.wix.com/skills/docs).
|
|
139
|
-
|
|
140
|
-
For REST API recipes covering common management operations (stores, bookings, contacts, CMS, and more) — see [https://www.wix.com/skills/manage](https://www.wix.com/skills/manage).
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
// The site context of a project folder — the one place that says which site a call targets.
|
|
2
|
-
//
|
|
3
|
-
// node <SKILL_ROOT>/install/context.mjs [--refresh] [--no-pull] (prints one JSON object)
|
|
4
|
-
//
|
|
5
|
-
// Two identities live in a Wix project and are the same site almost always:
|
|
6
|
-
// deploy — `wix.config.json` (`siteId`, `appId`): where `wix release` uploads. The CLI's business.
|
|
7
|
-
// content — `.env.local` (`WIX_CLIENT_ID`, what `wix env pull` writes): the app the SDK client
|
|
8
|
-
// runs as, on every stack (the Astro integration reads WIX_CLIENT_ID from the env and
|
|
9
|
-
// never the config; the other stacks get it copied into src/wix/config.ts by deploy.mjs).
|
|
10
|
-
// They differ on a MIGRATION PREVIEW: a project whose config points at a fresh site created only to
|
|
11
|
-
// host the deployment, while `.env.local` carries the credentials of the site being migrated (the
|
|
12
|
-
// parent) and says so. Then every admin, discovery and seed call targets the parent, the SDK client
|
|
13
|
-
// is the parent's, and only the release goes to the child. Completing the migration is a CLI step
|
|
14
|
-
// that does not exist yet; this module only reads the state.
|
|
15
|
-
//
|
|
16
|
-
// `env pull` runs here when `.env.local` is missing (or --refresh): it is the source of the content
|
|
17
|
-
// identity, and the Astro build refuses to run without it. Non-interactive (CI=1); a failure is
|
|
18
|
-
// reported in `pullError` and the config's ids stand in, so a caller can still work offline.
|
|
19
|
-
import { spawnSync } from "node:child_process";
|
|
20
|
-
import { copyFileSync, existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
21
|
-
import { tmpdir } from "node:os";
|
|
22
|
-
import { join } from "node:path";
|
|
23
|
-
|
|
24
|
-
// The variables `wix env pull` writes for a migration preview. The names are the platform's and are
|
|
25
|
-
// spelled once, here.
|
|
26
|
-
export const ENV = {
|
|
27
|
-
clientId: "WIX_CLIENT_ID",
|
|
28
|
-
parentSiteId: "WIX_MIGRATION_PARENT_SITE_ID",
|
|
29
|
-
migration: "WIX_MIGRATION",
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/** KEY=value lines of a dotenv file, quotes stripped; null when the file is absent. */
|
|
33
|
-
export function readEnvFile(file) {
|
|
34
|
-
if (!existsSync(file)) return null;
|
|
35
|
-
const out = {};
|
|
36
|
-
for (const raw of readFileSync(file, "utf8").split(/\r?\n/)) {
|
|
37
|
-
const line = raw.trim();
|
|
38
|
-
if (!line || line.startsWith("#")) continue;
|
|
39
|
-
const eq = line.indexOf("=");
|
|
40
|
-
if (eq === -1) continue;
|
|
41
|
-
const key = line.slice(0, eq).trim().replace(/^export\s+/, "");
|
|
42
|
-
let value = line.slice(eq + 1).trim();
|
|
43
|
-
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
44
|
-
value = value.slice(1, -1).replace(/\\"/g, '"');
|
|
45
|
-
}
|
|
46
|
-
out[key] = value;
|
|
47
|
-
}
|
|
48
|
-
return out;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function readWixConfig(cwd) {
|
|
52
|
-
const file = join(cwd, "wix.config.json");
|
|
53
|
-
if (!existsSync(file)) return null;
|
|
54
|
-
try { return JSON.parse(readFileSync(file, "utf8")); } catch { return null; }
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const truthy = (v) => typeof v === "string" && /^(1|true|yes|on)$/i.test(v.trim());
|
|
58
|
-
|
|
59
|
-
const ENV_PULL = ["-y", "@wix/cli@latest", "env", "pull"];
|
|
60
|
-
const runPull = (dir) => spawnSync("npx", ENV_PULL, { cwd: dir, env: { ...process.env, CI: "1" }, encoding: "utf8", timeout: 180_000 });
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* `wix env pull` into `cwd/.env.local`. The CLI mounts `env` only once the folder reads as an Astro
|
|
64
|
-
* project (an astro.config.* file, or `site.outputDirectory` in the config); a folder that holds just
|
|
65
|
-
* the downloaded `wix.config.json` gets "unknown command 'env'". Then the pull runs in a temp folder
|
|
66
|
-
* holding a copy of the config and an empty astro.config.mjs, and the `.env.local` comes back here.
|
|
67
|
-
*/
|
|
68
|
-
export function pullEnv(cwd) {
|
|
69
|
-
const envFile = join(cwd, ".env.local");
|
|
70
|
-
let r = runPull(cwd);
|
|
71
|
-
if (r.status === 0 && existsSync(envFile)) return { ok: true, via: "in place" };
|
|
72
|
-
const notAProjectYet = /unknown command 'env'/.test(`${r.stderr}${r.stdout}`);
|
|
73
|
-
if (notAProjectYet) {
|
|
74
|
-
const tmp = mkdtempSync(join(tmpdir(), "wix-env-pull-"));
|
|
75
|
-
try {
|
|
76
|
-
copyFileSync(join(cwd, "wix.config.json"), join(tmp, "wix.config.json"));
|
|
77
|
-
writeFileSync(join(tmp, "astro.config.mjs"), "");
|
|
78
|
-
r = runPull(tmp);
|
|
79
|
-
if (r.status === 0 && existsSync(join(tmp, ".env.local"))) {
|
|
80
|
-
copyFileSync(join(tmp, ".env.local"), envFile);
|
|
81
|
-
return { ok: true, via: "stub project" };
|
|
82
|
-
}
|
|
83
|
-
} finally {
|
|
84
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return { ok: false, error: (r.stderr || r.stdout || "env pull produced no .env.local — is the Wix CLI logged in? (npx @wix/cli@latest whoami)").trim().slice(-400) };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* `{ deploy: { siteId, appId }, content: { siteId, clientId }, migration: { active, parentSiteId },
|
|
92
|
-
* env: { file, present, pulled }, pullError?, warnings: [] }`.
|
|
93
|
-
* `pull`: "auto" (default) pulls when `.env.local` is missing; true always; false never.
|
|
94
|
-
*/
|
|
95
|
-
export function siteContext({ cwd = process.cwd(), pull = "auto" } = {}) {
|
|
96
|
-
const config = readWixConfig(cwd) ?? {};
|
|
97
|
-
const deploy = { siteId: config.siteId ?? config.projectId ?? null, appId: config.appId ?? null };
|
|
98
|
-
const envFile = join(cwd, ".env.local");
|
|
99
|
-
let pulled = false, pullError;
|
|
100
|
-
if (deploy.siteId && (pull === true || (pull === "auto" && !existsSync(envFile)))) {
|
|
101
|
-
const r = pullEnv(cwd);
|
|
102
|
-
if (r.ok) pulled = r.via;
|
|
103
|
-
else pullError = r.error;
|
|
104
|
-
}
|
|
105
|
-
const env = readEnvFile(envFile) ?? {};
|
|
106
|
-
const parentSiteId = env[ENV.parentSiteId] || null;
|
|
107
|
-
const active = !!parentSiteId && (truthy(env[ENV.migration]) || env[ENV.migration] === undefined);
|
|
108
|
-
const migration = { active, parentSiteId: active ? parentSiteId : null };
|
|
109
|
-
const clientId = env[ENV.clientId] || deploy.appId;
|
|
110
|
-
const content = { siteId: active ? parentSiteId : deploy.siteId, clientId };
|
|
111
|
-
const warnings = [];
|
|
112
|
-
if (env[ENV.clientId] && deploy.appId && env[ENV.clientId] !== deploy.appId && !active) {
|
|
113
|
-
warnings.push(`.env.local ${ENV.clientId} differs from wix.config.json appId and no migration is declared — the SDK client runs as the env's app, the release goes to the config's site`);
|
|
114
|
-
}
|
|
115
|
-
if (active && migration.parentSiteId === deploy.siteId) {
|
|
116
|
-
warnings.push("the migration's parent site is the deploy site itself — nothing is being migrated");
|
|
117
|
-
}
|
|
118
|
-
return { deploy, content, migration, env: { file: envFile, present: Object.keys(env).length > 0, pulled }, ...(pullError ? { pullError } : {}), warnings };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// ---- CLI ----------------------------------------------------------------------------------------
|
|
122
|
-
if (process.argv[1] && /context\.mjs$/.test(process.argv[1])) {
|
|
123
|
-
const argv = process.argv.slice(2);
|
|
124
|
-
const pull = argv.includes("--no-pull") ? false : argv.includes("--refresh") ? true : "auto";
|
|
125
|
-
console.log(JSON.stringify(siteContext({ pull }), null, 2));
|
|
126
|
-
}
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: "CMS Data Operations Extended"
|
|
3
|
-
description: Additional CMS data operations including count, upsert (bulk save), and update by filter patterns.
|
|
4
|
-
---
|
|
5
|
-
# CMS Data Operations Extended
|
|
6
|
-
|
|
7
|
-
This recipe covers additional CMS data operations not included in the basic CRUD recipe.
|
|
8
|
-
|
|
9
|
-
## Prerequisites
|
|
10
|
-
|
|
11
|
-
1. Wix CMS enabled on the site
|
|
12
|
-
2. Collections created with data
|
|
13
|
-
3. API access with CMS permissions
|
|
14
|
-
|
|
15
|
-
## Required APIs
|
|
16
|
-
|
|
17
|
-
- **Data Items API**: [REST](https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/introduction)
|
|
18
|
-
|
|
19
|
-
## Count Data Items
|
|
20
|
-
|
|
21
|
-
Count items in a collection, optionally with filters.
|
|
22
|
-
|
|
23
|
-
**Endpoint**: `POST /wix-data/v2/items/count`
|
|
24
|
-
|
|
25
|
-
**Count All Items**:
|
|
26
|
-
```bash
|
|
27
|
-
curl -X POST \
|
|
28
|
-
'https://www.wixapis.com/wix-data/v2/items/count' \
|
|
29
|
-
-H 'Content-Type: application/json' \
|
|
30
|
-
-H 'Authorization: <AUTH>' \
|
|
31
|
-
-d '{
|
|
32
|
-
"dataCollectionId": "Products"
|
|
33
|
-
}'
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
**Response**:
|
|
37
|
-
```json
|
|
38
|
-
{
|
|
39
|
-
"totalCount": 42
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
**Count with Filter**:
|
|
44
|
-
```bash
|
|
45
|
-
curl -X POST \
|
|
46
|
-
'https://www.wixapis.com/wix-data/v2/items/count' \
|
|
47
|
-
-H 'Content-Type: application/json' \
|
|
48
|
-
-H 'Authorization: <AUTH>' \
|
|
49
|
-
-d '{
|
|
50
|
-
"dataCollectionId": "Products",
|
|
51
|
-
"filter": {
|
|
52
|
-
"inStock": true
|
|
53
|
-
}
|
|
54
|
-
}'
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
**Count with Complex Filter**:
|
|
58
|
-
```json
|
|
59
|
-
{
|
|
60
|
-
"dataCollectionId": "Products",
|
|
61
|
-
"filter": {
|
|
62
|
-
"$and": [
|
|
63
|
-
{ "inStock": true },
|
|
64
|
-
{ "price": { "$gte": 50 } }
|
|
65
|
-
]
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Bulk Save (Upsert)
|
|
71
|
-
|
|
72
|
-
Insert new items or update existing items in a single operation. This is useful for syncing data.
|
|
73
|
-
|
|
74
|
-
**Endpoint**: `POST /wix-data/v2/bulk/items/save`
|
|
75
|
-
|
|
76
|
-
**Request Body**:
|
|
77
|
-
```json
|
|
78
|
-
{
|
|
79
|
-
"dataCollectionId": "Products",
|
|
80
|
-
"dataItems": [
|
|
81
|
-
{
|
|
82
|
-
"id": "existing-item-id",
|
|
83
|
-
"data": {
|
|
84
|
-
"title": "Updated Product",
|
|
85
|
-
"price": 199.99,
|
|
86
|
-
"inStock": true
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
"data": {
|
|
91
|
-
"title": "New Product",
|
|
92
|
-
"price": 79.99,
|
|
93
|
-
"inStock": true
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
],
|
|
97
|
-
"returnEntity": true
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### Bulk Save Behavior
|
|
102
|
-
|
|
103
|
-
| Scenario | Action |
|
|
104
|
-
|----------|--------|
|
|
105
|
-
| No `id` provided | INSERT - Creates new item with generated ID |
|
|
106
|
-
| `id` provided, doesn't exist | INSERT - Creates new item with provided ID |
|
|
107
|
-
| `id` provided, exists | UPDATE - Replaces existing item |
|
|
108
|
-
|
|
109
|
-
> **Warning**: When updating, the entire item is replaced. Include all fields you want to keep.
|
|
110
|
-
|
|
111
|
-
## Update by Filter Pattern
|
|
112
|
-
|
|
113
|
-
Wix CMS doesn't have a direct "update by filter" API. Use this two-step pattern:
|
|
114
|
-
|
|
115
|
-
### 3.1: Query Items to Update
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
curl -X POST \
|
|
119
|
-
'https://www.wixapis.com/wix-data/v2/items/query' \
|
|
120
|
-
-H 'Content-Type: application/json' \
|
|
121
|
-
-H 'Authorization: <AUTH>' \
|
|
122
|
-
-d '{
|
|
123
|
-
"dataCollectionId": "Products",
|
|
124
|
-
"query": {
|
|
125
|
-
"filter": {
|
|
126
|
-
"category": "electronics"
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}'
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
### 3.2: Bulk Update Those Items
|
|
133
|
-
|
|
134
|
-
> **Important**: Use `id` (not `_id`) at the element level. The `data` object should NOT contain `_id`.
|
|
135
|
-
|
|
136
|
-
```bash
|
|
137
|
-
curl -X POST \
|
|
138
|
-
'https://www.wixapis.com/wix-data/v2/bulk/items/update' \
|
|
139
|
-
-H 'Content-Type: application/json' \
|
|
140
|
-
-H 'Authorization: <AUTH>' \
|
|
141
|
-
-d '{
|
|
142
|
-
"dataCollectionId": "Products",
|
|
143
|
-
"dataItems": [
|
|
144
|
-
{
|
|
145
|
-
"id": "item-1-from-query",
|
|
146
|
-
"data": {
|
|
147
|
-
"title": "Updated Title 1",
|
|
148
|
-
"price": 99.99,
|
|
149
|
-
"onSale": true
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
"id": "item-2-from-query",
|
|
154
|
-
"data": {
|
|
155
|
-
"title": "Updated Title 2",
|
|
156
|
-
"price": 149.99,
|
|
157
|
-
"onSale": true
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
]
|
|
161
|
-
}'
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Alternative: Bulk Patch (Partial Update)
|
|
165
|
-
|
|
166
|
-
If you only want to update specific fields without replacing the entire item, use Bulk Patch:
|
|
167
|
-
|
|
168
|
-
**Endpoint**: `POST /wix-data/v2/bulk/items/patch`
|
|
169
|
-
|
|
170
|
-
> **Important**: This endpoint uses `patches` array with `fieldModifications`, NOT `dataItems`. Do not confuse with bulk update.
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
curl -X POST \
|
|
174
|
-
'https://www.wixapis.com/wix-data/v2/bulk/items/patch' \
|
|
175
|
-
-H 'Content-Type: application/json' \
|
|
176
|
-
-H 'Authorization: <AUTH>' \
|
|
177
|
-
-d '{
|
|
178
|
-
"dataCollectionId": "Products",
|
|
179
|
-
"patches": [
|
|
180
|
-
{
|
|
181
|
-
"dataItemId": "item-1",
|
|
182
|
-
"fieldModifications": [
|
|
183
|
-
{
|
|
184
|
-
"fieldPath": "onSale",
|
|
185
|
-
"action": "SET_FIELD",
|
|
186
|
-
"setFieldOptions": {
|
|
187
|
-
"value": true
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
]
|
|
191
|
-
}
|
|
192
|
-
]
|
|
193
|
-
}'
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
> **Common error**: If you get `WDE0080: patches must not be empty`, you sent `dataItems` instead of `patches`. Use the format above.
|
|
197
|
-
|
|
198
|
-
## Truncate Collection
|
|
199
|
-
|
|
200
|
-
Remove all items from a collection (dangerous operation).
|
|
201
|
-
|
|
202
|
-
**Endpoint**: `POST /wix-data/v2/items/truncate`
|
|
203
|
-
|
|
204
|
-
```bash
|
|
205
|
-
curl -X POST \
|
|
206
|
-
'https://www.wixapis.com/wix-data/v2/items/truncate' \
|
|
207
|
-
-H 'Content-Type: application/json' \
|
|
208
|
-
-H 'Authorization: <AUTH>' \
|
|
209
|
-
-d '{
|
|
210
|
-
"dataCollectionId": "TestCollection"
|
|
211
|
-
}'
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
> **Warning**: This permanently deletes ALL items in the collection. Use with extreme caution.
|
|
215
|
-
|
|
216
|
-
## Aggregate Data
|
|
217
|
-
|
|
218
|
-
Perform calculations on collection data using a pipeline of sequential stages.
|
|
219
|
-
|
|
220
|
-
**Endpoint**: `POST /wix-data/v2/items/aggregate-pipeline`
|
|
221
|
-
|
|
222
|
-
**Count by Category**:
|
|
223
|
-
```bash
|
|
224
|
-
curl -X POST \
|
|
225
|
-
'https://www.wixapis.com/wix-data/v2/items/aggregate-pipeline' \
|
|
226
|
-
-H 'Content-Type: application/json' \
|
|
227
|
-
-H 'Authorization: <AUTH>' \
|
|
228
|
-
-d '{
|
|
229
|
-
"dataCollectionId": "Products",
|
|
230
|
-
"pipeline": {
|
|
231
|
-
"stages": [
|
|
232
|
-
{
|
|
233
|
-
"group": {
|
|
234
|
-
"groupIds": [
|
|
235
|
-
{"key": "category", "expression": {"fieldPath": "category"}}
|
|
236
|
-
],
|
|
237
|
-
"accumulators": [
|
|
238
|
-
{
|
|
239
|
-
"resultFieldName": "count",
|
|
240
|
-
"sum": {"expression": {"numeric": 1}}
|
|
241
|
-
}
|
|
242
|
-
]
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
]
|
|
246
|
-
}
|
|
247
|
-
}'
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
## Operation Comparison
|
|
251
|
-
|
|
252
|
-
| Operation | Use Case | Behavior |
|
|
253
|
-
|-----------|----------|----------|
|
|
254
|
-
| **Bulk Insert** | Add new items only | Fails if ID exists |
|
|
255
|
-
| **Bulk Update** | Update existing items | Fails if ID doesn't exist, replaces entire item |
|
|
256
|
-
| **Bulk Save** | Upsert (insert or update) | Creates or updates based on ID |
|
|
257
|
-
| **Bulk Patch** | Partial update | Only modifies specified fields |
|
|
258
|
-
|
|
259
|
-
## Related Documentation
|
|
260
|
-
|
|
261
|
-
- [Data Items API Reference](https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/introduction)
|
|
262
|
-
- [CMS Operations Best Practices](cms-data-items-crud.md)
|
|
263
|
-
- [CMS Schema Management](cms-schema-management.md)
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: "CMS References And Relationships"
|
|
3
|
-
description: "Add, replace, or remove items from MULTI_REFERENCE fields. Use insert-references, replace-references, remove-references endpoints. Required for managing multi-reference relationships - these CANNOT be set via regular insert/update/patch operations. Also covers single references and querying with expanded references."
|
|
4
|
-
---
|
|
5
|
-
# CMS References & Relationships
|
|
6
|
-
|
|
7
|
-
> **Standard call shape (every curl below).** The `<AUTH>` placeholder is shorthand for `Authorization: Bearer <TOKEN>` only. Body-bearing requests also need `Content-Type: application/json`.
|
|
8
|
-
|
|
9
|
-
This recipe covers linking CMS collections together using reference fields.
|
|
10
|
-
|
|
11
|
-
## Prerequisites
|
|
12
|
-
|
|
13
|
-
1. Wix CMS enabled on the site
|
|
14
|
-
2. At least two collections to link together
|
|
15
|
-
3. API access with CMS permissions
|
|
16
|
-
|
|
17
|
-
## Required APIs
|
|
18
|
-
|
|
19
|
-
- **Collections API**: [REST](https://dev.wix.com/docs/api-reference/business-solutions/cms/collection-management/data-collections/introduction)
|
|
20
|
-
- **Data Items API**: [REST](https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/introduction)
|
|
21
|
-
|
|
22
|
-
## Reference Types
|
|
23
|
-
|
|
24
|
-
| Type | Field Type | Relationship | Example |
|
|
25
|
-
|------|------------|--------------|---------|
|
|
26
|
-
| Single Reference | `REFERENCE` | One-to-one, Many-to-one | Product → Category |
|
|
27
|
-
| Multi-Reference | `MULTI_REFERENCE` | One-to-many, Many-to-many | Product → Tags |
|
|
28
|
-
|
|
29
|
-
## Add a Single Reference Field
|
|
30
|
-
|
|
31
|
-
**Endpoint**: `POST /wix-data/v2/collections/create-field`
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
curl -X POST \
|
|
35
|
-
'https://www.wixapis.com/wix-data/v2/collections/create-field' \
|
|
36
|
-
-H 'Content-Type: application/json' \
|
|
37
|
-
-H 'Authorization: <AUTH>' \
|
|
38
|
-
-d '{
|
|
39
|
-
"dataCollectionId": "Products",
|
|
40
|
-
"field": {
|
|
41
|
-
"key": "category",
|
|
42
|
-
"displayName": "Category",
|
|
43
|
-
"type": "REFERENCE",
|
|
44
|
-
"typeMetadata": {
|
|
45
|
-
"reference": {
|
|
46
|
-
"referencedCollectionId": "Categories"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}'
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## Add a Multi-Reference Field
|
|
54
|
-
|
|
55
|
-
**Endpoint**: `POST /wix-data/v2/collections/create-field`
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
curl -X POST \
|
|
59
|
-
'https://www.wixapis.com/wix-data/v2/collections/create-field' \
|
|
60
|
-
-H 'Content-Type: application/json' \
|
|
61
|
-
-H 'Authorization: <AUTH>' \
|
|
62
|
-
-d '{
|
|
63
|
-
"dataCollectionId": "Products",
|
|
64
|
-
"field": {
|
|
65
|
-
"key": "tags",
|
|
66
|
-
"displayName": "Tags",
|
|
67
|
-
"type": "MULTI_REFERENCE",
|
|
68
|
-
"typeMetadata": {
|
|
69
|
-
"multiReference": {
|
|
70
|
-
"referencedCollectionId": "Tags",
|
|
71
|
-
"referencingFieldKey": "products",
|
|
72
|
-
"referencingDisplayName": "Products"
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}'
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Insert Multi-Reference Links
|
|
80
|
-
|
|
81
|
-
**Endpoint**: `POST /wix-data/v2/bulk/items/insert-references`
|
|
82
|
-
|
|
83
|
-
```json
|
|
84
|
-
{
|
|
85
|
-
"dataCollectionId": "Products",
|
|
86
|
-
"dataItemReferences": [
|
|
87
|
-
{
|
|
88
|
-
"referringItemId": "product-item-id",
|
|
89
|
-
"referringItemFieldName": "tags",
|
|
90
|
-
"referencedItemId": "tag-1-item-id"
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
"referringItemId": "product-item-id",
|
|
94
|
-
"referringItemFieldName": "tags",
|
|
95
|
-
"referencedItemId": "tag-2-item-id"
|
|
96
|
-
}
|
|
97
|
-
],
|
|
98
|
-
"returnEntity": true
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Replace All References
|
|
103
|
-
|
|
104
|
-
**Endpoint**: `POST /wix-data/v2/items/replace-references`
|
|
105
|
-
|
|
106
|
-
```json
|
|
107
|
-
{
|
|
108
|
-
"dataCollectionId": "Products",
|
|
109
|
-
"referringItemId": "product-item-id",
|
|
110
|
-
"referringItemFieldName": "tags",
|
|
111
|
-
"newReferencedItemIds": ["new-tag-1-id", "new-tag-2-id", "new-tag-3-id"]
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
> **Note**: To remove all references, pass an empty array for `newReferencedItemIds`.
|
|
116
|
-
|
|
117
|
-
## Remove References (Bulk)
|
|
118
|
-
|
|
119
|
-
**Endpoint**: `POST /wix-data/v2/bulk/items/remove-references`
|
|
120
|
-
|
|
121
|
-
```json
|
|
122
|
-
{
|
|
123
|
-
"dataCollectionId": "Products",
|
|
124
|
-
"dataItemReferences": [
|
|
125
|
-
{
|
|
126
|
-
"referringItemId": "product-id-1",
|
|
127
|
-
"referringItemFieldName": "tags",
|
|
128
|
-
"referencedItemId": "tag-to-remove-id"
|
|
129
|
-
}
|
|
130
|
-
]
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## Query with Referenced Items Expanded
|
|
135
|
-
|
|
136
|
-
**Endpoint**: `POST /wix-data/v2/items/query`
|
|
137
|
-
|
|
138
|
-
```json
|
|
139
|
-
{
|
|
140
|
-
"dataCollectionId": "Products",
|
|
141
|
-
"query": {
|
|
142
|
-
"filter": {
|
|
143
|
-
"inStock": true
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
|
-
"includeReferencedItems": ["category", "tags"]
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## Reference Query Operators
|
|
151
|
-
|
|
152
|
-
| Operator | Description | Example |
|
|
153
|
-
|----------|-------------|---------|
|
|
154
|
-
| `$eq` | Exact match (single reference) | `{ "category": "id" }` |
|
|
155
|
-
| `$hasSome` | Has at least one of | `{ "tags": { "$hasSome": ["id1", "id2"] } }` |
|
|
156
|
-
| `$hasAll` | Has all of | `{ "tags": { "$hasAll": ["id1", "id2"] } }` |
|
|
157
|
-
|
|
158
|
-
## Related Documentation
|
|
159
|
-
|
|
160
|
-
- [Data Items API Reference](https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/introduction)
|
|
161
|
-
- [Collections API Reference](https://dev.wix.com/docs/api-reference/business-solutions/cms/collection-management/data-collections/introduction)
|
|
162
|
-
- [CMS Schema Management Recipe](cms-schema-management.md)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|