@wix/agent-skills 1.14.0 → 1.15.1
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 +12 -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/DATA_COLLECTION.md +5 -3
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +25 -9
- package/skills/wix-app/references/SITE_PLUGIN.md +1 -1
- package/skills/wix-app/references/STORES_VERSIONING.md +9 -211
- 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/backend-event/COMMON-EVENTS.md +5 -0
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +1 -14
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +151 -0
- 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/COMPONENT-PREVIEW.md +57 -0
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +23 -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 +18 -16
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +25 -53
- package/skills/wix-app/references/stores/CATEGORIES.md +22 -0
- package/skills/wix-app/references/stores/GET_PRODUCT.md +99 -0
- package/skills/wix-app/references/stores/INVENTORY.md +37 -0
- package/skills/wix-app/references/stores/QUERY.md +87 -0
- package/skills/wix-app/references/stores/WRITE.md +55 -0
- 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 +89 -130
- package/skills/wix-headless/entry/bootstrap.mjs +93 -0
- package/skills/wix-headless/entry/skill.md +76 -0
- package/skills/wix-headless/references/AI_FEATURES.md +178 -0
- package/skills/wix-headless/references/CAPABILITIES.md +86 -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 +129 -0
- package/skills/wix-headless/references/IMAGE_GENERATION.md +69 -0
- package/skills/wix-headless/references/SDK_HANDOFF.md +99 -0
- package/skills/wix-headless/references/SEED.md +45 -187
- 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 +213 -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 +232 -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 +192 -0
- package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +155 -0
- package/skills/wix-headless/references/inline-recipes/setup-pricing-plans.md +229 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-experiences.md +73 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +197 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +136 -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 +79 -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 +15 -0
- package/skills/wix-headless/references/stripe/AUTHENTICATION.md +55 -0
- package/skills/wix-headless/references/stripe/DEPLOYMENT.md +71 -0
- package/skills/wix-manage/SKILL.md +29 -3
- package/skills/wix-manage/references/analytics/query-site-analytics.md +298 -0
- package/skills/wix-manage/references/app-installation/install-wix-apps.md +3 -0
- package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +1 -1
- package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +6 -5
- package/skills/wix-manage/references/bookings/create-course-service.md +30 -5
- package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +299 -0
- package/skills/wix-manage/references/cms/cms-schema-management.md +6 -0
- package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +30 -7
- package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +517 -0
- package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +218 -0
- package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +249 -0
- package/skills/wix-manage/references/sites/site-import.md +270 -0
- package/skills/wix-manage/references/stores/create-product-from-image.md +8 -6
- package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +57 -0
- package/skills/wix-vibe-headless/SKILL.md +142 -0
- package/skills/wix-vibe-headless/platforms/README.md +22 -0
- package/skills/wix-vibe-headless/platforms/base44.md +142 -0
- package/skills/wix-vibe-headless/platforms/generic.md +87 -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 +157 -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 +217 -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 +136 -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 +223 -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 +164 -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 +146 -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,223 @@
|
|
|
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
|
+
try {
|
|
40
|
+
const res = await wixApiRequest(COLLECTIONS_QUERY_URL, {
|
|
41
|
+
method: "POST",
|
|
42
|
+
body: {
|
|
43
|
+
includePageUrl: true,
|
|
44
|
+
query: cursor
|
|
45
|
+
? { cursorPaging: { limit, cursor } }
|
|
46
|
+
: {
|
|
47
|
+
filter: { hidden: false },
|
|
48
|
+
sort: [{ fieldName: "sortOrder", order: "ASC" }],
|
|
49
|
+
cursorPaging: { limit },
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
collections: res?.collections ?? [],
|
|
55
|
+
nextCursor: res?.metadata?.cursors?.next ?? null,
|
|
56
|
+
};
|
|
57
|
+
} catch (err) {
|
|
58
|
+
// Degrade to an empty page instead of rethrowing: an uncaught read would leave a
|
|
59
|
+
// component's `loading` flag stuck true and hang the gallery on a spinner. Empty
|
|
60
|
+
// renders the same empty state as a genuinely empty backend.
|
|
61
|
+
console.error("queryCollections failed:", err);
|
|
62
|
+
return { collections: [], nextCursor: null };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get a single visible collection by its URL slug. Returns null if not found / hidden.
|
|
68
|
+
* Portfolio has no get-by-slug endpoint, so this queries with a slug filter.
|
|
69
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/collections/query-collections.md
|
|
70
|
+
* @param {string} slug
|
|
71
|
+
* @returns {Promise<object|null>}
|
|
72
|
+
*/
|
|
73
|
+
export async function getCollectionBySlug(slug) {
|
|
74
|
+
const res = await wixApiRequest(COLLECTIONS_QUERY_URL, {
|
|
75
|
+
method: "POST",
|
|
76
|
+
body: {
|
|
77
|
+
includePageUrl: true,
|
|
78
|
+
query: { filter: { slug, hidden: false }, cursorPaging: { limit: 1 } },
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
return res?.collections?.[0] ?? null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Total number of visible collections. Used for empty-state logic
|
|
86
|
+
* (0 → prompt the user to add collections in their Wix dashboard).
|
|
87
|
+
* @returns {Promise<number>}
|
|
88
|
+
*/
|
|
89
|
+
export async function countCollections() {
|
|
90
|
+
try {
|
|
91
|
+
const res = await wixApiRequest(COLLECTIONS_QUERY_URL, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
body: { query: { filter: { hidden: false }, cursorPaging: { limit: 100 } } },
|
|
94
|
+
});
|
|
95
|
+
return res?.metadata?.total ?? (res?.collections?.length ?? 0);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
// On failure treat as empty (0) rather than rethrowing — a thrown count would hang
|
|
98
|
+
// the empty-state check; 0 falls through to the "add collections" prompt.
|
|
99
|
+
console.error("countCollections failed:", err);
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Query visible projects (one page), sorted newest-first. Use for an "all work" gallery.
|
|
106
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/projects/query-projects.md
|
|
107
|
+
* @param {{ limit?: number, cursor?: string }} [options]
|
|
108
|
+
* @returns {Promise<{ projects: object[], nextCursor: string|null }>}
|
|
109
|
+
*/
|
|
110
|
+
export async function queryProjects({ limit = 100, cursor } = {}) {
|
|
111
|
+
try {
|
|
112
|
+
const res = await wixApiRequest(PROJECTS_QUERY_URL, {
|
|
113
|
+
method: "POST",
|
|
114
|
+
body: {
|
|
115
|
+
includePageUrl: true,
|
|
116
|
+
query: cursor
|
|
117
|
+
? { cursorPaging: { limit, cursor } }
|
|
118
|
+
: {
|
|
119
|
+
filter: { hidden: false },
|
|
120
|
+
sort: [{ fieldName: "createdDate", order: "DESC" }],
|
|
121
|
+
cursorPaging: { limit },
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
projects: res?.projects ?? [],
|
|
127
|
+
nextCursor: res?.metadata?.cursors?.next ?? null,
|
|
128
|
+
};
|
|
129
|
+
} catch (err) {
|
|
130
|
+
// Degrade to an empty page instead of rethrowing (see queryCollections) — an uncaught
|
|
131
|
+
// read hangs the gallery on an infinite spinner; empty renders the empty state instead.
|
|
132
|
+
console.error("queryProjects failed:", err);
|
|
133
|
+
return { projects: [], nextCursor: null };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Query the visible projects that belong to a collection (one page), in dashboard order.
|
|
139
|
+
* Filters on `collectionIds` with `$hasSome`.
|
|
140
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/projects/query-projects.md
|
|
141
|
+
* @param {string} collectionId `collection.id` from queryCollections / getCollectionBySlug.
|
|
142
|
+
* @param {{ limit?: number, cursor?: string }} [options]
|
|
143
|
+
* @returns {Promise<{ projects: object[], nextCursor: string|null }>}
|
|
144
|
+
*/
|
|
145
|
+
export async function queryProjectsByCollection(collectionId, { limit = 100, cursor } = {}) {
|
|
146
|
+
try {
|
|
147
|
+
const res = await wixApiRequest(PROJECTS_QUERY_URL, {
|
|
148
|
+
method: "POST",
|
|
149
|
+
body: {
|
|
150
|
+
includePageUrl: true,
|
|
151
|
+
query: cursor
|
|
152
|
+
? { cursorPaging: { limit, cursor } }
|
|
153
|
+
: {
|
|
154
|
+
filter: { hidden: false, collectionIds: { $hasSome: [collectionId] } },
|
|
155
|
+
cursorPaging: { limit },
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
return {
|
|
160
|
+
projects: res?.projects ?? [],
|
|
161
|
+
nextCursor: res?.metadata?.cursors?.next ?? null,
|
|
162
|
+
};
|
|
163
|
+
} catch (err) {
|
|
164
|
+
// Degrade to an empty page instead of rethrowing (see queryCollections) — an uncaught
|
|
165
|
+
// read hangs the collection page on an infinite spinner; empty renders the empty state.
|
|
166
|
+
console.error("queryProjectsByCollection failed:", err);
|
|
167
|
+
return { projects: [], nextCursor: null };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Get a single visible project by its URL slug. Returns null if not found / hidden.
|
|
173
|
+
* Portfolio has no get-by-slug endpoint, so this queries with a slug filter.
|
|
174
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/projects/query-projects.md
|
|
175
|
+
* @param {string} slug
|
|
176
|
+
* @returns {Promise<object|null>}
|
|
177
|
+
*/
|
|
178
|
+
export async function getProjectBySlug(slug) {
|
|
179
|
+
const res = await wixApiRequest(PROJECTS_QUERY_URL, {
|
|
180
|
+
method: "POST",
|
|
181
|
+
body: {
|
|
182
|
+
includePageUrl: true,
|
|
183
|
+
query: { filter: { slug, hidden: false }, cursorPaging: { limit: 1 } },
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
return res?.projects?.[0] ?? null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get a single project by its GUID. Returns null if not found.
|
|
191
|
+
* Use when you already hold a project id (e.g. from a list) rather than a slug.
|
|
192
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/projects/get-project.md
|
|
193
|
+
* @param {string} projectId
|
|
194
|
+
* @returns {Promise<object|null>}
|
|
195
|
+
*/
|
|
196
|
+
export async function getProject(projectId) {
|
|
197
|
+
try {
|
|
198
|
+
const res = await wixApiRequest(`/portfolio/v1/projects/${encodeURIComponent(projectId)}`, {
|
|
199
|
+
method: "GET",
|
|
200
|
+
query: { includePageUrl: "true" },
|
|
201
|
+
});
|
|
202
|
+
return res?.project ?? null;
|
|
203
|
+
} catch {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* List all media items (images/videos) of a project, in dashboard order.
|
|
210
|
+
* This is the project's gallery — call it on the project detail screen.
|
|
211
|
+
* https://dev.wix.com/docs/api-reference/business-solutions/portfolio/project-items/list-project-items.md
|
|
212
|
+
* @param {string} projectId `project.id`.
|
|
213
|
+
* @param {{ limit?: number, offset?: number }} [options] Project items use offset paging, not cursors.
|
|
214
|
+
* @returns {Promise<{ items: object[], total: number }>}
|
|
215
|
+
*/
|
|
216
|
+
export async function listProjectItems(projectId, { limit = 100, offset = 0 } = {}) {
|
|
217
|
+
const res = await wixApiRequest(`/portfolio/v1/projectItems/${encodeURIComponent(projectId)}/items`, {
|
|
218
|
+
method: "GET",
|
|
219
|
+
query: { "paging.limit": String(limit), "paging.offset": String(offset) },
|
|
220
|
+
});
|
|
221
|
+
const items = (res?.items ?? []).slice().sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
|
|
222
|
+
return { items, total: res?.metadata?.total ?? items.length };
|
|
223
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
|
|
2
|
+
# Wix Restaurants Skill
|
|
3
|
+
|
|
4
|
+
> **Source files (in this skill):** the shared transport `references/shared/wix-client.js` and the helper file(s) you need from `references/restaurants/`. All helpers import from `"./wix-client.js"`, so copy them into the same folder (e.g. `src/rest/`).
|
|
5
|
+
>
|
|
6
|
+
> | Need | Copy |
|
|
7
|
+
> |---|---|
|
|
8
|
+
> | Menu display (always) | `wix-restaurants-menu.js` |
|
|
9
|
+
> | Online ordering (cart + checkout) | `wix-restaurants-ordering.js` |
|
|
10
|
+
> | Table reservations | `wix-restaurants-reservations.js` |
|
|
11
|
+
|
|
12
|
+
Builds a real, client-only Wix restaurant experience. The browser talks to Wix directly over a
|
|
13
|
+
public `WIX_CLIENT_ID`. Never mock the menu; never hand-build `/checkout` or reservation URLs —
|
|
14
|
+
always go through the official cart + redirect-session and the reservations hold/reserve flow.
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
- User wants a Wix restaurant site, an online food-ordering page, or a table-reservation page.
|
|
18
|
+
- User asks to "connect Wix Restaurants" or replace placeholder menu/ordering/booking UI with live data.
|
|
19
|
+
- Adding a menu, cart + checkout, or reservations over an existing Wix Restaurants setup.
|
|
20
|
+
|
|
21
|
+
## Prerequisites
|
|
22
|
+
1. A Wix site with the **Wix Restaurants Menus** app installed and **menu content already added**
|
|
23
|
+
(this skill is read-only over the menu — it does NOT create menus/items).
|
|
24
|
+
2. For **online ordering**: at least one online-ordering **Operation** configured (Wix Restaurants
|
|
25
|
+
Orders). For **reservations**: the **Table Reservations** app installed with at least one location
|
|
26
|
+
and online reservations enabled. If a flow's backing app/config isn't set up, that flow returns
|
|
27
|
+
empty — flag it and continue; don't fabricate data.
|
|
28
|
+
3. The site's public headless **`WIX_CLIENT_ID`**, provided in the handoff prompt (see the router `SKILL.md`).
|
|
29
|
+
Paste it into `src/rest/wix-client.js` in place of the placeholder. It is a buyer-facing
|
|
30
|
+
credential (it only mints anonymous visitor tokens), **not** a secret — hardcoding/committing
|
|
31
|
+
it is fine.
|
|
32
|
+
4. The deployed app domain must be allow-listed on the OAuth client for Wix-hosted checkout to
|
|
33
|
+
return. This is a **separate Wix setup flow the user completes later** — out of this skill's
|
|
34
|
+
scope. If checkout return fails before that setup is done, that's expected; flag it and continue.
|
|
35
|
+
|
|
36
|
+
## The API (copy as-is; do not re-derive it)
|
|
37
|
+
This skill ships only the REST layer — no UI components. Build the restaurant UI however the
|
|
38
|
+
project wants; wire it to these two snippets. Copy them into the app (e.g. `src/api/`) and only
|
|
39
|
+
adjust import paths:
|
|
40
|
+
- `src/rest/wix-client.js` — visitor-token mint/refresh + transport. Set `WIX_CLIENT_ID` to the id
|
|
41
|
+
from the prompt (replace the `<YOUR-CLIENT-ID>` placeholder). The visitor refresh token IS the
|
|
42
|
+
cart identity; it is persisted to localStorage. Do not re-mint anonymously per load or the cart
|
|
43
|
+
silently empties.
|
|
44
|
+
- `src/rest/wix-restaurants-menu.js` — **Menu (read-only):**
|
|
45
|
+
`getFullMenu` (the assembled tree — start here), `listMenus`, `listSections`, `listItems`,
|
|
46
|
+
`listVariants`, `listModifierGroups`, `listModifiers`, `listLabels`
|
|
47
|
+
- `src/rest/wix-restaurants-ordering.js` — **Online ordering:**
|
|
48
|
+
`listOperations`, `getDefaultOperation`, `addItemToCart`, `getCurrentCart`,
|
|
49
|
+
`updateCartItemQuantity`, `removeFromCart`, `checkout`
|
|
50
|
+
- `src/rest/wix-restaurants-reservations.js` — **Reservations:**
|
|
51
|
+
`listReservationLocations`, `getTimeSlots`, `createHeldReservation`, `reserveReservation`
|
|
52
|
+
|
|
53
|
+
The Menu, Item, ModifierGroup, Operation, Cart, ReservationLocation, TimeSlot, and Reservation
|
|
54
|
+
shapes are documented as JSDoc at the top of each helper file. Read the relevant file(s) before
|
|
55
|
+
building the UI — they describe the key fields and link to the full reference for anything not shown.
|
|
56
|
+
|
|
57
|
+
## How to wire it (UI is the project's choice)
|
|
58
|
+
- **Menu page** — call `getFullMenu()` once. It returns `{ menus: [{ ...menu, sections: [{ ...section,
|
|
59
|
+
items: [assembledItem] }] }] }`, already ordered by `sectionIds` / `itemIds`. Render each item's
|
|
60
|
+
`name`, `description`, `image`, `labels` (`name` + `icon`), and `featured` flag. For price, show
|
|
61
|
+
`item.price` (single) or the `item.variants[]` (each `{ name, price }`). **Restaurants prices are
|
|
62
|
+
plain decimal strings with NO currency symbol** — format with the site's currency in the UI.
|
|
63
|
+
- **Item detail** — render `item.modifierGroups[]`: each group's `name`, its `rule`
|
|
64
|
+
(`required`, `minSelections`, `maxSelections`), and `modifiers[]` (`name`, `additionalCharge`,
|
|
65
|
+
`preSelected`, `inStock`). If `orderSettings.acceptSpecialRequests`, offer a free-text field.
|
|
66
|
+
- **Online ordering** — resolve an operation with `getDefaultOperation()` (or let the user pick from
|
|
67
|
+
`listOperations()`); if it's `null`, show an "ordering unavailable" state. Add a dish with
|
|
68
|
+
`addItemToCart(item.id, { operationId, menuId, sectionId, quantity })` — `menuId`/`sectionId` are
|
|
69
|
+
the menu and section the item was shown under. Read the cart back with `getCurrentCart()`; mutate
|
|
70
|
+
with `updateCartItemQuantity(lineItemId, qty)` / `removeFromCart(lineItemId)` using
|
|
71
|
+
`cart.lineItems[].id` (not the item id).
|
|
72
|
+
- **Checkout** — `window.location.href = await checkout()`. After the visitor returns, the order is
|
|
73
|
+
placed and the cart is empty — re-fetch with `getCurrentCart()` on return (e.g. on mount +
|
|
74
|
+
`visibilitychange`) to clear the UI.
|
|
75
|
+
- **Reservations** — `listReservationLocations()` for the picker (use `location` details for the
|
|
76
|
+
label; if a location's `configuration.onlineReservations.onlineReservationsEnabled` is false, hide
|
|
77
|
+
it). Then `getTimeSlots(locationId, dateISO, partySize)` — render `availableTimeSlots` (already
|
|
78
|
+
filtered to `AVAILABLE`). On slot pick, `createHeldReservation(locationId, slot.startDate,
|
|
79
|
+
partySize)` → keep the returned `id` + `revision`. Collect the visitor's details, then
|
|
80
|
+
`reserveReservation(id, revision, { firstName, phone, lastName?, email? })`. A `RESERVED` status is
|
|
81
|
+
confirmed; `REQUESTED` means the location requires manual approval — tell the user it's pending.
|
|
82
|
+
- **Empty state** — if `getFullMenu()` returns no menus, show an empty state telling the user to add
|
|
83
|
+
a menu in their Wix dashboard. Never invent menu items.
|
|
84
|
+
|
|
85
|
+
## Hard rules (do not violate)
|
|
86
|
+
- ✅ Order ONLY through the cart: `addItemToCart()` → `checkout()` (`create-checkout` →
|
|
87
|
+
`/headless/v1/redirect-session` `fullUrl`), then redirect.
|
|
88
|
+
- ❌ Never hand-build `/checkout`, ordering, or reservation URLs.
|
|
89
|
+
- ❌ Never mock menus, items, prices, operations, locations, or time slots — render live Wix data or
|
|
90
|
+
the empty state.
|
|
91
|
+
- ❌ Never generate fake reviews, ratings, or testimonials. Empty review UI only.
|
|
92
|
+
- ✅ Set `WIX_CLIENT_ID` from the prompt's value (public client id — safe to hardcode).
|
|
93
|
+
- ✅ `addItemToCart` requires `operationId`, `menuId`, and `sectionId` — it throws if any is missing.
|
|
94
|
+
- ✅ `lineItemId` for cart mutations is `cart.lineItems[].id`, not the item id.
|
|
95
|
+
- ✅ Reservations: offer only `AVAILABLE` slots; a HELD reservation expires in 10 minutes — pass the
|
|
96
|
+
`revision` from the hold into `reserveReservation`, and restart the flow if it expired.
|
|
97
|
+
- ✅ Reservee `firstName` + `phone` (E.164, e.g. `+15551234567`) are mandatory to confirm.
|
|
98
|
+
- The engine fails loudly on purpose: `addItemToCart`/`checkout` throw on out-of-stock or empty
|
|
99
|
+
carts; reservation helpers throw on unavailable slots or expired holds. A green path means it is
|
|
100
|
+
really orderable/bookable — don't swallow these.
|
|
101
|
+
|
|
102
|
+
## Beyond the snippets
|
|
103
|
+
The snippets cover the common menu / ordering / reservation paths. For the "20%" they don't cover,
|
|
104
|
+
make the call yourself with `wixApiRequest` — but look up the exact endpoint, HTTP method, and
|
|
105
|
+
request body in the **official Wix API reference** first; never guess:
|
|
106
|
+
- Restaurants API reference: https://dev.wix.com/docs/api-reference/business-solutions/restaurants.md
|
|
107
|
+
- Selecting a specific **price variant** or applying **modifier up-charges** on the cart line: the
|
|
108
|
+
restaurants `catalogReference.options` shape for these is not documented for client add-to-cart.
|
|
109
|
+
The menu UI still displays them; confirm the shape before wiring them into `addItemToCart`:
|
|
110
|
+
https://dev.wix.com/docs/api-reference/business-solutions/restaurants/online-orders/sample-flows.md
|
|
111
|
+
- Fulfillment methods, delivery-address validation, scheduled (preorder) time slots, service fees:
|
|
112
|
+
see the Online Orders section of the reference.
|
|
113
|
+
- **Member login + a "my orders" account view** → the **members** vertical
|
|
114
|
+
(`references/members/INSTRUCTIONS.md`): ordering/reserving works anonymously, but signing a member
|
|
115
|
+
in (custom login on your own UI) lets them see their own order/reservation history.
|
|
116
|
+
|
|
117
|
+
Keep the snippets as the default for everything they already do; reach for the API reference only
|
|
118
|
+
for the gap.
|
|
119
|
+
|
|
120
|
+
## Point the user to their dashboard
|
|
121
|
+
In some cases, users need to access the Wix dashboard in order to edit the restaurant content for their site — across up to three apps. To facilitate this, provide the user with deep links directly to the relevant dashboard pages; only mention the apps the project actually uses. Those pages are:
|
|
122
|
+
- **Menu** (always) — `https://manage.wix.com/dashboard/{metaSiteId}/wix-restaurants-menus-new` (`Dashboard → Restaurant Menus`; click **Manage Items** to add dishes; only visible menus appear in the app)
|
|
123
|
+
- **Online ordering** (if wired) — `https://manage.wix.com/dashboard/{metaSiteId}/wix-restaurants-orders-new/settings` (`Dashboard → Restaurant Orders → Settings`). Enable at least one fulfillment method before the site accepts orders — each has its own page: pickup `https://manage.wix.com/dashboard/{metaSiteId}/wix-restaurants-orders-new/settings/pickup`, delivery `.../wix-restaurants-orders-new/settings/delivery`, dine-in `.../wix-restaurants-orders-new/settings/dine-in`.
|
|
124
|
+
- **Table reservations** (if wired) — `https://manage.wix.com/dashboard/{metaSiteId}/wix-table-reservations/table-reservations` (`Dashboard → Table Reservations` → **Settings**; configure tables, availability, and enable online reservations)
|
|
125
|
+
|
|
126
|
+
Substitute the site's `metaSiteId` to complete the links (you have it from the handoff / `ListWixSites`). Include the in-dashboard navigation as a fallback.
|
|
127
|
+
|
|
128
|
+
## Verification checklist (before declaring done)
|
|
129
|
+
- [ ] `WIX_CLIENT_ID` set to the prompt's value (not the `<YOUR-CLIENT-ID>` placeholder)
|
|
130
|
+
- [ ] Visitor token persists across reload (cart survives reload, same visitor)
|
|
131
|
+
- [ ] `getFullMenu()` renders real sections/items with prices, variants, modifiers, and labels
|
|
132
|
+
- [ ] Empty state shown when there are no menus (never invented items)
|
|
133
|
+
- [ ] Add to cart works with a real `operationId`/`menuId`/`sectionId`; out-of-stock items throw
|
|
134
|
+
- [ ] Quantity update / remove reflect in `getCurrentCart()`
|
|
135
|
+
- [ ] Checkout redirects via redirect-session `fullUrl` (no hand-built URL); cart re-fetched on return
|
|
136
|
+
- [ ] Reservations: only `AVAILABLE` slots offered; hold → reserve produces `RESERVED`/`REQUESTED`
|
|
137
|
+
- [ ] No mock data anywhere
|
|
138
|
+
- [ ] Told the user at least once that they can continue setting up their restaurant (menu / ordering / reservations) in the dashboard and provided deep links.
|