Hi all,
Firstly I just wanted to say a huge thank you to everyone who has participated in this forum over the last year or so - it’s been such a help for me and I’ve learnt so much!
I’ve been developing an e-commerce Wix site for an art gallery for the last few months - it’s been a labour of love especially as the gallery is almost 267 years old and so has amassed quite a collection of products - but the finish line is nearly in sight! Once it goes live I’ll share bits of the code which I hope the community will find useful (especially for custom Wix store pages - I’ve seen various unanswered questions over the last few months which I think I’ve solved… but equally if anyone wants to message me privately about how anything works I’m happy to share!)
WEBSITE OVERVIEW…
Rather than create a typical e-commerce shop front with hundreds of products/filters to choose from, I wanted to create a more personal shopping experience to help people discover paintings that are right for them. I then discovered the Wix Gift Quiz tutorial and thought my prayers had been answered… however I’ve hit a couple of snags and I just can’t get my head around it - I’ve read the tutorial back-to-back and searched the forums for answers but I can’t seem to find a resolution, so I hope you can help!
SITE STRUCTURE + ERRORS?
For the gift quiz code itself, I am actually keeping this basically exactly the same - however rather than use the Stores/Products database, I have a custom Products Database due to the complexities of the numerous product variations. I have replicated the same fields/collections used in the tutorial so thought this would work as it does in the demo but I’m getting a few problems, which I’ve listed below… I’m not sure if its due to the volume of products (I hope not) or just something stupid that I’ve missed!!!
I’ve created 3 versions of the same gift quiz to try and identify the problem…
-
Wix Store Collection + 4 Questions = Incorrect Results
https://www.toogood.london/perfect-painting-1 -
Preferred Custom Product Collection + 4 Questions = No Results?
https://www.toogood.london/perfect-painting-2 -
Wix Store Collection + 3 Questions = Better results, but not 100% correct
https://www.toogood.london/perfect-painting-3 (same as #1 but one less question)
I need to get the option 2 working as this database has all the extra product data in it… anyway I’ve copied the code below with a few screenshots. Any help in advanced would be super super much appreciated!
Many thanks,
C
PERFECT PAINTING #1:
//-------------Imports-------------//
import wixData from 'wix-data';
//-------------Global Variables-------------//
// List of selected answers.
const selectedAnswers = [];
// List of IDs of all the answer buttons.
const quizAnswersIds = ["wildlife", "townscape", "stilllife", "modern", "marine", "landscape", "figurative",
"oil", "sculpture", "watercolour",
"small", "medium", "large", "priceone", "pricetwo", "pricethree", "pricefour", "pricefive", "pricesix"
];
// Number of questions plus one for the results.
let numberOfSlides;
//-------------Page Setup-------------//
$w.onReady(() => {
// Set the global numberOfSlides variable from the slideshow length.
numberOfSlides = $w('#quizSlides').slides.length;
// For each answer button:
quizAnswersIds.forEach(answer => {
// Set the action that occurs when a user clicks the answer button.
$w(`#${answer}`).onClick(() => {
// Add the answer to the global selected answers list.
selectedAnswers.push(answer);
// Move to the next slide.
$w('#quizSlides').next();
})
})
});
//-------------Quiz Finish-------------//
// Set the action that occurs when a user is moved to the next slide.
export async function quizSlides_change(event, $w) {
// If the quiz is finished:
if (isQuizFinished()) {
// Get the keywords associated with each product by calling the getKeywordsPerProduct() function.
let quizProducts = await getKeywordsPerProduct();
// For each selected answer:
selectedAnswers.forEach(answer => {
// Filter out the products that do not match the answer.
quizProducts = filterProductsPerAnswer(quizProducts, answer);
});
// Extract the product IDs from the filtered product.
quizProducts = quizProducts.map(quizProduct => quizProduct.productId);
// Get a random list from the remaining filtered products.
quizProducts = getRandomItemsFromArray(quizProducts, numberOfSlides);
// Populate the recommended products repeater with the product data that corresponds to the randomly selected products.
$w('#recommendedProducts').data = await getProductsData(quizProducts);
}
}
// Checks if the quiz has been completed.
function isQuizFinished() {
// Check if the current slide is the last slide.
return $w('#quizSlides').currentIndex === numberOfSlides - 1;
}
// Get the keywords associated with each product.
async function getKeywordsPerProduct() {
// Query the "productsSearch" collection for the product keywords.
let productsSearch = await wixData.query("productsSearchTest").find();
// Extract the items from the query results.
productsSearch = productsSearch.items;
// Process the returned item data to make it easier to work with.
productsSearch = productsSearch.map(item => {
return {
productId: item.product,
keywords: item.keywords.split(",")
}
});
// Return the processed item data.
return productsSearch;
}
// Filter out products that don't match the specified answer.
function filterProductsPerAnswer(quizProducts, answer) {
// Use the JavaScript filter() function to filter out products that don't match the specified answer.
const filteredProducts = quizProducts.filter(quizProduct => {
return quizProduct.keywords.includes(answer)
});
// Return the filtered product list.
return filteredProducts;
}
// Get a specified number of random items from the specified array.
function getRandomItemsFromArray(productsArr, numberOfItems){
// List for storing the randomly selected products.
const productsIds = [];
// Number of products in the specified array.
const numberOfProducts = productsArr.length;
// For specified the number of items or the number of products that were specified, whichever is lower:
for (let i = 0; i < numberOfItems && i < numberOfProducts; i++){
// Get a random valid index.
const randomIndex = getRandomInt(0, numberOfProducts -1 );
// Add the product at that random index to the list of selected products.
productsIds.push(productsArr[randomIndex]);
// Remove the already selected product from the list of products to select from.
productsArr.splice(randomIndex, 1);
}
// Return the randomly selected products.
return productsIds;
}
// Get a random number between two specified values.
function getRandomInt(min, max) {
// Use JavaScript math functions to get a random number between two specified values.
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Get the product data associated with the specified product IDs.
async function getProductsData(productsIds) {
// Query the "Products" collection for products whose ID is one of the specified IDs.
const productsData = await wixData.query("Stores/Products")
.hasSome("_id", productsIds)
.find();
// Return the matching products.
return productsData.items;
}
// Set up each item in the recommended products repeater when it receives data as the quiz is finished.
export function recommendedProducts_itemReady($item, itemData, index) {
// Populate the elements from the current item's data.
$item('#name').text = itemData.name;
$item('#image').src = itemData.mainMedia;
$item('#image').link = itemData.productPageUrl;
$item('#price').text = itemData.formattedPrice;
}
PERFECT PAINTING #2:
//-------------Imports-------------//
import wixData from 'wix-data';
//-------------Global Variables-------------//
// List of selected answers.
const selectedAnswers = [];
// List of IDs of all the answer buttons.
const quizAnswersIds = ["wildlife", "townscape", "stilllife", "modern", "marine", "landscape", "figurative",
"oil", "sculpture", "watercolour",
"small", "medium", "large",
"priceone", "pricetwo", "pricethree", "pricefour", "pricefive", "pricesix"
];
// Number of questions plus one for the results.
let numberOfSlides;
//-------------Page Setup-------------//
$w.onReady(() => {
// Set the global numberOfSlides variable from the slideshow length.
numberOfSlides = $w('#quizSlides').slides.length;
// For each answer button:
quizAnswersIds.forEach(answer => {
// Set the action that occurs when a user clicks the answer button.
$w(`#${answer}`).onClick(() => {
// Add the answer to the global selected answers list.
selectedAnswers.push(answer);
// Move to the next slide.
$w('#quizSlides').next();
})
})
});
//-------------Quiz Finish-------------//
// Set the action that occurs when a user is moved to the next slide.
export async function quizSlides_change(event, $w) {
// If the quiz is finished:
if (isQuizFinished()) {
// Get the keywords associated with each product by calling the getKeywordsPerProduct() function.
let quizProducts = await getKeywordsPerProduct();
// For each selected answer:
selectedAnswers.forEach(answer => {
// Filter out the products that do not match the answer.
quizProducts = filterProductsPerAnswer(quizProducts, answer);
});
// Extract the product IDs from the filtered product.
quizProducts = quizProducts.map(quizProduct => quizProduct.productId);
// Get a random list from the remaining filtered products.
quizProducts = getRandomItemsFromArray(quizProducts, numberOfSlides);
// Populate the recommended products repeater with the product data that corresponds to the randomly selected products.
$w('#recommendedProducts').data = await getProductsData(quizProducts);
}
}
// Checks if the quiz has been completed.
function isQuizFinished() {
// Check if the current slide is the last slide.
return $w('#quizSlides').currentIndex === numberOfSlides - 1;
}
// Get the keywords associated with each product.
async function getKeywordsPerProduct() {
// Query the "productsSearch" collection for the product keywords.
let productsSearch = await wixData.query("productsSearch").find();
// Extract the items from the query results.
productsSearch = productsSearch.items;
// Process the returned item data to make it easier to work with.
productsSearch = productsSearch.map(item => {
return {
productId: item.product,
keywords: item.keywords.split(",")
}
});
// Return the processed item data.
return productsSearch;
}
// Filter out products that don't match the specified answer.
function filterProductsPerAnswer(quizProducts, answer) {
// Use the JavaScript filter() function to filter out products that don't match the specified answer.
const filteredProducts = quizProducts.filter(quizProduct => {
return quizProduct.keywords.includes(answer)
});
// Return the filtered product list.
return filteredProducts;
}
// Get a specified number of random items from the specified array.
function getRandomItemsFromArray(productsArr, numberOfItems){
// List for storing the randomly selected products.
const productsIds = [];
// Number of products in the specified array.
const numberOfProducts = productsArr.length;
// For specified the number of items or the number of products that were specified, whichever is lower:
for (let i = 0; i < numberOfItems && i < numberOfProducts; i++){
// Get a random valid index.
const randomIndex = getRandomInt(0, numberOfProducts -1 );
// Add the product at that random index to the list of selected products.
productsIds.push(productsArr[randomIndex]);
// Remove the already selected product from the list of products to select from.
productsArr.splice(randomIndex, 1);
}
// Return the randomly selected products.
return productsIds;
}
// Get a random number between two specified values.
function getRandomInt(min, max) {
// Use JavaScript math functions to get a random number between two specified values.
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Get the product data associated with the specified product IDs.
async function getProductsData(productsIds) {
// Query the "Products" collection for products whose ID is one of the specified IDs.
const productsData = await wixData.query("products")
.hasSome("_id", productsIds)
.find();
// Return the matching products.
return productsData.items;
}
// Set up each item in the recommended products repeater when it receives data as the quiz is finished.
export function recommendedProducts_itemReady($item, itemData, index) {
// Populate the elements from the current item's data.
$item('#name').text = itemData.name;
$item('#image').src = itemData.thumbnail;
$item('#size').text = itemData.size;
$item('#artist').text = itemData.artist;
}
P.s. There are various bits that are unfinished/not working on the site yet whilst I finish this area first… incase you wondered!