Implementing multiple images in Article structured-data type - schema.org

For example, there is a news article with 3 images. The first one — main picture, the other two — photos from social network.
I want: 1) define the first picture as main image. This one search engines should use for rich results.
2) Define other 2 images as related to the news topic.
#1 All images goes to Article.image property.
<html>
<head>
<title>Article headline</title>
<script type="application/ld+json">
{
"#context": "https://schema.org",
"#type": "NewsArticle",
"headline": "Article headline",
"image": [
"https://example.com/photos/photo1x1.jpg",
"https://example.com/photos/photo4x3.jpg",
"https://example.com/photos/photo16x9.jpg",
"https://example.com/photos/2.jpg",
"https://example.com/photos/3.jpg"
],
"datePublished": "2015-02-05T08:00:00+08:00",
"dateModified": "2015-02-05T09:20:00+08:00"
}
</script>
</head>
<body>
</body>
</html>
#2 Only first image goes to Article.image property, other two — Article.hasPart.
<html>
<head>
<title>Article headline</title>
<script type="application/ld+json">
{
"#context": "https://schema.org",
"#type": "NewsArticle",
"headline": "Article headline",
"image": [
"https://example.com/photos/photo1x1.jpg",
"https://example.com/photos/photo4x3.jpg",
"https://example.com/photos/photo16x9.jpg"
],
"datePublished": "2015-02-05T08:00:00+08:00",
"dateModified": "2015-02-05T09:20:00+08:00",
"hasPart": [
{
"#type": "ImageObject",
"url": "https://example.com/photos/2.jpg"
},
{
"#type": "ImageObject",
"url": "https://example.com/photos/3.jpg"
}
]
}
</script>
</head>
<body>
</body>
</html>
Which one is more correct?

Define other 2 images as related to the news topic.
Structured Data is highly dependent on the content of the linked web page. If we assume that your web page has the appropriate structure for three images, then, in this case, using the property about or subjectOf can help you. Embed a type that is most appropriate for the sub-subject. And for this type, set a separate image property. This can create rich results that present images for the subject of the entire article and images for sub-subjects of the same article. However, structured data depends on the details.

Related

Vector tiles are showing in the wrong place and in the wrong scale in esri-leaflet-vector plugin

I'm using esri-leaflet#3.0.0 and leaflet 1.7.1 and esri-leaflet-vector plugin.
When I'm adding VectorTileServer layer, rendered tiles are showing in the wrong place and in the wrong scale. Where I doing wrong?
VectorTileServer is published in Web Mercator "spatialReference":{"wkid":102100,"latestWkid":3857}.
Taka a look on the Norway.
it is shown in the wrong place and in the wrong scale?
const map = L.map('map').setView([50, 18], 3);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
L.esri.Vector.vectorTileLayer("https://services.geodataonline.no/arcgis/rest/services/GeocacheVector/GeocacheGraatone_WM/VectorTileServer", {
style: (style) => {
style.layers.forEach(function (layer) {
if (layer.layout['text-rotate']) {
layer.layout['text-rotate'].stops = [[0, 0]]
}
});
return style
}
}
).addTo(map);
body { margin:0; padding:0; }
#map {
position: absolute;
top:0;
bottom:0;
right:0;
left:0;
font-family: Arial, Helvetica, sans-serif;
font-size: 14px;
color: #323232;
}
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Esri Leaflet</title>
<!-- Load Leaflet from CDN -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""></script>
<!-- Load Esri Leaflet from CDN -->
<script src="https://unpkg.com/esri-leaflet#3.0.0/dist/esri-leaflet.js"></script>
<script src="https://unpkg.com/esri-leaflet-vector#3.0.0/dist/esri-leaflet-vector.js"></script>
</head>
<body>
<div id="map"></div>
</body>
</html>
Anyone can help ?
Regards
Mik
One thing I noticed with this layer you're using is that the scale properties of each zoom level seem to be off. From the esri-leaflet docs
Your map service must be published using the and the default scale options used by Google Maps, Bing Maps and ArcGIS Online. Esri Leaflet will not support any other spatial reference for tile layers.
If you go to arcgis's sample tutorial for vector tile layers, they have a sample example with a sample vector tile layer there: Santa Monica Mountain Parcels. If you open up that tile server url, you'll see the JSON with property lods:
"lods": [
{
"level": 0,
"resolution": 78271.51696399994,
"scale": 295828763.795777
},
{
"level": 1,
"resolution": 39135.7584820001,
"scale": 147914381.897889
},
{
"level": 2,
"resolution": 19567.87924099992,
"scale": 73957190.948944
},
...
}
I'm going to assume that these are the default scales accepted by esri-leaflet, considering these are the ones used in their sample vector tile layer. They're also listed here: What ratio scales do Google Maps zoom levels correspond to?
If you open up the tile server url for the layer you're trying to use for norway, you'll see the same, but the scale numbers seem to be off by one zoom level:
"lods": [
{
"level": 0,
"resolution": 156543.03392800014,
"scale": 591396864
},
{
"level": 1,
"resolution": 78271.51696399994
"scale": 295698432,
},
{
"level": 2,
"resolution": 39135.75848200009,
"scale": 147849216
},
...
This is why your norway layer is wrong, but at least is consistently wrong across all zoom layers (meaning it always shows up in the same, wrong spot, at half the size it should be).
If you have any control over / connection with the people who server that layer, I'd let them know their zoom levels are wrong.
In the meantime, there may be a way to override the JSON that esri-leaflet is using when loading that layer, but it would be a lot of work of digging into their source code, and very hacky.

Schema Markup : Using Service and Webpage Types on the Same Page

I have taken over the general administration of a business website. On the service pages, two separate instances of structured data are being loaded (the Service schema type, and the Webpage schema type).
<script type='application/ld+json'>
{
"#context": "http://schema.org/",
"#type": "Service",
"serviceType": "Service Type Here",
"alternateName": "Alternate Service Name Here",
"description": "Description Here",
"mainEntityOfPage": "https://www.WebsiteAddress.com/service-type",
"name": "Service Name"
}
</script>
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "WebPage",
"name": "Webpage Name",
"url": "https://www.WebsiteAddress.com/service-type",
"inLanguage":"en-US",
"description": "Description Here",
"publisher": {
"name": "Business Name"
}
}
</script>
Could the current setup cause conflicts with how search engines interpret the page?
As most of the tags are duplicates, would it make more sense to remove the Webpage type schema markup and add the brand tag into the Service schema?
Interested to hear opinions on this.
About your Q. The short answer is YES => It's ok to declare two types (-or- more) on the same page (No "one rule" her - it's related to page structure/content).
"duplication" -
First As most of the tags are duplicates is a wrong sentence (One time the name related to webPage object and one time for service object). If in your specific case "service name" = "page name" it's ok to use the same value (This is the true semantic meaning of your content).
WebPage & Service
WebPage is a special type:
Every web page is implicitly assumed to be declared to be of type
WebPage. https://schema.org/WebPage
If you look at this issue in the microdata approach it's easier to understand the structure/idea of the sentence above.
a.The webpage (Again - Every page assumed to be of type WebPage):
<body itemscope="" itemtype="http://schema.org/WebPage">
<h1 itemprop="name">Our services</h1>
</body>
b.The service
<div itemscope itemtype="http://schema.org/TaxiService">
<h2 itemprop="name">Drive to airport</h2>
</div>
a & b - could look like this:
<body itemscope itemtype="http://schema.org/WebPage">
<h1 itemprop="name">Our services</h1>
<div itemscope itemtype="http://schema.org/TaxiService">
<h2 itemprop="name">Drive to airport</h2>
</div>
</body>
If page name = service name - you could do something like this:
<body itemscope itemtype="http://schema.org/WebPage">
<meta itemprop="name" content="Drive to airport">
<div itemscope itemtype="http://schema.org/TaxiService">
<h1 itemprop="name">Drive to airport</h1>
</div>
</body>
Nothing wrong her.
1/2. The page name is "Drive to airport" (true):
2/2. And the service name is "Drive to airport" (true):
If the service is the main entity of webPage this outline is a good start point (Close to your Q code example):
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "WebPage",
"name": "Our services",
"breadcrumb": "main > Our services",
"mainEntity":{
"#type": "service",
"name": "Drive to airport"
}
}
</script>

Is the homepage implied in [BreadcrumbList JSON LD + Schema.org]?

Looking at the examples Google provides here, the first breadcrumb seems to be already 1 level deep.
Am I correct to assume that the homepage is then determined to be the root domain? What if it's a subdomain?
The example code from the link above, quoted:
{
"#context": "https://schema.org",
"#type": "BreadcrumbList",
"itemListElement": [{
"#type": "ListItem",
"position": 1,
"name": "Books",
"item": "https://example.com/books"
},{
"#type": "ListItem",
"position": 2,
"name": "Authors",
"item": "https://example.com/books/authors"
},{
"#type": "ListItem",
"position": 3,
"name": "Ann Leckie",
"item": "https://example.com/books/authors/annleckie"
}]
}
under schema.org docs:
beginning with '1' for the first item in the list
https://schema.org/BreadcrumbList
No zero value (No way to declare "the zero item in the list").
This markup is ok/valid (In my list home = first item in the list):
home > blog
<ol itemscope itemtype="http://schema.org/BreadcrumbList">
<li itemprop="itemListElement" itemscope
itemtype="http://schema.org/ListItem">
<a itemprop="item" href="https://example.com/">
<span itemprop="name">Home</span></a>
<meta itemprop="position" content="1" />
</li>
<li itemprop="itemListElement" itemscope
itemtype="http://schema.org/ListItem">
<a itemprop="item" href="https://example.com/blog/">
<span itemprop="name">blog</span></a>
<meta itemprop="position" content="2" />
</li>
</ol>
SUM: Schema.org give semantic meaning for you content. Position 1 could be root-domain or sub-domain.
Rich Snippet:
Most of the times google omits "homepage" (name) from the snippet (Moz "real source code" example):
I think the best answer is to check how Google displays your page in the search results. The breadcrumb markup are suggestions for the way the url part of the search result is displayed.
I've seen markup including "home" page items causing poor looking results by showing "home" in the snippet.
While other times Google has understood that it should be ignored.
Safest bet, don't include the root. You also don't need to include the current page.

How to add control to items statically

Sometimes in an aggregation binding, I need to add some controls to the generated list of items statically. Is there some elegant solution for this?
Let's say I have a Select with the following code:
<Select width="100%"
items="{project>/Milestones}"
selectedKey="0"
>
<core:Item
key="{project>Id}"
text="{project>Name}"
/>
</Select>
Bound to a model with these data:
{
Milestones: [
{
"Id": 1,
"Name": "Cost Estimation 1",
"Description": "Initial cost estimation"
},
{
"Id": 2,
"Name": "Pid Packages",
"Description": "Ready for RFQs"
},
...
]
}
I want to add an item to the Select with key="0" and value="< Blank >" and have that stay there even when the content of project>/Milestones is changed, but I don't want to add it to the actual aggregation.
The solutions that I have at the moment seem really hackish and create problems later on: creating a new model (property) leads to having the data duplicated in multiple lists and therefor it will probably get out of sync at some point. I've also tried adding the static items through binding events, but this is somewhat error prone and very verbose.
Ok here the promised snippet. First of all, if you just want to add a "blank" item, I recommend you to use ComboBox instead of Select, because you can always delete your selection. I added it to the snippet as well.
But if you want to add an item, you just need to use the addItem() function described here
I also added a button to modify your model, so you can see how the '< Blank >' item remains there even when you change it.
Snippet
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta charset="utf-8">
<title>MVC with XmlView</title>
<!-- Load UI5, select "blue crystal" theme and the "sap.m" control library -->
<script id='sap-ui-bootstrap' src='https://sapui5.hana.ondemand.com/resources/sap-ui-core.js' data-sap-ui-theme='sap_belize_plus' data-sap-ui-libs='sap.m' data-sap-ui-xx-bindingSyntax='complex'></script>
<!-- DEFINE RE-USE COMPONENTS - NORMALLY DONE IN SEPARATE FILES -->
<script id="view1" type="sapui5/xmlview">
<mvc:View xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" controllerName="my.own.controller">
<Title text="With Select" class="sapUiMediumMarginTop"></Title>
<Select id="mySelect" width="100%" items="{ path: 'project>/Milestones', events:{ change: '.onSelectBindingChange' }, templateShareable: false}" selectedKey="0">
<core:Item key="{project>Id}" text="{project>Name}" />
</Select>
<Title text="With ComboBox" class="sapUiMediumMarginTop"></Title>
<ComboBox width="100%" items="{ path: 'project>/Milestones', templateShareable: false}" selectedKey="0">
<core:Item key="{project>Id}" text="{project>Name}" />
</ComboBox>
<Button text="Modify Model" press="onButtonPressed" class="sapUiLargeMarginTop sapUiLargeMarginBottom"></Button>
</mvc:View>
</script>
<script>
// define a new (simple) Controller type
sap.ui.controller("my.own.controller", {
onSelectBindingChange: function(oEvent) {
var oNewItem = new sap.ui.core.Item({
key: 0,
text: "< Blank >"
});
this.getView().byId("mySelect").addItem(oNewItem);
},
onButtonPressed: function(oEvent) {
var aMilestones = this.getView().getModel("project").getProperty("/Milestones");
aMilestones.push({
Id: 4,
Name: "New Milestone",
Description: "Just a model modification"
});
this.getView().getModel("project").setProperty("/Milestones", aMilestones);
}
});
/*** THIS IS THE "APPLICATION" CODE ***/
// create some dummy JSON data
var data = {
Milestones: [{
"Id": 1,
"Name": "Cost Estimation 1",
"Description": "Initial cost estimation",
},
{
"Id": 2,
"Name": "Pid Packages",
"Description": "Ready for RFQs",
},
{
"Id": 3,
"Name": "Certificate Check",
"Description": null,
}
]
};
var oJSONModel = new sap.ui.model.json.JSONModel();
oJSONModel.setData(data);
// instantiate the View
var myView = sap.ui.xmlview({
viewContent: jQuery('#view1').html()
}); // accessing the HTML inside the script tag above
myView.setModel(oJSONModel, "project");
// put the View onto the screen
myView.placeAt('content');
</script>
</head>
<body id='content' class='sapUiBody'>
</body>
</html>

Google Webmaster Tools: "There was an error parsing your JSON-LD."

I have just logged into Google Webmaster Tools and am finding an error in structured data relating to a new WordPress theme I am using:
JSON-LD: There was an error parsing your JSON-LD.
The code it is referring to is:
<meta property="og:site_name" content="Townsville Nerds - Ph 0402 807 890" />
<script type='application/ld+json'>
execOnReady(function({{"#context":"http:\/\/schema.org","#type":"WebSite","url":"http:\/\/www.townsvillenerds.com\/","name":"Townsville Nerds - Ph 0402 807 890"}})
</script>
NOTE: In Webmaster Tools there is a red underscore under the "e" in the word "execOnReady".
Your data block does not contain valid JSON-LD (application/ld+json).
Instead of
<script type='application/ld+json'>
execOnReady(function({{"#context":"http:\/\/schema.org","#type":"WebSite","url":"http:\/\/www.townsvillenerds.com\/","name":"Townsville Nerds - Ph 0402 807 890"}})
</script>
it should be
<script type='application/ld+json'>
{"#context":"http:\/\/schema.org","#type":"WebSite","url":"http:\/\/www.townsvillenerds.com\/","name":"Townsville Nerds - Ph 0402 807 890"}
</script>
I guess you don’t need to escape the /, so it could be:
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "WebSite",
"url": "http://www.townsvillenerds.com/",
"name": "Townsville Nerds - Ph 0402 807 890"
}
</script>