top of page

Custom Ecommerce Product Page

In this series, we invited Eitan from the Wix Wiz YouTube channel, who is a master at Velo, to code a custom ecommerce product page. Below you will find all of the videos and code used for this series:


Custom Ecommerce Product Page in Wix Studio

Before you use the code, it is important to have a better understanding of what the code is doing, so we recommend watching the 8 videos in this series to learn how to code is used.



Now that you have watched the series and have a good understanding of the product page, here you can find the code we used from our website:


 

import { getProductVariants } from "backend/store";
import { cart } from "wix-stores-frontend";
import wixData from "wix-data";
import wixLocationFrontend from "wix-location-frontend";

let product;
let selectedOptions = {};

$w.onReady(function () {
  populateProductData();
  populateMediaItems();
  populateOptions();
  populateTestimonial();
  populateProductFeatures();
  $w("#addToCartButton").onClick(async () => {
    $w("#addToCartButton").disable();
    try {
      const productInfo = {
        productId: product._id,
        quantity: Number($w("#quantityInput").value),
        options: {
          choices: selectedOptions,
        },
      };
      const updatedCart = await cart.addProducts([productInfo]);
      wixLocationFrontend.to("/cart-page");
      // cart.showMiniCart();
      // setTimeout(()=>{
      //   cart.hideMiniCart();
      // }, 2000)
      console.log("updated cart", updatedCart);
    } catch (error) {
      console.log(error);
      $w("#addToCartButton").enable();
    }
  });
});

function populateOptions() {
  const { productOptions } = product;
  const optionKeys = Object.keys(productOptions); // [Size, Scent];
  let options = optionKeys.map((option) => productOptions[option]);
  console.log("options", options);

  if (optionKeys.includes("Size")) {
    const sizeOption = productOptions["Size"];
    options = options.filter((option) => option.name !== "Size");
    $w("#optionsSelectionTags").options = sizeOption.choices.map((choice) => ({
      label: choice.description,
      value: choice.description,
    }));

    $w("#optionsSelectionTags").onChange((event) => {
      const currentSelection =
        event.target.value[event.target.value.length - 1];
      $w("#optionsSelectionTags").value = [currentSelection];
      selectedOptions["Size"] = currentSelection;
      updateProductPageWithOptions();
    });

    $w("#optionsSelectionTags").expand();
  }

  $w("#dropdownOptionsRepeater").onItemReady(($item, itemData) => {
    $item("#optionDropdown").label = itemData.name;
    $item("#optionDropdown").options = itemData.choices.map((choice) => ({
      label: choice.description,
      value: choice.description,
    }));

    $item("#optionDropdown").onChange((event) => {
      selectedOptions[itemData.name] = event.target.value;
      updateProductPageWithOptions();
    });
  });

  $w("#dropdownOptionsRepeater").data = options.map((option) => ({
    ...option,
    _id: option.name,
  }));
}

async function updateProductPageWithOptions() {
  console.log(selectedOptions);

  const color = selectedOptions["Color"];
  if (color) {
    const colorOption = product.productOptions["Color"];
    console.log("colorOption", colorOption);
    const slectedChoice = colorOption.choices.filter(
      (choice) => choice.description === color
    )[0];
    console.log("selectedChoice", slectedChoice);
    $w("#mainMedia").src = slectedChoice.mainMedia;
  }

  // get a variant based on the options;
  const variants = await getProductVariants(product._id, {
    choices: selectedOptions,
  });

  console.log("variants", variants);
  if (variants.length > 1) return;

  const { variant } = variants[0];

  $w("#originalPrice").text = variant.formattedPrice;
  $w("#discountedPrice").text = variant.formattedDiscountedPrice;
  $w("#productSKU").text = variant.sku;

  // display mainMedia if relevant
}

function populateMediaItems() {
  const { mainMedia, mediaItems } = product;
  $w("#mainMedia").src = mainMedia;

  $w("#mediaItemsRepeater").onItemReady(($item, itemData) => {
    $item("#mediaItem").src = itemData.src;

    if (itemData.src === mainMedia) {
      $item("#mediaItemWrapper").style.borderColor = "blue";
    }

    $item("#mediaItem").onClick(() => {
      $w("#mainMedia").src = itemData.src;
      $w("#mediaItemWrapper").style.borderColor = "#F5E47E";
      $item("#mediaItemWrapper").style.borderColor = "blue";
    });
  });

  $w("#mediaItemsRepeater").data = mediaItems
    .filter((item) => !item.src.includes("wix:video://"))
    .map((item, index) => ({ ...item, _id: index.toString() }));
}

function populateProductData() {
  product = $w("#productsDataset").getCurrentItem();
  console.log(product);
  $w("#productName").text = product.name;
  if (product.price === product.discountedPrice) {
    $w("#originalPrice").hide();
  }
  $w("#originalPrice").text = product.formattedPrice;
  $w("#discountedPrice").text = product.formattedDiscountedPrice;
  if (!product.ribbon) {
    $w("#ribbonWrapper").hide();
  }
  $w("#ribbon").text = product.ribbon;
  $w("#productSKU").text = product.sku;
}

