Duplicate schema/structured data markup? - schema.org

Will this structure be problematic?
<script type="application/ld+json">
{
"#context":"http://schema.org",
"#type":"WebPage",
"name":"Postcards",
"url":"https://local.mysite.com/postcards.html",
"breadcrumb":{
"#type":"BreadcrumbList",
"itemListElement":[
{
"#type":"ListItem",
"position":1,
"item":{
"#id":"https://local.mysite.com",
"name":"My Site"
}
},
{
"#type":"ListItem",
"position":2,
"item":{
"#id":"https://local.mysite.com/postcards.html",
"name":"Postcards"
}
}
]
},
"mainEntity":{
"#type":"WebPageElement",
"offers":{
"#type":"Offer",
"itemOffered":[
{
"#type":"Product",
"name":"Christmas Postcards",
"url":"https://local.mysite.com/christmas-postcards.html"
},
{
"#type":"Product",
"name":"Getaway Postcards",
"url":"https://local.mysite.com/getaway-postcards.html"
}
]
}
}
}</script>
<script type="application/ld+json">
{
"#context":"http://schema.org",
"#type":"WebPage",
"name":"Postcards",
"url":"https://local.mysite.com/postcards.html",
"breadcrumb":{
"#type":"BreadcrumbList",
"itemListElement":[
{
"#type":"ListItem",
"position":1,
"item":{
"#id":"https://local.mysite.com",
"name":"My Site"
}
},
{
"#type":"ListItem",
"position":2,
"item":{
"#id":"https://local.mysite.com/postcards.html",
"name":"Postcards"
}
}
]
},
"mainEntity":{
"#type":"WebPageElement",
"offers":{
"#type":"Offer",
"itemOffered":[
{
"#type":"Product",
"name":"Mini Postcards",
"url":"https://local.mysite.com/mini-postcards.html"
},
{
"#type":"Product",
"name":"Summer Postcards",
"url":"https://local.mysite.com/summer-postcards.html"
}
]
}
}
}</script>
The reason there could be "duplicate" markup like this for a single category page is that the page may use multiple product templates.
In the current implementation, the markup is dynamically constructed in the product template. For example, if there are two product templates for a single Category Page, the markup will be reconstructed twice, but containing different WebPageElement.
Will this yield bad results? I checked in Google's testing tool and it didn't give me any errors or warnings.

Multiple nodes, same entity
If you have multiple nodes that represent the same entity on a page, the best practice is to give these nodes the same URI as identifier.
With JSON-LD, you can provide identifiers with #id.
So
both of your WebPage items could get "#id": "" (for the current URL; preferably specify your canonical URL here),
both of your BreadcrumbList items could get "#id": "#breadcrumbs",
both of your ListItem-1 items could get "#id": "#breadcrumbs-1", and
both of your ListItem-2 items could get "#id": "#breadcrumbs-2".
That way, Google’s SDTT will display each of these items only once, because it now knows that they are about the same entity.
Referencing nodes instead of duplicating them
#id also allows you to reference nodes instead of embedding them (and thereby duplicating their data). See an example.
In your case this would have the advantage that you don’t have to duplicate the WebPage/BreadcrumbList/ListItem nodes to begin with. You would specify these nodes once, and each product template would then outpout only the Offer/Product nodes. These nodes could include (reverse) references to the WebPage/etc. (might be easier for you to implement), or the WebPage/etc. could reference these nodes.

Related

How to format schema.org correctly with product sold by length?

I have a product which is sold by the length in 0.25-yard increments. 1 qty is equal to 0.25
While with Google Shopping Feed it was fairy easy to do with unit_pricing_measure and unit_pricing_base_measure:
<price>5 USD</price>
<unit_pricing_measure>0.25 yd</unit_pricing_measure>
<unit_pricing_base_measure>1 yd</unit_pricing_base_measure>
I expect above code to result in: "$20 per yard"
I cannot figure out how to replicate this in Schema.org. Is this even possible?
Maybe it could be something and repeat like this:
{
"#context":"https://schema.org",
"#type": "Product",
"name":"The name",
"description":"zzzzz",
"offers": {
"#type": "Offer",
"priceSpecification": {
"#type":"UnitPriceSpecification",
"price":"20",
"priceCurrency":"USD",
"referenceQuantity":{
"#type":"QuantitativeValue",
"name":"yard",
"value":"1",
"unitText":"yard",
"unitCode":"YRD",
"sameAs":"http://www.unece.org/fileadmin/DAM/cefact/recommendations/bkup_htm/add2h.htm"
}
}
}
}
The following chain is used here: Product => Offer => priceSpecification => UnitPriceSpecification => referenceQuantity => QuantitativeValue.
Note that the property sameAs with url used here is to identify.

Removing _embedded from a collection of REST resources

Maybe this goes against REST/HAL principles but I thought that if I was viewing a list of items they should not be contained in an _embedded tag. Below is the details returned when I navigate to /characters in my spring boot application.
I had expected _embedded to not be present for the characterDescriptions since they are the main focus of the page, is it possible to achieve this? Should I try to achieve this or would _embedded be the norm here?
On a related note when I navigate to a particular resource using the link ( like characters/1 for instance) should I be linking back to the /characters parent page or is it acceptable to only contain a self-link at these kinds of endpoints (I will be eventually linking to the user here but this is a general question about REST endpoints )
The controller method that returns this JSON is below the JSON
{
"_embedded": {
"characterDescriptions": [
{
"characterName": "Adrak",
"playerName": "Liam",
"userName": "liam",
"_links": {
"self": {
"href": "http://localhost:8080/characters/1"
}
}
},
{
"characterName": "Thorny",
"playerName": "Aedo",
"userName": "aedo",
"_links": {
"self": {
"href": "http://localhost:8080/characters/2"
}
}
},
{
"characterName": "Anin",
"playerName": "Saoirse",
"userName": "saoirse",
"_links": {
"self": {
"href": "http://localhost:8080/characters/3"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/characters"
}
}
}
Here's the relevant method
#GetMapping
public ResponseEntity<Resources<Resource<CharacterDescription>>> getAllCharacterDescriptions( ) {
List <Resource<CharacterDescription>> characters = repository.findAll()
.stream().map( character -> {
Link characterLink = linkTo(methodOn(CharacterDescriptionController.class)
.getCharacterDescription(character.getCharacterId()))
.withSelfRel();
return new Resource<>(character, characterLink);
}).collect(Collectors.toList());
Link allCharacterLink = linkTo(methodOn(CharacterDescriptionController.class)
.getAllCharacterDescriptions(auth))
.withSelfRel();
Resources<Resource<CharacterDescription>> resources = new Resources<>(characters, allCharacterLink);
return ResponseEntity.ok(resources);
}
According to the HAL spec you can either render a single resource, with its content and set of links, or you can render an aggregate resource, which has room for multiple resources-within-this-resource.
In your domain model, you clearly show multiple documents, each with a distinct self URI (/characters/1, /characters/2, etc.), hence, you aren't serving up a single item resource, but instead an aggregate root.
If you read the HAL spec, you'll find this definition underneath _embedded:
It is an object whose property names are link relation types (as defined by RFC5988) and values are either a Resource Object or an array of Resource Objects.
In fact, looking for the word array in the HAL spec, only leads you to section quoted above, and the _links section.
Hence, _embedded is the proper place to render an array of resources in HAL.

Error in Google SDTT: "A value for the valueName field is required"

I’m implementing Schema.org + JSON-LD for my site and trying to add the following in all pages of the site:
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "WebSite",
"url": "http://example.com/",
"potentialAction": {
"#type": "SearchAction",
"target": "http://example.com/search?&q={query}",
"query-input": "required",
"valueName":""
}
}
</script>
I tried to provide multiple values for valueName, but still Google Structured Data Testing Tool reports this as an error.
What is a valid value for valueName?
You can either provide a string value for query-input, in which case you have to specify the part of the target value that represents the placeholder ("query" in your case), prefixed by "required name=" (no space characters):
"target": "http://example.com/search?&q={query}",
"query-input": "required name=query",
Or you can provide a PropertyValueSpecification item value for query-input, in which case you can use valueName and valueRequired explicitly:
"target": "http://example.com/search?&q={query}",
"query-input": {
"#type": "PropertyValueSpecification",
"valueName": "query",
"valueRequired": true
}
In Sitelinks Searchbox, Google only documents the first way. The second way is what their testing tool parses when using the first way.

Is html form requried when using Google Sitelinks Searchbox

I am trying to implement Google sitelink on a website. I read Error: Page contains property "query-input" which is not part of the schema and few other articles.
I am using JSON LD format. Here is what it looks like...
[{
"#context" : "https://schema.org",
"#type" : "Organization",
"name" : "yrshaikh.com",
"url" : "https://www.yrshaikh.com/",
"logo" : "https://yrshaikh.com/smile.png",
"sameAs" : [
"https://www.facebook.com/yrshaikh",
"https://www.instagram.com/yrshaikh/",
"https://www.pinterest.com/yrshaikhdotcom/",
"https://www.youtube.com/user/yrshaikh",
"https://twitter.com/yrshaikh",
"https://plus.google.com/+yrshaikh",
"https://www.linkedin.com/company/yrshaikh",
"https://en.wikipedia.org/wiki/yrshaikh.com"
]
},
{
"#context":"https://schema.org",
"#type":"WebSite",
"name":"yrshaikh",
"alternateName":"yrshaikh.com",
"url":"https://www.yrshaikh.com/",
"potentialAction":{
"#type":"SearchAction",
"target":"https://www.yrshaikh.com/search.html?text={search_term_string}&pop=1766357",
"query-input":"required name=search_term_string"
}
}]
(pls ignore the domain name, have replaced the actual one with a dummy domain one - yrshaikh.com)
I do not have any <form> tag on my homepage.
When I search for my domain on Google I do see a Sitelinks Searchbox, but when I enter a search term and search, it does not redirect to my target url with the search term, instead it searches in Google by whatever-search-term site:yrshaikh.com.
I have also tested my JSON LD on Google's Structured Data Testing Tool and it looks good to me, no errors/warnings.
Also another point worth noting is that this search url is internally redirected to a different route based on the incoming keyword.
Please advice.
With an array of objects. Seems like the way to go forward can be this
(i.e. using #graph instead of a normal json array):
Can you try and check for your website?
source references: https://webmasters.stackexchange.com/a/90319, https://stackoverflow.com/a/33457312/1670511
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#graph":
[
{
"#type": "WebSite"
},
{
"#type": "Organization"
}
]
}
</script>

RESTful master/detail

Having 3 dropdown pickers in a web application. The web application uses a Restful service to populate pickers data.
The two first pickers get their values from something like /years and /colors. The third one should get its values depending on the settings of the two.
So it could be something like /models?year=1&color=red.
The question is, how to make this HATEOAS-compliant (so that the dev does not have to know the way he should create an url to get the models).
The root / gets me a number of links, such as:
{
"_links": {
"colors": "/colors",
"years": "/years",
"models": "???" }
}
What should be instead of ???? If there was some kind of template /models?color={color}&year={year}, the dev would have to create the url. Is this OK?
Or there could be a link to list of years on each color got from /colors and then a link to list of models on each year got from /years?color=red, but i'd have to first choose color, then populate years and then populate models. Any idea if i want to have the model dependent on both color and year, not just the year populated from color?
Is it even possible in this situation to make it hateoas-compliant?
I have not heard of HATEOAS before, but based on what I just read about it, it seems that it supposed to return links to where the consumer of the service can go forward in the "state machine".
In your case that would translate to the links being "function calls". The first two (/colors and /years) are functions that take no parameters (and return "something" at this point), while the third is a function call that takes two parameters: one that is a representation of a color, the other a year. For the first two having a simple URL will suffice for the link, but for the third, you need to include the parameter name/type information as well. Something like:
{
"_links": {
"colors": "/colors",
"years": "/years",
"models": {
"url": "/models",
"param1": {"color"}
"param2": {"year"}
}
}
}
Note: you can use the same layout as "models" for "colors" and "years" as well.
At this point the client knows what the URL to access the functions are and what the parameter (if any) names are to be passed to the function.
One more thing is missing: types. Although you could just use "string", it will not be obvious that the "color" parameter is actually a value from what "/colors" returns. You can be introducing a "type" Color that describes a color (and any functions that operate on a color: give a displayable name, HTML color code, etc.)
The "beefed up" signature becomes:
{
"_links": {
"colors": {
"url": "/colors",
"return": "/type/List?type=/type/Color"
},
"years": {
"url": "/years",
"return": "/type/List?type=/type/Integer"
},
"models": {
"url": "/models",
"param1": {
"name": "color",
"type": "/type/Color"
},
"param2": {
"name": "year",
"type": "/type/Integer"
}
"return": "/type/List?type=/type/Model"
}
}
}
Note: the path "/type" is used just to separate the types from functions, but is not necessary.
This will interchangeably and discoverably describe the functions, what parameters they take, and what values they are returning, so you can use the right value at the right place.
Of course implementing this on the service end will not be easy (especially with parameterized types, like "/type/List" -- think Generics in Java or templates in C++), but this is the most "safe" and "portable" way you can describe your interface to your clients.