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

Overview
- 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.
- 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



- 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)


Step 2: Set up the Shop Product Page
- 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.

- 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.

- 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

- 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.
1import wixData from 'wix-data';
2import wixWindow from 'wix-window';
3import wixLocation from 'wix-location';
4
5let product;
6
7$w.onReady(async function () {
8 product = await $w('#productPage1').getProduct();
9 initReviews();
10
11 wixLocation.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, and Wix Location 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'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
#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.
1async 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
#Reviews
productId
Step 6: Create the loadStatistics Function on the Product Page
The loadStatistics
function gets and displays statistics for the current product.
1async 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
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.
1export 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
#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.
1export 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
#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.
1export async function addReview_click(event, $w) {
2 const dataForLightbox = {
3 productId: product._id
4 };
5 let result = await wixWindow.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
#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
.
1export 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
#Reviews
Step 11: Prepare the Review Box Lightbox
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.
1import wixWindow from 'wix-window';
2import wixData from 'wix-data';
3
4let productId;
Understanding the Code
Lines 1-2: Import the modules we need to work with Wix Data and Wix Window libraries.
Line 4: Declare a global variable to store the product ID.
1$w.onReady(function () {
2
3 productId = wixWindow.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.
1$w('#SubmitReviews').onAfterSave(async () => {
2 await updateStatistics($w('#radioGroup1').value);
3 wixWindow.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
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.
1async 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
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.
1export 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
#rateError
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: