Velo Tutorial: Adding Ratings and Reviews to a Wix Stores Site

Visit the Velo by Wix website to onboard and continue learning.

Note: This tutorial and its steps are based on a Wix Editor site. You can adapt the steps for a Wix Studio site by using the equivalent Wix Studio features.

This article describes how you can use Velo to add ratings and reviews to a Wix Stores site. Throughout this article we're going to use this site to illustrate the process. We're going to explain how we set up the sample site and the code we added to make it work.

Overview

In our site we added the following:

  • A Review Box lightbox with user input elements for review submissions.
  • A repeater on the Product page to display the individual reviews.
  • A group of elements on the Product page that display the average rating results and the percentage of members who recommend the product.
  • A reviews collection to store review information.
  • A review-stats collection to store rating statistics for each product. 

Then we added code to do the following:

  • When the Product page loads, display the current statistics under the product description and display the reviews in the repeater.
  • When the reviewer clicks the "Write a Review" button, open the Review Box lightbox.
  • When a reviewer posts a review in the Review Box lightbox, save the new review data to the reviews collection, update the statistics in the review-stats collection, close the lightbox, and refresh the reviews and statistics in the Product page.

Step 1: Set up the Site

To recreate this functionality, you'll need to have Wix Stores added to your site with some products. Once you add Stores to your site, you'll see pages and collections automatically added to your site.

Note You may need to save or publish the site and refresh your browser to view the Stores collections in the Database.

This is what some of the data in our site looks like:

The Products and Collections collections are created automatically when you have a site with Wix Stores. Because these collections are read-only, you must use the Store Manager to create your product list. In this example we don't work with the Collections collection, although it is in our sample site's store.

We also added a Review Box lightbox to the site, and review-stats and reviews collections to our database. We'll describe the Review Box lightbox's setup later in this article.

The review-stats collection has the following fields:

  • rating: The sum of all ratings the product received
  • count: The number of times the product was rated
  • recommended: The number of times the product was recommended
  • ID: The ID of the product (hidden by default)

We use the statistics stored in the review-stats collection to calculate the number of reviews, the average rating, and the recommended percentage for each product.

The reviews collection has fields to store the review information entered via the Review Box lightbox, plus a field that references the item in the Products collection.

We use the data stored in the reviews collection to display each review on the Product page, and to calculate the statistics for each product stored in the review-stats collection.

Step 2: Set up the Shop Product Page

On the Shop Product Page we added:

  • A group of elements that display the average rating results:
    • A Ratings Display showing the number of ratings and the average rating for this product
    • Text displaying the percentage of reviewers who recommended the product
    • A thank you message, which is displayed after a review is added
  • A Write a Review button, which opens the review form in the Review Box lightbox.

We also added:

  • A Reviews dataset for displaying review details stored in the reviews collection.
  • A repeater to display the reviews. Each review contains:
    • Text elements for the reviewer's name, location, review title, and review text
    • An optional review image
    • A ratings display to show the individual reviewer's rating
    • Text stating whether the reviewer recommends the product
    • Text containing the review submission date and time
  • "load more" text at the bottom of the page for loading additional reviews.

Note that there are two types of ratings displayed on the Product page:

  • An average rating of the product and overall percentage of reviewers who recommended the product. This is displayed beneath the product description.
  • Each individual reviewer's rating and recommendation (or not) of the product, displayed in each review.

Step 3: Set Up the Review Box Lightbox

In the Review Box lightbox we added:

  • A SubmitReviews dataset to connect the data entered by the reviewer to the reviews collection.
  • A container box to hold all the input elements.
  • Two sets of radio buttons for rating and recommending the product.
  • Input elements to collect the reviewer's identification information and their review of the product.
  • A "Choose File" upload button for uploading an optional review image.
  • A "Post Review" button for submitting the review. Data is sent to the reviews and review-stats collections.

Step 4: Prepare the Product Page

On the Product Page we start by importing the modules we need to work with data collections and lightboxes in our code. Then we define a global variable to represent the current product. Finally, we run the initReviews function to load the current product's ratings and reviews on the page.

Note: Throughout this example we use the async/await JavaScript functionality.

Copy
1
import wixData from 'wix-data';
2
import wixWindowFrontend from 'wix-window-frontend';
3
import wixLocationFrontend from 'wix-location-frontend';
4
5
let product;
6
7
$w.onReady(async function () {
8
product = await $w('#productPage1').getProduct();
9
initReviews();
10
11
wixLocationFrontend.onChange(async (location) => {
12
product = await $w('#productPage1').getProduct();
13
initReviews();
14
})
15
})

Understanding the Code

