-
-
Save JakeLabate/b82b5e6eda165a902d1a7c93b04fb014 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// hotel framework | |
function HotelPack(hotel) { | |
// hotel variables | |
const hotelType = hotel.type || 'Hotel'; | |
const hotelId = id(hotelType, hotel.name); | |
const imageLicenseUrl = hotel.copyrightUrl || hotel.homepage; | |
// hotel amenities array | |
let amenities = []; | |
if (hotel.amenitiesArr) { | |
hotel.amenitiesArr.forEach(function (amenity) { | |
// hotel amenity image array | |
let amenityImage = []; | |
if (amenity.imageUrl) { | |
amenityImage = { | |
'@type': 'ImageObject', // https://schema.org/ImageObject | |
'@id': id('ImageObject', amenity.name), | |
'url': amenity.imageUrl, | |
'name': amenity.name, | |
'contentUrl': amenity.imageUrl, | |
'caption': amenity.name, | |
'license': imageLicenseUrl, | |
'acquireLicensePage': imageLicenseUrl, | |
'creditText': hotel.name, | |
'copyrightNotice': 'All right reserved', | |
'creator': { | |
'@type': 'Organization', // https://schema.org/Organization | |
'@id': hotelId, | |
}, | |
} | |
} | |
// if hotel amenity has a name | |
if (amenity.name) { | |
amenities.push({ | |
'@type': 'LocationFeatureSpecification', // https://schema.org/LocationFeatureSpecification | |
'@id': id('LocationFeatureSpecification', amenity.name), | |
'url': amenity.url || hotel.homepage, | |
'name': amenity.name, | |
'value': true, | |
'image': amenityImage || '', | |
}); | |
} | |
}); | |
} | |
// hotel room group array | |
let roomGroups = []; | |
if (hotel.roomGroupsArr) { | |
hotel.roomGroupsArr.forEach(function (room) { | |
roomGroups.push({ | |
'@type': 'QuantitativeValue', // https://schema.org/QuantitativeValue | |
'@id': id('QuantitativeValue', room.numberOfRooms + '-' + room.roomType), | |
'url': room.url || hotel.homepage, | |
'unitText': room.roomType, | |
'value': room.numberOfRooms, | |
}) | |
}); | |
} | |
// hotel images array | |
let images = []; | |
if (hotel.imageArr) { | |
hotel.imageArr.forEach(function (image) { | |
images.push({ | |
'@type': 'ImageObject', // https://schema.org/ImageObject | |
'@id': id('ImageObject', image.caption + '-' + (hotel.imageArr.indexOf(image) + 1)), | |
'url': image.url, | |
'contentUrl': image.url, | |
'name': image.caption, | |
'caption': image.caption, | |
'license': imageLicenseUrl, | |
'acquireLicensePage': imageLicenseUrl, | |
'creditText': hotel.name, | |
'copyrightNotice': 'All right reserved', | |
'creator': { | |
'@type': 'Organization', // https://schema.org/Organization | |
'@id': hotelId, | |
}, | |
}); | |
}); | |
} | |
// hotel rooms array | |
let rooms = []; | |
if (hotel.roomsArr) { | |
hotel.roomsArr.forEach(function (room) { | |
// set room variables | |
const capturedRoomType = room.type || 'HotelRoom'; // https://schema.org/HotelRoom | |
const effectiveRoomType = [capturedRoomType, 'Product']; // https://schema.org/HotelRoom + https://schema.org/Product | |
const roomId = id(capturedRoomType, room.name); | |
const roomUrl = room.url || hotel.homepage; | |
const petsBoolean = room.petsAllowedTrueOrFalse || hotel.petsAllowedTrueFalse; | |
// room amenities array | |
let roomAmenities = []; | |
if (room.roomAmenitiesArr) { | |
room.roomAmenitiesArr.forEach(function (roomAmenity) { | |
// room amenity variables | |
const imageLicenseUrl = hotel.copyrightUrl || hotel.homepage; | |
// room amenity image array | |
let roomAmenityImage = []; | |
if (roomAmenity.imageUrl) { | |
roomAmenityImage = { | |
'@type': 'ImageObject', // https://schema.org/ImageObject | |
'@id': id('ImageObject', roomAmenity.name), | |
'url': roomAmenity.imageUrl, | |
'name': roomAmenity.name, | |
'contentUrl': roomAmenity.imageUrl, | |
'caption': roomAmenity.name, | |
'license': imageLicenseUrl, | |
'acquireLicensePage': imageLicenseUrl, | |
'creditText': hotel.name, | |
'copyrightNotice': 'All right reserved', | |
'creator': { | |
'@type': 'Organization', // https://schema.org/Organization | |
'@id': hotelId, | |
}, | |
} | |
} | |
// if room amenity has a name | |
if (roomAmenity.name) { | |
roomAmenities.push({ | |
'@type': 'LocationFeatureSpecification', // https://schema.org/LocationFeatureSpecification | |
'@id': id('LocationFeatureSpecification', roomAmenity.name), | |
'url': roomAmenity.url || roomUrl, | |
'name': roomAmenity.name, | |
'value': true, | |
'image': roomAmenityImage, | |
}); | |
} | |
}); | |
} | |
// room images array | |
let roomImages = []; | |
if (room.images) { | |
room.images.forEach(function (image) { | |
// if image has a url | |
if (image.url) { | |
roomImages.push({ | |
'@type': 'ImageObject', // https://schema.org/ImageObject | |
'@id': id('ImageObject', image.caption + '-' + (images.indexOf(image) + 1)), | |
'url': image.url, | |
'name': image.caption, | |
'contentUrl': image.url, | |
'caption': image.caption, | |
'license': imageLicenseUrl, | |
'acquireLicensePage': imageLicenseUrl, | |
'creditText': hotel.name, | |
'copyrightNotice': 'All right reserved', | |
'creator': { | |
'@type': 'Organization', // https://schema.org/Organization | |
'@id': hotelId, | |
}, | |
}); | |
} | |
}); | |
} | |
// push each room | |
rooms.push({ | |
'@type': effectiveRoomType, // https://schema.org/HotelRoom + https://schema.org/Product | |
'@id': roomId, | |
'url': roomUrl, | |
'name': room.name, | |
'smokingAllowed': room.smokingBoolean || false, | |
'tourBookingPage': room.tourUrl || roomUrl, | |
'description': room.description, | |
'aggregateRating': {'@id': id('AggregateRating', hotel.name)}, | |
'brand': {'@id': id('Brand', hotel.name)}, | |
'containedInPlace': {"@id": hotelId}, | |
'amenityFeature': roomAmenities || [], | |
'petsAllowed': petsBoolean || false, | |
'photo': roomImages[0] | [], | |
'image': roomImages || [], | |
'occupancy': { | |
'@type': 'QuantitativeValue', // https://schema.org/QuantitativeValue | |
'@id': id('QuantitativeValue', name + '_occupancy'), | |
'url': roomUrl, | |
'name': 'Number of occupants', | |
'minValue': 1, | |
'maxValue': room.maxOccupancy, | |
}, | |
'bed': { | |
'@type': 'BedDetails', // https://schema.org/BedDetails | |
'@id': id('BedDetails', name + '_bed'), | |
'url': roomUrl, | |
'numberOfBeds': room.bedCount, | |
'typeOfBed': { | |
'@type': 'BedType', // https://schema.org/BedType | |
'@id': id('BedType', name + '_bedType-' + room.bedType), | |
'url': roomUrl, | |
'name': room.bedType, | |
}, | |
}, | |
'offers': { | |
'@type': 'Offer', // https://schema.org/Offer | |
'@id': id('Offer', room.name + '_offer'), | |
'url': roomUrl, | |
'name': room.name + ' offer', | |
'businessFunction': 'http://purl.org/goodrelations/v1#LeaseOut', | |
'availability': 'https://schema.org/InStock', // auditable | |
'priceValidUntil': new Date().toISOString().split('T')[0], // auditable | |
'hasMerchantReturnPolicy': { | |
'@type': 'MerchantReturnPolicy', // https://schema.org/MerchantReturnPolicy | |
'@id': id('MerchantReturnPolicy', room.name + '_returnPolicy'), | |
'url': roomUrl, | |
'name': hotel.name + ' ' + room.name + ' return policy', | |
'applicableCountry': hotel.location.country || 'USA', | |
'returnPolicyCountry': hotel.location.country || 'USA', | |
'returnPolicyCategory': 'MerchantReturnFiniteReturnWindow', // https://schema.org/MerchantReturnEnumeration | |
}, | |
'priceSpecification': { | |
'@type': 'UnitPriceSpecification', // https://schema.org/UnitPriceSpecification | |
'@id': id('UnitPriceSpecification', room.name), | |
'url': roomUrl, | |
'name': room.name + ' pricing', | |
'priceCurrency': 'USD', | |
'unitCode': 'DAY', | |
// 'minPrice': room.minPrice, | |
// 'price': room.minPrice || room.defaultPrice || room.maxPrice, // auditable | |
// 'maxPrice': room.maxPrice, | |
} | |
}, | |
'potentialAction': { | |
'@type': 'ReserveAction', // https://schema.org/ReserveAction | |
'@id': id('ReserveAction', room.name), | |
'url': roomUrl, | |
'name': 'Reserve', | |
'scheduledTime': room.checkInTime || hotel.checkInTime, | |
'startTime': room.checkInTime || hotel.checkInTime, | |
'provider': {"@id": hotelId}, | |
"target": room.bookUrl, | |
"object": { | |
'@type': 'LodgingReservation', // https://schema.org/LodgingReservation | |
'@id': id('LodgingReservation', room.name), | |
'url': room.bookUrl || roomUrl, | |
'name': room.name + ' reservation', | |
'mainEntityOfPage': room.url, | |
'checkinTime': room.checkInTime || hotel.checkInTime, | |
'checkoutTime': room.checkOutTime || hotel.checkOutTime, | |
'lodgingUnitDescription': room.description, | |
'lodgingUnitType': room.bedCount + ' total beds', | |
'provider': {"@id": hotelId}, | |
'reservationFor': {"@id": roomId}, | |
'subjectOf': room.bookUrl, | |
// 'totalPrice': '', | |
'potentialAction': { | |
'@type': 'ReserveAction', // https://schema.org/ReserveAction | |
'@id': id('ReserveAction', room.name), | |
'url': room.bookUrl || roomUrl, | |
'name': 'Reserve', | |
}, | |
}, | |
} | |
}) | |
}); | |
} | |
// page template | |
const schema = { | |
'@context': 'https://schema.org', | |
'@graph': [ | |
// WebSite | |
{ | |
"@type": "WebSite", // https://schema.org/WebSite | |
"@id": id('WebSite', hotel.name), | |
"url": hotel.homepage, | |
"name": hotel.name, | |
}, | |
// LodgingBusiness | |
{ | |
'@type': hotelType || 'Hotel', // https://schema.org/LodgingBusiness or a subtype | |
'@id': hotelId, | |
'url': hotel.homepage, | |
'name': hotel.name, | |
'description': hotel.description, | |
'checkinTime': hotel.checkInTime, | |
'checkoutTime': hotel.checkOutTime, | |
'petsAllowed': hotel.petsAllowedTrueFalse, | |
"sameAs": [hotel.facebookUrl, hotel.instagramUrl, hotel.twitterUrl, hotel.linkedinUrl], | |
'currenciesAccepted': hotel.currenciesAccepted, | |
'openingHours': hotel.openingHours, | |
'paymentAccepted': hotel.paymentAccepted, | |
'availableLanguage': hotel.availableLanguage, | |
'priceRange': hotel.priceRange, | |
'logo': {"@id": id('ImageObject', hotel.name + '#logo')}, | |
'image': images || {"@id": id('ImageObject', hotel.name + '#logo')}, | |
'containsPlace': rooms, | |
'amenityFeature': amenities, | |
'numberOfRooms': roomGroups || hotel.totalRoomCount, | |
"brand": { | |
"@type": "Brand", // https://schema.org/Brand | |
"@id": id('Brand', hotel.name), | |
"url": hotel.homepage, | |
"name": hotel.name, | |
"slogan": hotel.slogan, | |
}, | |
'starRating': { | |
'@type': 'Rating', // https://schema.org/Rating | |
'@id': id('Rating', hotel.name), | |
'url': hotel.homepage, | |
'name': hotel.name + ' Star Rating', | |
'ratingValue': hotel.rating.value, | |
}, | |
'address': { | |
'@type': 'PostalAddress', // https://schema.org/PostalAddress | |
'@id': id('PostalAddress', hotel.name + hotel.location.street), | |
'name': hotel.name, | |
'streetAddress': hotel.location.street, | |
'addressLocality': hotel.location.city, | |
'addressRegion': hotel.location.state, | |
'postalCode': hotel.location.state, | |
'addressCountry': hotel.location.country, | |
'telephone': hotel.contact.phone, | |
'email': hotel.contact.email, | |
}, | |
}, | |
// ImageObject (logo) | |
{ | |
"@type": "ImageObject", // https://schema.org/ImageObject | |
"@id": id('ImageObject', hotel.name + '#logo'), | |
"url": hotel.logoUrl, | |
"contentUrl": hotel.logoUrl, | |
"name": hotel.name + " logo", | |
"caption": hotel.name + " logo", | |
"copyrightNotice": "All rights reserved | " + hotel.name, | |
"creditText": hotel.name, | |
'license': hotel.copyrightUrl || hotel.homepage, | |
'acquireLicensePage': hotel.copyrightUrl || hotel.homepage, | |
"creator": { | |
'@type': 'Organization', // https://schema.org/Organization | |
'@id': hotelId, | |
}, | |
}, | |
], | |
} | |
// WebPage + BreadcrumbList | |
if (hotel.page.name && hotel.page.url) { | |
schema['@graph'].push([ | |
// WebPage | |
{ | |
"@type": "WebPage", // https://schema.org/WebPage | |
"@id": id('WebPage', hotel.name), | |
"url": hotel.page.url, | |
"name": hotel.page.name, | |
"about": {"@id": hotelId}, | |
"isPartOf": {"@id": id('WebSite', hotel.name)}, | |
"breadcrumb": {"@id": id('BreadcrumbList', hotel.name)}, | |
"speakable": { | |
"@type": "SpeakableSpecification", // https://schema.org/SpeakableSpecification | |
"@id": id('SpeakableSpecification', hotel.name), | |
"url": hotel.page.url, | |
"xPath": [ | |
"/html/head/title", | |
"/html/head/meta[@name='description']/@content" | |
] | |
} | |
}, | |
// BreadcrumbList | |
{ | |
"@type": "BreadcrumbList", // https://schema.org/BreadcrumbList | |
"@id": id('BreadcrumbList', hotel.name), | |
"url": hotel.page.url, | |
"name": hotel.page.name, | |
"itemListElement": [{ | |
"@type": "ListItem", // https://schema.org/ListItem | |
"@id": id('ListItem', hotel.name + '#breadcrumbListItem'), | |
"url": hotel.page.url, | |
"name": hotel.page.name, | |
"position": 1, | |
"item": hotel.page.url, | |
}] | |
} | |
]) | |
} | |
// AggregateRating | |
if (hotel.page.url && hotel.rating.count && hotel.rating.value) { | |
schema['@graph'].push({ | |
// AggregateRating (Hotel) | |
"@type": "AggregateRating", // https://schema.org/AggregateRating | |
"@id": id('AggregateRating', hotel.name), | |
"url": hotel.page.url, | |
"name": hotel.name + " Aggregate Rating", | |
"ratingCount": hotel.rating.count, | |
"ratingValue": hotel.rating.value, | |
"bestRating": 5, // seems safe enough to use static value of 5 | |
"itemReviewed": { | |
"@type": "Product", // https://schema.org/Product | |
"@id": id('Product', hotel.name + '-' + hotel.page.url), | |
"url": hotel.page.url, | |
"name": hotel.name, | |
"aggregateRating": { | |
"@type": "AggregateRating", // https://schema.org/AggregateRating | |
"@id": id('AggregateRating', hotel.name), | |
"url": hotel.page.url, | |
"name": hotel.name + " Aggregate Rating", | |
"ratingCount": hotel.rating.count, | |
"ratingValue": hotel.rating.value, | |
"bestRating": 5 // seems safe enough to use static value of 5 | |
}, | |
"offers": { | |
"@type": "AggregateOffer", // https://schema.org/AggregateOffer | |
"@id": id('AggregateOffer', hotel.name), | |
"url": hotel.page.url, | |
"priceCurrency": "USD" | |
// "lowPrice": hotel.lowestPrice, | |
// "highPrice": hotel.highestPrice, | |
} | |
} | |
}) | |
} | |
// VideoObject | |
if (hotel.page.video) { | |
if (hotel.page.video.thumbnailUrl && hotel.page.video.uploadDateISO && (hotel.page.video.contentUrl || hotel.page.video.embedUrl)) { | |
schema['@graph'].push({ | |
"@type": "VideoObject", // https://schema.org/VideoObject | |
"@id": id('VideoObject', hotel.name), | |
"url": hotel.page.url, | |
"name": hotel.page.video.name, | |
"description": hotel.page.video.description, | |
"thumbnailUrl": hotel.page.video.thumbnailUrl, | |
"uploadDate": hotel.page.video.uploadDateISO, | |
"duration": "PT" + hotel.page.video.duration.min + "M" + hotel.page.video.duration.sec + "S", | |
"contentUrl": hotel.page.video.contentUrl, | |
"embedUrl": hotel.page.video.embedUrl, | |
"regionsAllowed": "US,NL" | |
}) | |
} | |
} | |
// return schema | |
return schema; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment