How to populate the cart with product data with velo?

I’m having trouble with
Finding a solution or a way for my product to populate and carry over to the cart via velo code, its a dynamic page serving as a replacement product page, i cant get the product to the cart.

Working in
Wix Editor, Dev Mode, CMS, Velo, Dynamic Page

Heres my Backend Code so afar, some done my myself and AI mostly:

// /backend/store.jsw



import { getProductVariants } from 'wix-stores-backend'; 

import { cart } from 'wix-ecom-backend'; 



// ----------------------------------------------------------------------

// 1. VARIANT RETRIEVAL FUNCTION

// ----------------------------------------------------------------------

export async function getProductVariant(productId, options) {

try {

// ... (This function remains the same, as the error is now in cart function) ...

console.log("Backend: Calling API with options:", options);

const productOptions = { choices: options };

const variants = await getProductVariants(productId, productOptions); 

console.log("Backend: RAW VARIANTS RESPONSE:", variants); 

if (!variants || variants.length !== 1) {

console.error(`Backend: Failed to find unique variant. Found ${variants ? variants.length : 0} matching variants.`);

return null;

}



const foundVariant = variants[0];

const variantData = foundVariant['variant'] || foundVariant; 



const finalVariant = {

variantId: foundVariant['_id'],

choices: options, 

formattedPrice: variantData['formattedPrice'] || null,

sku: variantData['sku'] || null, 

stock: {

inStock: variantData['inStock'] ?? true 

}

};



console.log("Backend: Returning final variant object (PACKAGED):", finalVariant);

return finalVariant;



} catch (error) {

console.error("Backend Error in getProductVariant:", error); 

// Throwing a descriptive error here is crucial for debugging

throw new Error("Failed to retrieve variant data from Wix Stores API. Check product ID and options structure.");

}

}



// ----------------------------------------------------------------------

// 2. ADD TO CART FUNCTION (Re-introducing 'appId: wix-stores')

// ----------------------------------------------------------------------



/**

 * Adds a specific product variant to the cart using the reliable cart['addProducts'] method.

 * Re-introduced the 'appId' as it is the standard, documented requirement for wix-ecom-backend.

 */

export function addVariantToCart(productId, variantId, quantity) {

// NEW LOGS: Confirm the data received from the frontend

console.log(`Backend CART: STARTING addVariantToCart.`);

console.log(`Backend CART: Received ProductId: ${productId}`);

console.log(`Backend CART: Received VariantId: ${variantId}`);

console.log(`Backend CART: Received Quantity: ${quantity}`);



// Construct the product item object

const productItem = {

catalogReference: {

// REVERTED FIX ATTEMPT: Re-added 'appId' as this is the standard, often mandatory structure.

appId: 'wix-stores', 

catalogItemId: productId,

// Options structure required to specify the variant ID

options: { 

variantId: variantId 

}

},

quantity: quantity

};

// NEW LOG: Show the final object structure before calling the API

console.log("Backend CART: Final ProductItem object being sent to API:", JSON.stringify(productItem));

// Using the working bracket notation for 'addProducts'

return cart['addProducts']([productItem])

.then(result => {

console.log("Backend CART: SUCCESS! Cart update result:", result);

return result; // Pass success result back to frontend

})

.catch(error => {

// CRITICAL: Log the raw, specific API error

console.error("Backend CART: API Call FAILED! Raw Error:", error);

// Throw a specific error message back to the frontend

const errorMessage = (typeof error === 'object' && error !== null && error.message) 

? error.message 

: (typeof error === 'string' ? error : 'Unknown API Failure');

throw new Error(`Cart API Error: ${errorMessage}. Please check product variant stock and ID integrity.`);

});

}

Heres my frontend:

import wixData from 'wix-data';
import wixWindow from 'wix-window';
import wixStores from "wix-stores"; 
import { getProductVariant, addToCartProduct } from 'backend/store'; // <-- Restored backend import

// --- CONFIGURATION ---
const LIGHTBOX_PRODUCT_IDS = ['HPBEDCOVER', 'HPCAP', 'HPSINGLE', 'HPTWIN']; 
const LIGHTBOX_NAME = 'ContactUsLightbox';
const STANDARD_COLOR_SIZE = '150ml'; // Used in filtering logic
// ---------------------

// Component IDs 
const PRICE_TEXT_ID = "#priceText";
const SKU_TEXT_ID = "#text1";
const ADD_TO_CART_BUTTON_ID = "#addToCartButton";
const SIZE_DROP_ID = "#sizeDrop";
const COLOUR_DROP_ID = "#colourDrop";
const QUANTITY_INPUT_ID = "#quantityInput";
const BREADCRUMBS_ID = "#breadcrumbs1"; 

// Global variables
let productOptionsMap = {};
let currentSelectedVariantId = null; 
let baseFormattedPrice = "";
let currentProductId = ""; 
let currentProductSku = ""; 

// Helper function to safely handle messages
function safelyHandleMessage(id, action, message = "") {
    if ($w(id).type === 'Text') {
        if (action === 'show') {
            $w(id).text = message;
            $w(id).show();
            console.log(`UI: Showing message on ${id}: ${message}`);
        } else {
            $w(id).hide();
            console.log(`UI: Hiding message on ${id}.`);
        }
    }
}

$w.onReady(function () {
    console.log("--- Page Load: Starting $w.onReady ---");
    
    // Initial UI setup (ensure dropdowns are hidden initially)
    $w(SIZE_DROP_ID).hide();
    $w(COLOUR_DROP_ID).hide();
    
    safelyHandleMessage("#textSuccess", 'hide');

    $w("#dynamicDataset").onReady(async () => {
        const currentItem = $w("#dynamicDataset").getCurrentItem();
        
        if (!currentItem) {
            console.error("Initialization Error: No product data found.");
            return;
        }

        currentProductId = currentItem._id; 
        currentProductSku = currentItem.sku; 
        
        // --- BREADCRUMBS FIX ---
        updateBreadcrumbs(currentItem.name);
        
        // --- 1. GET BASE PRICE & INITIAL SETUP ---
        baseFormattedPrice = getBasePrice(currentItem);
        $w(PRICE_TEXT_ID).text = baseFormattedPrice; 
        
        // --- 2. GET FULL PRODUCT DATA FOR VARIANTS & TABS ---
        const product = await wixData.get("Stores/Products", currentProductId);
        
        // Setup tabs with the FULL product data here
        setupInfoTabs(product); 
        
        // --- SKU CHECK & BUTTON OVERRIDE ---
        const isLightbox = isLightboxProduct(currentProductSku);
        if (isLightbox) {
            setupLightboxButton();
        } 
        
        if (!isLightbox) {
            // Variant logic only runs for non-lightbox products
            if (product && product.productOptions) {
                productOptionsMap = product.productOptions;
            }
            
            // Determine which options have more than one choice
            const hasSize = productOptionsMap.Size && productOptionsMap.Size.choices.length > 1;
            const hasColour = productOptionsMap.Colour && productOptionsMap.Colour.choices.length > 1;

            if (hasSize || hasColour) {
                console.log(`Product has variants. Has Size: ${hasSize}, Has Colour: ${hasColour}. Setting up dropdowns.`);
                
                // Populate and show only the required dropdowns
                populateDropdowns(productOptionsMap, hasSize, hasColour);
                
                // Only attach onChange handlers if the dropdown is visible
                if (hasSize) {
                    $w(SIZE_DROP_ID).show();
                    $w(SIZE_DROP_ID).onChange(() => filterDropdownOptions('Size'));
                }
                if (hasColour) {
                    $w(COLOUR_DROP_ID).show();
                    $w(COLOUR_DROP_ID).onChange(() => filterDropdownOptions('Colour'));
                }

                // If only one option type exists, or none need selection, run variant check immediately
                if (!hasSize || !hasColour) {
                    checkForValidVariant();
                }
                
            } else {
                // Set currentSelectedVariantId to currentProductId for single-variant products
                console.log("Product is single variant (no meaningful options). Setting default variant ID.");
                currentSelectedVariantId = currentProductId; 
                $w(ADD_TO_CART_BUTTON_ID).enable(); 
                if ($w(SKU_TEXT_ID)) $w(SKU_TEXT_ID).text = `SKU: ${currentItem.sku || 'N/A'}`;
            }
        }
        
        // Setup final handlers
        $w(ADD_TO_CART_BUTTON_ID).onClick(handleAddToCartClick);
    });
});