Lines 1-3: Import the modules we need to work with Wix Data, Wix Window Frontend, and Wix Location Frontend libraries.
Line 5: Define the global product variable.
Line 7: When the page loads, do the following:
Line 8: Using the getProduct function on the current product page, set the product variable to the currently displayed product.
Line 9: Run the initReviews function to load the current product's ratings and reviews.
Line 11: Some functionalities change the product without refreshing the page (for example, next/previous buttons and related products gallery). This change triggers Wix Location Frontend's onChange() API, then:
Line 12: Update the product variable for the newly displayed product.
Line 13: Run the initReviews function to load the current product's ratings and reviews.

Identifiers you may need to change based on your site's elements

If you want to use this exact scenario and code in your site, you may need to modify these items to match the ones on your site:

  • #productPage1

Step 5: Create the initReviews Function on the Product Page

The initReviews function filters the Reviews dataset to contain only reviews of the currently displayed product, and then displays the product's reviews and statistics.

Note There are two ways to filter a dataset: using code (as in this example) or via the Dataset Settings panel of the dataset.

Copy
1
async function initReviews() {
2
await $w('#Reviews').setFilter(wixData.filter().eq('productId', product._id));
3
showReviews();
4
loadStatistics();
5
}

Understanding the Code

Line 2: Chain an eq function to setFilter to filter out all items in the Reviews dataset where the product ID doesn't match the ID of the currently displayed product.
Line 3: Run the showReviews function to display all filtered reviews.
Line 4: Run the loadStatistics function to load and display statistics for the current product.

Identifiers you may need to change based on your site's collections

If you want to use this exact scenario and code in your site, you may need to modify these items to match the ones on your site:

  • #Reviews
  • productId

Step 6: Create the loadStatistics Function on the Product Page

The loadStatistics function gets and displays statistics for the current product.

Copy
1
async function loadStatistics() {
2
const stats = await wixData.get('review-stats', product._id);
3
if (stats) {
4
let avgRating = (Math.round(stats.rating * 10 / stats.count) / 10);
5
let percentRecommended = Math.round(stats.recommended / stats.count * 100);
6
let ratings = $w('#generalRatings');
7
ratings.rating = avgRating;
8
ratings.numRatings = stats.count;
9
$w('#recoPercent').text = `${percentRecommended} % would recommend`;
10
$w('#generalRatings').show();
11
} else {
12
$w('#recoPercent').text = 'There are no reviews yet';
13
}
14
$w('#recoPercent').show();
15
}

Understanding the Code

Line 2: Use the current product's ID to get the product's statistics from the review-stats collection and assign them to the stats variable.
Line 3: Check whether there are any statistics related to the current product, indicating that one or more users have rated the product. If there are stats, do the following:
Line 4: Calculate the average rating of the product by dividing the sum of all ratings the product received from all reviewers by the number of times the product was rated, multiplying by ten, and rounding the number.
Line 5: Calculate the percentage of people who recommended the product by dividing the total number of recommendations the product received by the number of times the product was rated, multiplying by 100, and rounding the number.
Line 6: Get the generalRatings ratings element and assign it to the ratings variable.
Line 7: Set the ratings element's rating value to the average rating calculated above.
Line 8: Set the ratings element's total number of ratings from the count field in the review-stats collection for the current product.
Line 9: Set the text that displays the recommended percent.
Line 10: Show the ratings element.
Lines 11-14: If there are no stats (indicating that no reviewers have rated the product yet), display text stating that there are no reviews yet.

Identifiers you may need to change based on your site's collections

If you want to use this exact scenario and code in your site, you may need to modify these items to match the ones on your site:

  • review-stats
  • #generalRatings
  • #recoPercent

Step 7: Create the reviewsRepeater_itemReady Function on the Product Page

We selected the reviewsRepeater element and, in the Properties & Events panel, added an onItemReady event handler.

In Step 5 the initReviews function filters the Reviews dataset to contain only reviews of the currently displayed product. Each filtered item (row) in the collection is passed to the reviewsRepeater_itemReady event handler as the itemData parameter.

After the page loads and the filtered dataset connects to the repeater, reviewsRepeater_itemReady loads data from the collection into each element in the repeater.

Copy
1
export function reviewsRepeater_itemReady($w, itemData, index) {
2
if (itemData.recommends) {
3
$w('#recommendation').text = 'I recommend this product.';
4
} else {
5
$w('#recommendation').text = "I don't recommend this product.";
6
}
7
if (itemData.photo) {
8
$w('#reviewImage').src = itemData.photo;
9
$w('#reviewImage').expand();
10
}
11
$w('#oneRating').rating = itemData.rating;
12
let date = itemData._createdDate;
13
$w('#submissionTime').text = date.toLocaleString();
14
}

Understanding the Code

