Claudius
2 years agoBoss
How to add Event / Occasion Structured Data markup
Event Structured Data markup on your community's OccasionPage in your blog "makes it easier for people to discover and attend events through Google Search results and other Google products, like Google Maps.".
Here's some working code to add a simple JSON linked data set to be used on the OccasionPage. Ideally, you would drop this in a custom component which you add to the page layout. Since it's not rendering I would recommend adding it somewhere towards the end of the page, e. g. in the footer.
<#-- This component will add structured markup in form of JSON linked data for OccasionPage (Event). See doc at https://developers.google.com/search/docs/appearance/structured-data/event -->
<#assign occasionQuery = "SELECT occasion_data.start_time, occasion_data.end_time, occasion_data.status, occasion_data.featured_guests FROM messages WHERE id = '${page.context.thread.topicMessage.uniqueId}'"/>
<#assign occasionInfo = rest("2.0", "/search?q=" + occasionQuery?url("UTF-8") + "&restapi.response_style=view").data.items />
<#attempt>
<#assign images = (liql('SELECT original_href,width FROM images WHERE messages.id = "${page.context.message.uniqueId}"').data.items) />
<#recover>
<#if DEBUG?? && DEBUG>
${query}
${.error}
</#if>
</#attempt>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Event",
"name": "${page.context.message.subject}",
"startDate": "${occasionInfo[0].occasion_data.start_time?datetime} GMT${occasionInfo[0].occasion_data.start_time?datetime?string('Z')}",
"endDate": "${occasionInfo[0].occasion_data.end_time?datetime} GMT${occasionInfo[0].occasion_data.end_time?datetime?string('Z')}",
"eventStatus": "https://schema.org/EventScheduled",
"eventAttendanceMode": "https://schema.org/OnlineEventAttendanceMode",
"location": {
"@type": "VirtualLocation",
"url": "${page.context.thread.webUi.url}"
},
<#if images?? && (images?size gt 0) >
<#attempt>
"image": "${http.request.serverName}${images[0].original_href}",
<#recover>
"image": "${http.request.serverName}${asset.get("/html/assets/community-default-image.png")}",
</#attempt>
</#if>
"description": "${page.context.message.bodyRaw}",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"validFrom": "${page.context.message.postDate?datetime} GMT${page.context.message.postDate?datetime?string('Z')}",
"url": "${page.context.thread.webUi.url}"
},
"organizer": [{
"@type": "Person",
"name": "${page.context.thread.topicMessage.author.login}",
"url": "${page.context.thread.topicMessage.author.webUi.url}"
}]
}
</script>
Some comments:
- If no image is found with the Event message then a default community placeholder cover image is expected at /html/assets/community-default-image.png
- I'm assuming all events are virtual ones. If that's not the case for your community you might want to check against occasion_data.is_live_stream
- Google's markup definition also includes more variants for eventStatus if the event got moved from in person to virtual, cancelled etc. I couldn't find a good equivalent in Khoros Event data so every event is just marked up as EventScheduled (with a future or past start_time) 🙂
- Event guests should probably be included in the markup as "performers", but I gave up listing the content of the occasion_data.featured_guests hash. Maybe you can make it work and share back the improved code?