> Portal Navigation: > > - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version. > - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages). > - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`). > - Top-level index of all portals: https://dev.wix.com/docs/llms.txt > - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt ## Resource: Tutorial: Request a Quote ## Article: Tutorial: Request a Quote ## Article Link: https://dev.wix.com/docs/develop-websites/articles/code-tutorials/wix-e-commerce-stores/tutorial-request-a-quote.md ## Article Content: # Tutorial: Adding a Request A Quote Option to a Wix Store Product Page > This feature is currently only available for [Wix Studio](https://dev.wix.com/docs/develop-websites/articles/coding-with-velo/overview/about-coding-with-wix-studio.md) sites. This article demonstrates how you can add an option for site visitors to request a quote for a specific product on a Wix Stores Product Page. A site visitor may want to add this option, for example, to request a discount when purchasing a large quantity of a specific product, or to request a product with custom dimensions and specifications. In this example, we show how you can replace either the **Add To Cart** or the **Buy Now** button with a **Request a quote** button on a Wix Store Product Page. When a site visitor clicks **Request a quote**, a modal with a submission form opens to submit the quote request to the site owner. The site owner can then see the submission in the **Form submissions** tab in the site's dashboard. > **Note:** The terms popup and lightbox refer to the same element. While the editor and dashboard now refer to it as a [popup](https://support.wix.com/en/article/studio-editor-using-popups), the API methods continue to use the term lightbox for backward compatibility. The documentation uses both terms accordingly. To do this, we: 1. Add a [popup](https://support.wix.com/en/article/studio-editor-using-popups) to create the modal. 2. Create a submission form and add it to the popup. 3. Write the code for our Product Page to change the specific product's **Add To Cart** button's label to **Request a quote**, and to connect the button to the modal. 4. Implement the [eCommerce Validations SPI custom extension](https://www.wix.com/velo/reference/spis/wix-ecom/ecom-validations). You can also use this example for other use cases such as adding a **Contact us to Purchase** option. >**Note:** This tutorial provides an example of how you can override the **Add To Cart** or **Buy Now** button's functionality using the [`onAddToCart()`](https://www.wix.com/velo/reference/$w/productpage/onaddtocart) or [`onBuyNow()`](https://www.wix.com/velo/reference/$w/productpage/onbuynow) function. ## Before You Begin + This article assumes you have a [Wix Stores Product Page](https://support.wix.com/en/article/wix-stores-customizing-the-new-product-page) on your site. + For any product in a Wix Stores Product Page, you can provide site visitors with the option to either purchase a product (with predefined specifications, quantities, and price), or to request a quote. However, if you only want to provide site visitors with the option to request a quote for a specific product, and don't want them to be able to purchase it, you need to implement the [eCommerce Validations SPI custom extension](https://www.wix.com/velo/reference/spis/wix-ecom/ecom-validations). This custom extension can be used to validate the site visitor's cart and checkout to make sure that the specific product can't be purchased. We show this implementation in the last step of this tutorial. To learn more about custom extensions, see [Custom App Extensions Using SPIs](https://dev.wix.com/docs/develop-websites/articles/coding-with-velo/integrations/service-plugins-formerly-spis/about-service-plugins.md). ## Introduction We created the following custom bookshelf on a Wix Store Product Page for this tutorial. When a site visitor navigates to this Product Page, we want them to see a **Request a quote** button instead of the **Add To Cart** button. When a site visitor selects their [product options](https://support.wix.com/en/article/wix-stores-adding-and-customizing-product-options) for the bookshelf and clicks the **Request a quote** button, we want a modal with a submission form to open, and we want to stop the site visitor from proceeding with the Wix Checkout process. Once the site visitor fills out and submits the form, we want the site owner to receive the form information along with the site visitor's selected product option choices. ![product page add to cart](https://wixmp-833713b177cebf373f611808.wixmp.com/images/2de05a3808854f230a3c7dda42c1cc70.png) ## Step 1: Create the modal First we create the modal by adding a [popup](https://support.wix.com/en/article/studio-editor-using-popups) to our site from the **Layout Tools** section of the **Add** panel. We name our popup 'Request a quote'. ## Step 2: Create a submission form Next, we add a submission form from the **Contact & Forms** section of the **Add** panel, and place it in the popup. Our form has the following fields and looks like this: ![request a quote popup](https://wixmp-833713b177cebf373f611808.wixmp.com/images/e0f09f843980e40eb827068a4177cd30.png) ## Step 3: Write the code Last, we write the code for our Product page. We break the code into steps to understand how it works: 1. First we import our frontend modules and declare our variables. ```js import wixWindowFrontend from 'wix-window-frontend'; import wixLocationFrontend from 'wix-location-frontend'; let product; const bookshelfId = 'cd59cd36-b6d2-2cf3-9d48-81793a7bdbbd'; ``` **Understanding the Code** **Lines 1-2:** We import the `wixWindowFrontend` and `wixLocationFrontend` modules. **Lines 4-5:** We declare our variables to be used later in our code, including the bookshelf ID. To get the bookshelf ID, do the following: 1. In the editor, open the CMS panel on the left and click **Wix App collections**. 2. Scroll down to the **Stores** section and click **Products** to open the Products collection. 3. Find the bookshelf item in your collection, and copy the value in the `ID (_id)` field. In our example, the value should be `cd59cd36-b6d2-2cf3-9d48-81793a7bdbbd`. This is your bookshelf ID. To learn more, see [Working with Wix App Collections and Code](https://dev.wix.com/docs/develop-websites/articles/databases/wix-data/collections/working-with-wix-app-collections-and-code.md). 2. When the Product Page loads or when a site visitor selects a different product in the Product Page, we get the product's information. If the ID of the product on the Product Page matches the bookshelf's product ID, then we change the **Add To Cart** button's label to **Request a quote**, and add an event handler that runs when this button is clicked. ```js $w.onReady(function () { initProductPage(); }); wixLocationFrontend.onChange((location) => { let newPath = location.path; if (newPath?.[0] === 'product-page') { initProductPage(); } }); async function initProductPage() { product = await $w('#productPage1').getProduct(); if (product._id === bookshelfId) { $w('#productPage1').setAddToCartLabel('Request a quote'); $w('#productPage1').onAddToCart(onAddToCartHandler); } } ``` **Understanding the Code** **Lines 1-3:** When the Product Page loads, we call the `initProductPage()` function. **Lines 5-10:** When a site visitor selects a different product on the Product Page, we call the `initProductPage()` function. **Lines 12-13:** In the `initProductPage()` function, we get the information of the product on the Product Page. **Lines 14-18:** If the ID of the product on the Product Page matches the bookshelf's product ID, then we use the `setAddToCartLabel()` function to change the **Add To Cart** button's label to **Request a quote**, and call the `onAddToCart()` event handler when this button is clicked. >**Note:** You can change the **Buy Now** button's label to **Request a quote** instead by replacing the [`setAddToCartLabel()`](https://www.wix.com/velo/reference/$w/productpage/setaddtocartlabel) function with the [`setBuyNowLabel()`](https://www.wix.com/velo/reference/$w/productpage/setbuynowlabel) function, and the [`onAddToCart()`](https://www.wix.com/velo/reference/$w/productpage/onaddtocart) function with the [`onBuyNow()`](https://www.wix.com/velo/reference/$w/productpage/onbuynow) function. After implementing the code, the Product Page should look like this: ![product page request a quote](https://wixmp-833713b177cebf373f611808.wixmp.com/images/3a06f7acc786919c1bee0dd20a679b4c.png) 3. When a site visitor clicks the **Request a quote** button, get the site visitor's selected product option choices (color, number of shelves, and measurements), open the modal with the submission form, and stop the site visitor from proceeding with the Wix Checkout process. ``` js async function onAddToCartHandler(resume, cancel) { const data = await getSelectedProductData(); wixWindowFrontend.openLightbox('Request a quote', data) .then((bookshelfOptionData) => { console.log(bookshelfOptionData) cancel(); }); } async function getSelectedProductData() { const bookshelfQuantity = await $w('#productPage1').getQuantity(); const bookshelfChoices = await $w('#productPage1').getSelectedChoices(); const bookshelfCustomText = await $w('#productPage1').getCustomText(); return { product: product, quantity: bookshelfQuantity, choices: bookshelfChoices, customTextFields: bookshelfCustomText, } } ``` **Understanding the Code** **Line 1:** We write an `onAddToCartHandler()` function to handle the event when a site visitor clicks the **Request a quote** button, and pass in the `resume` and `cancel` functions. **Lines 2-8:** In the `onAddToCartHandler()` function, we call the `getSelectedProductData()` function to get the bookshelf option choices that the site visitor selected. Next we open our 'Request a quote' popup, passing in the bookshelf option data. We then console log the data and call the `cancel()` function to stop the site visitor from proceeding with the Wix Checkout process. **Lines 10-20:** In the `getSelectedProductData()` function, we use the `getQuantity()` function to get the bookshelf's quantity, the `getSelectedChoices()` function to get the selected color and number of shelves, and the `getCustomText()` function to get the measurements (Width/Height/Depth). We then return this data. ### Full Code Example ```js import wixWindowFrontend from 'wix-window-frontend'; import wixLocationFrontend from 'wix-location-frontend'; let product; const bookshelfId = 'cd59cd36-b6d2-2cf3-9d48-81793a7bdbbd'; $w.onReady(function () { initProductPage(); }); wixLocationFrontend.onChange((location) => { let newPath = location.path; if (newPath?.[0] === 'product-page') { initProductPage(); } }); async function initProductPage() { product = await $w('#productPage1').getProduct(); if (product._id === bookshelfId) { $w('#productPage1').setAddToCartLabel('Request a Quote'); $w('#productPage1').onAddToCart(onAddToCartHandler); } } async function onAddToCartHandler(resume, cancel) { const data = await getProductInfo(); wixWindowFrontend.openLightbox('Request a quote', data) .then((results) => { cancel(); }); } async function getProductInfo() { const bookshelfQuantity = await $w('#productPage1').getQuantity(); const bookshelfChoices = await $w('#productPage1').getSelectedChoices(); const bookshelfCustomText = await $w('#productPage1').getCustomText(); return { product: product, quantity: bookshelfQuantity, choices: bookshelfChoices, customTextFields: bookshelfCustomText, } } ``` ## Step 4: Implement the Validation SPI custom extension The last step we need to do is validate the cart and checkout using the [eCommerce Validations SPI custom extension](https://www.wix.com/velo/reference/spis/wix-ecom/ecom-validations) to make sure that a site visitor can only request a quote for the bookshelf and can't purchase it. To do this: 1. In the Studio Editor, click ![](https://d2x3xhvgiqkx42.cloudfront.net/12345678-1234-1234-1234-1234567890ab/76096845-8b12-44f1-91f6-3dc2e838fdd9/2022/08/29/23d50509-633d-4616-9f56-65add8fa6d0b/d910e041-d150-4f35-aa75-30ad262abc7a.png), then **Packages & Apps**. 2. Hover over Custom Extensions and click **eComm Validation SPI** to add the validations integration. Then follow the prompts to add the extension and accept any terms and conditions that display. 3. Enter a name for your integration and click **Add & Edit Code**. We named ours **validation-spi**. The name can't contain spaces or special characters. Open the Wix IDE, and go to **/src/backend/__spi__**. You should see the spi folder there. It should look something like **ecom-validations/validation-spi**. If the Custom Extension doesn't appear, try refreshing both the Studio Editor and the Wix IDE. 4. In this spi folder, you should see 2 files, **validation-spi.js** and **validation-spi-config.js**. We write the following code in the **validation-spi-config.js** file to validate the cart as well as the checkout. ```js import * as ecomValidations from 'interfaces-ecommerce-v1-validations-provider'; export function getConfig() { return {validateInCart: true}; } ``` **Understanding the Code** **Line 1:** We import all modules from the ecom validations provider. **Lines 3-5:** We want to also validate a site visitor's cart, so we set the `validateInCart` parameter to `true` in the exported config function. 6. We write the following code in the **validation-spi.js** file to validate whether the bookshelf is in the site visitor's cart or checkout. If so, we return the validation violation and give a violation description. ```js import * as ecomValidations from 'interfaces-ecommerce-v1-validations-provider'; const bookshelfId = 'cd59cd36-b6d2-2cf3-9d48-81793a7bdbbd'; export const getValidationViolations = async (options, context) => { let violations = []; const severity = ecomValidations.Severity.ERROR; const description = "You can't purchase this product. You can only request a quote." const requestAQuoteLineItem = options.validationInfo.lineItems.find(lineItem => isBookshelf(lineItem.catalogReference?.catalogItemId)); if (requestAQuoteLineItem != undefined) { const quantity = requestAQuoteLineItem.quantity; if (quantity > 0 && quantity < 200) { violations.push({ severity, target: { lineItem: { name: ecomValidations.NameInLineItem.LINE_ITEM_DEFAULT, _id: requestAQuoteLineItem._id } }, description: description }); } } return { violations }; }; const isBookshelf = (catalogItemId) => { return catalogItemId != undefined && (catalogItemId == bookshelfId); } ``` **Understanding the Code** **Line 1:** We import all modules from the ecom validations provider. **Line 3:** We declare the bookshelf product ID as a variable. **Line 5:** We declare a validation logic to run on each item in the cart and checkout. **Line 6:** We declare an empty array of validation violations. **Lines 7-8:** We define the validation to prevent the site visitor from proceeding with the Wix Checkout process, and define the validation message. **Line 9:** This line searches for a specific line item in the `options.validationInfo.lineItems` array. It uses the find method and a callback function that checks if the line item’s `catalogItemId` matches the `bookshelfId` using the `isBookshelf()` helper function. **Line 10-25:** If we find a match, we add a validation rule to prevent the site visitor from purchasing this item.