Line 2: Check if the reviewer recommended the product using the boolean recommends field in the reviews collection of the current item.
Lines 3-4: Display text that states whether the reviewer recommended or didn't recommend the product.
Lines 7-9: If the reviewer uploaded a photo, set the image URL from the item photo and expand the image.
Line 11: Set the rating value for the review in the oneRating ratings display as the rating of the current item.
Line 12: Get the date the review was submitted and assign it to the date variable.
Line 13: Use the toLocalString function to format the date text according to date format settings on the visitor's computer.

Identifiers you may need to change based on your site's collections

If you want to use this exact scenario and code in your site, you may need to modify these items to match the ones on your site:

  • #recommendation
  • #reviewImage
  • #oneRating
  • #submissionTime

Step 8: Create the showReviews Function on the Product Page

showReviews expands or collapses the review strip that displays the reviews depending on whether any reviews were submitted.

Copy
1
export function showReviews() {
2
if ($w('#Reviews').getTotalCount() > 0) {
3
$w('#reviewsStrip').expand();
4
} else {
5
$w('#reviewsStrip').collapse();
6
}
7
}

Understanding the Code

Line 2: Use the getTotalCount function to check whether there are any reviews in the Reviews dataset for the current product.
Lines 3-5: If there are reviews, expand the review strip. If there are no reviews, collapse the review strip.

Identifiers you may need to change based on your site's elements

If you want to use this exact scenario and code in your site, you may need to modify these items to match the ones on your site:

  • #Reviews
  • #reviewsStrip

Step 9: Create the addReview_click Function on the Product Page

addReview_click runs when the reviewer clicks the "Write a Review" button. We selected the "Write a Review" button and, in the Properties & Events panel, added an onClick event handler.
The function opens the Review Box lightbox, sends it the current product's ID, and waits for the lightbox to close.
After the lightbox has closed, the function refreshes the Reviews dataset so the new reviews appear on the page, reloads the product statistics to reflect the new rating, and displays a thank you message.

Copy
1
export async function addReview_click(event, $w) {
2
const dataForLightbox = {
3
productId: product._id
4
};
5
let result = await wixWindowFrontend.openLightbox('Review Box', dataForLightbox);
6
$w('#Reviews').refresh();
7
setTimeout(() => {
8
loadStatistics();
9
}, 2000);
10
$w('#thankYouMessage').show();
11
}

Understanding the Code

Lines 2-3: Create a dataForLightbox object contaning the current product's ID to be sent to the Review Box lightbox.
Line 5: Open the Review Box lightbox, send it the product ID object created above, and wait for it to close.
Line 6: After the review lightbox is closed, refresh the Reviews dataset so the new review appears on the page.
Line 7-9: Reload the current products statistics to reflect the new rating.
Line 10: Show a thank you message.

Identifiers you may need to change based on your site's elements

If you want to use this exact scenario and code in your site, you may need to modify these items to match the ones on your site:

  • #Reviews
  • #thankYouMessage

Step 10: Create the resultsPages_click Function on the Product Page

resultsPages_click runs when the reviewer clicks the "load more" text at the bottom of the Product page. We selected the "load more" text and, in the Properties & Events panel, added an onClick event handler.

When the visitor clicks the text, the resultsPages_click event handler loads another page (chunk) of reviews into the reviewsRepeater.

Note The number of reviews displayed in each page (chunk) of the repeater is defined in the Reviews dataset. Click the dataset, click Manage Dataset, and enter the Number of items to display.

Copy
1
export function resultsPages_click(event, $w) {
2
$w('#Reviews').loadMore();
3
}

Understanding the Code

Lines 1-2: When the event handler is triggered, the Reviews dataset loads the next page (chunk) of reviews using the loadMore function.

Identifiers you may need to change based on your site's elements

If you want to use this exact scenario and code in your site, you may need to modify these items to match the ones on your site:

  • #Reviews

Step 11: Prepare the Review Box Lightbox

In the Review Box lightbox, we started by importing the modules we need to work with data collections and lightboxes in our code. Then we declare a variable to store the current product ID. 

When the lightbox finishes loading, we get the current product ID passed to the lightbox in Step 9 via the openLightbox function.

After reviewers complete their review and click the "Post Review" button, the new review data is sent to the SubmitReview dataset. Before the new review is saved to the reviews collection, we use the onBeforeSave event handler to check whether the reviewer rated the product. If the user did not rate the product, an error message is displayed and the review is not saved.

After the new review is saved to the reviews collection, we use the onAfterSave event handler to update the statistics for the current product, and to close the lightbox.

First, add the following to the lightbox page's code:

Copy
1
import wixWindowFrontend from 'wix-window-frontend';
2
import wixData from 'wix-data';
3
4
let productId;

Understanding the Code

Lines 1-2: Import the modules we need to work with Wix Data and Wix Window Frontend libraries.
Line 4: Declare a global variable to store the product ID.

