Critical bug using SEO on Dynamic Pages not solved for 4 months and today solved in 4 hours!

This is in the onReady function of the item page

import wixSeo from 'wix-seo';

$w.onReady( function () {
$w('#dynamicDataset').onReady(() => {
thisCourse = $w('#dynamicDataset').getCurrentItem();
// console.log("this course : " , JSON.stringify(thisCourse));
courseSchema(thisCourse._id)
.then(schema => {
if (!schema) throw new Error("schema is undefined or null")
console.log("setting schema")
console.log(schema);
wixSeo.setStructuredData(schema)
.then(() => {
console.log("structured data set");
})
.catch(e => {
console.log("failed setting structured data : ", e.message);
});
})
.catch(err => {
console.log("Error : ", err, err.message)
});
})
}

Backend

import wixData from 'wix-data';
const baseUrl = "https://www.scottishrockandwater.com/";
const DBOptions = { suppressAuth: true };
const validFromMonth = 8;
let courseShema = {
"@context": "https://schema.org",
"@type": "Event",
"name": "{name}",
"description": "{description}",
"location": {
"@type": "Place",
"name": "{name}",
"address": {
"@type": "PostalAddress",
"streetAddress": "{streetAddress}",
"addressLocality": "{locality}",
"postalCode": "{code}",
"addressRegion": "{region}",
"addressCountry": "{country}"
}
},
"image": [
"{image1}",
"{image2}",
"{image3}"
],
"performer": {
"@type": "PerformingGroup",
"name": "{name}"
},
"offers": {
"@type": "Offer",
"url": "{url}",
"price": "{price}",
"priceCurrency": "GBP",
"availability": "https://schema.org/InStock",
"validFrom": "{validDate}"
},
"startDate": "{startDate}",
"endDate": "{endDate}",
};
const dates = ["dateone", "dateTwo", "datethree", "dateFour", "dateFive", "dateSix", "dateOneYh", "dateTwoYh", "dateThreeYh", "dateFourYh", "dateFiveYh", "dateSixYh"];
export async function courseSchema(courseId) {
let schema = [];
try {
let course = await wixData.get("Courses", courseId);
console.log("deleting HTML...");
delete course.accommodationDetails;
delete course.details;
delete course.navigationButtons;
delete course.tripDetails;
delete course.tripHighlights;
delete course.whatDoINeedToBring;
delete course.whatElseCanWeProvide;
delete course.whatsIncluded;
delete course.whatsNotIncluded;
console.log("currect course input : " , course);
courseShema.name = course.title;
courseShema.description = course.description;
let rating = await getAvgRating(course._id, false);
if (rating.success) {
// Object.assign(schema, rating.data);
Object.assign(courseShema, rating.data);
}
let schemadetails = await wixData.query("Shema").eq("course", courseId).find(DBOptions);
console.log("schema Details : ",schemadetails);
// Object.assign(courseShema, schemadetails);
if (schemadetails.length === 0) {
// no matching items found
throw new Error("no result found");
}
console.log("currect course input 1 : " , course);
schemadetails = schemadetails.items[0];
// Todo : check visible column in the database?
// Check if it's no allow to schema
//
if (!schemadetails.visible) {
throw new Error("schema is not avaiable, visible is false")
}
courseShema.location.name = schemadetails.locationName;
courseShema.location.address.streetAddress = schemadetails.streetAddress;
courseShema.location.address.addressLocality = schemadetails.addressLocality;
courseShema.location.address.addressRegion = schemadetails.addressRegion;
courseShema.location.address.addressCountry = schemadetails.addressCountry;
courseShema.location.address.postalCode = schemadetails.postalCode;
courseShema.image[0] = removeWixImageURL(schemadetails.image1);
courseShema.image[1] = removeWixImageURL(schemadetails.image2);
courseShema.image[2] = removeWixImageURL(schemadetails.image3);
courseShema.offers.price = String(course.price);
courseShema.offers.url = baseUrl + course["link-courses-test-title"];
courseShema.performer.name = schemadetails.performerName;
console.log("currect course input 2 : " , course);
// demo
//convert this push to forloop for each date for 12 date
let totalDays = course.duration;
totalDays = Number(totalDays.split(" ")[0]);
console.log("currect course input 3 : " , course);
console.log("genr schema is created: " , courseShema)
dates.forEach(dateFieldKey => {
try{
// set Start date
let currDate = course[dateFieldKey];
console.log("currDate!!!" , currDate, typeof currDate);
let startDate = convtDate(currDate);
console.log("start date : " , startDate, typeof startDate)
// set End date
currDate.setDate(currDate.getDate() + totalDays);
let endDate = convtDate(currDate);
// set vali date 8 months before the start date
currDate.setDate(currDate.getDate() - totalDays);
currDate.setMonth(currDate.getMonth() - validFromMonth);
let validFromDate = convtDate(currDate);
console.log("valid from date : " , validFromDate)
// Update the course schema
courseShema.startDate = startDate;
courseShema.endDate = endDate;
courseShema.offers.validFrom = validFromDate;
// update the the array
schema.push(JSON.parse(JSON.stringify(courseShema)));
}
catch(e) {
console.log("Error on data" , e.message)
}
});
if(schema.length === 0) return undefined;
return schema;
}
// something went wrong
catch (error) {
console.log("Error schema is not set up : ", error, error.message);
}
}
export async function categoryCourseSchema(categoryName) {
try {
let schema = [];
let categorySchema = {
"@context": "https://schema.org/",
"@type": "Product",
"name": categoryName,
}
let rating = await getAvgRating(categoryName, true);
if (rating.success) {
Object.assign(categorySchema, rating.data);
} else {
// no rating found so stop the schema
throw new Error("rating is empty for category page : ", schema)
}
if (categorySchema) {
console.log(categorySchema);
return categorySchema;
}
// no matching items found
console.log("schema : ", schema);
throw new Error("schema is not working !!");
} catch (error) {
console.log("Error on schema : ", error.message);
}
}
async function getAvgRating(data, isCategory = true) {
let filter = wixData.filter();
if (isCategory) {
filter = filter.eq("courseCategory", data);
} else {
filter = filter.eq("courseId", data);
}
try {
// https://developers.google.com/search/docs/data-types/review-snippet
// https://developers.google.com/search/docs/data-types/event
let result = await wixData.aggregate("Reviews").filter(filter).avg("rating").count().run();
console.log(result);
if (result._items.length > 0) {
let res = result._items[0];
return {
"success": true,
"data": {
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": res.ratingAvg,
"bestRating": 5,
"ratingCount": res.count
}
}
}
}
return {
"success": false,
"No result": true
}
} catch (e) {
return {
"success": false,
"error": true,
"msg": e
}
}
}
function removeWixImageURL(url) {
if (!url) return null;
return "https://static.wixstatic.com/media/" + url.substring(url.indexOf("v1/") + 3, url.indexOf(".") + 4)
}
function convtDate(date) {
if(!date) throw new Error("date is either null or undefined");
if(typeof date === "string") return date.split("T")[0];
return date.toISOString().split("T")[0]
}
function priceConvert(str) {
if (str === null || str.length === 0) return null;
str = String(str);
str = str.split("Ā£")[1];
return Number(str);
}