async function populateTestimonial() {
  const productId = product._id;
  const additionalInfoQueryResult = await wixData
    .query("ProductAdditionalInfo")
    .hasSome("product", productId)
    .find();
  const additionalInfo = additionalInfoQueryResult.items[0];
  console.log("additionalInfo", additionalInfo);
  $w("#testimonialText").text = additionalInfo.testimonial;
  $w("#testimonialGiverText").text = additionalInfo.name;
}

async function populateProductFeatures() {
  const productId = product._id;
  const featuresQueryResult = await wixData
    .query("ProductFeatureTest")
    .hasSome("product", productId)
    .find();
  const features = featuresQueryResult.items;
  $w("#productFeaturesRepeater").onItemReady(($item, itemData) => {
    $item("#productFeatureTitle").text = itemData.title;
    $item("#productFeatureText").text = itemData.description;
    $item("#productFeatureIcon").src = itemData.icon;
  });
  $w("#productFeaturesRepeater").data = features;
}

/*
{
  {
  "seoData": "null",
  "inStock": true,
  "weight": 0.4,
  "name": "Product 3 - Body Spray",
  "sku": "003",
  "formattedDiscountedPrice": "$6.99",
  "productOptions": {
    "Size": {
      "optionType": "drop_down",
      "name": "Size",
      "choices": [
        {
          "inStock": true,
          "visible": true,
          "mainMedia": "null",
          "description": "12oz",
          "mediaItems": [],
          "value": "12oz"
        },
        {
          "inStock": true,
          "visible": true,
          "mainMedia": "null",
          "description": "6oz",
          "mediaItems": [],
          "value": "6oz"
        },
        {
          "inStock": true,
          "visible": true,
          "mainMedia": "null",
          "description": "8oz",
          "mediaItems": [],
          "value": "8oz"
        }
      ]
    },
    "Scent": {
      "optionType": "drop_down",
      "name": "Scent",
      "choices": [
        {
          "inStock": true,
          "visible": true,
          "mainMedia": "null",
          "description": "Lavender",
          "mediaItems": [],
          "value": "Lavender"
        },
        {
          "inStock": true,
          "visible": true,
          "mainMedia": "null",
          "description": "Sunrise",
          "mediaItems": [],
          "value": "Sunrise"
        },
        {
          "inStock": true,
          "visible": true,
          "mainMedia": "null",
          "description": "Vanilla",
          "mediaItems": [],
          "value": "Vanilla"
        }
      ]
    }
  },
  "mainMedia": "wix:image://v1/df045c_b739f2e9ed5c4541b97046a07b9420c2~mv2.png/file.png#originWidth=576&originHeight=576",
  "description": "Introducing our organic mist fragrance, the perfect addition to your daily beauty routine. Made with all-natural ingredients, this mist will leave you feeling refreshed and rejuvenated. Our unique blend of essential oils and botanical extracts will invigorate your senses and uplift your mood. This mist can be used as a face toner, body mist, or room spray, making it a versatile must-have. Treat yourself to a little luxury with our organic mist fragrance.",
  "_id": "dea50d8e-b999-3024-862e-b09644ef0c66",
  "discountedPrice": 6.99,
  "link-products-slug": "/products/product-3",
  "formattedPrice": "$6.99",
  "price": 6.99,
  "quantityInStock": 64,
  "collections": "null",
  "inventoryItem": "215af271-4666-cfdb-79d1-4f69bb10f399",
  "_updatedDate": "Tue Jan 09 2024 14:10:04 GMT+0900 (Japan Standard Time)",
  "formattedPricePerUnit": "null",
  "slug": "product-3",
  "productType": "physical",
  "brand": "null",
  "ribbons": [],
  "pricePerUnitData": "null",
  "mediaItems": [
    {
      "description": "",
      "id": "df045c_b739f2e9ed5c4541b97046a07b9420c2~mv2.png",
      "link": "null",
      "src": "wix:image://v1/df045c_b739f2e9ed5c4541b97046a07b9420c2~mv2.png/file.png#originWidth=576&originHeight=576",
      "title": "Product-3.png",
      "type": "Image"
    }
  ],
  "trackInventory": true,
  "customTextFields": [],
  "pricePerUnit": "null",
  "ribbon": "",
  "currency": "USD",
  "productPageUrl": "/product-page/product-3",
  "numericId": "1694026398898000",
  "manageVariants": false,
  "discount": {
    "type": "NONE",
    "value": 0
  },
  "additionalInfoSections": [],
  "createdDate": "Thu Sep 07 2023 03:53:18 GMT+0900 (Japan Standard Time)"
}
*/
 

Hope this series helped you create your own custom ecommerce page! Enjoy!

Comments


bottom of page