// ----------------------------------------------------------------------
// --- SKU CHECK AND BUTTON SETUP FUNCTIONS ---
// ----------------------------------------------------------------------

function isLightboxProduct(sku) {
    if (!sku) return false;
    return LIGHTBOX_PRODUCT_IDS.includes(sku.toUpperCase());
}

function setupLightboxButton() {
    console.log("Lightbox Product detected. Overriding button for Contact Us.");
    $w(SIZE_DROP_ID).hide();
    $w(COLOUR_DROP_ID).hide();
    $w(ADD_TO_CART_BUTTON_ID).label = "Contact Us For More";
    $w(ADD_TO_CART_BUTTON_ID).enable();
}


// ----------------------------------------------------------------------
// --- BREADCRUMBS LOGIC ---
// ----------------------------------------------------------------------

function updateBreadcrumbs(productName) {
    const breadcrumbs = $w(BREADCRUMBS_ID);
    
    if (productName && breadcrumbs && breadcrumbs.items && breadcrumbs.items.length > 0) {
        const items = breadcrumbs.items;
        
        const updatedItems = items.map((item, index) => {
            if (index === items.length - 1) {
                return {
                    ...item, 
                    label: productName 
                };
            }
            return item;
        });
        
        breadcrumbs.items = updatedItems;
        console.log(`Breadcrumbs: Updated last item label to "${productName}".`);
    }
}

// ----------------------------------------------------------------------
// --- CORE LOGIC FUNCTIONS: PRICE & VARIANT SELECTION ---
// ----------------------------------------------------------------------

function getBasePrice(item) {
    let price = "Base Price N/A";
    
    // 1. Try formatted prices from the data source
    if (item.formattedPrice) { 
        price = item.formattedPrice; 
    }
    else if (item.price && item.price.formatted) { 
        price = item.price.formatted; 
    }
    else if (item.pricing && item.pricing.formattedPrice) { 
        price = item.pricing.formattedPrice; 
    }
    // 2. Fallback: Use raw price and format with GBP sign
    else if (item.price) {
        price = item.price.toFixed(2); 
    } 
    
    // Ensure the Pound sign is present at the start
    if (price !== "Base Price N/A" && !price.startsWith('£') && !price.startsWith('GBP')) {
        const cleanedPrice = price.toString().replace(/[^0-9.]/g, ''); 
        return `£${cleanedPrice}`; 
    }
    
    return price;
}

// Updated to only populate visible dropdowns
function populateDropdowns(optionsMap, hasSize, hasColour) {
    if (hasSize) {
        const sizeOptions = optionsMap.Size.choices.map(c => ({ label: c.description, value: c.description }));
        $w(SIZE_DROP_ID).options = [{ label: "Select Size", value: "" }, ...sizeOptions];
        $w(SIZE_DROP_ID).value = "";
    }
    
    if (hasColour) {
        const colourOptions = optionsMap.Colour.choices.map(c => ({ label: c.description, value: c.description }));
        $w(COLOUR_DROP_ID).options = [{ label: "Select Colour", value: "" }, ...colourOptions];
        $w(COLOUR_DROP_ID).value = "";
    }
}

