@wix/agent-skills 1.14.0 → 1.15.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 +4 -1
- package/package.json +1 -1
- package/skills/README.md +23 -0
- package/skills/wix-app/SKILL.md +10 -2
- package/skills/wix-app/references/AUTO_PATTERNS_DASHBOARD.md +326 -0
- package/skills/wix-app/references/CODE_QUALITY.md +1 -0
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +124 -115
- package/skills/wix-app/references/DASHBOARD_PAGE.md +3 -0
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +23 -9
- package/skills/wix-app/references/SITE_PLUGIN.md +1 -1
- package/skills/wix-app/references/auto-patterns-dashboard/action-cell.md +115 -0
- package/skills/wix-app/references/auto-patterns-dashboard/app-config-structure.md +264 -0
- package/skills/wix-app/references/auto-patterns-dashboard/app-context.md +37 -0
- package/skills/wix-app/references/auto-patterns-dashboard/bulk-actions.md +86 -0
- package/skills/wix-app/references/auto-patterns-dashboard/collection-page-actions.md +119 -0
- package/skills/wix-app/references/auto-patterns-dashboard/collection-page.md +103 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-actions-override.md +76 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-columns-override.md +82 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-components-override.md +89 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-header-override.md +124 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-sections-override.md +91 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-slots-override.md +71 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page-actions.md +70 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page-view-actions.md +73 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page.md +98 -0
- package/skills/wix-app/references/auto-patterns-dashboard/example-patterns.json +278 -0
- package/skills/wix-app/references/auto-patterns-dashboard/pages-configuration.md +94 -0
- package/skills/wix-app/references/auto-patterns-dashboard/resolved-action.md +43 -0
- package/skills/wix-app/references/auto-patterns-dashboard/sdk-utilities.md +66 -0
- package/skills/wix-app/references/auto-patterns-dashboard/views.md +76 -0
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +1 -14
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +54 -29
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +2 -2
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +17 -105
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +127 -0
- package/skills/wix-app/references/editor-react-component/PARTS.md +2 -1
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +15 -15
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +25 -53
- package/skills/wix-app/scripts/generate-auto-patterns.js +510 -0
- package/skills/wix-auth/SKILL.md +12 -0
- package/skills/wix-auth/references/device-flow.md +140 -0
- package/skills/wix-docs/SKILL.md +188 -0
- package/skills/wix-docs/references/API_SPEC_SEARCH.md +213 -0
- package/skills/wix-docs/references/EXTRACTING.md +120 -0
- package/skills/wix-headless/SKILL.md +84 -130
- package/skills/wix-headless/entry/bootstrap.mjs +93 -0
- package/skills/wix-headless/entry/skill.md +78 -0
- package/skills/wix-headless/references/AI_FEATURES.md +178 -0
- package/skills/wix-headless/references/CAPABILITIES.md +84 -0
- package/skills/wix-headless/references/DISCOVERY.md +34 -56
- package/skills/wix-headless/references/DOC_DISCOVERY.md +37 -0
- package/skills/wix-headless/references/FEEDBACK.md +118 -0
- package/skills/wix-headless/references/IMAGE_GENERATION.md +69 -0
- package/skills/wix-headless/references/SDK_HANDOFF.md +97 -0
- package/skills/wix-headless/references/SEED.md +44 -188
- package/skills/wix-headless/references/SETUP.md +32 -103
- package/skills/wix-headless/references/astro.md +98 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +196 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +236 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-bookings.md +279 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-cms.md +163 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-events.md +203 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +222 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +124 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +160 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +118 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-portfolio.md +132 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +124 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +188 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +173 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurants.md +161 -0
- package/skills/wix-headless/references/inline-recipes/setup-blog.md +175 -0
- package/skills/wix-headless/references/inline-recipes/setup-bookings.md +228 -0
- package/skills/wix-headless/references/inline-recipes/setup-cms.md +200 -0
- package/skills/wix-headless/references/inline-recipes/setup-events.md +196 -0
- package/skills/wix-headless/references/inline-recipes/setup-forms.md +174 -0
- package/skills/wix-headless/references/inline-recipes/setup-online-store.md +176 -0
- package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +153 -0
- package/skills/wix-headless/references/inline-recipes/setup-pricing-plans.md +229 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +161 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +117 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +152 -0
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +57 -0
- package/skills/wix-headless/references/managed/CONNECT.md +74 -0
- package/skills/wix-headless/references/managed/CREATE.md +130 -0
- package/skills/wix-headless/references/managed/DEPLOYMENT.md +57 -0
- package/skills/wix-headless/references/non-astro.md +59 -0
- package/skills/wix-headless/references/self-managed/AUTHENTICATION.md +22 -0
- package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +7 -0
- package/skills/wix-headless/references/stripe/AUTHENTICATION.md +55 -0
- package/skills/wix-headless/references/stripe/DEPLOYMENT.md +63 -0
- package/skills/wix-manage/SKILL.md +24 -1
- package/skills/wix-manage/references/analytics/query-site-analytics.md +241 -0
- package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +1 -1
- package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +265 -0
- package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +436 -0
- package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +209 -0
- package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +249 -0
- package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +51 -0
- package/skills/wix-vibe-headless/SKILL.md +136 -0
- package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +128 -0
- package/skills/wix-vibe-headless/references/blog/wix-blog.js +217 -0
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +153 -0
- package/skills/wix-vibe-headless/references/bookings/wix-bookings-checkout.js +147 -0
- package/skills/wix-vibe-headless/references/bookings/wix-bookings-services.js +215 -0
- package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +154 -0
- package/skills/wix-vibe-headless/references/cms/wix-cms.js +186 -0
- package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +142 -0
- package/skills/wix-vibe-headless/references/events/wix-events-browse.js +135 -0
- package/skills/wix-vibe-headless/references/events/wix-events-registration.js +187 -0
- package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +211 -0
- package/skills/wix-vibe-headless/references/members/wix-members-auth.js +387 -0
- package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +111 -0
- package/skills/wix-vibe-headless/references/portfolio/wix-portfolio.js +194 -0
- package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +127 -0
- package/skills/wix-vibe-headless/references/pricing-plans/wix-pricing-plans.js +157 -0
- package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +138 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-menu.js +224 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-ordering.js +156 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-reservations.js +107 -0
- package/skills/wix-vibe-headless/references/shared/wix-client.js +186 -0
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +155 -0
- package/skills/wix-vibe-headless/references/storefront/wix-store-cart.js +147 -0
- package/skills/wix-vibe-headless/references/storefront/wix-store-catalog.js +142 -0
- package/skills/wix-headless/references/BUILD-astro.md +0 -253
- package/skills/wix-headless/references/BUILD-own-build.md +0 -167
- package/skills/wix-headless/references/BUILD.md +0 -105
- package/skills/wix-headless/references/DESIGN_SYSTEM.md +0 -165
- package/skills/wix-headless/references/DISCOVERY-connect.md +0 -55
- package/skills/wix-headless/references/DISCOVERY-create.md +0 -238
- package/skills/wix-headless/references/PLAN-connect.md +0 -19
- package/skills/wix-headless/references/PLAN-create.md +0 -17
- package/skills/wix-headless/references/PLAN.md +0 -92
- package/skills/wix-headless/references/astro/blog/BLOG_PAGES.md +0 -300
- package/skills/wix-headless/references/astro/blog/BLOG_SETUP.md +0 -218
- package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +0 -45
- package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +0 -77
- package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +0 -214
- package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +0 -231
- package/skills/wix-headless/references/astro/cms/PORTFOLIO.md +0 -453
- package/skills/wix-headless/references/astro/cms/RESOURCE_LIBRARY.md +0 -354
- package/skills/wix-headless/references/astro/cms/TEAM_DIRECTORY.md +0 -299
- package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +0 -351
- package/skills/wix-headless/references/astro/ecom/CART_PAGES.md +0 -119
- package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +0 -103
- package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +0 -132
- package/skills/wix-headless/references/astro/forms/CONTACT_FORM.md +0 -463
- package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +0 -119
- package/skills/wix-headless/references/astro/gift-cards/PAGES.md +0 -129
- package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +0 -178
- package/skills/wix-headless/references/astro/stores/CATEGORY_PAGES.md +0 -85
- package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +0 -129
- package/skills/wix-headless/references/astro/stores/HOME_AND_NAV.md +0 -229
- package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +0 -215
- package/skills/wix-headless/references/astro/stores/SHARED_WIRING.md +0 -165
- package/skills/wix-headless/references/astro/templates/Layout.astro +0 -132
- package/skills/wix-headless/references/astro/templates/astro.config.mjs +0 -41
- package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +0 -374
- package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +0 -136
- package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +0 -25
- package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +0 -71
- package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +0 -54
- package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +0 -49
- package/skills/wix-headless/references/astro/templates/bookings/bookingDriver.ts +0 -245
- package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +0 -424
- package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +0 -176
- package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +0 -181
- package/skills/wix-headless/references/astro/templates/ecom/CartBadge.tsx +0 -84
- package/skills/wix-headless/references/astro/templates/ecom/CartView.tsx +0 -543
- package/skills/wix-headless/references/astro/templates/ecom/cart.astro +0 -13
- package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +0 -302
- package/skills/wix-headless/references/astro/templates/ecom/discounts.ts +0 -71
- package/skills/wix-headless/references/astro/templates/ecom/thank-you.astro +0 -24
- package/skills/wix-headless/references/astro/templates/gift-cards/GiftCardPurchase.tsx +0 -172
- package/skills/wix-headless/references/astro/templates/gift-cards/_home-teaser-snippet.astro +0 -42
- package/skills/wix-headless/references/astro/templates/gift-cards/_nav-snippet.astro +0 -11
- package/skills/wix-headless/references/astro/templates/gift-cards/components-gift-cards.css +0 -220
- package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.astro +0 -51
- package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.ts +0 -75
- package/skills/wix-headless/references/astro/templates/global.css +0 -288
- package/skills/wix-headless/references/astro/templates/stores/AddToCartButton.tsx +0 -77
- package/skills/wix-headless/references/astro/templates/stores/BackInStockForm.tsx +0 -176
- package/skills/wix-headless/references/astro/templates/stores/CategoryRail.astro +0 -69
- package/skills/wix-headless/references/astro/templates/stores/ProductCard.astro +0 -79
- package/skills/wix-headless/references/astro/templates/stores/ProductPurchase.tsx +0 -397
- package/skills/wix-headless/references/astro/templates/stores/SeoTags.astro +0 -21
- package/skills/wix-headless/references/astro/templates/stores/back-in-stock.ts +0 -67
- package/skills/wix-headless/references/astro/templates/stores/categories.ts +0 -155
- package/skills/wix-headless/references/astro/templates/stores/category/[slug].astro +0 -130
- package/skills/wix-headless/references/astro/templates/stores/components-stores.css +0 -400
- package/skills/wix-headless/references/astro/templates/stores/products/[slug].astro +0 -128
- package/skills/wix-headless/references/astro/templates/stores/products/index.astro +0 -101
- package/skills/wix-headless/references/blog/BLOG_CONTENT.md +0 -161
- package/skills/wix-headless/references/blog/INSTRUCTIONS.md +0 -32
- package/skills/wix-headless/references/bookings/FLOW.md +0 -246
- package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +0 -95
- package/skills/wix-headless/references/bookings/SERVICES_DATA.md +0 -355
- package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +0 -176
- package/skills/wix-headless/references/cms/INSTRUCTIONS.md +0 -71
- package/skills/wix-headless/references/commands/known-apps.json +0 -6
- package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +0 -142
- package/skills/wix-headless/references/custom/INSTRUCTIONS.md +0 -88
- package/skills/wix-headless/references/custom/blog/WIRING.md +0 -52
- package/skills/wix-headless/references/custom/bookings/WIRING.md +0 -197
- package/skills/wix-headless/references/custom/cms/WIRING.md +0 -97
- package/skills/wix-headless/references/custom/ecom/WIRING.md +0 -67
- package/skills/wix-headless/references/custom/forms/WIRING.md +0 -101
- package/skills/wix-headless/references/custom/stores/WIRING.md +0 -80
- package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +0 -59
- package/skills/wix-headless/references/forms/INSTRUCTIONS.md +0 -43
- package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +0 -51
- package/skills/wix-headless/references/images/INSTRUCTIONS.md +0 -357
- package/skills/wix-headless/references/seed-recipes.md +0 -49
- package/skills/wix-headless/references/shared/AGENTS_MD.md +0 -47
- package/skills/wix-headless/references/shared/AUTHENTICATION.md +0 -108
- package/skills/wix-headless/references/shared/BUILD_NOISE.md +0 -8
- package/skills/wix-headless/references/shared/DESIGN_MD.md +0 -84
- package/skills/wix-headless/references/shared/DOCS_SEARCH.md +0 -41
- package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +0 -186
- package/skills/wix-headless/references/shared/IMPLEMENTER.md +0 -206
- package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +0 -97
- package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +0 -143
- package/skills/wix-headless/references/shared/STYLING.md +0 -140
- package/skills/wix-headless/references/stores/INSTRUCTIONS.md +0 -126
- package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +0 -252
- package/skills/wix-headless/references/verticals/_schema.json +0 -74
- package/skills/wix-headless/references/verticals/_schema.md +0 -95
- package/skills/wix-headless/references/verticals/blog.md +0 -31
- package/skills/wix-headless/references/verticals/bookings.md +0 -41
- package/skills/wix-headless/references/verticals/cms.md +0 -30
- package/skills/wix-headless/references/verticals/ecom.md +0 -25
- package/skills/wix-headless/references/verticals/forms.md +0 -26
- package/skills/wix-headless/references/verticals/gift-cards.md +0 -24
- package/skills/wix-headless/references/verticals/stores.md +0 -33
- package/skills/wix-headless/scripts/check-manifest.mjs +0 -335
- package/skills/wix-headless/scripts/compose.mjs +0 -520
- package/skills/wix-headless/scripts/emit-design-tokens.mjs +0 -157
- package/skills/wix-headless/scripts/flatten.sh +0 -61
- package/skills/wix-headless/scripts/generate-images.mjs +0 -242
- package/skills/wix-headless/scripts/patch-decorative-slots.mjs +0 -154
- package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +0 -190
- package/skills/wix-headless/scripts/scaffold.sh +0 -139
- package/skills/wix-headless/scripts/seed-utilities.sh +0 -93
- package/skills/wix-headless/scripts/write-decorative-json.mjs +0 -62
- package/skills/wix-headless/shared-utilities/analytics.ts +0 -40
- package/skills/wix-headless/shared-utilities/ricos.ts +0 -179
- package/skills/wix-headless/shared-utilities/wix-image.ts +0 -72
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "How to Code CMS"
|
|
3
|
+
description: The frontend read/write contract for Wix CMS (Wix Data) — the `@wix/data` `items.query` builder, the `_id`-and-fields-on-the-item shape (not `item.data.field`), why public-read collections need no `auth.elevate`, how to resolve images and render Ricos rich text, and the visitor-write path for collaborative collections (`items.insert`/`update`/`remove`, the update-replaces-whole-item footgun, shared/unscoped data). Specifies the *how* (module + exact calls + the failure modes the docs omit); which collections to render/write come from the request.
|
|
4
|
+
---
|
|
5
|
+
**RECIPE**: How to Code a Wix CMS Frontend (`@wix/data`, Wix Data v2)
|
|
6
|
+
|
|
7
|
+
A concise contract for writing the **frontend code** that reads Wix CMS collections: listing items, filtering, following references, and rendering images and rich text. **This recipe is the *how* (which module, which calls, which fields), not the *what*** — which collections to show, how the page looks, and the framework are decided by the request you're fulfilling.
|
|
8
|
+
|
|
9
|
+
> **This recipe is for CODING the frontend, not for seeding it.** It assumes the collections and items already exist and are **public-read** (created by `setup-cms.md`). It says nothing about creating collections or inserting data — only how to read them from frontend code.
|
|
10
|
+
|
|
11
|
+
> **⚠️ Reading rule — always append `.md?apiView=SDK` to every doc link below.** The Wix docs render two views of the same page. The **bare / REST view** describes the REST shape — items nested under `item.data.<field>` and queried via a `POST /items/query` body. The **`?apiView=SDK` view** describes the SDK shape — items with **fields on the item itself** and a chainable `items.query(...)` builder. The SDK is what your frontend calls; reading the REST view by mistake is the source of the `item.data.title`-returns-`undefined` bug below. Fetch the `.md?apiView=SDK` form directly.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## The module and the client (read this first)
|
|
16
|
+
|
|
17
|
+
**⚠️ CRITICAL: the Wix Data items API is the `items` named export of `@wix/data`** — `import { items } from "@wix/data"`, then `items.query` / `items.get` / `items.insert` / `items.update` / `items.remove` (plus `items.bulkInsert` / `items.queryReferenced`). Do **not** import from the internal `@wix/wix-data-items-sdk` — `@wix/data` is the single documented package.
|
|
18
|
+
|
|
19
|
+
| Need | Package | Module / export |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| Read collection items (query, get, filter, references) | `@wix/data` | `items` |
|
|
22
|
+
| Resolve `wix:image://` URIs to URLs | `@wix/sdk` | `media` |
|
|
23
|
+
|
|
24
|
+
**Collection id has NO namespace.** A native collection's id is just the name the seed created (`"team-members"`, `"faq"`, `"Projects"`) — pass it straight to `items.query("team-members")`. The `<namespace>/<name>` form is only for Wix App collections. Stay consistent with the `collectionId` the seed recipe kept.
|
|
25
|
+
|
|
26
|
+
**Auth / client — framework split:**
|
|
27
|
+
- **Astro (Wix-managed):** authentication is ambient. Call `items.query(...)` directly from server components and backend routes (`src/pages/api/*.ts`) — **no `createClient`, no `OAuthStrategy`, no `clientId`.**
|
|
28
|
+
- **Non-Astro (Vite/React/Vue/static):** build one manual visitor client and reuse it:
|
|
29
|
+
```js
|
|
30
|
+
import { createClient, OAuthStrategy } from '@wix/sdk';
|
|
31
|
+
import { items } from '@wix/data';
|
|
32
|
+
|
|
33
|
+
const client = createClient({
|
|
34
|
+
modules: { items },
|
|
35
|
+
auth: OAuthStrategy({ clientId: /* the project's PUBLIC OAuth client id */ }),
|
|
36
|
+
});
|
|
37
|
+
// then: client.items.query('team-members').find()
|
|
38
|
+
```
|
|
39
|
+
The `clientId` is public, not a secret.
|
|
40
|
+
|
|
41
|
+
**⚠️ CRITICAL: do NOT call `auth.elevate` — public collections are public-read, and member-scoped ones use the member token.** `setup-cms.md` creates a public collection with `read: "ANYONE"`, so the visitor token reads it directly. A pure SPA/static frontend has **no server and cannot elevate** at all; even on Astro the read is visitor-scoped and needs no elevation. (Elevation is only for collections that genuinely can't be public — not the case here.) **If a query on a PUBLIC collection comes back empty, it wasn't seeded public-read — that's a permissions bug in the seed, not a query bug** (re-check the collection's `read` permission); don't reach for `elevate` to paper over it.
|
|
42
|
+
|
|
43
|
+
**Member-scoped collections (only when the run includes members login).** A collection seeded member-scoped (`setup-cms.md` → `SITE_MEMBER_AUTHOR` for per-user-private, or `SITE_MEMBER` for member-only) is read/written with the **logged-in member's token** — the same client, just after the member has logged in (see `how-to-code-members-astro.md` / `how-to-code-members-non-astro.md`). Key rules:
|
|
44
|
+
- **Still NO `auth.elevate`.** The member token carries the identity; the platform scopes the rows server-side. Reaching for elevate here is the wrong axis (it's for admin/site-wide reads, not a member's own data).
|
|
45
|
+
- **`SITE_MEMBER_AUTHOR` returns only the caller's OWN rows automatically** (matched on the item's `_owner`) — you don't filter by owner in the query, and you **must not** set `_owner` on insert (the platform stamps it from the member identity). `items.query('my-notes').find()` as member A returns A's notes; as member B, B's.
|
|
46
|
+
- **An anonymous / not-yet-logged-in read returns ZERO items — that's the gate, not a bug.** Don't render a member-scoped surface to anonymous visitors: gate the route/page behind login first (bounce to the login flow), *then* query. An empty result after a confirmed login on a `SITE_MEMBER_AUTHOR` collection just means that member has no rows yet (show an empty state), not a permissions error.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## The shape you read (field cheat-sheet)
|
|
51
|
+
|
|
52
|
+
```jsonc
|
|
53
|
+
// items.query("CollectionId").find() → result.items[]
|
|
54
|
+
item = {
|
|
55
|
+
_id, // the item id (SDK normalizes to _id, NOT id)
|
|
56
|
+
_createdDate, _updatedDate, _owner, // system fields
|
|
57
|
+
name, role, bio, order, // YOUR fields — directly on the item (NOT item.data.name)
|
|
58
|
+
}
|
|
59
|
+
// result also has: result.length, result.hasNext(), result.pageSize
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`result.items[]` is the array; paging via `result.hasNext()` / a follow-up `.find()`. A `wix:image://` value in an IMAGE field and a Ricos object in a RICH_TEXT/RICH_CONTENT field both need resolving before render (see below).
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## The features (build the ones the site needs)
|
|
67
|
+
|
|
68
|
+
Each section is a **self-contained feature** — implement only what the site uses, in any order.
|
|
69
|
+
|
|
70
|
+
### Listing / reading (and the field-access rule)
|
|
71
|
+
|
|
72
|
+
Query a collection with the chainable builder; `.find()` resolves to `{ items, ... }`.
|
|
73
|
+
Doc: <https://dev.wix.com/docs/sdk/business-solutions/data/items/query.md?apiView=SDK>
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
const { items: rows } = await items.query('team-members')
|
|
77
|
+
.ascending('order')
|
|
78
|
+
.limit(50)
|
|
79
|
+
.find();
|
|
80
|
+
// rows[0] === { _id, name, role, bio, order, _createdDate, ... }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**⚠️ CRITICAL: fields are on the item itself — `item.name`, NOT `item.data.name`.** The SDK returns each field as a top-level property of the item (the API was revised to match the Velo `wix-data` shape). `item.data.name` is the **REST** response shape and reads `undefined` in SDK code — the silent "every field is blank" bug. If you're reaching through `.data`, you're reading the REST doc view; re-open it with `?apiView=SDK`.
|
|
84
|
+
|
|
85
|
+
**⚠️ CRITICAL: the id is `_id`, never `id`.** `item.id` is `undefined`; use `item._id` for keys, links, and reference lookups.
|
|
86
|
+
|
|
87
|
+
**⚠️ `items.queryDataItems(...)` does NOT exist in the SDK.** The chainable entry point is `items.query("collectionId")` — `queryDataItems` is a REST/method name. Don't mix the two.
|
|
88
|
+
|
|
89
|
+
### Filtering and single-item lookup
|
|
90
|
+
|
|
91
|
+
Chain filter/sort/page methods on the query builder, then `.find()`:
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
// by slug (detail page)
|
|
95
|
+
const { items: [post] } = await items.query('articles').eq('slug', slug).limit(1).find();
|
|
96
|
+
// compound filter + sort
|
|
97
|
+
const { items: rows } = await items.query('products')
|
|
98
|
+
.eq('inStock', true).gt('price', 25).ascending('title').limit(50).find();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Builder methods: `.eq` / `.ne` / `.gt` / `.ge` / `.lt` / `.le` / `.contains` / `.startsWith` / `.hasSome` / `.ascending` / `.descending` / `.limit` / `.skip`. (No `$`-operator JSON body — that's the REST `/items/query` shape; in the SDK the operators are builder methods.)
|
|
102
|
+
|
|
103
|
+
### Following references
|
|
104
|
+
|
|
105
|
+
A `REFERENCE` / `MULTI_REFERENCE` field stores only ids by default. To inline the referenced items, add `.include("<fieldKey>")`:
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
const { items: rows } = await items.query('projects').include('teamMembers').find();
|
|
109
|
+
// rows[0].teamMembers is now an array of full team-member items, not ids
|
|
110
|
+
```
|
|
111
|
+
Doc: <https://dev.wix.com/docs/sdk/business-solutions/data/items/query-referenced.md?apiView=SDK> (for `items.queryReferenced`, the alternative when a multi-reference set is large). Without `.include(...)`, the field is just ids — resolve them yourself or use `include`.
|
|
112
|
+
|
|
113
|
+
### Rendering images (IMAGE fields)
|
|
114
|
+
|
|
115
|
+
An `IMAGE` field comes back as a **`wix:image://v1/<hash>/<file>#…` identifier, not a ready URL** — putting it straight into `<img src>` shows nothing (`ERR_UNKNOWN_URL_SCHEME`). Resolve it with the SDK media module, and reuse one helper on every render path:
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
import { media } from '@wix/sdk';
|
|
119
|
+
function imgSrc(v, w = 800, h = 600) {
|
|
120
|
+
if (!v) return '';
|
|
121
|
+
if (typeof v === 'string' && v.startsWith('wix:image://')) return media.getScaledToFillImageUrl(v, w, h, {});
|
|
122
|
+
return typeof v === 'string' ? v : (v?.url ?? ''); // an already-absolute https URL passes through
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Never hand-build a `static.wixstatic.com/.../v1/fit/...` URL** — the format is easy to get wrong and the image then **403s**. Only `wix:image://` values need resolving; an already-absolute `https://` URL (e.g. an Unsplash placeholder seeded when imagery was off) goes straight into `<img src>`. Doc: <https://dev.wix.com/docs/sdk/core-modules/sdk/media>
|
|
127
|
+
|
|
128
|
+
**⚠️ When imagery is OFF (the seed default), IMAGE fields are EMPTY — fall back, don't render a broken `<img>`.** The seed is text-only unless imagery is on, so a `photo`/`coverImage`/`headshot` field is often **absent or empty** on every item. Guard the render: only emit `<img>` when the field resolves to a real URL, otherwise show a graceful fallback (an initials avatar, a colored placeholder, or simply omit the image) — never an empty/broken `<img src="">`. A missing image is expected content state here, not an error.
|
|
129
|
+
|
|
130
|
+
### Rendering rich text (RICH_TEXT / RICH_CONTENT fields)
|
|
131
|
+
|
|
132
|
+
Wix CMS stores `RICH_TEXT` / `RICH_CONTENT` as **Ricos JSON** — a structured node tree (PARAGRAPH, HEADING, BULLETED_LIST…), not HTML and not a string.
|
|
133
|
+
|
|
134
|
+
**⚠️ Do NOT `set:html={item.bio}` or `String(item.bio)` directly.** That dumps `[object Object]` or `{"nodes":...}` into the page. Render the Ricos node tree — either with a small SSR Ricos→HTML walker (covers PARAGRAPH, HEADING, lists, BLOCKQUOTE, BOLD/ITALIC/LINK; renders anything else defensively as a `<p>`), or with `@wix/ricos`'s React `RicosViewer` as a client island when the content carries the full feature set (galleries, embeds). For short bound fields a plain-text variant is fine; for a body field, render it **formatted**.
|
|
135
|
+
|
|
136
|
+
### Writing from the frontend (only to a visitor-writable collection)
|
|
137
|
+
|
|
138
|
+
Most collections are **read-only** from the visitor client — admin-owned content (catalog, team, articles) the site only displays. **Fire-and-forget visitor input** (contact, signup, lead capture) goes through **Wix Forms**, not CMS — don't `items.insert` for those.
|
|
139
|
+
|
|
140
|
+
But when the site is built around **shared, visitor-editable data** — a guestbook, a community board, a collaborative list anyone can add to and edit — that collection is seeded **visitor-writable** (`insert`/`update`/`remove: ANYONE`, see `setup-cms.md`), and the client does full CRUD with the same `items` module:
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
const created = await items.insert('community-board', { title, note, status: 'open' }); // → item with _id
|
|
144
|
+
await items.update('community-board', { ...item, status: 'claimed' }); // see footgun below
|
|
145
|
+
await items.remove('community-board', item._id);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**⚠️ CRITICAL: `items.update()` REPLACES the whole item — it does NOT patch.** Per the docs: *"If the existing item had fields with values and those fields aren't included in the updated item, the values in those properties are lost."* So `update('c', { _id, status })` **wipes `title`, `note`, and every other field** — the classic "toggling status erases the row" bug. **Always pass the FULL item** on update (spread the record you already hold in state: `{ ...item, status }`). If you only have the id + one changed field and not the whole record, use **`items.bulkPatch('c', [id]).setField('status', v).run()`** instead — `bulkPatch` modifies only the named fields. Doc: <https://dev.wix.com/docs/sdk/business-solutions/data/items/update.md?apiView=SDK>
|
|
149
|
+
|
|
150
|
+
**⚠️ A write needs the collection seeded with the matching open permission — else it 403s.** `items.insert`/`update`/`remove` only succeed if the collection was created with that verb at `ANYONE` (`setup-cms.md`). A write to an `ADMIN`-write collection 403s from the visitor client (there's no `auth.elevate` on this path to get around it). If writes 403, fix the seed permission, not the call.
|
|
151
|
+
|
|
152
|
+
**⚠️ On the ANONYMOUS path the data is SHARED and unscoped — no per-user identity.** The visitor token has no per-user identity, so an `ANYONE`-writable collection is **global/shared across all visitors** (not per-user, not cross-device) and **any visitor can edit or delete any row**. That's the intended model for a collaborative board; surface it as such. **For per-user-private data, that's the member-scoped path** (`SITE_MEMBER_AUTHOR`, see the member-scoped note above): the same `items.insert`/`update`/`remove` calls, but run under a **logged-in member's token**, and each member touches only their own `_owner`-matched rows. On Astro you may route writes through a backend `src/pages/api/*` endpoint, but the permission facts are identical — no `_owner` set by hand, no elevate.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Conclusion
|
|
157
|
+
A correct Wix CMS frontend:
|
|
158
|
+
- imports the **`items`** export of **`@wix/data`** (never `@wix/wix-data-items-sdk`), and `media` from `@wix/sdk` for images;
|
|
159
|
+
- queries with **`items.query("collectionId")` + builder methods + `.find()`** (no namespace on the id; `queryDataItems` doesn't exist);
|
|
160
|
+
- reads fields **on the item** (`item.name`) and the id as **`item._id`** — never `item.data.name`, never `item.id`;
|
|
161
|
+
- does **no `auth.elevate`** — a public collection is read on the visitor token (an empty result there is a seed permissions bug, not a query bug), and a **member-scoped** collection (opt-in, `SITE_MEMBER_AUTHOR`/`SITE_MEMBER`) is read on the **logged-in member's token** with the same no-elevate rule (an anonymous read returning empty is the gate, not a bug);
|
|
162
|
+
- resolves `wix:image://` via `media.getScaledToFillImageUrl` and renders Ricos rich text formatted (never raw `set:html`/`String`);
|
|
163
|
+
- treats CMS as **read-only by default** (fire-and-forget input → Forms); writes to a **visitor-writable** collection use `items.insert`/`update`/`remove` — always passing the **full item** on `update` (it replaces, not patches), expecting the data to be **shared/unscoped**, and relying on the collection's seeded `ANYONE` write permission (no `auth.elevate`). For **per-user-private** data (opt-in, members login in the run) the same calls run under the **member token** against a `SITE_MEMBER_AUTHOR` collection — each member sees/edits only their own `_owner`-matched rows, `_owner` is never set by hand, and the surface is gated behind login.
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "How to Code Events"
|
|
3
|
+
description: The frontend read/registration contract for a Wix Events (Events V3) site — which SDK modules to import, how to list upcoming events, read one by slug, list ticket tiers, and run the two registration paths (ticketed = reserve → redirect to Wix's hosted checkout; free = createRsvp). Specifies the *how* (modules + exact calls + the failure modes the docs omit); which events to render and how the page looks come from the request.
|
|
4
|
+
---
|
|
5
|
+
**RECIPE**: How to Code a Wix Events Frontend (Events V3 + hosted-checkout redirect)
|
|
6
|
+
|
|
7
|
+
A concise contract for writing the **frontend code** of an events site: a listing, per-event detail pages, ticketed checkout (reserve the tickets, then redirect to Wix's hosted checkout), and free RSVP registration. **This recipe is the *how* (which modules, which calls, which fields), not the *what*** — which events to show, how the page looks, and the framework are decided by the request you're fulfilling.
|
|
8
|
+
|
|
9
|
+
> **This recipe is for CODING the registration flow, not for seeding it.** It assumes an Events V3 backend already exists (published events with future dates, ticket definitions for ticketed events). It says nothing about creating events — only how to read and register for them from frontend code.
|
|
10
|
+
|
|
11
|
+
> **The whole flow is a site-visitor operation — no server route, no elevation.** Reserving tickets, minting the checkout redirect, and creating an RSVP all run under the **anonymous visitor** identity (the Events Checkout scope is granted to visitors), the same client-side model as the bookings pack. If you reach for a `src/pages/api/*` route or `auth.elevate()` to make a reservation work, **stop** — that masks the real gate (the payment-method precondition below) and the redirect call actively **fails** when elevated.
|
|
12
|
+
|
|
13
|
+
> **⚠️ Reading rule — always append `.md?apiView=SDK` to every doc link below.** The Wix docs render two views of the same page. The **bare / REST view shows `id`**; the **`?apiView=SDK` view shows `_id`** — and the SDK is what your frontend calls. Reading the REST view by mistake is the most common source of the `event.id`-is-`undefined` bug. If a field name surprises you, you're probably reading the REST view — re-open it with `?apiView=SDK`. Discover any shape not pinned here with `SearchWixSDKDocumentation`, not by guessing a URL.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## The modules and the client (read this first)
|
|
18
|
+
|
|
19
|
+
No app-id constant is needed in frontend code — the only id the client needs is the public **`clientId`** (non-Astro only; see below). Ticketed checkout hands off to Wix's hosted checkout via the Redirects API, so there is **no on-site cart and no `catalogReference`**.
|
|
20
|
+
|
|
21
|
+
| Need | Package | Module |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| List events / get one by slug | `@wix/events` | `wixEventsV2` (`queryEvents`, `getEventBySlug`) |
|
|
24
|
+
| Ticket tiers (ticketed) | `@wix/events` | `orders` (`queryAvailableTickets`) — the visitor-public storefront read |
|
|
25
|
+
| Reserve tickets (ticketed) | `@wix/events` | `ticketReservations` (`createTicketReservation`) |
|
|
26
|
+
| Create an RSVP (free) | `@wix/events` | **`rsvpV2`** (`createRsvp`) — NOT the legacy `rsvp` module (v1 → 400) |
|
|
27
|
+
| Redirect to hosted checkout (ticketed) | `@wix/redirects` | `redirects` (`createRedirectSession`) |
|
|
28
|
+
|
|
29
|
+
- **The events query/get namespace is `wixEventsV2`** (despite the name, this is the current Events V3 module from `@wix/events`). Import `wixEventsV2`, `orders`, `ticketReservations`, `rsvpV2` from `@wix/events`.
|
|
30
|
+
- **⚠️ CRITICAL: read ticket tiers with `orders.queryAvailableTickets`, NOT `ticketDefinitions(V2).queryTicketDefinitions`.** The `ticketDefinitions*` namespaces are the **management** API (`TicketDefinitionManagement`, a manage scope) — the **anonymous visitor is `403`-denied** on every one of them (`queryTicketDefinitions`, `queryTicketDefinitionsV2`, `listTicketDefinitions`), so a storefront that reads tiers that way gets an empty picker. **Do NOT work around it with `auth.elevate()`** — that's the wrong axis (an app/admin permission elevation), it's SSR-only (useless on a non-Astro SPA), and it's unnecessary: the **visitor-public storefront read** is `orders.queryAvailableTickets({ filter: { eventId }, limit })` → `{ definitions }` (visitor-public — works for the anonymous visitor on Astro *and* SPA). The event read (`queryEvents`/`getEventBySlug`) is visitor-public too — **no elevation anywhere in this recipe.**
|
|
31
|
+
- **Never use the deprecated `orders.createReservation`** — reserve with `ticketReservations.createTicketReservation`.
|
|
32
|
+
- **Never complete a paid purchase with `orders.checkout` (inline payment)** — that path leaves orders unpaid without a payment integration. The supported headless completion is the **hosted redirect** (below).
|
|
33
|
+
|
|
34
|
+
**Auth / client — framework split:**
|
|
35
|
+
- **Astro (Wix-managed):** authentication is ambient. Call the modules directly — from server components for the SSR reads (listing/detail) and from browser islands for the visitor-session writes (reserve / redirect / rsvp) via the `@wix/astro` visitor client — **no `createClient`, no `OAuthStrategy`, no `clientId`.** Nothing here needs elevation (every read and write runs as the visitor — "no elevation anywhere"); a public-env `clientId` read in `.astro` SSR is `undefined` at server render → 500, so don't build an `OAuthStrategy` client there.
|
|
36
|
+
- **Non-Astro (Vite/React/Vue/static):** build one manual visitor client and reuse it:
|
|
37
|
+
```js
|
|
38
|
+
import { createClient, OAuthStrategy } from '@wix/sdk';
|
|
39
|
+
import { wixEventsV2, orders, ticketReservations, rsvpV2 } from '@wix/events';
|
|
40
|
+
import { redirects } from '@wix/redirects';
|
|
41
|
+
|
|
42
|
+
const client = createClient({
|
|
43
|
+
modules: { wixEventsV2, orders, ticketReservations, rsvpV2, redirects },
|
|
44
|
+
auth: OAuthStrategy({ clientId: /* the project's PUBLIC OAuth client id */ }),
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
The `clientId` is public, not a secret. A mis-wired public env var inlines as `undefined` and 400s every call.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## The shapes you read (field cheat-sheet)
|
|
52
|
+
|
|
53
|
+
```jsonc
|
|
54
|
+
// wixEventsV2.getEventBySlug(slug, { fields: [...] }) → { event }
|
|
55
|
+
// wixEventsV2.queryEvents(...) → result.events[]
|
|
56
|
+
event = {
|
|
57
|
+
_id, // routes · reserve/rsvp bind to it (NOT .id → undefined)
|
|
58
|
+
slug, // the URL slug — checkout redirect needs it
|
|
59
|
+
title, shortDescription,
|
|
60
|
+
mainImage, // image ref (render via the media helper)
|
|
61
|
+
dateAndTimeSettings: { formatted: { dateAndTime } }, // human-formatted date string
|
|
62
|
+
location: { name, type }, // "VENUE" | "ONLINE" | TBD
|
|
63
|
+
registration: { initialType }, // "TICKETING" | "RSVP" — BRANCH on this
|
|
64
|
+
// categories?: { categories: [{ _id, name }] } // runtime shape when fields:['CATEGORIES'] is requested — but NOT on the typed Event (SDK gap): read via a cast, see below
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// orders.queryAvailableTickets({ filter: { eventId }, limit }) → { definitions } (VISITOR-public)
|
|
68
|
+
tier = {
|
|
69
|
+
_id, // reserve by this (NOT .id)
|
|
70
|
+
name, description,
|
|
71
|
+
price: { value, currency }, // value is a STRING (e.g. "45.00"); also at pricing.fixedPrice.value
|
|
72
|
+
free, // boolean
|
|
73
|
+
saleStatus, // "SALE_STARTED" | "SALE_ENDED" | "SALE_SCHEDULED" — gate the picker on this
|
|
74
|
+
limitPerCheckout, // max qty per order for this tier
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**⚠️ CRITICAL: entity ids are `_id`, NOT `id`.** `event._id`, `tier._id`. `event.id` is `undefined` in SDK code — a surprise `id`/`undefined` means you're reading the REST doc view; re-open it with `?apiView=SDK`.
|
|
79
|
+
|
|
80
|
+
**Filtering by event format/track (talk/workshop/social)** — if the site groups events by a format, the seed models it as **Event Categories** (`setup-events.md` STEP 4). Read the assigned category off the event and filter **client-side** — two gotchas:
|
|
81
|
+
- **Request `CATEGORIES` as the 2nd positional arg**, not inside the flat query: `queryEvents({ filter, sort, paging }, { fields: ['CATEGORIES'] })` and `getEventBySlug(slug, { fields: ['CATEGORIES'] })`. (`fields` lives on the options arg, not on `EventQuery`.)
|
|
82
|
+
- **`categories` is NOT on the typed `Event` (an SDK type gap** — the `CATEGORIES` enum and `EventCategory`/`EventCategories` types ship, but `Event` omits the property, so a direct `event.categories` read fails `tsc`/`astro check`). **Read it through a cast:** `const cats = (event as any).categories?.categories ?? []` — each entry is `{ _id, name }`; map `cats[].name` → your format enum.
|
|
83
|
+
- **Do NOT call the management categories endpoints** (`/events/v1/categories*`, `listEventsByCategory`) from the frontend — they're admin-scope; the visitor read is just the cast `CATEGORIES` field on the event.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## The registration features (build the ones the site needs)
|
|
88
|
+
|
|
89
|
+
Each section is a **self-contained feature** — implement only what the site uses. **Branch on the event's `registration.initialType`:** `TICKETING` → ticket picker (tiers + quantities → reserve → redirect); `RSVP` → the built-in name+email form → `createRsvp`. Never render an RSVP event with a ticket picker (or a ticketed event with an RSVP form).
|
|
90
|
+
|
|
91
|
+
### Listing events (upcoming only, and the `_id` rule)
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
const { events } = await wixEventsV2.queryEvents({
|
|
95
|
+
filter: { status: { $in: ['UPCOMING', 'STARTED'] } }, // exclude DRAFT / ENDED / CANCELED
|
|
96
|
+
sort: [{ fieldName: 'dateAndTimeSettings.startDate', order: 'ASC' }],
|
|
97
|
+
paging: { limit: 100 }, // ⚠️ MUST be > 0
|
|
98
|
+
}); // → result.events[]
|
|
99
|
+
```
|
|
100
|
+
Doc: <https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/query-events.md?apiView=SDK>
|
|
101
|
+
|
|
102
|
+
- **⚠️ CRITICAL: `queryEvents` takes the query object FLAT as its first arg — `queryEvents({ filter, sort, paging })`, NOT `queryEvents({ query: { … } })`.** The signature is `queryEvents(query, options)` where `query` *is* `{ filter, sort, paging }`. Wrapping it in an extra `{ query: … }` (the REST body shape, and the `.queryServices({ query })` builder shape from other verticals) is **not** rejected — the SDK silently ignores the unrecognized `query` key, so `paging` never applies, `limit` defaults to **0**, and you get **`events: []` with no error**. This is the #1 "my listing is empty even though events are published" trap. (The flat form returns the events; the nested form returns zero.)
|
|
103
|
+
- **⚠️ `paging.limit` MUST be > 0.** Even with the flat shape, `queryEvents` defaults `paging.limit` to **`0`, which returns zero events**. Always set a positive limit.
|
|
104
|
+
- The result array is **`result.events`** (not `.items`).
|
|
105
|
+
- **Filter to upcoming/published and never list or link a past event** — a past event isn't purchasable/registerable (the seed uses future dates). Filter by `status` (above) or by a future `startDate`.
|
|
106
|
+
- Read `event._id` / `event.slug` / `event.title`. A **single-event** site collapses the listing — lead the home page straight into the one event's detail. **Still drive that homepage from the listing query** (take the first/only result), never a hardcoded lone slug — so a second event the owner adds later automatically brings the listing back instead of staying invisible.
|
|
107
|
+
|
|
108
|
+
### One event by slug + its ticket tiers
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
const { event } = await wixEventsV2.getEventBySlug(slug, {
|
|
112
|
+
fields: ['DETAILS', 'TEXTS', 'REGISTRATION', 'URLS'], // REGISTRATION carries initialType — you branch on it
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// ticketed only — list the tiers (VISITOR-public; NOT ticketDefinitions* — those 403 the visitor):
|
|
116
|
+
const { definitions: tiers } = await orders.queryAvailableTickets({
|
|
117
|
+
filter: { eventId: event._id }, limit: 20,
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
Docs: <https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/get-event-by-slug.md?apiView=SDK> · <https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/orders/query-available-tickets.md?apiView=SDK>
|
|
121
|
+
|
|
122
|
+
- **Request `REGISTRATION` in `fields`** so `event.registration.initialType` is populated — that's the value you branch on.
|
|
123
|
+
- Per tier read `tier._id`, `tier.name`, `tier.price.value` (a **string**) + `tier.price.currency`, `tier.free`, and `tier.saleStatus` (gate the picker on `SALE_STARTED`).
|
|
124
|
+
- **⚠️ The confirmation page (post-checkout) reads the event by ID, and the return envelope DIFFERS from `getEventBySlug`.** After the hosted checkout redirects back to your `postFlowUrl` (carrying `?eventId=…`), look the event up with **`wixEventsV2.getEvent(eventId, { fields: ['TEXTS', 'URLS'] })`** — this returns the **`Event` object DIRECTLY (unwrapped)**: read `event.title` / `event.slug`, **not** `{ event }`. This is the one read that isn't wrapped (`getEventBySlug` *is* `{ event }`); assume the wrapper and the page crashes. Use this exact call — don't inspect the installed `.d.ts` to rediscover it.
|
|
125
|
+
|
|
126
|
+
### Ticketed checkout — reserve → redirect (the exact sequence)
|
|
127
|
+
|
|
128
|
+
Two steps, both as the visitor. **Use as-is — the payload shapes are easy to get subtly wrong.**
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
// 1 · Reserve the selected tiers (PENDING; auto-expires after the event's reservation window).
|
|
132
|
+
const reservation = await ticketReservations.createTicketReservation({
|
|
133
|
+
tickets: selections // one entry per chosen tier, quantity ≥ 1
|
|
134
|
+
.filter((s) => s.quantity > 0)
|
|
135
|
+
.map((s) => ({ ticketDefinitionId: s.ticketDefinitionId, quantity: s.quantity })),
|
|
136
|
+
});
|
|
137
|
+
const reservationId = reservation._id; // ⚠️ _id, not id
|
|
138
|
+
|
|
139
|
+
// 2 · Mint the hosted-checkout redirect and hand off.
|
|
140
|
+
const origin = window.location.origin; // ⚠️ the published https:// host — see below
|
|
141
|
+
const { redirectSession } = await redirects.createRedirectSession({
|
|
142
|
+
eventsCheckout: { reservationId, eventSlug: event.slug },
|
|
143
|
+
callbacks: {
|
|
144
|
+
thankYouPageUrl: `${origin}/event-confirmation`, // Wix appends ?orderNumber=&eventId=
|
|
145
|
+
postFlowUrl: `${origin}/events/${event.slug}`, // back to the event on abandon
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
window.location.href = redirectSession.fullUrl; // Wix collects guest details + payment, emails the PDF/QR ticket
|
|
149
|
+
```
|
|
150
|
+
Docs: <https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/ticket-reservations/create-ticket-reservation.md?apiView=SDK> · <https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md?apiView=SDK>
|
|
151
|
+
|
|
152
|
+
- **⚠️ CRITICAL: don't hand-build the checkout URL.** `{base}/event-details/{slug}/ticket-form?reservationId=…` **404s on a headless site** (there's no Wix-hosted event page). The Redirects API mints a checkout URL on Wix's own domain — `eventsCheckout: { reservationId, eventSlug }` → `redirectSession.fullUrl` is the **only** path that works headless.
|
|
153
|
+
- **⚠️ CRITICAL: the redirect call must run in the VISITOR (headless-OAuth) context — never elevated/admin.** `createRedirectSession` embeds the headless app's `clientId`; an admin/elevated token fails with *"client Id does not correspond to a headless oauth app."* On Astro the **browser island** calls it (ambient visitor client), never a server endpoint; on non-Astro it's the `OAuthStrategy` client. Don't elevate it.
|
|
154
|
+
- **⚠️ CRITICAL: `origin` MUST be the published `https://` host — from `window.location.origin`, never a server-derived `new URL(request.url).origin`.** The Headless redirect allowlist registers the `https://` host and treats `http://<same host>` as a different, unlisted origin; an `http://` `postFlowUrl` makes the return ("Continue Browsing") **403** with *"… isn't listed as an allowed redirect domain."* Pass `window.location.origin` from the client. Doc: <https://dev.wix.com/docs/go-headless/getting-started/setup/manage-urls/add-allowed-redirect-domains>.
|
|
155
|
+
- **⚠️ Handle the paid-ticket precondition softly.** Reserving a **paid** ticket as a visitor fails with **`403 "No payment method configured"`** until the site has a premium plan **and** a configured payment method (a dashboard step the seed already flagged). This is the **real gate** — not a permissions bug, and **not** something elevation should paper over (elevating just creates an unpayable `INITIATED` order). Catch the error; if its message matches `/payment method|not configured|premium/i`, show *"Ticket sales aren't switched on yet — the organizer needs to connect a payment method."* Free / RSVP events are unaffected.
|
|
156
|
+
- Wrap both calls in try/catch (sold out, sale ended, no payment method) and surface a friendly message; don't crash the page.
|
|
157
|
+
|
|
158
|
+
### Free RSVP — the built-in form
|
|
159
|
+
|
|
160
|
+
```js
|
|
161
|
+
await rsvpV2.createRsvp({
|
|
162
|
+
eventId: event._id,
|
|
163
|
+
firstName, lastName, email, // the built-in form fields — collect EXACTLY these
|
|
164
|
+
status: 'YES', // 'NO' only for YES_AND_NO events
|
|
165
|
+
});
|
|
166
|
+
// then show an inline confirmation — no reservation, no redirect, no payment
|
|
167
|
+
```
|
|
168
|
+
Doc: <https://dev.wix.com/docs/api-reference/business-solutions/events/registration/rsvp-v2/create-rsvp.md?apiView=SDK>
|
|
169
|
+
|
|
170
|
+
- **⚠️ CRITICAL: use the `rsvpV2` module, NOT `rsvp`.** The legacy `rsvp.createRsvp` posts to `/events/v1/rsvp` and **400s** with `"rsvp.firstName/lastName/email must not be empty"` even when you pass those fields — that v1 surface expects a different form-response body. Import **`rsvpV2`** from `@wix/events` and call `rsvpV2.createRsvp(rsvp)` with the rsvp object **directly as the first arg** (not wrapped in `{ rsvp: … }`, which is the elevated/`@wix/essentials` style). The flat `{ eventId, firstName, lastName, email, status }` object is correct for `rsvpV2` and **works for the anonymous visitor**.
|
|
171
|
+
- **The RSVP registration form is built-in** (firstName, lastName, email) — add exactly those fields; **don't fetch a form schema** or hand-build extra fields.
|
|
172
|
+
- Wrap in try/catch — a duplicate email or closed registration rejects; surface a friendly message.
|
|
173
|
+
|
|
174
|
+
### Rendering & mounting
|
|
175
|
+
|
|
176
|
+
- **Date**: `event.dateAndTimeSettings.formatted.dateAndTime` (already human-formatted) — request the `DETAILS` field to populate it.
|
|
177
|
+
- **Image**: `event.mainImage` is a Wix media ref — render it via the media helper (`@wix/sdk` `media.getScaledToFillImageUrl` / `getImageUrl`); **never** hand-build a `static.wixstatic.com` URL (→ 403).
|
|
178
|
+
- **Price**: `tier.price.value` (string) + `tier.price.currency` (the event's stored currency — format from it, don't assume USD).
|
|
179
|
+
- **Mount the ticket picker / RSVP form in a `client:only="react"` island** (Astro) — they run visitor-session SDK calls and redirect. **SSR only the read pages** (listing/detail) for SEO.
|
|
180
|
+
|
|
181
|
+
### SEO on item pages (Astro, Wix-managed)
|
|
182
|
+
|
|
183
|
+
An **event detail** page is a Wix **item page**: its `<title>`/description/OG/canonical come from what the owner sets in the dashboard. On the Astro (Wix-managed) frontend, wire it per the canonical guide — **[Add SEO Support to Item Pages](https://dev.wix.com/docs/go-headless/wix-managed-headless/seo/add-seo-support-to-item-pages.md)** — which covers the three steps: export `wixMetadata` (registers the route → sitemap + dashboard SEO editor), call `loadSEOTagsServiceConfig(...)`, and render `<SEO.Tags>` (from `@wix/seo`; deps + `@wix/essentials ≥ 1.0.10` are in the guide's "Before you begin").
|
|
184
|
+
|
|
185
|
+
For an event page use:
|
|
186
|
+
- **`wixMetadata`** from `WIX_APPS.events.eventPageMetadata` — referenced **directly** in the export (module scope). Route param `slug` → `identifiers.slug`.
|
|
187
|
+
- **`itemType`**: `seoTags.ItemType.EVENTS_PAGE`.
|
|
188
|
+
|
|
189
|
+
Fold `loadSEOTagsServiceConfig` into the same `Promise.all` as the ambient `getEventBySlug` read, with `.catch(() => null)` (it needs only the slug — still a visitor-safe ambient call), so a SEO hiccup falls back to the layout's default title. Optional: render an `Event` schema.org JSON-LD `<script>` from the fetched event (see the guide's structured-data step).
|
|
190
|
+
|
|
191
|
+
### Out of scope
|
|
192
|
+
Assigned seating / seat maps (display + reserve flat ticket definitions only); coupons & gift cards at checkout (Wix's hosted checkout handles those — don't build a discount UI); on-site order management / cancel / refund (handled by the hosted flow + the buyer's email); manual `orders.checkout` inline payment (use the hosted redirect).
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Conclusion
|
|
197
|
+
A correct Events V3 registration frontend:
|
|
198
|
+
- imports **`wixEventsV2` / `orders` / `ticketReservations` / `rsvpV2`** from `@wix/events` plus **`redirects`** from `@wix/redirects` — and never inline `orders.checkout` or the legacy `rsvp` (v1 → 400) module;
|
|
199
|
+
- uses **`event._id` / `tier._id`** (never `.id`) and reads the flat fields (`event.slug`, `registration.initialType`, `tier.price.value`);
|
|
200
|
+
- lists with **`queryEvents({ filter, sort, paging })` FLAT** (never `{ query: { … } }` — that silently returns `events: []`) and **`paging.limit > 0`**, filtered to **upcoming/published** events, never past ones;
|
|
201
|
+
- reads ticket tiers with the **visitor-public `orders.queryAvailableTickets({ filter: { eventId }, limit })`** (→ `definitions`) — **never** the management `ticketDefinitions*` query (visitor 403s) and **never** `auth.elevate()` (wrong axis, SSR-only); no elevation anywhere;
|
|
202
|
+
- **branches on `registration.initialType`**: `TICKETING` → reserve (`createTicketReservation` → `reservation._id`) → **`createRedirectSession({ eventsCheckout })`** → `redirectSession.fullUrl`; `RSVP` → **`rsvpV2.createRsvp`** with the built-in firstName/lastName/email and an inline confirmation;
|
|
203
|
+
- runs the reserve/redirect/rsvp **client-side as the visitor** (no server route, no elevation), uses `window.location.origin` (the `https://` host) for the callbacks, and **fails soft** on the `403 "No payment method configured"` paid-ticket precondition.
|