@wix/agent-skills 1.16.3 → 1.18.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/package.json +1 -1
- package/skills/wix-app/SKILL.md +115 -12
- package/skills/wix-app/references/APP_MARKET_REVIEW.md +1 -1
- package/skills/wix-app/references/BACKEND_API.md +18 -0
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +6 -0
- package/skills/wix-app/references/DASHBOARD_MODAL.md +10 -2
- package/skills/wix-app/references/DASHBOARD_PAGE.md +32 -70
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +145 -127
- package/skills/wix-app/references/SITE_PLUGIN.md +14 -2
- package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +74 -68
- package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +2 -2
- package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +79 -0
- package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +73 -0
- package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +52 -0
- package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +184 -0
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +182 -99
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +94 -49
- package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +16 -6
- package/skills/wix-app/references/editor-react-component/BROWSER-SUPPORT.md +56 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +275 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +35 -40
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +167 -445
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +56 -29
- package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +53 -158
- package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +78 -0
- package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +42 -134
- package/skills/wix-app/references/editor-react-component/MANIFEST-ERRORS.md +11 -3
- package/skills/wix-app/references/editor-react-component/PARTS.md +46 -24
- package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +63 -179
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +79 -163
- package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +36 -21
- package/skills/wix-app/references/editor-react-component/SSR.md +30 -99
- package/skills/wix-base44-connector/SKILL.md +156 -50
- package/skills/wix-base44-connector/references/CAPABILITY_MAP.md +78 -0
- package/skills/wix-base44-connector/scripts/utils.js +239 -45
- package/skills/wix-headless/entry/bootstrap.mjs +9 -2
- package/skills/wix-headless/entry/skill.md +1 -1
- package/skills/wix-headless/references/CAPABILITIES.md +9 -1
- package/skills/wix-headless/references/DESIGN.md +1 -0
- package/skills/wix-headless/references/DISCOVERY.md +2 -1
- package/skills/wix-headless/references/IMAGE_GENERATION.md +1 -0
- package/skills/wix-headless/references/SDK_HANDOFF.md +5 -2
- package/skills/wix-headless/references/SEED.md +2 -1
- package/skills/wix-headless/references/SETUP.md +1 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +2 -2
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +68 -31
- package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +26 -10
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +8 -8
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +10 -8
- package/skills/wix-headless/references/inline-recipes/how-to-code-rentals.md +254 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +27 -24
- package/skills/wix-headless/references/inline-recipes/setup-online-store.md +13 -0
- package/skills/wix-headless/references/inline-recipes/setup-rentals.md +254 -0
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +5 -0
- package/skills/wix-headless/references/non-astro.md +1 -1
- package/skills/wix-headless-fast/SKILL.md +166 -0
- package/skills/wix-headless-fast/entry/skill.md +99 -0
- package/skills/wix-headless-fast/install/deploy.mjs +433 -0
- package/skills/wix-headless-fast/install/fast-path.mjs +141 -0
- package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +137 -0
- package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +137 -0
- package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +113 -0
- package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +42 -0
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +123 -0
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +70 -0
- package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +99 -0
- package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +76 -0
- package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +62 -0
- package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +99 -0
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +24 -0
- package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +16156 -0
- package/skills/wix-headless-fast/references/blog/seed/SEED.md +72 -0
- package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +287 -0
- package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +129 -0
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +143 -0
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +119 -0
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +138 -0
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +54 -0
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +206 -0
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +96 -0
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +70 -0
- package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +76 -0
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +22 -0
- package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +11962 -0
- package/skills/wix-headless-fast/references/bookings/seed/SEED.md +61 -0
- package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +302 -0
- package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +179 -0
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +83 -0
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +57 -0
- package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +151 -0
- package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +75 -0
- package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +41 -0
- package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +11262 -0
- package/skills/wix-headless-fast/references/cms/seed/SEED.md +103 -0
- package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +324 -0
- package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +149 -0
- package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +66 -0
- package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +176 -0
- package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +118 -0
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +117 -0
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +59 -0
- package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +136 -0
- package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +128 -0
- package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +61 -0
- package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +12 -0
- package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +80 -0
- package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +21 -0
- package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +11884 -0
- package/skills/wix-headless-fast/references/events/seed/SEED.md +86 -0
- package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +276 -0
- package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +150 -0
- package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +317 -0
- package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +269 -0
- package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +231 -0
- package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +135 -0
- package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +10593 -0
- package/skills/wix-headless-fast/references/forms/seed/SEED.md +108 -0
- package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +320 -0
- package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +63 -0
- package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +60 -0
- package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +155 -0
- package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +78 -0
- package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +47 -0
- package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +66 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +88 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +53 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +122 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +50 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +21 -0
- package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +42 -0
- package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +10 -0
- package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +11 -0
- package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +10329 -0
- package/skills/wix-headless-fast/references/members/seed/SEED.md +39 -0
- package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +94 -0
- package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +134 -0
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +110 -0
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +90 -0
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +115 -0
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +59 -0
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +39 -0
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +58 -0
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +165 -0
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +55 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +30 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +21 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +29 -0
- package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +10197 -0
- package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +78 -0
- package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +258 -0
- package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +133 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +58 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +126 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +37 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +39 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +75 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +45 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +30 -0
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +41 -0
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +40 -0
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +21 -0
- package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +11226 -0
- package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +71 -0
- package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +279 -0
- package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +165 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +142 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +26 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +121 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +155 -0
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +55 -0
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +43 -0
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +177 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +165 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +103 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +254 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +146 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +168 -0
- package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +47 -0
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +22 -0
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +12 -0
- package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +12560 -0
- package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +81 -0
- package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +479 -0
- package/skills/wix-headless-fast/references/shared/CONTENT.md +22 -0
- package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +73 -0
- package/skills/wix-headless-fast/references/shared/DESIGN.md +26 -0
- package/skills/wix-headless-fast/references/shared/app/styles/global.css +52 -0
- package/skills/wix-headless-fast/references/shared/app/wix/config.ts +15 -0
- package/skills/wix-headless-fast/references/shared/app/wix/media.ts +27 -0
- package/skills/wix-headless-fast/references/shared/app/wix/money.ts +24 -0
- package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +76 -0
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +46 -0
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +46 -0
- package/skills/wix-headless-fast/references/shared/seed/images.mjs +145 -0
- package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +149 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +26 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +121 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +100 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +130 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +48 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +66 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +103 -0
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +48 -0
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +140 -0
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +80 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +101 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +221 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +215 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +109 -0
- package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +46 -0
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +56 -0
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +23 -0
- package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +12247 -0
- package/skills/wix-headless-fast/references/storefront/seed/SEED.md +85 -0
- package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +415 -0
- package/skills/wix-manage/SKILL.md +28 -2
- package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +20 -13
- package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +24 -11
- package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +5 -5
- package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +141 -0
- package/skills/wix-manage/references/google-business-profile/connect-google-business-profile.md +134 -0
- package/skills/wix-manage/references/google-business-profile/manage-google-business-profile-locations.md +182 -0
- package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +3 -0
- package/skills/wix-manage/references/seo/manage-seo-tags.md +315 -0
- package/skills/wix-manage/references/seo/manage-url-redirects.md +250 -0
- package/skills/wix-manage/references/sites/query-sites.md +72 -161
- package/skills/wix-manage/references/stores/create-product-catalog-v3.md +21 -6
- package/skills/wix-manage/references/stores/update-product-with-options.md +83 -0
- package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +5 -6
- package/skills/wix-vibe-headless/SKILL.md +18 -4
- package/skills/wix-vibe-headless/install/deploy.cjs +12 -4
- package/skills/wix-vibe-headless/install/pin-agents-md.cjs +2 -1
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +16 -10
- package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +13 -8
- package/skills/wix-vibe-headless/platforms/base44.md +27 -62
- package/skills/wix-vibe-headless/platforms/generic.md +6 -3
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +45 -0
- package/skills/wix-vibe-headless/references/bookings/app/components/RentalDurationPicker.jsx +67 -0
- package/skills/wix-vibe-headless/references/bookings/app/hooks/useRentalDuration.js +128 -0
- package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +5 -3
- package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-checkout.js +9 -8
- package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-rentals.js +250 -0
- package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-services.js +12 -5
- package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +41 -0
- package/skills/wix-vibe-headless/references/bookings/seed/seed-rentals.js +267 -0
- package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +6 -3
- package/skills/wix-vibe-headless/references/forms/INSTRUCTIONS.md +470 -0
- package/skills/wix-vibe-headless/references/forms/app/hooks/useWixForm.js +425 -0
- package/skills/wix-vibe-headless/references/forms/app/lib/wix-form-schema-utils.js +187 -0
- package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms-submissions.js +238 -0
- package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms.js +108 -0
- package/skills/wix-vibe-headless/references/forms/seed/SEED.md +1762 -0
- package/skills/wix-vibe-headless/references/rentals/INSTRUCTIONS.md +13 -0
- package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +4 -1
- package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +23 -11
- package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +1 -1
- package/skills/wix-vibe-headless/references/restaurants/app/rest/wix-restaurants-ordering.js +29 -31
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +152 -92
- package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +37 -38
- package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +2 -2
- package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +15 -8
- package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +37 -0
- package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-cart.js +35 -35
- package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-catalog.js +18 -6
- package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +30 -7
- package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +46 -10
- package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +0 -172
- package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +0 -143
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +0 -516
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +0 -225
- package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +0 -6
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +0 -95
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +0 -110
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +0 -51
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +0 -49
- package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +0 -92
- package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +0 -139
|
@@ -24,22 +24,24 @@ A concise contract for writing the **frontend code** of a storefront against a C
|
|
|
24
24
|
| Products (list, get, search, filter) | `@wix/stores` | `productsV3` |
|
|
25
25
|
| Variants (to resolve `variantId`) | `@wix/stores` | `readOnlyVariantsV3` |
|
|
26
26
|
| Categories | `@wix/stores` | `categories` |
|
|
27
|
-
| Cart (add / get / checkout) | `@wix/ecom` | `
|
|
27
|
+
| Cart (add / get / checkout) | `@wix/ecom` | `currentCartV2` |
|
|
28
28
|
| Redirect to hosted checkout | `@wix/redirects` | `redirects` |
|
|
29
29
|
|
|
30
|
+
> Migrating from Cart V1 / Checkout V1? The code below is V2-only — see the [migration guide](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/migration-guide) for the before/after.
|
|
31
|
+
|
|
30
32
|
**Never** import the V1 `products` or `collections` modules from `@wix/stores`.
|
|
31
33
|
|
|
32
34
|
**Auth / client — framework split:**
|
|
33
|
-
- **Astro (Wix-managed):** authentication is ambient. Call `
|
|
35
|
+
- **Astro (Wix-managed):** authentication is ambient. Call `currentCartV2` / `productsV3` / `readOnlyVariantsV3` directly from server components and backend routes (`src/pages/api/*.ts`) — **no `createClient`, no `OAuthStrategy`, no `clientId`.**
|
|
34
36
|
- **Non-Astro (Vite/React/Vue/static):** build one manual visitor client and reuse it:
|
|
35
37
|
```js
|
|
36
38
|
import { createClient, OAuthStrategy } from '@wix/sdk';
|
|
37
39
|
import { productsV3, readOnlyVariantsV3 } from '@wix/stores';
|
|
38
|
-
import {
|
|
40
|
+
import { currentCartV2 } from '@wix/ecom';
|
|
39
41
|
import { redirects } from '@wix/redirects';
|
|
40
42
|
|
|
41
43
|
const client = createClient({
|
|
42
|
-
modules: { productsV3, readOnlyVariantsV3,
|
|
44
|
+
modules: { productsV3, readOnlyVariantsV3, currentCartV2, redirects },
|
|
43
45
|
auth: OAuthStrategy({ clientId: /* the project's PUBLIC OAuth client id */ }),
|
|
44
46
|
});
|
|
45
47
|
```
|
|
@@ -49,16 +51,19 @@ A concise contract for writing the **frontend code** of a storefront against a C
|
|
|
49
51
|
|
|
50
52
|
## The shapes you read (field cheat-sheet)
|
|
51
53
|
|
|
52
|
-
The exact field paths the storefront reads, and the **plausible-wrong sibling** each is mistaken for — the sections below reference these instead of re-describing them. All `amount`s are **strings**. These are **read** shapes; the cart-add body (under *Adding to cart*) is a separate **write** shape, and the `_id` rule applies to read **entities**, not to
|
|
54
|
+
The exact field paths the storefront reads, and the **plausible-wrong sibling** each is mistaken for — the sections below reference these instead of re-describing them. All `amount`s are **strings**. These are **read** shapes; the cart-add body (under *Adding to cart*) is a separate **write** shape, and the `_id` rule applies to read **entities**, not to request params (note the redirect session's `checkoutId`, which is just the cart's `_id`).
|
|
53
55
|
|
|
54
56
|
```jsonc
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
+
// Request CURRENCY and PLAIN_DESCRIPTION on every product read — they populate formattedAmount and plainDescription.
|
|
58
|
+
const PRODUCT_FIELDS = ['CURRENCY', 'PLAIN_DESCRIPTION'];
|
|
59
|
+
// productsV3.queryProducts({ fields: PRODUCT_FIELDS }).…find() → result.items[]
|
|
60
|
+
// productsV3.searchProducts({ ..., fields: PRODUCT_FIELDS }) → result.products[]
|
|
57
61
|
product = {
|
|
58
62
|
_id, // links · cart catalogItemId · variant filter (NOT .id → empty → HTTP 500)
|
|
59
63
|
slug, name, visible, // only visible:true is returned to a visitor token
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
currency, // present when CURRENCY is requested
|
|
65
|
+
actualPriceRange: { minValue: { amount, formattedAmount } }, // PRICE (NOT price.actualPrice.amount — that's the seed/WRITE shape → $NaN)
|
|
66
|
+
compareAtPriceRange: { minValue: { amount, formattedAmount } }, // strike-through price
|
|
62
67
|
inventory: { availabilityStatus }, // product-level stock, "IN_STOCK"
|
|
63
68
|
media: { main: { image } }, // image is a wix:image:// id → resolve it (see Rendering images)
|
|
64
69
|
plainDescription, // plain string; description.nodes is the rich-text form
|
|
@@ -72,11 +77,12 @@ variant = {
|
|
|
72
77
|
inventoryStatus: { inStock }, // variant-level stock (boolean)
|
|
73
78
|
}
|
|
74
79
|
|
|
75
|
-
//
|
|
76
|
-
lineItem = {
|
|
80
|
+
// currentCartV2.getCurrentCart() → { cart: { _id, lineItems: [...] } } // NOTE: returns { cart } — destructure it
|
|
81
|
+
lineItem = { _id, name: { original }, quantityInfo: { confirmedQuantity }, pricing: { unitPrice: { amount } }, attributes: { image } }
|
|
82
|
+
// price → pricing.unitPrice (ConvertedMoney, NO formatted string in V2 — format it yourself; .amount is site currency, .convertedAmount the buyer's display currency); qty → quantityInfo.confirmedQuantity; image → attributes.image (wix:image:// → resolve)
|
|
77
83
|
|
|
78
|
-
//
|
|
79
|
-
// redirects.createRedirectSession({ ecomCheckout: { checkoutId }, callbacks }) → { redirectSession: { fullUrl } }
|
|
84
|
+
// the cart's _id is the checkout id → pass to the redirect session:
|
|
85
|
+
// redirects.createRedirectSession({ ecomCheckout: { checkoutId: cart._id }, callbacks }) → { redirectSession: { fullUrl } }
|
|
80
86
|
```
|
|
81
87
|
|
|
82
88
|
---
|
|
@@ -87,18 +93,30 @@ Each section below is a **self-contained storefront feature** — implement only
|
|
|
87
93
|
|
|
88
94
|
### Listing products (and the `_id` rule)
|
|
89
95
|
|
|
90
|
-
Query products with `productsV3.queryProducts()` / `.searchProducts()`.
|
|
96
|
+
Query products with `productsV3.queryProducts()` / `.searchProducts()`. **Every product listing,
|
|
97
|
+
category search, and detail read must request `CURRENCY` and `PLAIN_DESCRIPTION`**. Without `CURRENCY`, `formattedAmount` is omitted
|
|
98
|
+
and a product card renders an unsymbolled number such as `34.99` instead of a localized price. Without `PLAIN_DESCRIPTION`, `product.plainDescription` is absent for cards and detail pages.
|
|
91
99
|
Doc: <https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/query-products.md?apiView=SDK>
|
|
92
100
|
|
|
93
|
-
**⚠️ `queryProducts()`
|
|
101
|
+
**⚠️ `queryProducts()` returns a builder, not a Promise.** Pass requested fields when needed, then chain `.eq(...)`/`.limit(...)`/`.find()` — for example:
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
const PRODUCT_FIELDS = ['CURRENCY', 'PLAIN_DESCRIPTION'];
|
|
105
|
+
const { items } = await productsV3
|
|
106
|
+
.queryProducts({ fields: PRODUCT_FIELDS })
|
|
107
|
+
.limit(50)
|
|
108
|
+
.find();
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Do not pass a search/filter object to `queryProducts`; use `searchProducts` for that (see category filtering below). Reuse the same `PRODUCT_FIELDS` constant for every product read so home, shop, category, and detail pages cannot drift.
|
|
94
112
|
|
|
95
113
|
**⚠️ CRITICAL: the entity id is `_id`, NOT `id`.** The SDK normalizes every entity's id to **`_id`**. `product.id` is `undefined` in SDK code. This is the cart-killer: feeding `product.id` into the cart's `catalogItemId` sends an empty string and the add returns **HTTP 500** (`"catalogItemId" has size 0`). Use `product._id` everywhere — in links, as the cart `catalogItemId`, and as the variant-query filter value. (If a field name surprises you, you are probably reading the REST doc view — re-open it with `?apiView=SDK`.)
|
|
96
114
|
|
|
97
|
-
**Scope of the `_id` rule — entity reads only.** `_id` is the id of a read **entity** (product, variant, cart line item). It is **not** a universal "every id field is `_id`" rule:
|
|
115
|
+
**Scope of the `_id` rule — entity reads only.** `_id` is the id of a read **entity** (product, variant, cart line item). It is **not** a universal "every id field is `_id`" rule: request params name their own fields (e.g. the redirect session takes `ecomCheckout.checkoutId`, *not* `_id` — see the *Checkout* section below — even though the value you pass is the cart's `_id`). Don't assume every id-shaped field is spelled `_id`.
|
|
98
116
|
|
|
99
117
|
**Visibility:** only `visible: true` products are returned to a visitor token, so a missing product usually means it wasn't seeded visible — not a query bug.
|
|
100
118
|
|
|
101
|
-
**Price
|
|
119
|
+
**Price:** after requesting `CURRENCY`, render `actualPriceRange.minValue.formattedAmount` (and the matching `compareAtPriceRange` value) directly. Fall back to raw `.amount` only if the formatted value is unexpectedly absent. Never use `price.actualPrice.amount`: that is the seed/write shape and reads `undefined` → `$NaN`.
|
|
102
120
|
|
|
103
121
|
### Category navigation — list categories live
|
|
104
122
|
|
|
@@ -111,7 +129,7 @@ const res = await categories.queryCategories({
|
|
|
111
129
|
}).exists('name', true).find(); // read the returned array per the SDK doc; ids are `_id`; link each to /category/<slug>
|
|
112
130
|
```
|
|
113
131
|
|
|
114
|
-
**⚠️ The query MUST carry a filter condition — chain `.exists('name', true)` (as above), do NOT call a bare `.find()`.** A `.find()` with no chained filter serializes an empty `"filter": {}`, which `categories/v1/categories/query` rejects with `400 INVALID_FILTER` ("Filter expression cannot contain an empty condition"). **This is fatal on the visitor/manual-client (non-Astro) path** — the call throws and the nav never renders; managed-Astro's server-side transport happens to tolerate the empty filter, so a bare `.find()` *looks* fine there but breaks the moment the same code runs client-side. `.exists('name', true)` is a tautology (every category has a `name`), so it matches **all** categories and is accepted on **both** paths — use this one shape everywhere. **Do NOT filter on `visible`** (`.eq('visible', true)`): unlike `name`, `visible` is **not declared filterable** on `queryCategories`, so it triggers a silently-swallowed `400` and the nav renders blank; if you ever need to hide a category, filter the returned array **client-side**. (`getCategoryBySlug(slug, { appNamespace: '@wix/stores' })` on the category page is unaffected — it takes no query filter.) This is a **distinct API from bookings' `categoriesV2`** — don't copy that module's query shape here; read the exact result-array key + field names from the `@wix/categories` SDK doc: <https://dev.wix.com/docs/
|
|
132
|
+
**⚠️ The query MUST carry a filter condition — chain `.exists('name', true)` (as above), do NOT call a bare `.find()`.** A `.find()` with no chained filter serializes an empty `"filter": {}`, which `categories/v1/categories/query` rejects with `400 INVALID_FILTER` ("Filter expression cannot contain an empty condition"). **This is fatal on the visitor/manual-client (non-Astro) path** — the call throws and the nav never renders; managed-Astro's server-side transport happens to tolerate the empty filter, so a bare `.find()` *looks* fine there but breaks the moment the same code runs client-side. `.exists('name', true)` is a tautology (every category has a `name`), so it matches **all** categories and is accepted on **both** paths — use this one shape everywhere. **Do NOT filter on `visible`** (`.eq('visible', true)`): unlike `name`, `visible` is **not declared filterable** on `queryCategories`, so it triggers a silently-swallowed `400` and the nav renders blank; if you ever need to hide a category, filter the returned array **client-side**. (`getCategoryBySlug(slug, { appNamespace: '@wix/stores' })` on the category page is unaffected — it takes no query filter.) This is a **distinct API from bookings' `categoriesV2`** — don't copy that module's query shape here; read the exact result-array key + field names from the `@wix/categories` SDK doc: <https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/categories/introduction.md?apiView=SDK>.
|
|
115
133
|
|
|
116
134
|
### Filtering products by category
|
|
117
135
|
|
|
@@ -122,6 +140,7 @@ const res = await categories.queryCategories({
|
|
|
122
140
|
```js
|
|
123
141
|
const { products } = await productsV3.searchProducts({
|
|
124
142
|
filter: { 'directCategoriesInfo.categories': { $matchItems: [{ id: categoryId }] } },
|
|
143
|
+
fields: PRODUCT_FIELDS,
|
|
125
144
|
});
|
|
126
145
|
```
|
|
127
146
|
|
|
@@ -149,11 +168,11 @@ Doc: <https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v
|
|
|
149
168
|
|
|
150
169
|
Each `variant` carries `variant.optionChoices[].optionChoiceNames` — `{ optionName, choiceName }`. Match the buyer's selected options (Size = "Small", Color = "Red", …) against those names to pick the variant. For a **single-variant** product, use the only item. Fall back to `items[0]` if matching yields nothing. The id to send to the cart is **`variant.variantId ?? variant._id`**.
|
|
151
170
|
|
|
152
|
-
**2 · Add it.** Doc: <https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart/add-to-current-cart.md?apiView=SDK> · catalogReference contract: <https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/e-commerce-integration.md?apiView=SDK>
|
|
171
|
+
**2 · Add it.** Doc: <https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/add-line-items-to-current-cart.md?apiView=SDK> · catalogReference contract: <https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/e-commerce-integration.md?apiView=SDK>
|
|
153
172
|
|
|
154
173
|
```js
|
|
155
|
-
await
|
|
156
|
-
|
|
174
|
+
await currentCartV2.addLineItemsToCurrentCart({
|
|
175
|
+
catalogItems: [{ // the write shape uses `catalogItems`
|
|
157
176
|
quantity,
|
|
158
177
|
catalogReference: {
|
|
159
178
|
catalogItemId: product._id, // the product's _id (the `_id` rule above)
|
|
@@ -164,28 +183,46 @@ await currentCart.addToCurrentCart({
|
|
|
164
183
|
});
|
|
165
184
|
```
|
|
166
185
|
|
|
167
|
-
**⚠️ CRITICAL: `options.variantId` is MANDATORY for any product that has variants.** Adding by `catalogItemId` alone
|
|
186
|
+
**⚠️ CRITICAL: `options.variantId` is MANDATORY for any product that has variants.** Adding by `catalogItemId` alone **fails** — the catalog can't resolve a variant-bearing product without it, and Cart V2 **rejects the add with an explicit error** rather than accepting an invalid line. The cart method's required-params list omits `variantId`, so it's an easy one to miss. Always resolve and include it (part 1 above).
|
|
187
|
+
|
|
188
|
+
**CRITICAL: `ITEM_NOT_FOUND_IN_CATALOG` for a product that exists is a catalog defect, not a stale id.** A `DIGITAL` product whose variant has no `digitalProperties.digitalFile` is rejected under that code, and one with no stock is rejected as `exceeds available inventory` — both read back `visible: true` and in the catalog. Fix the product (`setup-online-store.md` → digital products); re-reading ids won't help.
|
|
168
189
|
|
|
169
|
-
**⚠️ CRITICAL: `options.options` is for MODIFIERS, not variant selection.** Product option selections (Size/Color) are resolved to a **variant** and referenced by `variantId`. `options.options` is only for free-text / TEXT_CHOICES add-on **modifiers**. Do **not** encode Size/Color as `options.options` — that is the coffee-grind bug
|
|
190
|
+
**⚠️ CRITICAL: `options.options` is for MODIFIERS, not variant selection.** Product option selections (Size/Color) are resolved to a **variant** and referenced by `variantId`. `options.options` is only for free-text / TEXT_CHOICES add-on **modifiers**. Do **not** encode Size/Color as `options.options` — that is the coffee-grind bug: the variant never resolves, so Cart V2 rejects the add with an explicit error.
|
|
170
191
|
|
|
171
|
-
### Checkout
|
|
192
|
+
### Checkout — redirect to the hosted checkout page
|
|
172
193
|
|
|
173
|
-
|
|
174
|
-
|
|
194
|
+
The cart's `_id` **is** the checkout id — pass it into the redirect session's `ecomCheckout.checkoutId`. Read the current cart, then hand its id to a redirect session, which carries the visitor/member session across to the hosted checkout on its own domain.
|
|
195
|
+
Doc: <https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/get-current-cart.md?apiView=SDK>
|
|
175
196
|
|
|
176
197
|
```js
|
|
177
|
-
const
|
|
198
|
+
const { cart } = await currentCartV2.getCurrentCart(); // NOTE: returns { cart } — destructure it
|
|
178
199
|
const session = await redirects.createRedirectSession({
|
|
179
|
-
ecomCheckout: { checkoutId:
|
|
200
|
+
ecomCheckout: { checkoutId: cart._id }, // the cart's _id IS the checkout id
|
|
180
201
|
callbacks: { postFlowUrl: `${origin}/`, thankYouPageUrl: `${origin}/` },
|
|
181
202
|
});
|
|
182
203
|
window.location.href = session.redirectSession.fullUrl; // the hosted-checkout URL
|
|
183
204
|
```
|
|
184
205
|
|
|
185
|
-
**⚠️
|
|
206
|
+
**⚠️ The cart's `_id` is the checkout id.** Pass `cart._id` straight into the redirect session's `ecomCheckout.checkoutId`. And `getCurrentCart()` returns **`{ cart }`** — destructure it, or `cart` is `undefined` and `cart._id` throws *"Cannot read properties of undefined (reading '_id')"*.
|
|
186
207
|
|
|
187
208
|
**⚠️ CRITICAL: `origin` for `postFlowUrl`/`thankYouPageUrl` MUST be the `https://` published host — derive it from `window.location.origin`, NEVER `new URL(request.url).origin`.** The Headless redirect allowlist registers the site's **`https://`** host and treats **`http://<same host>` as a different, unlisted origin**. When the buyer returns from the hosted checkout (e.g. clicks "Continue Browsing"), the redirect goes through the allowlist — and an `http://` `postFlowUrl` **403s** with *"… isn't listed as an allowed redirect domain."* If you build the redirect session in a **server route** (`src/pages/api/*`), `new URL(request.url).origin` resolves to **`http://`** behind Wix's TLS-terminating proxy → guaranteed 403 on return. So **pass `window.location.origin` from the client** into the route (don't read the origin off the request), or force the scheme to `https`. Doc: <https://dev.wix.com/docs/go-headless/getting-started/setup/manage-urls/add-allowed-redirect-domains>.
|
|
188
209
|
|
|
210
|
+
### Formatting cart prices
|
|
211
|
+
|
|
212
|
+
**Product** prices from `productsV3` still carry a ready-to-show `actualPriceRange.minValue.formattedAmount` — use it directly. But **Cart V2 money does not**: every cart amount — line-item `pricing.unitPrice` / `pricing.totalPrice` **and** the `estimateCurrentCart`/`calculateCurrentCart` `summary.priceSummary.*` — is a `ConvertedMoney` `{ amount, convertedAmount }` with **no** formatted string. So once items are in the cart, you format the price yourself. The currency isn't on the money object; read it from the cart (`cart.customerInfo?.currencyCode ?? cart.businessInfo?.currencyCode`), and use `convertedAmount` (buyer's display currency) when present, else `amount` (site currency):
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
function formatCartMoney(money, cart) {
|
|
216
|
+
const value = money?.convertedAmount ?? money?.amount;
|
|
217
|
+
const currency = cart?.customerInfo?.currencyCode ?? cart?.businessInfo?.currencyCode ?? 'USD';
|
|
218
|
+
return value == null ? '' : new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(Number(value));
|
|
219
|
+
}
|
|
220
|
+
// e.g. line item: formatCartMoney(item.pricing.totalPrice, cart)
|
|
221
|
+
// subtotal: formatCartMoney(estimate.summary.priceSummary.subtotal, cart)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Never hardcode `$` or assume USD — stores run in EUR/GBP too.
|
|
225
|
+
|
|
189
226
|
### Showing stock state
|
|
190
227
|
|
|
191
228
|
Read the **V3** inventory fields: product-level in-stock is `product.inventory.availabilityStatus` (`"IN_STOCK"`); variant-level is `variant.inventoryStatus.inStock`. Reading the V1 inventory field on V3 data returns `undefined` → everything renders out-of-stock (the all-OOS bug). These come from `productsV3` / `readOnlyVariantsV3`, not the V1 module.
|
|
@@ -208,7 +245,7 @@ function imgSrc(mediaMain, w = 600, h = 600) {
|
|
|
208
245
|
|
|
209
246
|
**Never hand-build a `static.wixstatic.com/.../v1/fit/...` URL** either — the format is easy to get wrong and the image then **403s**. Only `wix:image://` values need resolving; an already-absolute `https://` URL goes straight into `<img src>`. Doc: <https://dev.wix.com/docs/sdk/core-modules/sdk/media>
|
|
210
247
|
|
|
211
|
-
**This applies to cart line-item images too, not just product reads.** A cart `lineItem.image` is the same `wix:image://` identifier — run it through the same `imgSrc()` helper before `<img src>`. (If you build the cart over an API route, resolve there and return a ready URL so the component never sees a `wix:image://`.)
|
|
248
|
+
**This applies to cart line-item images too, not just product reads.** A cart `lineItem.attributes.image` is the same `wix:image://` identifier — run it through the same `imgSrc()` helper before `<img src>`. (If you build the cart over an API route, resolve there and return a ready URL so the component never sees a `wix:image://`.)
|
|
212
249
|
|
|
213
250
|
### Rendering product descriptions
|
|
214
251
|
|
|
@@ -230,7 +267,7 @@ Optional: render a `Product` schema.org JSON-LD `<script>` from the fetched prod
|
|
|
230
267
|
|
|
231
268
|
## Conclusion
|
|
232
269
|
A correct Catalog V3 storefront frontend:
|
|
233
|
-
- imports **`productsV3` / `readOnlyVariantsV3` / `categories` / `
|
|
270
|
+
- imports **`productsV3` / `readOnlyVariantsV3` / `categories` / `currentCartV2` / `redirects`** — never the V1 `products`/`collections` modules;
|
|
234
271
|
- uses **`product._id`** (never `product.id`) as the cart's `catalogItemId`;
|
|
235
272
|
- resolves the **mandatory `variantId`** via `readOnlyVariantsV3` and passes it as `options.variantId` (not `options.options`);
|
|
236
273
|
- builds its category nav from a **live `categories.queryCategories()`** and filters category pages server-side with **`searchProducts` + `$matchItems: [{ id: categoryId }]`** keyed on the live `categoryId` — never a frozen seed-time `productIds` map, never `queryProducts` for category filtering, never `$hasSome`, never V1 `collectionIds`;
|
|
@@ -456,7 +456,7 @@ async function submitContact(formEl) {
|
|
|
456
456
|
formId: SEEDED_FORM_ID, // from seeded.forms[].formId
|
|
457
457
|
submissions: values, // map of target -> value (or -> nested object, for an address)
|
|
458
458
|
});
|
|
459
|
-
return { _id, status }; //
|
|
459
|
+
return { _id, status }; // any status → the submission exists; render a thank-you (see the status note below)
|
|
460
460
|
}
|
|
461
461
|
```
|
|
462
462
|
|
|
@@ -482,13 +482,28 @@ construction, with no hand-maintained list to drift.
|
|
|
482
482
|
|
|
483
483
|
Both are fixed in `setup-forms.md` STEP 2.
|
|
484
484
|
|
|
485
|
-
**⚠️
|
|
486
|
-
Wix Forms namespace it
|
|
487
|
-
|
|
488
|
-
|
|
485
|
+
**⚠️ Read `status` from the result — but a resolved call means the submission EXISTS, whatever the
|
|
486
|
+
status.** For the Wix Forms namespace it's `CONFIRMED` (recorded). Some namespaces return `PENDING`,
|
|
487
|
+
which is **not yet recorded** in the Wix Forms collection but **is a created submission**;
|
|
488
|
+
`PAYMENT_WAITING` is a created submission on a form that collects payment
|
|
489
489
|
([Submission status](https://dev.wix.com/docs/api-reference/crm/forms/form-submissions/introduction#submission-status)).
|
|
490
|
-
|
|
491
|
-
|
|
490
|
+
|
|
491
|
+
**All three are a successful submit — show the thank-you.** The visitor has done everything the form
|
|
492
|
+
asked of them; confirming a `PENDING` is a server-side step they play no part in. Showing an error
|
|
493
|
+
instead invites them to submit again, so the cost of getting this wrong is duplicate submissions in
|
|
494
|
+
the owner's inbox for a submission that already exists.
|
|
495
|
+
|
|
496
|
+
`PAYMENT_WAITING` is the same call: the entry is in the owner's inbox and the *submit* succeeded, so
|
|
497
|
+
**never fail it back to the visitor**. Payment is a separate step — surface it *inside* the success
|
|
498
|
+
state (a "complete your payment" link or instruction) rather than as a failed submission. Since this
|
|
499
|
+
renderer skips `PAYMENT` fields it shouldn't arise at all; if it does, the schema has a payment field
|
|
500
|
+
the UI isn't rendering.
|
|
501
|
+
|
|
502
|
+
```js
|
|
503
|
+
const { _id, status } = await submissions.createSubmission({ formId, submissions: values });
|
|
504
|
+
// CONFIRMED | PENDING | PAYMENT_WAITING → the submission exists. Thank-you either way.
|
|
505
|
+
if (status === "PAYMENT_WAITING") { /* …and surface the payment step within it */ }
|
|
506
|
+
```
|
|
492
507
|
|
|
493
508
|
**⚠️ Per-field validation errors — the SDK buries them two levels deeper than the docs' shape.** The
|
|
494
509
|
documented entries (`errorPath`, `errorType`, `errorMessage`, `params` — see
|
|
@@ -667,9 +682,10 @@ A correct Wix Forms frontend:
|
|
|
667
682
|
`target`** so the `submissions` map is keyed by `target` by construction;
|
|
668
683
|
- submits on the **plain visitor token with NO `auth.elevate`** (anonymous submit works; a pure SPA
|
|
669
684
|
can't elevate anyway) and, at the default `ADVANCED` protection, **no captcha**;
|
|
670
|
-
- **only writes submissions** — reading them back is owner-only — and
|
|
671
|
-
**`
|
|
672
|
-
the
|
|
685
|
+
- **only writes submissions** — reading them back is owner-only — and shows the thank-you for
|
|
686
|
+
**`CONFIRMED`, `PENDING` *or* `PAYMENT_WAITING`** (all three are created submissions; a payment
|
|
687
|
+
form surfaces the payment step *within* that success state, never as a failed submit); reads the
|
|
688
|
+
created id as **`result._id`**, never `result.id`;
|
|
673
689
|
- is **accessible by construction** (the inputs are generated, so a slip repeats on every field):
|
|
674
690
|
each error carries a deterministic id from its `errorPath` and is referenced by `aria-describedby`
|
|
675
691
|
+ `role="alert"` and persisted (not conditionally unmounted); a choice group's error and
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "How to Code Members (Astro)"
|
|
3
|
-
description: The frontend contract for member sign-up / log-in / log-out and member-gated surfaces on a Wix-managed **Astro** frontend — the built-in `/api/auth/login` + `/api/auth/logout` routes that `@wix/astro` ships, the `
|
|
3
|
+
description: The frontend contract for member sign-up / log-in / log-out and member-gated surfaces on a Wix-managed **Astro** frontend — the built-in `/api/auth/login` + `/api/auth/logout` routes that `@wix/astro` ships, the `returnToUrl` param, gating a page by resolving the member in SSR / a backend route, reading the current member with `@wix/members` `getCurrentMember`, and the two rules that keep this path from breaking: **no `OAuthStrategy`/no client** (that 500s under auto-auth) and **no `auth.elevate`** for a member reading their own data. Specifies the *how* for the Astro axis only — read `how-to-code-members-non-astro.md` for any non-Astro frontend.
|
|
4
4
|
---
|
|
5
5
|
**RECIPE**: How to Code Member Auth on a Wix-managed **Astro** Frontend (built-in `/api/auth/*`, `@wix/members`)
|
|
6
6
|
|
|
@@ -39,16 +39,16 @@ So a paywall that only needs "logged-in vs not" runs on identity alone; anything
|
|
|
39
39
|
<a href="/api/auth/login">Log in / Sign up</a>
|
|
40
40
|
|
|
41
41
|
<!-- land the member somewhere specific afterward -->
|
|
42
|
-
<a href="/api/auth/login?
|
|
42
|
+
<a href="/api/auth/login?returnToUrl=/account">Log in</a>
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
Logout is a **POST** to `/api/auth/logout` (optionally with `?
|
|
45
|
+
Logout is a **POST** to `/api/auth/logout` (optionally with `?returnToUrl=`):
|
|
46
46
|
|
|
47
47
|
```astro
|
|
48
48
|
<form method="POST" action="/api/auth/logout"><button>Log out</button></form>
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
-
|
|
51
|
+
- **The param is `returnToUrl` — not `returnUrl`.** The routes validate their query with a strict schema that silently DROPS unknown params, so a misspelled param doesn't error — the member just lands on `/`. The value must be a **relative path** (the callback refuses absolute URLs).
|
|
52
52
|
- After login the member identity **rides on every subsequent SDK call automatically** — no client, no token handling. That's auto-auth (`astro.md`).
|
|
53
53
|
|
|
54
54
|
---
|
|
@@ -67,14 +67,14 @@ try {
|
|
|
67
67
|
me = res.member ?? null;
|
|
68
68
|
} catch { /* not a member / not installed — treat as anonymous */ }
|
|
69
69
|
|
|
70
|
-
if (!me) return Astro.redirect('/api/auth/login?
|
|
70
|
+
if (!me) return Astro.redirect('/api/auth/login?returnToUrl=/account');
|
|
71
71
|
---
|
|
72
72
|
<h1>Welcome, {me.profile?.nickname ?? me.loginEmail}</h1>
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
- **Guard the SSR call in `try/catch`** — an unguarded throw truncates the response mid-stream (white screen; `astro.md` A3). An anonymous visitor is a normal state, not an error: catch → treat as logged-out → redirect to login.
|
|
76
76
|
- **Don't render account/gated UI as a client island that checks auth in the browser.** Resolve identity server-side and gate the route; render only what a member should see. (Same reasoning as the blog-comment API-endpoint path — avoid the browser-auth detour.)
|
|
77
|
-
- For an **action** that only *some* callers may take (post a comment, place a member order), don't gate the whole page: render the control always, and on submit POST to a `src/pages/api/*.ts` endpoint that resolves the session and, if the caller isn't a member, redirects to `/api/auth/login?
|
|
77
|
+
- For an **action** that only *some* callers may take (post a comment, place a member order), don't gate the whole page: render the control always, and on submit POST to a `src/pages/api/*.ts` endpoint that resolves the session and, if the caller isn't a member, redirects to `/api/auth/login?returnToUrl=…`.
|
|
78
78
|
|
|
79
79
|
---
|
|
80
80
|
|
|
@@ -116,8 +116,8 @@ So: browsing the plans grid is public, but the **subscribe** button and the **my
|
|
|
116
116
|
|
|
117
117
|
## Conclusion
|
|
118
118
|
Correct member auth on an Astro frontend:
|
|
119
|
-
- uses the **built-in `/api/auth/login`** (login *and* sign-up) and **POST `/api/auth/logout`** routes with an allow-listed `
|
|
120
|
-
- gates surfaces **server-side** (SSR frontmatter or a `src/pages/api/*.ts` route), guarded in `try/catch`, bouncing anonymous visitors to `/api/auth/login?
|
|
119
|
+
- uses the **built-in `/api/auth/login`** (login *and* sign-up) and **POST `/api/auth/logout`** routes with an allow-listed `returnToUrl` — the login handshake **never** builds an `OAuthStrategy` client, and one must never be built in **SSR frontmatter** (the public-env `clientId` is `undefined` at server render → 500). (The one exception is the custom-login surface — `how-to-code-members-custom-login.md` — which builds an explicit client in a backend route or client island, never in SSR frontmatter.)
|
|
120
|
+
- gates surfaces **server-side** (SSR frontmatter or a `src/pages/api/*.ts` route), guarded in `try/catch`, bouncing anonymous visitors to `/api/auth/login?returnToUrl=…`;
|
|
121
121
|
- reads the current member via **`@wix/members` `getCurrentMember`** (not the dev-preview `@wix/site-members`), resolving the photo `wix:image://` URI and expecting only PUBLIC fields for other members;
|
|
122
122
|
- does **no `auth.elevate`** for a member reading their own data (elevation is a different, admin-only axis that lives in a backend route);
|
|
123
123
|
- treats **login as required** whenever pricing-plans is present (subscribe + my-subscription), and as a soft add-on for the "my …" surfaces of the other verticals;
|
|
@@ -15,7 +15,7 @@ A concise contract for building your **own** login / sign-up / logout UI and dri
|
|
|
15
15
|
> **⚠️ This is a client-driven (`OAuthStrategy`) flow — it is the non-Astro shape.** `register`/`login` live on `client.auth`, i.e. the manual visitor client `non-astro.md` builds. Astro's auto-auth ships **no client** to call them on. So: on a **non-Astro** frontend (SPA / static), this is the natural path. On **Astro**, custom login means stepping *outside* auto-auth — instantiate an explicit `OAuthStrategy` client (in a backend route or a client island) to run these calls; do **not** expect the built-in `/api/auth/*` routes to do custom login (they only drive the Wix login page). If the brief is Astro *and* doesn't demand a custom form, prefer the Wix login page (`how-to-code-members-astro.md`).
|
|
16
16
|
|
|
17
17
|
Pinned docs (read before wiring — `curl` the `.md` directly):
|
|
18
|
-
- Custom login via the JS SDK: <https://dev.wix.com/docs/go-headless/
|
|
18
|
+
- Custom login via the JS SDK: <https://dev.wix.com/docs/go-headless/authentication/members/custom-login-page/build-a-custom-login-page-js-sdk.md>
|
|
19
19
|
- `OAuthStrategy` reference (`register`/`login`/`processVerification`/`getMemberTokensForDirectLogin`/`sendPasswordResetEmail`, the `StateMachine` + `IdentityProfile` objects): <https://dev.wix.com/docs/sdk/core-modules/sdk/oauth-strategy.md>
|
|
20
20
|
- Current member (SDK): <https://dev.wix.com/docs/sdk/frontend-modules/members/current-member/introduction> (open with `?apiView=SDK`)
|
|
21
21
|
|
|
@@ -11,7 +11,7 @@ A concise contract for wiring **login / sign-up / logout and member-gated surfac
|
|
|
11
11
|
> **One mechanism, not three.** Sign-up, log-in and log-out are the *same* flow — the Wix login page **logs in an existing member or registers a new one** in one step; you never build a separate "sign up" call. Member tokens are the **same shape** as visitor tokens, just `role: member`: login just swaps the token set on the client you already have.
|
|
12
12
|
|
|
13
13
|
Pinned docs (read before wiring — `curl` the `.md` directly):
|
|
14
|
-
- Wix-managed login via the JS SDK: <https://dev.wix.com/docs/go-headless/
|
|
14
|
+
- Wix-managed login via the JS SDK: <https://dev.wix.com/docs/go-headless/authentication/members/wix-login-page/add-a-wix-login-page-js-sdk.md>
|
|
15
15
|
- `OAuthStrategy` reference (member flows, token/session methods): <https://dev.wix.com/docs/sdk/core-modules/sdk/oauth-strategy.md>
|
|
16
16
|
- Handle visitors & members via the JS SDK: <https://dev.wix.com/docs/go-headless/self-managed-headless/authentication/visitors/handle-visitors-using-the-js-sdk.md>
|
|
17
17
|
- Current member (SDK): <https://dev.wix.com/docs/sdk/frontend-modules/members/current-member/introduction> (open with `?apiView=SDK`)
|
|
@@ -23,7 +23,9 @@ A contract for the **frontend code** of a pricing-plans site: showing the plans
|
|
|
23
23
|
| List / read plans (the grid) | `@wix/pricing-plans` | `plansV3` (Plans V3 — `queryPlans`, `getPlan`) |
|
|
24
24
|
| Order a plan + read a member's orders | `@wix/pricing-plans` | `orders` (`createOnlineOrder`, `memberListOrders`, `memberGetOrder`) |
|
|
25
25
|
| Member login / current member | `@wix/members` + `@wix/sdk` auth | see the members recipe (`getCurrentMember`, `loggedIn()`) |
|
|
26
|
-
| Book a service with a membership (integration) | `@wix/bookings` + `@wix/ecom` (+ `@wix/redirects`) | `bookings` (`createBooking`), ecom `
|
|
26
|
+
| Book a service with a membership (integration) | `@wix/bookings` + `@wix/ecom` (+ `@wix/redirects`) | `bookings` (`createBooking`), ecom `currentCartV2` (line-item `membershipPayment`) — see *Booking with a membership* |
|
|
27
|
+
|
|
28
|
+
> Migrating from Cart V1 / Checkout V1? The code below is V2-only — see the [migration guide](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/migration-guide) for the before/after.
|
|
27
29
|
|
|
28
30
|
**Never** import `@wix/site-pricing-plans` in headless code, and don't reach for a V1 `plans`-collection query — Plans V3 (`queryPlans` → `pricingVariants`) is the shape the seed creates.
|
|
29
31
|
|
|
@@ -98,15 +100,15 @@ This is the payoff of the seed's STEP 2: a member who holds a plan that **covers
|
|
|
98
100
|
|
|
99
101
|
1. **Require login** — membership payment resolves against the member identity (a covered service booked anonymously just falls back to pay-per-booking).
|
|
100
102
|
2. **On `createBooking`, set `selectedPaymentOption: "MEMBERSHIP"`** (instead of `ONLINE`/`OFFLINE`). Enum values: `ONLINE`, `OFFLINE`, **`MEMBERSHIP`** (pay with a pricing plan), `MEMBERSHIP_OFFLINE`. Doc: <https://dev.wix.com/docs/api-reference/business-solutions/bookings/bookings/bookings-writer-v2/create-booking.md?apiView=SDK>
|
|
101
|
-
3. **The booking still rides the ecom
|
|
102
|
-
- `
|
|
103
|
-
- apply
|
|
104
|
-
Doc: <https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/
|
|
103
|
+
3. **The booking still rides the ecom cart** (Bookings is an ecom catalog, appId `13d21c63-b5ec-5912-8397-c3a5ddb27a97`) — the membership is applied **on the cart line item**, not on the booking object. Set membership selection on the line item via `updateLineItemsInCurrentCart`:
|
|
104
|
+
- **Apply one** by setting the line item's `membershipPayment` via `currentCartV2.updateLineItemsInCurrentCart({ lineItems: [{ lineItemId: <booking line item id>, membershipPayment: { existingMembership: { membershipId, appId } } }] })` — `membershipId`/`appId` identify the member's existing plan membership (the Pricing Plans app); the line item reads it back as `paymentConfig.membership`. When the membership covers the full price, the calculated total drops to `0`.
|
|
105
|
+
- **Which plan to apply / eligibility:** the cart has **no** candidate-memberships read in V2 — `calculateCurrentCart` → `summary.paymentSummary.memberships` lists memberships **already applied**, not candidates — so which plan to apply comes from the member's plans + live coverage (see the LIVE-read note below). **⚠️ VERIFY IN A LIVE BUILD** which `appId`/`membershipId` a headless member token must pass.
|
|
106
|
+
Doc: <https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/update-line-items.md?apiView=SDK>
|
|
105
107
|
4. **⚠️ Do NOT call `confirmBooking`** — for a membership payment Wix **auto-confirms** the booking on redemption (the same "no confirmBooking" rule as `how-to-code-bookings.md`; the membership drives confirmation).
|
|
106
108
|
|
|
107
|
-
- **⚠️ Eligibility / coverage is a LIVE read, never a hardcoded plan→service map.** A new eligible plan, or a service newly added to a plan's coverage in the backoffice, **must be honored with no code change** — so never freeze the seed-time `{ planId → serviceIds }` map into the frontend.
|
|
109
|
+
- **⚠️ Eligibility / coverage is a LIVE read, never a hardcoded plan→service map.** A new eligible plan, or a service newly added to a plan's coverage in the backoffice, **must be honored with no code change** — so never freeze the seed-time `{ planId → serviceIds }` map into the frontend. Since Cart V2 has no per-line "eligible memberships" read, compute eligibility from the member's own plans against live coverage: list the member's active orders (`orders.memberListOrders`, `status: ACTIVE` within the date window) and match each `planId` against the plan's **live** Benefit-Program coverage (query the program's items — the same API `setup-pricing-plans.md` STEP 2 wrote to — at request time; do **not** read a coverage map baked into code). Set `selectedPaymentOption: "MEMBERSHIP"` on the booking + the line item's `membershipPayment.existingMembership` from the matched plan.
|
|
108
110
|
- **⚠️ A `MEMBERSHIP` booking on a service the plan does NOT cover fails at checkout** (unless `skipSelectedPaymentOptionValidation`, which needs elevation — don't use in a member flow). Only offer "book with membership" for services actually covered by one of the member's active plans; otherwise fall back to the normal paid booking (`how-to-code-bookings.md`).
|
|
109
|
-
- **Credit/session plans:** for a limited (non-unlimited) plan, `
|
|
111
|
+
- **Credit/session plans:** for a limited (non-unlimited) plan, don't pre-read a balance — apply the membership, then `calculateCurrentCart`/`estimateCurrentCart`. The summary lists the applied memberships (`summary.paymentSummary.memberships`), the covered line's `paymentConfig.membership` carries `redemptionCost` (balance deducted for this booking; `0` = unlimited) + `redemptionType` (`CREDITS`/`SESSIONS`), and an exhausted/over-limit plan surfaces **explicitly** as a `summary.violations` entry (or an error at place-order) — treat that as "not eligible." The ecom cart itself carries no remaining-balance read; the balance is owned by the plan's **Benefit-Program** domain (the same source as the coverage check above), so if you need the actual number read it there — not off the cart. An unlimited plan (seed `price:"0"`) has no ceiling.
|
|
110
112
|
|
|
111
113
|
### Out of scope (do not build these)
|
|
112
114
|
- **Completing/activating payment from code** — connecting a payments account, marking orders paid, forcing an order `ACTIVE`, "activating" a subscription server-side. Payment is the member's hosted-flow step or a merchant dashboard/config task, never frontend code (see the SCOPE callout under *Subscribing*).
|
|
@@ -121,4 +123,4 @@ A correct Pricing Plans frontend:
|
|
|
121
123
|
- imports **`@wix/pricing-plans`** (`plansV3`, `orders`) — **never** `@wix/site-pricing-plans` (its `startOnlinePurchase` is Wix-site page-code, not headless);
|
|
122
124
|
- lists the grid publicly with **`plansV3.queryPlans().eq('visibility','PUBLIC')`**, reads **`plan._id`** and price from **`pricingVariants[].pricingStrategies[].flatRate.amount`** (decimal string) — never a top-level `price` — and only shows a buy button on `buyable` plans;
|
|
123
125
|
- treats **subscribe and my-subscription as login-gated** (the hard members dependency), orders with **`orders.createOnlineOrder(planId)`** (no `onBehalf`, no elevate), renders free plans as `ACTIVE` immediately, and drives paid plans through a payment redirect (**exact headless redirect to be confirmed in a live build**) — and **stops at the redirect**: no payments-account connect, no order activation / mark-as-paid from code (see *Out of scope*);
|
|
124
|
-
- for the Bookings integration, books a covered service by setting **`selectedPaymentOption: "MEMBERSHIP"`** on `createBooking`, applies the membership on the **ecom
|
|
126
|
+
- for the Bookings integration, books a covered service by setting **`selectedPaymentOption: "MEMBERSHIP"`** on `createBooking`, applies the membership on the **ecom cart line item** (`membershipPayment.existingMembership` via `updateLineItemsInCurrentCart`), never calls `confirmBooking`, and falls back to matching the member's active-order `planId`s to the service's coverage when the cart eligibility field isn't readable client-side.
|