function filterDropdownOptions(changedOption) {
    const selectedSize = $w(SIZE_DROP_ID).value;
    const selectedColour = $w(COLOUR_DROP_ID).value;
    console.log(`Filter: Changed Option: ${changedOption}. Current Selections: Size=${selectedSize}, Colour=${selectedColour}`);

    let dropdownToFilter, optionToFilter, currentSelection;

    // Determine which dropdown to filter based on which one was changed, 
    // only if the dropdown being filtered is visible.
    if (changedOption === 'Size' && $w(COLOUR_DROP_ID).isVisible) {
        dropdownToFilter = $w(COLOUR_DROP_ID);
        optionToFilter = 'Colour';
        currentSelection = selectedSize;
    } else if (changedOption === 'Colour' && $w(SIZE_DROP_ID).isVisible) { 
        dropdownToFilter = $w(SIZE_DROP_ID);
        optionToFilter = 'Size';
        currentSelection = selectedColour;
    } else {
        // Only one dropdown visible, or the other dropdown is already hidden.
        checkForValidVariant(); 
        return;
    }
    
    const allChoices = productOptionsMap[optionToFilter].choices.map(c => c.description);
    let uniqueValidOptions = [];

    // --- Custom Filtering Logic (preserved) ---
    if (!currentSelection) {
        uniqueValidOptions = allChoices;
    } else if (optionToFilter === 'Colour') { 
        uniqueValidOptions = (currentSelection === STANDARD_COLOR_SIZE) 
            ? allChoices 
            : allChoices.filter(color => color === 'White');
    } else if (optionToFilter === 'Size') {
        uniqueValidOptions = (currentSelection !== 'White')
            ? allChoices.filter(size => size === STANDARD_COLOR_SIZE)
            : allChoices;
    } else {
         uniqueValidOptions = allChoices; 
    }
    // ----------------------------------------

    const newOptions = uniqueValidOptions.map(value => ({ label: value, value: value }));
    const currentValue = dropdownToFilter.value;
    
    dropdownToFilter.options = [{ label: `Select ${optionToFilter}`, value: "" }, ...newOptions];

    // Restore selected value if valid, or select single option
    if (currentValue && uniqueValidOptions.includes(currentValue)) {
        dropdownToFilter.value = currentValue;
    } else if (uniqueValidOptions.length === 1) {
         dropdownToFilter.value = newOptions[0].value;
    } else {
        dropdownToFilter.value = "";
    }
    
    checkForValidVariant();
}

// NOTE: This function relies on the external backend function 'getProductVariant' 
// to correctly return the 'variantId' which is CRITICAL for the price/stock logic.
async function checkForValidVariant() {
    if (isLightboxProduct(currentProductSku)) return; 
    
    const options = {};
    const requiredSelections = [];

    // Safely build the options object based on visibility
    if ($w(SIZE_DROP_ID).isVisible) {
        const selectedSize = $w(SIZE_DROP_ID).value;
        options["Size"] = selectedSize;
        requiredSelections.push(selectedSize);
    } else if (productOptionsMap.Size && productOptionsMap.Size.choices.length === 1) {
        // If Size is not visible but has exactly one choice, use that as the option
        options["Size"] = productOptionsMap.Size.choices[0].description;
    }

    if ($w(COLOUR_DROP_ID).isVisible) {
        const selectedColour = $w(COLOUR_DROP_ID).value;
        options["Colour"] = selectedColour;
        requiredSelections.push(selectedColour);
    } else if (productOptionsMap.Colour && productOptionsMap.Colour.choices.length === 1) {
        // If Colour is not visible but has exactly one choice, use that as the option
        options["Colour"] = productOptionsMap.Colour.choices[0].description;
    }

    // Check if all *visible* dropdowns have a value selected
    if (requiredSelections.some(s => !s)) {
        resetToBaseProduct("Select All Options");
        // Ensure to clear the variant ID if selections are incomplete
        currentSelectedVariantId = null; 
        return;
    }
    
    // If no variants exist, reset to base and rely on onReady
    if (Object.keys(options).length === 0) {
        if (currentSelectedVariantId === currentProductId) {
             $w(ADD_TO_CART_BUTTON_ID).enable();
        } else {
             resetToBaseProduct("Ready to Add");
        }
        return;
    }
    
    $w(ADD_TO_CART_BUTTON_ID).disable(); 
    
    try {
        // Use the backend function to find the variant ID and check stock/price
        const selectedVariant = await getProductVariant(currentProductId, options); 
        const variantExists = !!selectedVariant;
        
        if (variantExists) {
            const currentPrice = selectedVariant.formattedPrice || baseFormattedPrice; 
            $w(PRICE_TEXT_ID).text = currentPrice; 
            if ($w(SKU_TEXT_ID)) $w(SKU_TEXT_ID).text = `SKU: ${selectedVariant.sku || 'N/A'}`;
            
            const isAvailable = selectedVariant.stock && selectedVariant.stock.inStock === true;
            
            if (isAvailable) {
                $w(ADD_TO_CART_BUTTON_ID).enable();
                $w(ADD_TO_CART_BUTTON_ID).label = "Add to Cart";
                // Store the unique Variant ID here for internal check, not for the API call anymore
                currentSelectedVariantId = selectedVariant.variantId; 
            } else {
                resetToBaseProduct("Out of Stock");
                $w(PRICE_TEXT_ID).text = `${currentPrice} (Out of Stock)`;
                currentSelectedVariantId = null; // Clear ID if out of stock
            }
            
        } else {
            resetToBaseProduct("Invalid Combination");
            console.log("Variant Check Failed: Invalid combination selected."); 
            currentSelectedVariantId = null;
        }

    } catch (error) {
        console.error("Variant Check ERROR:", error);
        resetToBaseProduct("Error checking");
        console.log("Variant Check Failed: Error checking options. Try refreshing the page.");
        currentSelectedVariantId = null;
    }
}

// ----------------------------------------------------------------------
// --- 3. FINAL BUTTON HANDLER (Opens Lightbox OR Adds to Cart - WIX STORES API) ---
// ----------------------------------------------------------------------

export async function handleAddToCartClick(event) {
    console.log("Button Clicked. Attempting stable Add to Cart via BACKEND Web Module.");
    
    // --- Step 1: Handle Lightbox Products (Check SKU) ---
    if (isLightboxProduct(currentProductSku)) {
        console.log("Button Handler: Opening Lightbox for Contact Us.");
        wixWindow.openLightbox(LIGHTBOX_NAME, {
            productSku: currentProductSku, 
            productId: currentProductId 
        });
        return; 
    }
    
    // --- Step 2: Handle Add to Cart Products ---
    
    const quantity = $w(QUANTITY_INPUT_ID).value || 1; 
    const numericQuantity = Number(quantity);
    
    // Validate if a valid variant has been selected and set
    if (!currentSelectedVariantId) {
        console.log("Add to Cart Aborted: No valid variant ID selected/checked."); 
        checkForValidVariant(); 
        return;
    }

    // --- Build the options payload for the wixStores API ---
    const options = {};
    if ($w(SIZE_DROP_ID).isVisible) {
        options["Size"] = $w(SIZE_DROP_ID).value;
    } else if (productOptionsMap.Size && productOptionsMap.Size.choices.length === 1) {
        options["Size"] = productOptionsMap.Size.choices[0].description;
    }

    if ($w(COLOUR_DROP_ID).isVisible) {
        options["Colour"] = $w(COLOUR_DROP_ID).value;
    } else if (productOptionsMap.Colour && productOptionsMap.Colour.choices.length === 1) {
        options["Colour"] = productOptionsMap.Colour.choices[0].description;
    }
    
    console.log("Cart Payload Strategy: Using backend addToCartProduct.");
    console.log(`Payload: Product ID=${currentProductId}, Quantity=${numericQuantity}, Options=${JSON.stringify(options)}`);
    
    // Execute the backend API Call
    try {
        $w(ADD_TO_CART_BUTTON_ID).disable(); 
        safelyHandleMessage("#textSuccess", 'hide');
        
        // 1. Call the new stable backend function
        const responseData = await addToCartProduct(currentProductId, numericQuantity, options);
        
        // --- 1.5. CRITICAL SYNCHRONIZATION PAUSE ---
        // Wait a moment for the server to update the cart data before opening the UI component.
        await new Promise(resolve => setTimeout(resolve, 100)); 
        
        // 2. Open the side cart using bracket notation on the frontend API
        wixStores['openCart'](); 
        
        console.log("SUCCESS: Item added to cart (via backend) and side cart opened.", responseData);

        // 3. Show local success message
        safelyHandleMessage("#textSuccess", 'show', `Added to cart!`);
        setTimeout(() => safelyHandleMessage("#textSuccess", 'hide'), 3000); 
        
    } catch (error) {
        // Errors from the stable Backend API call are caught here
        console.error("Add to Cart FAILED (Backend Catch):", error);
        
        let errorMessage = "Failed to add item to cart. Please ensure selections are valid.";
        if (error && error.message) {
             errorMessage = `Failed to add item to cart. Error: ${error.message}`;
        }
        safelyHandleMessage("#textSuccess", 'show', errorMessage);
        console.log(`Add to Cart UI Error (Visible): ${errorMessage}`); 
        
    } finally {
        $w(ADD_TO_CART_BUTTON_ID).enable(); 
    }
}


