Velo Tutorial: Adding a Related Products Area to a Wix Store Product Page

Overview
- Products that we manually define as relating to the current product. We create that relationship in a relatedProducts collection.
- Products whose price is 20% greater or 20% less than the current product.
- Get the ID of the currently displayed product.
- Query the relatedProducts collection and return the products that we defined manually as relating to the currently displayed product.
- Query the Products collection for items whose price falls within a specific range, relative to the current item's price.
- Add the results of both queries into an array.
- First try to display the products that we defined manually as relating to the currently displayed product. If there are none, then display the items whose price falls within a specific range. Display a maximum of four related items.
- If neither query returns results, hide the repeater.
Step 1: Site Setup

Database Setup


The relatedProducts collection has two fields: Product A and Product B, which are both reference fields. For each item, Product A values reference an item in the Products collection. Product B values then reference the product related to the item in Product A. Note that a product may appear in both the Product A or Product B fields. Note also that the field keys for the two fields are productA
and productB
.

Step 2: Setting up the Related Products Area

Step 3: Create the loadRelatedProducts Function
loadRelatedProducts
is called from onReady. It gets the current product from the product page and passes that to the functions that find the related products. It then calls the functions to display the results.
1import wixData from 'wix-data';
2import wixLocation from 'wix-location';
3
4$w.onReady(function () {
5 loadRelatedProducts();
6});
7
8async function loadRelatedProducts() {
9 let product = await $w('#productPage').getProduct();
10 let relatedProductResults = await Promise.all([
11 relatedProductsByTable(product),
12 relatedProductsByPrice(product)
13 ]);
14
15 if (relatedProductResults[0].length > 0)
16 showRelatedProducts(relatedProductResults[0]);
17 else
18 showRelatedProducts(relatedProductResults[1]);
19};
Understanding the Code
Line 1-2: Import the modules we need to work with Wix Data and Wix Location libraries.
Lines 4-5: Call loadRelatedProducts
inside the page's onReady function. loadRelatedProducts
calls the functions that run the related product queries. It then calls the function to display the query results.
Note that we don't return the loadRelatedProducts
result promise from $w.onReady
. If we return a promise from $w.onReady
, it will delay the page load until the promise is resolved. By not returning the promise, we allow the page to load as fast as possible while the related products load in the background.
Line 9: Get the current product from the Product page.
Lines 10-12: Create the relatedProductResults
array from the results of the relatedProductsByTable
and relatedProductsByPrice
functions. Each of these functions accepts the current product as a parameter and returns an array of related products.
Lines 15-18: If the relatedProductResults
isn't empty, then first try to display the results of relatedProductsByTable
. If there are none, display the results of relatedProductsByPrice
.
Identifiers you may need to change based on your site's elements
productPage
Step 4: Create the relatedProductsByTable Function
relatedproductsByTable
finds all the products that relate to the current product, based on the relationships defined in the relatedProducts collection.
1async function relatedProductsByTable(product) {
2 let productId = product._id;
3
4 // find related products by relation table
5 let relatedByTable = await Promise.all([
6 wixData.query('relatedProducts')
7 .eq('productA', productId)
8 .include('productB')
9 .find(),
10 wixData.query('relatedProducts')
11 .eq('productB', productId)
12 .include('productA')
13 .find()
14 ]);
15
16 let relatedProducts = [
17 ...relatedByTable[0].items.map(_ => _.productB),
18 ...relatedByTable[1].items.map(_ => _.productA)
19 ];
20 return relatedProducts;
21};
Understanding the Code
Lines 5-14: Run two parallel queries on the relatedProducts
collection. Each query returns the value in the productA or productB fields that relate to the currently displayed product. Use .include
to include all the data from the referenced field for the related product.
Lines 16-19: Use the spread operator and map function to build an array of related products from both fields. The spread operator flattens the results of both queries into one array. The map function extracts only the related product from the item object of the query results while removing the current product.
Note that the _ is a variable that represents the current element being processed in the array.
Items you may need to change based on your site's collections
relatedProducts
productA
productB
Step 5: Create the relatedProductsByPrice Function
relatedproductsByPrice
finds all the products that relate to the current product, based on a price range.
1async function relatedProductsByPrice(product) {
2 let productId = product._id;
3
4 // find related products by price
5 let relatedByPrice = await wixData.query('Stores/Products')
6 .between('price', product.price * 0.8, product.price * 1.2)
7 .ne('_id', productId)
8 .find();
9 return relatedByPrice.items;
10};
Understanding the Code
Lines 5-8: Run a query on the Products collection for any products whose price is within 20% of the price of the currently displayed product. Use .ne
to exclude the current product from the results.
Line 9: Return the .items
object of the query results.
Step 6: Create the showRelatedProducts Function
showrelatedProducts
accepts the results of relatedProductsByTable
or relatedProductsByPrice
and truncates the results so only a maximum of four items are displayed. It then sets the onItemReady
function for the repeater, defines the repeater data, and decide whether to hide or display the repeater.
1function showRelatedProducts(relatedProducts) {
2 if (relatedProducts.length > 0) {
3 relatedProducts.splice(4, relatedProducts.length);
4 $w('#relatedItemsRepeater').onItemReady(relatedItemReady);
5 $w("#relatedItemsRepeater").data = relatedProducts;
6 $w("#relatedItems").expand();
7 } else {
8 $w("#relatedItems").collapse();
9 }
10};
Understanding the Code
Line 2: Check if relatedProducts
contains data. If it does, run lines 3-6.
Line 3: Remove all but the first four results from relatedProducts
.
Line 4: Set the onItemReady
function for the repeater to relatedItemReady
. We'll define that function in the next step.
Line 5: Set the data
property for the repeater.
Line 6: Expand the repeater.
Line 7-8: If the relatedProducts
does not contains data, collapse it.
Identifiers you may need to change based on your site's elements
relatedItemsRepeater
relatedItems
Step 7: Create the relatedItemReady Function
relatedItemReady
is the onItemReady function for the repeater. It's the function that runs when a new repeated item is created.
1function relatedItemReady($w, product) {
2 $w("#productImage").src = product.mainMedia;
3 $w("#productName").text = product.name;
4 $w("#productPrice").text = product.formattedPrice;
5 $w('#productImage').onClick(() => {
6 wixLocation.to(product.productPageUrl);
7 });
8};
Understanding the Code
Lines 2-4: Bind each element in the repeater to the corresponding data for the product.
Lines 5-6: Set the onClick
property of the productImage
element to open the product page for the specific product.
Identifiers you may need to change based on your site's elements
productImage
productName
productPrice
productImage
Next Steps
- Open this example in the Editor to work with the template.
- Publish the site and refresh your browser so the Stores collections appear in the Database.
- Try other Velo Store examples: