@wix/agent-skills 1.13.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 -244
- 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/Footer.astro +0 -27
- package/skills/wix-headless/references/astro/templates/Layout.astro +0 -132
- package/skills/wix-headless/references/astro/templates/Navigation.astro +0 -38
- 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/index.astro +0 -56
- 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 -141
- 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 -525
- 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 -148
- 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,111 @@
|
|
|
1
|
+
|
|
2
|
+
# Wix Portfolio Skill
|
|
3
|
+
|
|
4
|
+
> **Source files (in this skill):** the shared transport `references/shared/wix-client.js` and this vertical's `references/portfolio/wix-portfolio.js`. Copy **both** into your app's `src/rest/` side by side — the helper does `import { wixApiRequest } from "./wix-client.js"`, so they must land in the same folder.
|
|
5
|
+
|
|
6
|
+
Builds a real, client-only Wix portfolio showcase. The browser talks to Wix directly over a
|
|
7
|
+
public `WIX_CLIENT_ID`. Portfolio is **read-only**: never mock projects, never invent media,
|
|
8
|
+
and always render live Wix data (or an honest empty state). The content tree is
|
|
9
|
+
**Collection → Project → Project Item (image/video)**.
|
|
10
|
+
|
|
11
|
+
## When to use
|
|
12
|
+
- User wants a Wix portfolio / showcase site or asks to "connect Wix Portfolio".
|
|
13
|
+
- Replacing placeholder/mock galleries with live Wix Portfolio data.
|
|
14
|
+
- Adding a collections gallery, project grids, or a project detail page (media gallery +
|
|
15
|
+
details/links) over an existing Wix Portfolio.
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
1. A Wix site with **Wix Portfolio installed and content already added** — at least one
|
|
19
|
+
collection with projects, and projects with items (this skill does NOT provision; it is
|
|
20
|
+
read-only over the content).
|
|
21
|
+
2. The site's public headless **`WIX_CLIENT_ID`**, provided in the handoff prompt (the Wix
|
|
22
|
+
Business Manager surfaces a copyable prompt with the id filled in — see the router `SKILL.md`).
|
|
23
|
+
Paste it into `src/rest/wix-client.js` in place of the placeholder. It is a visitor-facing
|
|
24
|
+
credential (it only mints anonymous visitor tokens), **not** a secret, so
|
|
25
|
+
hardcoding/committing it is fine.
|
|
26
|
+
3. If the read calls return `403`/`428` before content is published, the Portfolio app or its
|
|
27
|
+
content may not be live yet. That is a **Wix dashboard setup step the owner completes** —
|
|
28
|
+
out of this skill's scope. Flag it and continue; don't fall back to mock data.
|
|
29
|
+
|
|
30
|
+
## The API (copy as-is; do not re-derive it)
|
|
31
|
+
This skill ships only the REST layer — no UI components. Build the portfolio's UI however the
|
|
32
|
+
project wants; wire it to these two snippets. Copy them into the app (e.g. `src/api/`) and only
|
|
33
|
+
adjust import paths:
|
|
34
|
+
- `src/rest/wix-client.js` — visitor-token mint/refresh + transport. Set `WIX_CLIENT_ID` to the
|
|
35
|
+
id from the prompt (replace the `<YOUR-CLIENT-ID>` placeholder). The visitor refresh token is
|
|
36
|
+
persisted to localStorage; do not re-mint anonymously per load.
|
|
37
|
+
- `src/rest/wix-portfolio.js` — exports:
|
|
38
|
+
- **Collections:** `queryCollections`, `getCollectionBySlug`, `countCollections`
|
|
39
|
+
- **Projects:** `queryProjects`, `queryProjectsByCollection`, `getProjectBySlug`, `getProject`
|
|
40
|
+
- **Project items (media):** `listProjectItems`
|
|
41
|
+
|
|
42
|
+
The Collection, Project, and Project Item shapes are documented as JSDoc comments at the top of
|
|
43
|
+
`wix-portfolio.js`. Read them before building the UI — they describe the key fields (cover
|
|
44
|
+
image/video, media resolutions, details rows) and link to the full API reference.
|
|
45
|
+
|
|
46
|
+
## How to wire it (UI is the project's choice)
|
|
47
|
+
- **Collections gallery (home)** — `queryCollections()` for the listing (visible collections
|
|
48
|
+
only, in dashboard order); pass `nextCursor` back as `cursor` to load the next page. Render
|
|
49
|
+
`collection.title`, `collection.description`, and `collection.coverImage.imageInfo.url`. Link
|
|
50
|
+
each card to a collection page keyed on `collection.slug`.
|
|
51
|
+
- **Collection page** — `getCollectionBySlug(slug)` for the header (returns null on miss — show
|
|
52
|
+
a not-found state, never invent one). Then `queryProjectsByCollection(collection.id, { limit?, cursor? })`
|
|
53
|
+
for its project grid; paginate exactly like `queryCollections`.
|
|
54
|
+
- **All-work gallery (optional)** — `queryProjects()` to list every visible project across
|
|
55
|
+
collections (newest-first); paginate the same way.
|
|
56
|
+
- **Project grid card** — render `project.title` and the cover: use `project.coverImage.imageInfo.url`
|
|
57
|
+
when present, else the `project.coverVideo.videoInfo.posters[0]` / first
|
|
58
|
+
`coverVideo.videoInfo.resolutions[]` entry. Link each card to a project page keyed on `project.slug`.
|
|
59
|
+
- **Project detail page** — `getProjectBySlug(slug)` for the header (title, description, and the
|
|
60
|
+
`details[]` rows: each has a `label` plus either `text` or `link: { text, url, target }`).
|
|
61
|
+
Then `listProjectItems(project.id)` for the media gallery — render IMAGE items from
|
|
62
|
+
`image.imageInfo.url` and VIDEO items from the first `video.videoInfo.resolutions[]` entry
|
|
63
|
+
(with `video.videoInfo.posters[0]` as the poster). Honor each item's optional `link`.
|
|
64
|
+
- If you already hold a project id (not a slug), use `getProject(projectId)` instead.
|
|
65
|
+
- **Empty state** — if `countCollections()` is 0, show an empty state telling the user to add
|
|
66
|
+
collections and projects in their Wix dashboard. Never invent projects or media.
|
|
67
|
+
|
|
68
|
+
## Hard rules (do not violate)
|
|
69
|
+
- ✅ Render only live Wix Portfolio data — collections, projects, and items as returned.
|
|
70
|
+
- ❌ Never mock projects, collections, or media — render live data or the empty state.
|
|
71
|
+
- ❌ Never hand-build Wix Media URLs or page permalinks — use the `url`/`imageInfo.url`/
|
|
72
|
+
`videoInfo.resolutions[].url` fields Wix returns.
|
|
73
|
+
- ❌ Never invent project details, captions, dates, or testimonials. Show only what the API returns.
|
|
74
|
+
- ❌ Never show `hidden: true` collections or projects to visitors (the helpers already filter
|
|
75
|
+
`hidden` out — don't add them back).
|
|
76
|
+
- ✅ Set `WIX_CLIENT_ID` from the prompt's value (public client id — safe to hardcode).
|
|
77
|
+
- ✅ Route on `slug` (`getCollectionBySlug` / `getProjectBySlug`); fall back to `getProject(id)`
|
|
78
|
+
only when you hold a GUID.
|
|
79
|
+
- The helpers fail soft on read: single fetches return `null` on a miss so you render a
|
|
80
|
+
not-found/empty state rather than a crash — surface that state, don't paper over it with fake data.
|
|
81
|
+
|
|
82
|
+
## Beyond the snippets
|
|
83
|
+
The snippets cover the common portfolio paths. If you hit a use case they don't cover (e.g.
|
|
84
|
+
collection SEO tags, project watermark settings, portfolio-wide settings, or filtering by a
|
|
85
|
+
field not shown), make the call yourself with `wixApiRequest` — but look up the exact endpoint,
|
|
86
|
+
HTTP method, and request body in the **official Wix API reference** first; never guess:
|
|
87
|
+
- Wix Portfolio API reference: https://dev.wix.com/docs/api-reference/business-solutions/portfolio.md
|
|
88
|
+
- Portfolio Settings (logo, layout, options): https://dev.wix.com/docs/api-reference/business-solutions/portfolio/portfolio-settings/get-portfolio-settings.md
|
|
89
|
+
- API query language (filters, sort, paging): https://dev.wix.com/docs/rest/articles/getting-started/api-query-language.md
|
|
90
|
+
|
|
91
|
+
Keep the snippets as the default for everything they already do; reach for the API reference
|
|
92
|
+
only for the gap.
|
|
93
|
+
|
|
94
|
+
## Point the user to their dashboard
|
|
95
|
+
In some cases, users need to access the Wix dashboard in order to edit the portfolio content for their site. To facilitate this, provide the user with deep links directly to the relevant dashboard pages. For portfolio data those pages are:
|
|
96
|
+
- **Portfolio** — `https://manage.wix.com/dashboard/{metaSiteId}/wix-portfolio/projects` (`Dashboard → Portfolio`). Projects and Collections are tabs on this one page: the **Projects** tab adds projects and their media galleries; the **Collections** tab groups projects into collections.
|
|
97
|
+
|
|
98
|
+
Substitute the site's `metaSiteId` to complete the links (you have it from the handoff / `ListWixSites`). Include the in-dashboard navigation as a fallback.
|
|
99
|
+
|
|
100
|
+
## Verification checklist (before declaring done)
|
|
101
|
+
- [ ] `WIX_CLIENT_ID` set to the prompt's value (not the `<YOUR-CLIENT-ID>` placeholder)
|
|
102
|
+
- [ ] Visitor token persists across reload (no re-mint storm; reads stay fast)
|
|
103
|
+
- [ ] Collections gallery renders live collections with cover images, in dashboard order
|
|
104
|
+
- [ ] Clicking a collection lists its projects via `queryProjectsByCollection`
|
|
105
|
+
- [ ] Project page renders the project's media gallery from `listProjectItems` (images AND videos)
|
|
106
|
+
- [ ] Project `details[]` rows render (text rows and link rows both)
|
|
107
|
+
- [ ] Slug routing works; an unknown slug shows a not-found state (no invented project)
|
|
108
|
+
- [ ] Hidden collections/projects never appear
|
|
109
|
+
- [ ] Empty state shown when `countCollections()` is 0
|
|
110
|
+
- [ ] No mock projects, collections, or media anywhere
|
|
111
|
+
- [ ] Told the user at least once that they can continue setting up their portfolio in the dashboard and provided deep links.
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { wixApiRequest } from "./wix-client.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wix Portfolio — read-only showcase. 3-level tree:
|
|
5
|
+
* Collection → Project → Project Item (image or video)
|
|
6
|
+
* Hidden entities (hidden: true) are editor-only — every helper here filters them out.
|
|
7
|
+
*
|
|
8
|
+
* Collection: { id, title, description, slug, hidden, sortOrder,
|
|
9
|
+
* coverImage.imageInfo: { id, url, height, width, altText },
|
|
10
|
+
* url: { relativePath, url } (only when includePageUrl=true) }
|
|
11
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/portfolio/collections/collection-object.md
|
|
12
|
+
*
|
|
13
|
+
* Project: { id, title, description, slug, hidden, collectionIds {string[]},
|
|
14
|
+
* details {array} — [{ label, text? OR link: { text, url, target } }],
|
|
15
|
+
* coverImage.imageInfo: { id, url, height, width, altText } (ONE-OF with coverVideo),
|
|
16
|
+
* coverVideo.videoInfo: { id, url, posters, resolutions },
|
|
17
|
+
* url: { relativePath, url } (only when includePageUrl=true) }
|
|
18
|
+
* Full media gallery is in Project Items — fetch with listProjectItems(project.id).
|
|
19
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/portfolio/projects/project-object.md
|
|
20
|
+
*
|
|
21
|
+
* Project Item: { id, projectId, sortOrder, title, description,
|
|
22
|
+
* type "IMAGE"|"VIDEO"|"UNDEFINED",
|
|
23
|
+
* image.imageInfo: { id, url, height, width, altText } (when IMAGE),
|
|
24
|
+
* video.videoInfo: { id, url, posters, resolutions } (when VIDEO; render first resolution),
|
|
25
|
+
* link: { text, url, target } }
|
|
26
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/portfolio/project-items/project-item-object.md
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const COLLECTIONS_QUERY_URL = "/portfolio/v1/collections/query";
|
|
30
|
+
const PROJECTS_QUERY_URL = "/portfolio/v1/projects/query";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Query visible portfolio collections (one page), sorted by their dashboard order.
|
|
34
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/collections/query-collections.md
|
|
35
|
+
* @param {{ limit?: number, cursor?: string }} [options]
|
|
36
|
+
* @returns {Promise<{ collections: object[], nextCursor: string|null }>}
|
|
37
|
+
*/
|
|
38
|
+
export async function queryCollections({ limit = 100, cursor } = {}) {
|
|
39
|
+
const res = await wixApiRequest(COLLECTIONS_QUERY_URL, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
body: {
|
|
42
|
+
includePageUrl: true,
|
|
43
|
+
query: cursor
|
|
44
|
+
? { cursorPaging: { limit, cursor } }
|
|
45
|
+
: {
|
|
46
|
+
filter: { hidden: false },
|
|
47
|
+
sort: [{ fieldName: "sortOrder", order: "ASC" }],
|
|
48
|
+
cursorPaging: { limit },
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
collections: res?.collections ?? [],
|
|
54
|
+
nextCursor: res?.metadata?.cursors?.next ?? null,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get a single visible collection by its URL slug. Returns null if not found / hidden.
|
|
60
|
+
* Portfolio has no get-by-slug endpoint, so this queries with a slug filter.
|
|
61
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/collections/query-collections.md
|
|
62
|
+
* @param {string} slug
|
|
63
|
+
* @returns {Promise<object|null>}
|
|
64
|
+
*/
|
|
65
|
+
export async function getCollectionBySlug(slug) {
|
|
66
|
+
const res = await wixApiRequest(COLLECTIONS_QUERY_URL, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
body: {
|
|
69
|
+
includePageUrl: true,
|
|
70
|
+
query: { filter: { slug, hidden: false }, cursorPaging: { limit: 1 } },
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
return res?.collections?.[0] ?? null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Total number of visible collections. Used for empty-state logic
|
|
78
|
+
* (0 → prompt the user to add collections in their Wix dashboard).
|
|
79
|
+
* @returns {Promise<number>}
|
|
80
|
+
*/
|
|
81
|
+
export async function countCollections() {
|
|
82
|
+
const res = await wixApiRequest(COLLECTIONS_QUERY_URL, {
|
|
83
|
+
method: "POST",
|
|
84
|
+
body: { query: { filter: { hidden: false }, cursorPaging: { limit: 100 } } },
|
|
85
|
+
});
|
|
86
|
+
return res?.metadata?.total ?? (res?.collections?.length ?? 0);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Query visible projects (one page), sorted newest-first. Use for an "all work" gallery.
|
|
91
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/projects/query-projects.md
|
|
92
|
+
* @param {{ limit?: number, cursor?: string }} [options]
|
|
93
|
+
* @returns {Promise<{ projects: object[], nextCursor: string|null }>}
|
|
94
|
+
*/
|
|
95
|
+
export async function queryProjects({ limit = 100, cursor } = {}) {
|
|
96
|
+
const res = await wixApiRequest(PROJECTS_QUERY_URL, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
body: {
|
|
99
|
+
includePageUrl: true,
|
|
100
|
+
query: cursor
|
|
101
|
+
? { cursorPaging: { limit, cursor } }
|
|
102
|
+
: {
|
|
103
|
+
filter: { hidden: false },
|
|
104
|
+
sort: [{ fieldName: "createdDate", order: "DESC" }],
|
|
105
|
+
cursorPaging: { limit },
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
return {
|
|
110
|
+
projects: res?.projects ?? [],
|
|
111
|
+
nextCursor: res?.metadata?.cursors?.next ?? null,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Query the visible projects that belong to a collection (one page), in dashboard order.
|
|
117
|
+
* Filters on `collectionIds` with `$hasSome`.
|
|
118
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/projects/query-projects.md
|
|
119
|
+
* @param {string} collectionId `collection.id` from queryCollections / getCollectionBySlug.
|
|
120
|
+
* @param {{ limit?: number, cursor?: string }} [options]
|
|
121
|
+
* @returns {Promise<{ projects: object[], nextCursor: string|null }>}
|
|
122
|
+
*/
|
|
123
|
+
export async function queryProjectsByCollection(collectionId, { limit = 100, cursor } = {}) {
|
|
124
|
+
const res = await wixApiRequest(PROJECTS_QUERY_URL, {
|
|
125
|
+
method: "POST",
|
|
126
|
+
body: {
|
|
127
|
+
includePageUrl: true,
|
|
128
|
+
query: cursor
|
|
129
|
+
? { cursorPaging: { limit, cursor } }
|
|
130
|
+
: {
|
|
131
|
+
filter: { hidden: false, collectionIds: { $hasSome: [collectionId] } },
|
|
132
|
+
cursorPaging: { limit },
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
return {
|
|
137
|
+
projects: res?.projects ?? [],
|
|
138
|
+
nextCursor: res?.metadata?.cursors?.next ?? null,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get a single visible project by its URL slug. Returns null if not found / hidden.
|
|
144
|
+
* Portfolio has no get-by-slug endpoint, so this queries with a slug filter.
|
|
145
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/projects/query-projects.md
|
|
146
|
+
* @param {string} slug
|
|
147
|
+
* @returns {Promise<object|null>}
|
|
148
|
+
*/
|
|
149
|
+
export async function getProjectBySlug(slug) {
|
|
150
|
+
const res = await wixApiRequest(PROJECTS_QUERY_URL, {
|
|
151
|
+
method: "POST",
|
|
152
|
+
body: {
|
|
153
|
+
includePageUrl: true,
|
|
154
|
+
query: { filter: { slug, hidden: false }, cursorPaging: { limit: 1 } },
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
return res?.projects?.[0] ?? null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get a single project by its GUID. Returns null if not found.
|
|
162
|
+
* Use when you already hold a project id (e.g. from a list) rather than a slug.
|
|
163
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/projects/get-project.md
|
|
164
|
+
* @param {string} projectId
|
|
165
|
+
* @returns {Promise<object|null>}
|
|
166
|
+
*/
|
|
167
|
+
export async function getProject(projectId) {
|
|
168
|
+
try {
|
|
169
|
+
const res = await wixApiRequest(`/portfolio/v1/projects/${encodeURIComponent(projectId)}`, {
|
|
170
|
+
method: "GET",
|
|
171
|
+
query: { includePageUrl: "true" },
|
|
172
|
+
});
|
|
173
|
+
return res?.project ?? null;
|
|
174
|
+
} catch {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* List all media items (images/videos) of a project, in dashboard order.
|
|
181
|
+
* This is the project's gallery — call it on the project detail screen.
|
|
182
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/project-items/list-project-items.md
|
|
183
|
+
* @param {string} projectId `project.id`.
|
|
184
|
+
* @param {{ limit?: number, offset?: number }} [options] Project items use offset paging, not cursors.
|
|
185
|
+
* @returns {Promise<{ items: object[], total: number }>}
|
|
186
|
+
*/
|
|
187
|
+
export async function listProjectItems(projectId, { limit = 100, offset = 0 } = {}) {
|
|
188
|
+
const res = await wixApiRequest(`/portfolio/v1/projectItems/${encodeURIComponent(projectId)}/items`, {
|
|
189
|
+
method: "GET",
|
|
190
|
+
query: { "paging.limit": String(limit), "paging.offset": String(offset) },
|
|
191
|
+
});
|
|
192
|
+
const items = (res?.items ?? []).slice().sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
|
|
193
|
+
return { items, total: res?.metadata?.total ?? items.length };
|
|
194
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
|
|
2
|
+
# Wix Pricing Plans Skill
|
|
3
|
+
|
|
4
|
+
> **Source files (in this skill):** the shared transport `references/shared/wix-client.js` and this vertical's `references/pricing-plans/wix-pricing-plans.js`. Copy **both** into your app's `src/rest/` side by side — the helper does `import { wixApiRequest } from "./wix-client.js"`, so they must land in the same folder.
|
|
5
|
+
|
|
6
|
+
Builds a real, client-only Wix pricing-plans / membership front end. The browser talks to Wix
|
|
7
|
+
directly over a public `WIX_CLIENT_ID`. Never mock plans; never hand-build a `/checkout` or
|
|
8
|
+
purchase URL — purchasing always goes through the Wix-hosted **redirect-session** (which also
|
|
9
|
+
handles member login and payment).
|
|
10
|
+
|
|
11
|
+
## When to use
|
|
12
|
+
- User wants a "Plans & Pricing", membership, or subscription page on a Wix site.
|
|
13
|
+
- User asks to "connect Wix pricing plans" or sell memberships / subscriptions / paid plans.
|
|
14
|
+
- Replacing placeholder/mock plans with live Wix data.
|
|
15
|
+
- Adding a plan detail page, a buy/subscribe button, or a "my plans" area over existing plans.
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
1. A Wix site with **Pricing Plans installed and at least one plan created** (this skill does
|
|
19
|
+
NOT provision — it's read-only over the plans the merchant added in the dashboard).
|
|
20
|
+
2. The site's public headless **`WIX_CLIENT_ID`**, provided in the handoff prompt (the Wix
|
|
21
|
+
Business Manager surfaces a copyable prompt with the id filled in — see the router `SKILL.md`). Paste
|
|
22
|
+
it into `src/rest/wix-client.js` in place of the placeholder. It is a buyer-facing credential
|
|
23
|
+
(it only mints anonymous visitor tokens), **not** a secret, so hardcoding/committing it is fine.
|
|
24
|
+
3. **Purchasing a plan is members-only and uses Wix-hosted checkout.** The hosted flow handles
|
|
25
|
+
member login/signup + the order form + payment, then returns to your site. The deployed app
|
|
26
|
+
domain must be allow-listed on the OAuth client for that return to work — this is a **separate
|
|
27
|
+
Wix setup flow the user completes later**, out of this skill's scope. If the return fails
|
|
28
|
+
before that setup is done, that's expected; flag it and continue.
|
|
29
|
+
4. To actually charge for paid plans, the site needs a payment method connected and (where
|
|
30
|
+
applicable) tax/business-address configured in the Wix dashboard. Free plans work without this.
|
|
31
|
+
|
|
32
|
+
## The API (copy as-is; do not re-derive it)
|
|
33
|
+
This skill ships only the REST layer — no UI components. Build the page's UI however the project
|
|
34
|
+
wants; wire it to these two snippets. Copy them into the app (e.g. `src/api/`) and only adjust
|
|
35
|
+
import paths:
|
|
36
|
+
- `src/rest/wix-client.js` — visitor-token mint/refresh + transport. Set `WIX_CLIENT_ID` to the
|
|
37
|
+
id from the prompt (replace the `<YOUR-CLIENT-ID>` placeholder). The visitor refresh token is
|
|
38
|
+
persisted to localStorage; after a hosted checkout the same identity returns as a logged-in
|
|
39
|
+
member. Do not re-mint anonymously per load.
|
|
40
|
+
- `src/rest/wix-pricing-plans.js` — exports:
|
|
41
|
+
- **Plans:** `queryPlans`, `getPlanById`, `getPlanBySlug`
|
|
42
|
+
- **Purchase:** `checkout`
|
|
43
|
+
- **Member:** `getMyPlanOrders`
|
|
44
|
+
|
|
45
|
+
The Plan and Order shapes are documented as JSDoc comments at the top of `wix-pricing-plans.js`.
|
|
46
|
+
Read them before building the UI — pricing has several models (recurring subscription,
|
|
47
|
+
single-payment-for-duration, single-payment-unlimited, free, plus free trials) and the JSDoc
|
|
48
|
+
shows exactly how to read price, cycle, and trial for display.
|
|
49
|
+
|
|
50
|
+
## How to wire it (UI is the project's choice)
|
|
51
|
+
- **Plans grid** — `queryPlans()` for the listing (PUBLIC plans only); pass `nextCursor` back as
|
|
52
|
+
`cursor` to load the next page. For each plan render `name`, `description`, `perks[].description`
|
|
53
|
+
as feature bullets, and the price from `pricingVariants[0]` (see the JSDoc "Reading the price"
|
|
54
|
+
notes: `pricingStrategies[0].flatRate.amount` + plan `currency`, plus `billingCycle` for
|
|
55
|
+
recurring and `freeTrialDays` for trials). Show a "Subscribe"/"Buy" button only when
|
|
56
|
+
`plan.buyable` is true.
|
|
57
|
+
- **Plan detail** — `getPlanBySlug(slug)` keyed off the URL slug (or `getPlanById(id)`); returns
|
|
58
|
+
null on miss — show a not-found state, never invent a plan. Render perks, the full price/billing
|
|
59
|
+
summary, free-trial note, and `termsAndConditions` if present.
|
|
60
|
+
- **Purchase** — `window.location.href = await checkout(planId, { thankYouPageUrl })`. This
|
|
61
|
+
redirects to Wix-hosted checkout, which logs the member in (or signs them up), collects the
|
|
62
|
+
order form, and takes payment. On success Wix returns to `thankYouPageUrl` with a
|
|
63
|
+
`?planOrderId=<GUID>` query param (and `wixMemberLoggedIn`); on abandon/interrupt it returns to
|
|
64
|
+
`postFlowUrl` (defaults to the current page). Never create the order or build the URL yourself.
|
|
65
|
+
- **My plans / confirmation** — `getMyPlanOrders()` for the logged-in member's purchases; filter
|
|
66
|
+
with `{ orderStatuses: ["ACTIVE"] }` for current memberships. After returning from checkout,
|
|
67
|
+
re-fetch (e.g. on mount + `visibilitychange`, or when `planOrderId` is in the URL) to show the
|
|
68
|
+
new order. Returns `[]` for anonymous visitors — show a "log in to see your plans" state, and wire
|
|
69
|
+
that log-in via the **members** vertical (`references/members/`) so they can sign in on your own UI.
|
|
70
|
+
- **Empty state** — if `queryPlans()` returns no plans, show an empty state telling the user to
|
|
71
|
+
create plans in their Wix dashboard. Never invent plans.
|
|
72
|
+
|
|
73
|
+
## Hard rules (do not violate)
|
|
74
|
+
- ✅ Purchase ONLY via `checkout()` (`/headless/v1/redirect-session` with `paidPlansCheckout`),
|
|
75
|
+
then redirect to `redirectSession.fullUrl`.
|
|
76
|
+
- ❌ Never hand-build a checkout, purchase, or `/plans-checkout` URL; never call create-order
|
|
77
|
+
directly from the client to "skip" the hosted flow.
|
|
78
|
+
- ❌ Never mock plans — render live Wix data or the empty state.
|
|
79
|
+
- ❌ Never invent perks, prices, trials, testimonials, or member counts. Render only what the
|
|
80
|
+
plan object returns; empty perks → no feature list.
|
|
81
|
+
- ✅ Set `WIX_CLIENT_ID` from the prompt's value (public client id — safe to hardcode).
|
|
82
|
+
- ✅ Treat plan objects as display-only — never compute the final charge; Wix settles price, tax,
|
|
83
|
+
proration, and schedule during hosted checkout.
|
|
84
|
+
- ✅ Show the buy button only when `plan.buyable` is true; otherwise the plan is merchant-assigned.
|
|
85
|
+
- The engine fails loudly on purpose: `checkout()` throws if it can't create the redirect session.
|
|
86
|
+
A green path means it really reached Wix-hosted checkout — don't swallow these.
|
|
87
|
+
|
|
88
|
+
## Beyond the snippets
|
|
89
|
+
The snippets cover the common plans paths. If you hit a use case they don't cover, make the call
|
|
90
|
+
yourself with `wixApiRequest` — but look up the exact endpoint, HTTP method, and request body in
|
|
91
|
+
the **official Wix API reference** first; never guess:
|
|
92
|
+
- Pricing Plans API reference: https://dev.wix.com/docs/api-reference/business-solutions/pricing-plans.md
|
|
93
|
+
- Orders (cancel / pause / resume a member's order, price preview): https://dev.wix.com/docs/api-reference/business-solutions/pricing-plans/orders.md
|
|
94
|
+
- Headless redirect session (login, logout, other checkouts): https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
|
|
95
|
+
|
|
96
|
+
Common genuine gaps and where to look:
|
|
97
|
+
- **Cancel / pause / resume** a member's subscription → Orders API (`request-cancellation`,
|
|
98
|
+
`pause-order`, `resume-order`). Gate on `plan.buyerCanCancel`.
|
|
99
|
+
- **Member login / logout** outside of a purchase → use the **members** vertical
|
|
100
|
+
(`references/members/INSTRUCTIONS.md`) for *custom* login (email+password / Google / Facebook / SSO)
|
|
101
|
+
on your own UI — so a member can log in *before* subscribing and see "my plans" without going through
|
|
102
|
+
a purchase. Pair it with this vertical whenever plans need a real account surface.
|
|
103
|
+
- **Coupons / custom start date** at purchase → covered by the hosted checkout; for a fully
|
|
104
|
+
custom flow see Create Online Order in the Orders reference.
|
|
105
|
+
|
|
106
|
+
Keep the snippets as the default for everything they already do; reach for the API reference only
|
|
107
|
+
for the gap.
|
|
108
|
+
|
|
109
|
+
## Point the user to their dashboard
|
|
110
|
+
In some cases, users need to access the Wix dashboard in order to edit the pricing plans content for their site. To facilitate this, provide the user with deep links directly to the relevant dashboard pages. For pricing plans data those pages are:
|
|
111
|
+
- **Pricing Plans** — `https://manage.wix.com/dashboard/{metaSiteId}/pricing-plans` (`Dashboard → Pricing Plans`) → **+ Create Plan** (set the name, pricing model, perks, and connect the plan to the content/services it unlocks)
|
|
112
|
+
|
|
113
|
+
Substitute the site's `metaSiteId` to complete the links (you have it from the handoff / `ListWixSites`). Include the in-dashboard navigation as a fallback.
|
|
114
|
+
|
|
115
|
+
## Verification checklist (before declaring done)
|
|
116
|
+
- [ ] `WIX_CLIENT_ID` set to the prompt's value (not the `<YOUR-CLIENT-ID>` placeholder)
|
|
117
|
+
- [ ] Plans list renders live data; price, billing cycle, and free trial read correctly across
|
|
118
|
+
pricing models (recurring, single-payment, free)
|
|
119
|
+
- [ ] Plan detail loads by slug and shows a not-found state on a bad slug
|
|
120
|
+
- [ ] Buy button shown only for `buyable` plans
|
|
121
|
+
- [ ] Purchase redirects via redirect-session `fullUrl` (no hand-built URL) and reaches
|
|
122
|
+
Wix-hosted login + payment
|
|
123
|
+
- [ ] On return, the new order appears via `getMyPlanOrders()` (and a "log in" state shows for
|
|
124
|
+
anonymous visitors)
|
|
125
|
+
- [ ] Empty state shown when `queryPlans()` returns no plans
|
|
126
|
+
- [ ] No mock plans, perks, or prices anywhere
|
|
127
|
+
- [ ] Told the user at least once that they can continue setting up their plans in the dashboard and provided deep links.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { wixApiRequest } from "./wix-client.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wix Pricing Plans V3 Plan — key fields for a Plans & Pricing page.
|
|
5
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/pricing-plans/plans-v3/plan-object.md
|
|
6
|
+
*
|
|
7
|
+
* id {string}, name {string}, description {string}, slug {string},
|
|
8
|
+
* image {object} — { id, width, height, altText } (id is a WixMedia id),
|
|
9
|
+
* currency {string} — ISO-4217 e.g. "USD", termsAndConditions {string},
|
|
10
|
+
* visibility "PUBLIC"|"PRIVATE" — queryPlans returns PUBLIC only,
|
|
11
|
+
* buyable {boolean} — hide buy button when false, buyerCanCancel {boolean},
|
|
12
|
+
* perks {array} — [{ id, description }] feature bullets,
|
|
13
|
+
* pricingVariants {array} — 1 variant per plan:
|
|
14
|
+
* [{ id, name, freeTrialDays, pricingStrategies[0].flatRate.amount (decimal string, "0" = free),
|
|
15
|
+
* billingTerms: { billingCycle: { period "DAY"|"WEEK"|"MONTH"|"YEAR", count },
|
|
16
|
+
* startType "ON_PURCHASE"|"CUSTOM", endType "UNTIL_CANCELLED"|"CYCLES_COMPLETED" } }]
|
|
17
|
+
* Display price: amount = v.pricingStrategies[0].flatRate.amount + plan.currency.
|
|
18
|
+
* Never compute a final charge — Wix settles price, tax, and schedule at hosted checkout.
|
|
19
|
+
*
|
|
20
|
+
* Order (member's purchase) — key fields for "My plans" screen.
|
|
21
|
+
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/pricing-plans/orders/order-object.md
|
|
22
|
+
* id {string}, planId {string}, planName {string},
|
|
23
|
+
* status "DRAFT"|"PENDING"|"ACTIVE"|"PAUSED"|"ENDED"|"CANCELED",
|
|
24
|
+
* lastPaymentStatus "PAID"|"REFUNDED"|"FAILED"|"UNPAID"|"NOT_APPLICABLE",
|
|
25
|
+
* startDate {string}, endDate {string}, freeTrialDays {number},
|
|
26
|
+
* currentCycle { index, startedDate, endedDate }, autoRenewCanceled {boolean}
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const REDIRECT_SESSION_URL = "/headless/v1/redirect-session";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Query public, listable pricing plans (one page).
|
|
33
|
+
* Returns only PUBLIC plans (the ones meant for the Plans & Pricing page). Some plans may have
|
|
34
|
+
* `buyable: false` (merchant-assigned only) — keep them for display but hide the buy button.
|
|
35
|
+
*
|
|
36
|
+
* Reference: https://dev.wix.com/docs/api-reference/business-solutions/pricing-plans/plans-v3/query-plans.md
|
|
37
|
+
*
|
|
38
|
+
* @param {{ limit?: number, cursor?: string }} [options]
|
|
39
|
+
* @returns {Promise<{ plans: object[], nextCursor: string|null }>}
|
|
40
|
+
*/
|
|
41
|
+
export async function queryPlans({ limit = 100, cursor } = {}) {
|
|
42
|
+
const res = await wixApiRequest("/pricing-plans/v3/plans/query", {
|
|
43
|
+
method: "POST",
|
|
44
|
+
body: {
|
|
45
|
+
query: {
|
|
46
|
+
...(cursor ? {} : { filter: { visibility: "PUBLIC" } }),
|
|
47
|
+
cursorPaging: cursor ? { limit, cursor } : { limit },
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
plans: res?.plans ?? [],
|
|
53
|
+
nextCursor: res?.pagingMetadata?.cursors?.next ?? null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Fetch a single plan by its GUID. Returns null if not found.
|
|
59
|
+
* Reference: https://dev.wix.com/docs/api-reference/business-solutions/pricing-plans/plans-v3/get-plan.md
|
|
60
|
+
*
|
|
61
|
+
* @param {string} planId Plan GUID (`plan.id`).
|
|
62
|
+
* @returns {Promise<object|null>}
|
|
63
|
+
*/
|
|
64
|
+
export async function getPlanById(planId) {
|
|
65
|
+
try {
|
|
66
|
+
const res = await wixApiRequest(`/pricing-plans/v3/plans/${encodeURIComponent(planId)}`, {
|
|
67
|
+
method: "GET",
|
|
68
|
+
});
|
|
69
|
+
return res?.plan ?? null;
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Fetch a single PUBLIC plan by its URL slug. Returns null if not found.
|
|
77
|
+
* There is no get-by-slug endpoint, so this queries with a slug filter and returns the first match.
|
|
78
|
+
* Reference: https://dev.wix.com/docs/api-reference/business-solutions/pricing-plans/plans-v3/query-plans.md
|
|
79
|
+
*
|
|
80
|
+
* @param {string} slug
|
|
81
|
+
* @returns {Promise<object|null>}
|
|
82
|
+
*/
|
|
83
|
+
export async function getPlanBySlug(slug) {
|
|
84
|
+
const res = await wixApiRequest("/pricing-plans/v3/plans/query", {
|
|
85
|
+
method: "POST",
|
|
86
|
+
body: {
|
|
87
|
+
query: {
|
|
88
|
+
filter: { visibility: "PUBLIC", slug },
|
|
89
|
+
cursorPaging: { limit: 1 },
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
return res?.plans?.[0] ?? null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Start a purchase for a plan and return the Wix-hosted checkout URL.
|
|
98
|
+
*
|
|
99
|
+
* Pricing Plans purchases are MEMBERS-ONLY: the hosted flow handles member login (or signup),
|
|
100
|
+
* the order form, and payment, then returns the visitor to your site. Redirect the browser to the
|
|
101
|
+
* returned URL — do NOT create the order yourself; Wix settles price, tax, and the subscription.
|
|
102
|
+
*
|
|
103
|
+
* On return:
|
|
104
|
+
* - postFlowUrl is hit when the flow completes, is abandoned, or is interrupted.
|
|
105
|
+
* - thankYouPageUrl (if given) is hit only on success, with a `?planOrderId=<GUID>` query param.
|
|
106
|
+
* - Both callbacks also carry `wixMemberLoggedIn` (true if a member logged in during the flow).
|
|
107
|
+
* After a successful purchase the visitor is a logged-in member — call getMyPlanOrders() to confirm.
|
|
108
|
+
*
|
|
109
|
+
* Reference: https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
|
|
110
|
+
*
|
|
111
|
+
* @param {string} planId Plan GUID (`plan.id`). Must be a buyable plan.
|
|
112
|
+
* @param {{ thankYouPageUrl?: string, postFlowUrl?: string }} [options]
|
|
113
|
+
* @returns {Promise<string>} The hosted checkout URL to redirect to.
|
|
114
|
+
*/
|
|
115
|
+
export async function checkout(planId, { thankYouPageUrl, postFlowUrl } = {}) {
|
|
116
|
+
if (!planId) throw new Error("Cannot check out: a planId is required.");
|
|
117
|
+
const callbacks = { postFlowUrl: postFlowUrl ?? window.location.href };
|
|
118
|
+
if (thankYouPageUrl) callbacks.thankYouPageUrl = thankYouPageUrl;
|
|
119
|
+
|
|
120
|
+
const redirect = await wixApiRequest(REDIRECT_SESSION_URL, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
body: { paidPlansCheckout: { planId }, callbacks },
|
|
123
|
+
});
|
|
124
|
+
const url = redirect?.redirectSession?.fullUrl;
|
|
125
|
+
if (!url) throw new Error("Failed to create the pricing-plan checkout redirect session.");
|
|
126
|
+
return url;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* List the currently logged-in member's own plan orders (their purchases / subscriptions).
|
|
131
|
+
* Use for a "My plans" screen and to confirm a purchase after returning from checkout.
|
|
132
|
+
*
|
|
133
|
+
* Requires a MEMBER identity. For an anonymous visitor (not logged in) Wix returns no member
|
|
134
|
+
* context — this resolves to `[]` rather than throwing, so the UI can show a "log in to see your
|
|
135
|
+
* plans" state. Up to 50 orders are returned per call.
|
|
136
|
+
*
|
|
137
|
+
* Reference: https://dev.wix.com/docs/api-reference/business-solutions/pricing-plans/orders/member-orders-service-list-orders.md
|
|
138
|
+
*
|
|
139
|
+
* @param {{ orderStatuses?: string[], limit?: number, offset?: number }} [options]
|
|
140
|
+
* orderStatuses: filter, e.g. ["ACTIVE"] | ["ACTIVE","PENDING","PAUSED"].
|
|
141
|
+
* @returns {Promise<object[]>} The member's orders (empty array if none / not a member).
|
|
142
|
+
*/
|
|
143
|
+
export async function getMyPlanOrders({ orderStatuses, limit, offset } = {}) {
|
|
144
|
+
try {
|
|
145
|
+
const res = await wixApiRequest("/pricing-plans/v2/member/orders", {
|
|
146
|
+
method: "GET",
|
|
147
|
+
query: {
|
|
148
|
+
orderStatuses,
|
|
149
|
+
limit: limit !== undefined ? String(limit) : undefined,
|
|
150
|
+
offset: offset !== undefined ? String(offset) : undefined,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
return res?.orders ?? [];
|
|
154
|
+
} catch {
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
}
|