// ----------------------------------------------------------------------
// --- INFO TAB FUNCTIONS ---
// ----------------------------------------------------------------------

function setupInfoTabs(productItem) {
  const infoSections = productItem?.additionalInfoSections; 
  
  if (!infoSections || infoSections.length < 3) {
      console.warn("Info Tabs Setup: Not enough sections found in product data (requires at least 3).");
      return;
  }

  console.log(`Info Tabs Setup: Found ${infoSections.length} sections. Populating tabs.`);
  
  $w("#tabTitle1").text = infoSections[0].title;
  $w("#tabDescription1").html = infoSections[0].description;
  $w("#tabTitle2").text = infoSections[1].title;
  $w("#tabDescription2").html = infoSections[1].description;
  $w("#tabTitle3").text = infoSections[2].title;
  $w("#tabDescription3").html = infoSections[2].description;

  $w("#group45").show(); 
}

function resetToBaseProduct(label = "Select Options") {
    currentSelectedVariantId = null;
    $w(ADD_TO_CART_BUTTON_ID).disable();
    $w(ADD_TO_CART_BUTTON_ID).label = label;
    $w(PRICE_TEXT_ID).text = baseFormattedPrice;
    if ($w(SKU_TEXT_ID)) $w(SKU_TEXT_ID).text = `SKU: N/A`;
}

// ----------------------------------------------------------------------
// --- TAB CLICK HANDLERS ---
// ----------------------------------------------------------------------

export function descTab_click(event) {
  console.log("Tab Click: Description");
  $w("#group45").show(); 
  $w("#group44").hide(); 
  $w("#group46").hide(); 
}

export function specsTab_click(event) {
  console.log("Tab Click: Specifications");
  $w("#group45").hide();
  $w("#group44").show(); 
  $w("#group46").hide();
}

export function instrTab_click(event) {
  console.log("Tab Click: Instructions");
  $w("#group45").hide();
  $w("#group44").hide();
  $w("#group46").show(); 
}

Much help appreciated.

Welcome @iambenjaminwild,

Based on the message, it sounds like you’ve already created a dynamic page using your store products. If not, this is a good place to start. CMS: Displaying Your Wix Stores Products on a Dynamic List Page | Help Center | Wix.com

If you’re populating the dynamic page, you can then use the CMS connection on buttons to allow users to Add to Cart using the native functionality.

What console logs are you seeing? Those should help you see at which point the code stops and which steps are not executing.

Hi,

I’m Aware of the Add to cart button and the link in CMS, but with products that have options the button opens quick view which I don’t want as options can be selected on the page.

Here’s my console log:

Button Clicked. Attempting stable Add to Cart via BACKEND Web Module.
createConsoleProxy.ts:70 Cart Payload Strategy: Using backend addToCartProduct.
createConsoleProxy.ts:70 Payload: Product ID=2c95dbc8-c3eb-6743-78ea-291eb12dc1e5, Quantity=1, Options={"Size":"150ml","Colour":"Magenta"}
createConsoleProxy.ts:70 Add to Cart FAILED (Backend Catch): TypeError: (0 , u.addToCartProduct) is not a function
    at eval (ot0e7.js:410:36)
    at s (external commonjs "wix-stores":1:36)
    at Generator.eval [as _invoke] (external commonjs "wix-stores":1:36)
    at Generator.eval [as next] (external commonjs "wix-stores":1:36)
    at g (external commonjs "wix-stores":1:36)
    at a (external commonjs "wix-stores":1:36)
    at eval (external commonjs "wix-stores":1:36)
    at new Promise (<anonymous>)
    at eval (external commonjs "wix-stores":1:36)
    at G (ot0e7.js:362:1)
    at eval (corvidEvents.js:73:9)
    at registerEvent.ts:51:5
    at Function.<anonymous> (clientWorker.ts:160:7)
    at MessagePort.r (comlink.ts:312:36)
    at MessagePort.n (helpers.js:72:23)
(anonymous) @ instrument.js:109
(anonymous) @ createConsoleProxy.ts:70
eval @ active$wBiEvent.js:56
eval @ ot0e7.js:427
s @ external commonjs "wix-stores":1
eval @ external commonjs "wix-stores":1
eval @ external commonjs "wix-stores":1
g @ external commonjs "wix-stores":1
a @ external commonjs "wix-stores":1
eval @ external commonjs "wix-stores":1
eval @ external commonjs "wix-stores":1
G @ ot0e7.js:362
eval @ corvidEvents.js:73
(anonymous) @ registerEvent.ts:51
(anonymous) @ clientWorker.ts:160
r @ comlink.ts:312
n @ helpers.js:72
createConsoleProxy.ts:70 Add to Cart UI Error (Visible): Failed to add item to cart. Error: (0 , u.addToCartProduct) is not a function

I’ve Updated the backend code:

import { getProductVariants } from 'wix-stores-backend';
import { cart } from 'wix-ecom-backend';

// ----------------------------------------------------------------------
// 1. VARIANT RETRIEVAL FUNCTION (No changes needed here)
// ----------------------------------------------------------------------
export async function getProductVariant(productId, options) {
    try {
        console.log("Backend: Calling API with options:", options);
        const productOptions = { choices: options };
        const variants = await getProductVariants(productId, productOptions); 

        if (!variants || variants.length !== 1) {
            console.error(`Backend: Failed to find unique variant. Found ${variants ? variants.length : 0} matching variants.`);
            return null;
        }

        const foundVariant = variants[0];
        const variantData = foundVariant['variant'] || foundVariant; 

        const finalVariant = {
            variantId: foundVariant['_id'],
            choices: options, 
            formattedPrice: variantData['formattedPrice'] || null,
            sku: variantData['sku'] || null, 
            stock: {
                inStock: variantData['inStock'] ?? true 
            }
        };

        console.log("Backend: Returning final variant object (PACKAGED):", finalVariant);
        return finalVariant;

    } catch (error) {
        console.error("Backend Error in getProductVariant:", error); 
        throw new Error("Failed to retrieve variant data from Wix Stores API. Check product ID and options structure.");
    }
}

// ----------------------------------------------------------------------
// 2. ADD TO CART FUNCTION 
// FIX: Renamed, updated signature, and made async to match frontend call.
// ----------------------------------------------------------------------
/**
 * Adds a product to the cart by first resolving the variant ID from the selected options,
 * then calling the stable wix-ecom-backend cart.
 */
export async function addToCartProduct(productId, quantity, options) {
    console.log(`Backend CART: STARTING addToCartProduct.`);
    console.log(`Backend CART: Received ProductId: ${productId}, Quantity: ${quantity}, Options: ${JSON.stringify(options)}`);

    // CRITICAL STEP: Reuse the existing logic to find the specific variant ID based on options.
    const selectedVariant = await getProductVariant(productId, options);

    if (!selectedVariant || !selectedVariant.variantId) {
        throw new Error("Cannot add to cart: Selected options do not resolve to a valid product variant. Check stock and option values.");
    }
    
    const variantId = selectedVariant.variantId;
    
    // Construct the product item object
    const productItem = {
        catalogReference: {
            appId: 'wix-stores', 
            catalogItemId: productId,
            // Options structure required to specify the variant ID for the API
            options: { 
                variantId: variantId 
            }
        },
        quantity: quantity
    };

    console.log("Backend CART: Final ProductItem object being sent to API:", JSON.stringify(productItem));

    // Using the working bracket notation for 'addProducts'
    return cart['addProducts']([productItem])
        .then(result => {
            console.log("Backend CART: SUCCESS! Cart update result:", result);
            return result; // Pass success result back to frontend
        })
        .catch(error => {
            console.error("Backend CART: API Call FAILED! Raw Error:", error);
            const errorMessage = (typeof error === 'object' && error !== null && error.message) 
                ? error.message 
                : (typeof error === 'string' ? error : 'Unknown API Failure');
            throw new Error(`Cart API Error: ${errorMessage}. Please check product variant stock and ID integrity.`);
        });
}

