Reputation: 67
Below is the HTML actually used to display the breadcrumbs on each page
<c:forEach items="${breadcrumbArray}" var="breadcrumb" varStatus="loopCounter">
<c:if test="${breadcrumb ne 'store'}">
<li class="breadcrumb__item">
<c:choose>
<c:when test="${not loopCounter.last}">
<a href="/${breadcrumb}">${breadcrumb}</a>
</c:when>
<c:otherwise>
${fn:replace(breadcrumb, '-', ' ')}
</c:otherwise>
</c:choose>
</li>
</c:if>
</c:forEach>
Javascript used to generate the schema dynamically
<script type="text/javascript">
$(document).ready(function(){
var el = document.createElement('script');
el.type = 'application/ld+json';
el.text = JSON.stringify({ "@context": "https://schema.org/",
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "",
"item": ""
}]
});
document.querySelector('head').appendChild(el);
});
</script>
The schema for example for " Home > Our Mission > Who We Are " should be generated like:
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://corp.com/"
},{
"@type": "ListItem",
"position": 2,
"name": "Our Mission",
"item": "https://corp.com/our-mission/"
},{
"@type": "ListItem",
"position": 3,
"name": "Who We Are",
"item": "https://corp.com/our-mission/who-we-are"
}]
}
</script>
The script is not getting appended to the 'head' tag ..
Upvotes: 1
Views: 2987
Reputation: 67
I found that we don't need javascript for dynamically populating the values. HTML5 works well. Below is the final script that i am using to render the schema
P.S. The business requirement was to use json-ld only and not rdfa
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1
"name": "Home",
"item": "${baseURL}",
},
<c:forEach items="${breadcrumbArray}" var="breadcrumb" varStatus="loopCounter">
{
"@type": "ListItem",
"position": ${loopCounter.index+1}
"name": "${fn:replace(breadcrumb, '-', ' ')}",
"item": "${baseURL}${breadcrumbArray[loopCounter.index-1]}/${breadcrumb}",
}
</c:forEach>
]
}
</script>
Upvotes: 0
Reputation: 3629
There are a few pieces to this one.
This might require more information, what you have in your code should at least render the JSON-LD script
tag in your head
. There might be something going on in your environment preventing you from writing to head
. You could try changing your code to something like:
document.head.appendChild(el)
or document.getElementsByTagName('head')[0].appendChild(el)
(If you need to support older browsers).
More info on that can be found at these SO threads:
Again, I have doubts that this is the issue. I'd also try rendering the script
somewhere else on the page instead of head
to see if that works for you (also related, see my final note at the end of this answer).
Here's a rough, jQuery free but ES5 compatable solution to how you could generate this:
<ol class="breadcrumbs">
<li class="breadcrumb-item">
<a class="breadcrumb-link" href="https://mypage.com/page1">Page 1</a>
</li>
<li class="breadcrumb-item">
<a class="breadcrumb-link" href="https://mypage.com/page2">Page 2</a>
</li>
<li class="breadcrumb-item">
<a class="breadcrumb-link" href="https://mypage.com/page3">Page 3</a>
</li>
</ol>
<!-- Testing Purposes -->
<div class="output"></div>
// Create Script
var el = document.createElement('script');
el.type = 'application/ld+json';
// Set initial position
var position = 0;
// Create breadcrumb object
var breadcrumb = {
position:0,
name:"",
item:""
}
// Empty array for list items
var listArray = []
// Loop through each breadcrumb link and set attributes
var items = document.querySelectorAll('.breadcrumb-link');
for(var i = 0; i < items.length; i++) {
var newItem = Object.create(breadcrumb);
var curItem = items[i];
newItem["@type"] = "ListItem";
position++;
newItem.position = position;
newItem.name = curItem.text;
newItem.item = curItem.getAttribute('href');
listArray.push(newItem);
}
// Create overarching Schema object
var breadcrumbSchema = {
"@context": "https://schema.org/",
"@type": "BreadcrumbList",
"itemListElement": listArray
};
// Stringify JSON
var finalSchema = JSON.stringify(breadcrumbSchema);
// Add schema to Script
el.text = finalSchema;
// Set head variable with browser fallback
var head = document.head || document.getElementsByTagName("head")[0];
// Add to head (This won't work in codepen)
head.appendChild(el);
// Testing purposes - Show example of string in HTML
document.querySelector('.output').innerHTML = finalSchema;
// Testing purposes - Inspect source to see script generated inside of the "output" div
document.querySelector('.output').appendChild(el);
As a commenter mentioned writing out JSON-LD with JavaScript could be a problem. If your intentions for this are SEO related you might want to play the safe bet and render this server side. There's no guarantee search engine bots are catching something like this rendered on the client side.
Update: It looks like Google will play nicely with JSON-LD rendered dynamically, but this still may be a problem with other search engines. I also like to err on the side of caution. Thanks @JayGray
If you have to hardcode values for JSON-LD, as the commenter mentioned you could use RDFa which is still supported (even if not preferred compared to JSON-LD). Based on your code the HTML is rendered dynamically. Here's an example of what that looks like from the BreadcrumbList on schema.org:
<ol vocab="https://schema.org/" typeof="BreadcrumbList">
<li property="itemListElement" typeof="ListItem">
<a property="item" typeof="WebPage" href="https://example.com/dresses">
<span property="name">Dresses</span>
</a>
<meta property="position" content="1">
</li>
<li property="itemListElement" typeof="ListItem">
<a property="item" typeof="WebPage" href="https://example.com/dresses/real">
<span property="name">Real Dresses</span>
</a>
<meta property="position" content="2">
</li>
</ol>
(Keep in mind that RDFa and Microdata - unlike JSON-LD - will not get picked up by search engines if generated dynamically).
Even though JSON-LD is recommended to be in head
, it does NOT need to be in order to be picked up properly (at least with Google). It can really be anywhere in your content and it will work as well.
Additionally if you run your page through the Structured Data Testing tool - any JSON-LD in the body will still validate fine. I assume the Rich Snippets tool would also validate but I haven't confirmed that yet.
Upvotes: 3