@stephenmccall Hi. Sure, Iā€™ll see what I can do.
To make things a bit more focused, could you please send me a list of specific dynamic pages (live urls) and describe which exactly schemas you expect them to display in the search engine results that they donā€™t display?
Thanks in advance

@aleksander-denga That would be great thank you.

What Iā€™m expecting to see on search results are in this image (The image has been edited to show what Iā€™m expecting to see)

I currently have 76 URLsā€¦ do you wish me to post them all?? It is for every item of this dynamic page. It might be easier to access my editor? Or Google Console?

@stephenmccall Thank you, one example should be enough to investigate. Iā€™ll take a look.
Regards, Alex

Hi @stephenmccall
I took this issue with our SEO experts and we did some analysis.

Two pages were tested: one displaying the schema in search results https://www.scottishrockandwater.com/courses/Winter-Skills/Winter-Skills-2-day
and another one from the same router, which doesnā€™t display the schema yet https://www.scottishrockandwater.com/courses/Winter-Climbing/Winter-Climbing-Intro

Googleā€™s structured data testing tool showed that both pages has appropriate data structure:
Winter-Climbing-Intro page results
Winter-Skills-2-day page results
You can see that both pages contain 12 schemas of Event type and neither shows errors or warnings.

There is another Googleā€™s tool, which tests rich results compatibility and can even visualize the schema youā€™ve created on both pages. It also displays that both pages are rich results compatible:
Winter-Climbing-Intro page results
Winter-Skills-2-day page results