Then, add the following code to the onReady function:

Copy
1
$w.onReady(function () {
2
3
productId = wixWindowFrontend.lightbox.getContext().productId;
4
5
$w('#SubmitReviews').onBeforeSave(() => {
6
if ($w('#radioRating').value === '') {
7
$w('#rateError').show();
8
return Promise.reject();
9
}
10
11
$w('#SubmitReviews').setFieldValues({
12
productId,
13
rating: $w('#radioRating').value,
14
recommends: $w('#radioGroup1').value
15
});
16
});
17
});

Understanding the Code

Line 3: When the page loads, use the getContext function to get the object passed to the lightbox when it was opened. In this case, the object containins the current product ID.
Line 5: Set the action that occurs before the new review is saved to the reviews collection via the SubmitReviews dataset.
Line 6: Check if the reviewer rated the product.
Lines 7-8: If the reviewer did not rate the product, show the rateError error message and do not save the the new review.
Line 11: If the reviewer did rate the product, use the setFieldValues function to update the SubmitReviews dataset.
Lines 12-14: Update the dataset item with the input element values. The item will then be saved to the reviews collection.

And finally, add the following code to the onReady function:

Copy
1
$w('#SubmitReviews').onAfterSave(async () => {
2
await updateStatistics($w('#radioGroup1').value);
3
wixWindowFrontend.lightbox.close();
4
});

Understanding the Code

Line 1: Set the action that occurs after the new review is saved to the reviews collection via the SubmitReviews dataset.
Line 2: Update the product's statistics using the updateStatistics function. The reviewer's recommendation (or not), as stored in the radioGroup1 radio buttons, is sent as a parameter to the function.
Line 3: After the statistics are updated, close the lightbox to return the reviewer to the Product page.

Identifiers you may need to change based on your site's elements

If you want to use this exact scenario and code in your site, you may need to modify these items to match the ones on your site:

  • productID
  • #SubmitReviews
  • #radioRating
  • #rateError
  • #radioGroup1

Step 12: Create the updateStatistics Function in the Review Box Lightbox

This function updates the statistics stored in the review-stats collection to include data from the current review. If no previous statistics exist for the current product, it creates a new statistics item.

Copy
1
async function updateStatistics(isRecommended) {
2
let stats = await wixData.get('review-stats', productId);
3
4
if (stats) {
5
stats.rating += parseInt($w('#radioRating').value, 10);
6
stats.count += 1;
7
stats.recommended += (isRecommended === "true") ? 1 : 0;
8
return wixData.update('review-stats', stats)
9
}
10
11
stats = {
12
_id: productId,
13
rating: parseInt($w('#radioRating').value, 10),
14
count: 1,
15
recommended: (isRecommended === "true") ? 1 : 0
16
}
17
return wixData.insert('review-stats', stats)
18
}

Understanding the Code

Line 2: Get the review statistics for the current product from the review-stats collection.
Line 4: If statistics data already exist for this product, do the following:
Line 5: Extract the string representing the value of the radio button rating selected by the user. Use the parseInt function to convert the string to an integer. Add the integer to the total rating points.
Line 6: Increase the ratings count by one.
Line 7: Check if the reviewer recommended the product. If the isRecommended input parameter from the reviews collection is true, increase the recommendation count by one.
Line 8: Update the product's statistics in the review-stats collection.
Line 11: If no previous statistics data exist for this product, create a new statistics item:
LIne 12: Set the statistics item's ID to the current product's ID.
Line 13: Extract the string representing the value of the radio button rating selected by the user. Use the parseInt function to convert the string to an integer. Set the statistics item's rating to the integer.
Line 14: Set the statistics item's ratings count to 1 because this is the first rating.
Line 15: Check if the reviewer recommended the product. If they did, set the recommendation count to 1.
Line 17: Insert the new product's statistics into the review-stats collection.

Identifiers you may need to change based on your site's elements

If you want to use this exact scenario and code in your site, you may need to modify these items to match the ones on your site:

  • review-stats
  • #radioRating

Step 13: Create the radioRating_change Function in the Review Box Lightbox

radioRating_change runs when the reviewer chooses a rating. We selected the radioRating radio buttons element under "Overall Rating" and, in the Properties & Events panel, added an onChange event handler.

When the visitor chooses a rate, the radioRating_change event handler hides the error message displayed when a visitor fails to rate the product.

Copy
1
export function radioRating_change(event, $w) {
2
$w('#rateError').hide();
3
}

Understanding the Code

Lines 1-2: When the vistor selects a rate, hide the error message stating "Please rate this product".

Identifiers you may need to change based on your site's elements

If you want to use this exact scenario and code in your site, you may need to modify these items to match the ones on your site:

  • #rateError

Next Steps

Was this helpful?
Yes
No