The console log i have outputs the following:

Button Clicked. Attempting stable Add to Cart via BACKEND Web Module.
createConsoleProxy.ts:70 Cart Payload Strategy: Using backend addToCartProduct.
createConsoleProxy.ts:70 Payload: Product ID=2c95dbc8-c3eb-6743-78ea-291eb12dc1e5, Quantity=1, Options={"Size":"150ml","Colour":"Cyan"}
timeoutsManager.ts:15 TypeError: Failed to fetch
    at Object.flushHandler (reporter.js:13:7)
    at xe.flush (batch-queue.js:14:18)
    at flushThrottled.Ce.leading (batch-queue.js:8:47)
    at y (debounce.js:95:19)
    at w (debounce.js:144:14)
    at _ (debounce.js:132:14)
    at n (helpers.js:72:23)
(anonymous) @ instrument.js:109
(anonymous) @ reporter.js:14
Promise.catch
(anonymous) @ reporter.js:13
flush @ batch-queue.js:14
flushThrottled.Ce.leading @ batch-queue.js:8
y @ debounce.js:95
w @ debounce.js:144
_ @ debounce.js:132
n @ helpers.js:72
setTimeout
self.setTimeout @ timeoutsManager.ts:15
(anonymous) @ trycatch.js:86
(anonymous) @ debounce.js:103
S @ debounce.js:172
enqueue @ batch-queue.js:22
(anonymous) @ batch-plugin.js:26
invoke @ hooks-manager.js:39
report @ panorama-client-base.js:47
reportTransactionStart @ panorama-client-base.js:77
start @ panorama-transaction.js:16
j @ fedopsLogger.ts:162
S.interactionStarted @ fedopsLogger.ts:227
S @ platformLogger.ts:179
eval @ active$wBiEvent.js:56
getJSON @ elementorySupport.ts:96
eval @ active$wBiEvent.js:56
r.D @ store.jsw:2
(anonymous) @ ot0e7.js:410
s @ external commonjs "wix-stores":1
(anonymous) @ external commonjs "wix-stores":1
(anonymous) @ external commonjs "wix-stores":1
g @ external commonjs "wix-stores":1
a @ external commonjs "wix-stores":1
(anonymous) @ external commonjs "wix-stores":1
(anonymous) @ external commonjs "wix-stores":1
H @ ot0e7.js:362
G @ ot0e7.js:362
eval @ corvidEvents.js:73
(anonymous) @ registerEvent.ts:51
(anonymous) @ clientWorker.ts:160
r @ comlink.ts:312
n @ helpers.js:72
createConsoleProxy.ts:70 Add to Cart FAILED (Backend Catch): TypeError: Error: Unable to handle the request. Contact the site administrator or view site monitoring logs for more information.
(anonymous) @ instrument.js:109
(anonymous) @ createConsoleProxy.ts:70
eval @ active$wBiEvent.js:56
(anonymous) @ ot0e7.js:427
s @ external commonjs "wix-stores":1
(anonymous) @ external commonjs "wix-stores":1
(anonymous) @ external commonjs "wix-stores":1
g @ external commonjs "wix-stores":1
c @ external commonjs "wix-stores":1
Promise.then
g @ external commonjs "wix-stores":1
a @ external commonjs "wix-stores":1
(anonymous) @ external commonjs "wix-stores":1
(anonymous) @ external commonjs "wix-stores":1
H @ ot0e7.js:362
G @ ot0e7.js:362
eval @ corvidEvents.js:73
(anonymous) @ registerEvent.ts:51
(anonymous) @ clientWorker.ts:160
r @ comlink.ts:312
n @ helpers.js:72
createConsoleProxy.ts:70 Add to Cart UI Error (Visible): Failed to add item to cart. Error: Error: Unable to handle the request. Contact the site administrator or view site monitoring logs for more information.

Alternatively, Is there a way in Wix Editor to have the button not show Quick View when clicking for a Variant Product?