So, it seems like the schema was built properly for these pages.
One possible explanation why it is not displayed could be that the SEO data is not aligned with Googleā€™s guidelines .

Iā€™d suggest to check with their policy and see if something is not on the right place.

There is one more test we can do - verify the Google Search Console results for your page and see if there are any errors/warnings there. Please let know if you need information about how to share access to Search Console with our tech account wixpromote@wix.com

Regards, Alex

@aleksander-denga Thank you for all of your efforts. You should have access to the account as shown in the photo.

We had tested the pages via the tool for testing on Google and all the pages came back good. The item pages should also have a rating on search results, this has never worked but dates have come and gone over the past year.

The professional that coded the job checked the document for guidelines and said everything was good.

I look forward to your reply

Stephen

@stephenmccall Hi.
We tested this page with the Search Console and didnā€™t see any issue with the schema structure there as well. There are no errors or warnings shown. Technically, all is okay from our side.

On the other hand, looking into the Googleā€™ documentation , you can see that their guidelines are suggesting to use only a single Event per page, instead of multiple ones, like on the dynamic page in question.
Please take a look at the highlights on the following screenshot:


Please let me know if adjusting schema to these recommendations will help
Regards, Alex

@aleksander-denga thank you for the detailed response. And sorry for the delayed reply.

I have spoken to my coder and he reckons the code should function regardless, now Iā€™m stuck after paying three times to get this working and other wix professionals checking the code (minus yourself) and still donā€™t have an outcomeā€¦ Is there anyone that you know specialises in this that could help?

Best wishes

Stephen

@stephenmccall We have a Wix Arena service, which is the only thing I can recommend.

Also, try to reach out for webmasters community , or see another helpful information in the troubleshooting section of the Googleā€™s docs

Hope youā€™ll find a solution soon.

I have spoken to my coder and he reckons the code should function regardless
Google claims that they are not giving their guarantees to render structured data properly after a webmaster meets their guidelines precisely. So the chances are getting even lower after violating the standards. Just wondering how does your specialist explain this?

@aleksander-denga If Iā€™m honest this has been ongoing for about 10 months now and communication has been limited and sparse at times, this was the last comment

ā€œThatā€™s a very less chance and I donā€™t think google will mistake like thisā€

So Iā€™m stuck really. I really appreciate your help but my coding knowledge is limited when it comes to more complex areas like this, so even asking for help in the webmasters community and troubleshooting section itā€™s beyond my skill set, hence why I paid some people to write, check and implement the code. It looks like I might need to pay someone else, again with no guarantees that it will function :frowning:

@stephenmccall I understand - it must be an exhausting experience. My point is that since this dynamic page structured data was implemented incorrectly (and we confirmed this), at least you can ask your developer to complete the work properly

@aleksander-denga Thank you. Just so I can be clear when speaking to the developer, I presume you are talking about there being more then one event per item/dynamic page?

@stephenmccall Yes, exactly. This was a recommendation that I got from our Wix SEO experts. Again, no guarantees (as Google also claims ), but at least the chances are higher