@wix/agent-skills 1.24.0 → 1.26.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 +16 -14
- package/skills/wix-app/references/BUSINESS_MANAGER_THEME.md +107 -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 +13 -11
- package/skills/wix-app/references/DASHBOARD_PLUGIN.md +19 -4
- package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +3 -2
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +66 -68
- package/skills/wix-app/references/dashboard-page/DYNAMIC_PARAMETERS.md +21 -38
- package/skills/wix-app/references/data-collection/LIFECYCLE.md +6 -4
- 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-kit/SKILL.md +4 -4
- package/skills/wix-headless-kit/install/AGENTS.md +2 -2
- package/skills/wix-headless-kit/install/bootstrap.mjs +156 -0
- package/skills/wix-headless-kit/install/check.mjs +1 -1
- package/skills/wix-manage/SKILL.md +2 -8
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +250 -18
- package/skills/wix-manage/references/cms/cms-schema-management.md +52 -1
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_COLLECTION.md +0 -184
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +0 -203
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_SETTINGS.md +0 -44
- 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
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
# Draft Template — Cases A, B and D (router-wired)
|
|
2
|
-
|
|
3
|
-
**Applies to [DRAFT_TEMPLATE.md](DRAFT_TEMPLATE.md)'s Cases A, B and D.** All three need `PatternsReactRouter`, because in all three a row opens a page of its own — a panel is not the drill-in ([UX_SUCCESS_MODEL.md](UX_SUCCESS_MODEL.md)). Case A's detail route is read-only (§4); B and D route to a full `EntityPage`. The collection and settings components live in [DRAFT_TEMPLATE.md](DRAFT_TEMPLATE.md); this file covers only what a router adds — the entry file, the app shell, and the detail/entity page.
|
|
4
|
-
|
|
5
|
-
Every snippet below is copied from the installed `dist/docs/*.md` this session read, not from memory.
|
|
6
|
-
|
|
7
|
-
## 1. Entry — `location` is manual in a Wix CLI app, and only because the router needs it
|
|
8
|
-
|
|
9
|
-
`PatternsReactRouter` reads the page location through `container.usePageLocation()`, which only `withDashboard`'s `location` prop feeds — nothing supplies it automatically in a Wix CLI app the way Yoshi BM flow does:
|
|
10
|
-
|
|
11
|
-
```tsx
|
|
12
|
-
// {feature}.tsx — Case A, B or D
|
|
13
|
-
import { useEffect, useState, type FC } from 'react';
|
|
14
|
-
import { dashboard } from '@wix/dashboard';
|
|
15
|
-
import { WixDesignSystemProvider } from '@wix/design-system';
|
|
16
|
-
import '@wix/design-system/styles.global.css';
|
|
17
|
-
import { {Feature}App } from './{Feature}App';
|
|
18
|
-
|
|
19
|
-
type PageLocation = Parameters<Parameters<typeof dashboard.observeState>[0]>[1]['pageLocation'];
|
|
20
|
-
|
|
21
|
-
const Page: FC = () => {
|
|
22
|
-
const [location, setLocation] = useState<PageLocation | undefined>();
|
|
23
|
-
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
const subscription = dashboard.observeState((_pageParams, environment) => {
|
|
26
|
-
setLocation(environment.pageLocation);
|
|
27
|
-
});
|
|
28
|
-
return () => subscription.disconnect();
|
|
29
|
-
}, []);
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<WixDesignSystemProvider>
|
|
33
|
-
{location ? <{Feature}App location={location} /> : null}
|
|
34
|
-
</WixDesignSystemProvider>
|
|
35
|
-
);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export default Page;
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
**Skipping this is a runtime-only failure.** Per `PatternsReactRouter`'s own docs: "Nothing catches this before runtime — type checking and bundling both pass, because neither renders the page." `tsc` and `wix build` will not catch a missing `location` — only opening the page in a browser will. This is exactly why [Step 5's Preview](../../SKILL.md#validation) is not optional for Case B/D.
|
|
42
|
-
|
|
43
|
-
## 2. App shell — provider, router, routes
|
|
44
|
-
|
|
45
|
-
```tsx
|
|
46
|
-
// {Feature}App.tsx — Case A, B or D
|
|
47
|
-
import { withDashboard } from '@wix/patterns';
|
|
48
|
-
import { WixPatternsProvider } from '@wix/patterns/provider';
|
|
49
|
-
import { PatternsReactRouter, PatternsReactRoute } from '@wix/patterns/router';
|
|
50
|
-
import { {Feature}CollectionPage } from './{Feature}CollectionPage';
|
|
51
|
-
import { {Feature}EntityPage } from './{Feature}EntityPage';
|
|
52
|
-
// Case D only:
|
|
53
|
-
import { {Feature}SettingsPage } from './{Feature}SettingsPage';
|
|
54
|
-
|
|
55
|
-
export const {Feature}App = withDashboard(() => (
|
|
56
|
-
<WixPatternsProvider>
|
|
57
|
-
<PatternsReactRouter>
|
|
58
|
-
<PatternsReactRoute type="collection" path="/" element={<{Feature}CollectionPage />} />
|
|
59
|
-
{/* Case B/D — editable record. Case A registers this ONE route instead, with
|
|
60
|
-
{Feature}DetailPage as the element and no /new route (§4). Either way the
|
|
61
|
-
type is `editEntity`: it wires back-navigation to the collection. */}
|
|
62
|
-
<PatternsReactRoute type="editEntity" path="/:id" element={<{Feature}EntityPage />} />
|
|
63
|
-
{/* Case B/D only — Case A has nothing to create: */}
|
|
64
|
-
<PatternsReactRoute type="createEntity" path="/new" element={<{Feature}EntityPage />} />
|
|
65
|
-
{/* Case D only: */}
|
|
66
|
-
<PatternsReactRoute type="other" path="/settings" element={<{Feature}SettingsPage />} />
|
|
67
|
-
</PatternsReactRouter>
|
|
68
|
-
</WixPatternsProvider>
|
|
69
|
-
));
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
`PatternsReactRoute`'s `type` is one of exactly `"collection" | "createEntity" | "editEntity" | "other"` — no dedicated settings value, so a settings route is `"other"`. Case B: delete the `/settings` route and the import above it — nothing else changes.
|
|
73
|
-
|
|
74
|
-
`{Feature}CollectionPage` is [DRAFT_TEMPLATE_COLLECTION.md](DRAFT_TEMPLATE_COLLECTION.md)'s component, unchanged; `{Feature}SettingsPage` (Case D) is [DRAFT_TEMPLATE_SETTINGS.md](DRAFT_TEMPLATE_SETTINGS.md).
|
|
75
|
-
|
|
76
|
-
## 2b. The collection side of the handoff
|
|
77
|
-
|
|
78
|
-
The router file above registers `/new`; something has to navigate there. All three of these live on
|
|
79
|
-
the collection page, and `usePatternsNavigate` comes from **`@wix/patterns/router`** — not the root
|
|
80
|
-
export, which is where it is easy to reach for it:
|
|
81
|
-
|
|
82
|
-
```tsx
|
|
83
|
-
import { PrimaryPageButton } from '@wix/patterns';
|
|
84
|
-
import { usePatternsNavigate } from '@wix/patterns/router';
|
|
85
|
-
|
|
86
|
-
const { navigateToEntityPage } = usePatternsNavigate<{Entity}>();
|
|
87
|
-
const openNew = () => navigateToEntityPage({ path: '/new' }); // no record yet — omit `entity`
|
|
88
|
-
|
|
89
|
-
// CollectionPage.Header — primaryAction takes an ELEMENT, not a { text, onClick } config:
|
|
90
|
-
<CollectionPage.Header
|
|
91
|
-
title={{ text: '{Page Title}' }}
|
|
92
|
-
primaryAction={<PrimaryPageButton text="Add {entity}" onClick={openNew} />}
|
|
93
|
-
/>
|
|
94
|
-
|
|
95
|
-
// the empty state should offer the same action, and this one IS a config object:
|
|
96
|
-
<CollectionEmptyState title="No {feature} yet" addNewCta={{ text: 'Add {entity}', onClick: openNew }} />
|
|
97
|
-
|
|
98
|
-
// and a row opens the edit route:
|
|
99
|
-
onRowClick={(item) => navigateToEntityPage({ path: `/${item.id}`, entity: item })}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
The two shapes differ on purpose — `primaryAction` is an element, `addNewCta` is `{ text, onClick }`.
|
|
103
|
-
Guessing either costs a compile round.
|
|
104
|
-
|
|
105
|
-
## 3. Entity page — one component for both `/new` and `/:id`
|
|
106
|
-
|
|
107
|
-
Full call details (both generics, what `onSave` receives, the `UseEntityPageParams` pick list) are in `<pkgRoot>/dist/docs/useEntityPage.md` — read it before filling in fields. The part specific to this router-based shape:
|
|
108
|
-
|
|
109
|
-
```tsx
|
|
110
|
-
// {Feature}EntityPage.tsx — Case B or D (sketch — see dist/docs/useEntityPage.md for the full call)
|
|
111
|
-
import { useParams } from 'react-router-dom'; // NOT @wix/patterns/router — PatternsReactRoute wraps react-router-dom's Route, but only exports PatternsReactRoute/PatternsReactRouter/usePatternsNavigate itself
|
|
112
|
-
import { useEntityPage, EntityPage } from '@wix/patterns';
|
|
113
|
-
import { useForm } from '@wix/patterns/form';
|
|
114
|
-
import { fetch{Entity}, save{Entity}, type {Entity} } from './{feature}-api';
|
|
115
|
-
|
|
116
|
-
// The form's shape is yours to declare, and need not match the saved entity type.
|
|
117
|
-
type {Entity}FormFields = { name: string };
|
|
118
|
-
|
|
119
|
-
export const {Feature}EntityPage = () => {
|
|
120
|
-
const { id } = useParams<{ id?: string }>();
|
|
121
|
-
const form = useForm<{Entity}FormFields>();
|
|
122
|
-
|
|
123
|
-
const state = useEntityPage<{Entity}, {Entity}FormFields>({
|
|
124
|
-
parentPath: '/', // NOT parentPageId — this shape always uses Patterns Router
|
|
125
|
-
isNewEntity: () => !id, // a getter: the route can change (/new -> /:id after save) while this stays mounted
|
|
126
|
-
form,
|
|
127
|
-
fetch: () => (id ? fetch{Entity}(id).then((entity) => ({ entity })) : Promise.resolve({ entity: undefined })),
|
|
128
|
-
onSave: ({ widgetsFormData }) =>
|
|
129
|
-
save{Entity}({ id, ...form.getValues(), ...widgetsFormData }).then((updatedEntity) => ({ updatedEntity })),
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
return (
|
|
133
|
-
<EntityPage state={state}>
|
|
134
|
-
<EntityPage.Header title={{ text: id ? 'Edit {Entity}' : 'New {Entity}' }} />
|
|
135
|
-
<EntityPage.Content>
|
|
136
|
-
<EntityPage.MainContent>{/* form cards — see dist/docs/EntityPage.md */}</EntityPage.MainContent>
|
|
137
|
-
</EntityPage.Content>
|
|
138
|
-
</EntityPage>
|
|
139
|
-
);
|
|
140
|
-
};
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
`useEntityPage`'s own docs are explicit about both details above: `parentPath` "Must be passed if using Patterns Router" (`parentPageId` is the non-router alternative — irrelevant here, since Case B/D always uses the router), and `isNewEntity` should be "a getter when the route can change while the page stays mounted" — exactly this component's case, since a successful create typically navigates `/new` → `/:newId`.
|
|
144
|
-
|
|
145
|
-
**`UseEntityPageParams` is a `Pick<>`, so a param missing from it is a compile error, not an ignored prop.** `isNewEntity` is in that list at 1.470.0 and absent before ~1.46x. If it doesn't compile, read the pick list in your installed `dist/types/hooks/useEntityPage.d.ts` and upgrade — deleting the line makes a create route behave as an edit.
|
|
146
|
-
|
|
147
|
-
## 4. Read-only detail route — Case A
|
|
148
|
-
|
|
149
|
-
A display-only collection still routes its rows to a page — but not an `EntityPage`, which has no
|
|
150
|
-
read-only mode and still has none at **1.471.0**: `fetch` and `onSave` are both required, and
|
|
151
|
-
`actionsBarConfig` (`saveCta.text`, `cancelCta`) can retext Save but not remove it. It would ship
|
|
152
|
-
two buttons that either do nothing or save a form nobody was offered.
|
|
153
|
-
|
|
154
|
-
Use a WDS `Page` — what Cairo does itself: `example-bm`'s `DataExtensionEntityViewPage` and
|
|
155
|
-
auto-patterns' `ViewModeEntityPage` are both plain WDS `Page`s, the latter unexported.
|
|
156
|
-
|
|
157
|
-
```tsx
|
|
158
|
-
// {Feature}DetailPage.tsx — Case A
|
|
159
|
-
import { useEffect, useState } from 'react';
|
|
160
|
-
import { useParams } from 'react-router-dom';
|
|
161
|
-
import { Card, Loader, Page, Text } from '@wix/design-system';
|
|
162
|
-
import { usePatternsNavigate } from '@wix/patterns/router';
|
|
163
|
-
import { fetch{Entity}, type {Entity} } from './{feature}-api';
|
|
164
|
-
|
|
165
|
-
export const {Feature}DetailPage = () => {
|
|
166
|
-
const { id } = useParams<{ id: string }>();
|
|
167
|
-
const { navigateToCollectionPage } = usePatternsNavigate();
|
|
168
|
-
const [entity, setEntity] = useState<{Entity} | undefined>();
|
|
169
|
-
|
|
170
|
-
useEffect(() => {
|
|
171
|
-
if (id) {
|
|
172
|
-
fetch{Entity}(id).then(setEntity);
|
|
173
|
-
}
|
|
174
|
-
}, [id]);
|
|
175
|
-
|
|
176
|
-
return (
|
|
177
|
-
<Page>
|
|
178
|
-
{/* The way back is the header's back button — a read-only page has no Cancel. */}
|
|
179
|
-
<Page.Header
|
|
180
|
-
title={entity?.name ?? '{Entity}'}
|
|
181
|
-
showBackButton
|
|
182
|
-
onBackClicked={() => navigateToCollectionPage({ path: '/' })}
|
|
183
|
-
/>
|
|
184
|
-
<Page.Content>
|
|
185
|
-
{entity ? (
|
|
186
|
-
<Card>
|
|
187
|
-
<Card.Header title="Details" />
|
|
188
|
-
<Card.Divider />
|
|
189
|
-
<Card.Content>
|
|
190
|
-
<Text>{entity.name}</Text>
|
|
191
|
-
</Card.Content>
|
|
192
|
-
</Card>
|
|
193
|
-
) : (
|
|
194
|
-
<Loader />
|
|
195
|
-
)}
|
|
196
|
-
</Page.Content>
|
|
197
|
-
</Page>
|
|
198
|
-
);
|
|
199
|
-
};
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
If the request later grows an edit form this becomes §3's `EntityPage`, route type and `onRowClick`
|
|
203
|
-
unchanged — which is why Case A registers `editEntity`, not `other`.
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# Draft Template — Settings page (Cases C and D)
|
|
2
|
-
|
|
3
|
-
> Pick your case in [DRAFT_TEMPLATE.md](DRAFT_TEMPLATE.md) first; this page covers Case C or D.
|
|
4
|
-
|
|
5
|
-
## The settings page
|
|
6
|
-
|
|
7
|
-
No dedicated toolkit file exists for this yet (unlike Entity/Collection) — the shape, verified against `useSettingsPage.md`:
|
|
8
|
-
|
|
9
|
-
```tsx
|
|
10
|
-
// {Feature}SettingsPage.tsx — Case C or D
|
|
11
|
-
import { SettingsPage, useSettingsPage, useSettings } from '@wix/patterns';
|
|
12
|
-
import { useForm } from '@wix/patterns/form';
|
|
13
|
-
import { fetch{Feature}Settings, save{Feature}Settings, type {Feature}Settings } from './{feature}-api';
|
|
14
|
-
|
|
15
|
-
// The form's shape is yours to declare, and need not match the saved settings type —
|
|
16
|
-
// one field per control on the page.
|
|
17
|
-
type {Feature}SettingsFormFields = { reminderHours: number; notifyStaff: boolean };
|
|
18
|
-
|
|
19
|
-
export const {Feature}SettingsPage = () => {
|
|
20
|
-
const form = useForm<{Feature}SettingsFormFields>();
|
|
21
|
-
|
|
22
|
-
const state = useSettingsPage<{Feature}Settings, {Feature}SettingsFormFields>({
|
|
23
|
-
form,
|
|
24
|
-
fetch: () => fetch{Feature}Settings().then((settings) => ({ settings })),
|
|
25
|
-
onSave: () => save{Feature}Settings(form.getValues()),
|
|
26
|
-
onCancel: async () => form.reset(),
|
|
27
|
-
saveSuccessToast: 'Settings saved',
|
|
28
|
-
saveErrorToast: (err, { retry }) => ({ message: 'Failed to save settings', action: { text: 'Retry', onClick: retry } }),
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const settings = useSettings<{Feature}Settings, {Feature}SettingsFormFields>(state);
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<SettingsPage state={state}>
|
|
35
|
-
<SettingsPage.Header title={{ text: '{Settings Page Title}' }} />
|
|
36
|
-
<SettingsPage.Content>
|
|
37
|
-
<SettingsPage.MainContent>{/* form cards — same field-controller patterns as EntityPage */}</SettingsPage.MainContent>
|
|
38
|
-
</SettingsPage.Content>
|
|
39
|
-
</SettingsPage>
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
`useSettingsPage`'s params are all required except `saveSuccessToast`/`saveErrorToast`: `form`, `fetch`, `onSave`, `onCancel`. There is no `parentPath`/`parentPageId` — a settings page isn't reached by drilling into a row, so it carries no back-navigation contract, and Case C needs no router at all to reach it (Section 1's entry renders it directly).
|
|
@@ -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)
|