1

I'm working on website that displays hotels on a map. A user lands on a page associated with a place and we display a map of all the hotels in that place (e.g. Key West).

I'm trying to improve the schema.org markup that we use. Currently the bulk of the page is marked up as a place. We then include the map in that markup. Then within all that we have individual hotels. So our markup looks something like -

<div id="mainwrap" itemscope itemtype="http://schema.org/Place">
    <div id="map_canvas" style="height:100%;" itemprop="hasMap" itemscope itemtype="https://schema.org/Map"></div>
        <div itemscope itemtype="http://schema.org/Hotel">...</div>
        <div itemscope itemtype="http://schema.org/Hotel">...</div>
        <div itemscope itemtype="http://schema.org/Hotel">...</div>
    </div>
</div>

I think it would make more sense to mark everything up as a list of hotels using itemList. Then we can communicate how many hotels are in the list, how they're sorted, and even mark up some of the filter controls.

Is it possible to have overlapping schema? So for example, can I do something like this..

<div id="mainwrap" itemscope itemtype="http://schema.org/ItemList">
    <div itemProp="PotentialAction" class="filterWidget">...</div>
    <div itemProp="PotentialAction" class="sortWidget">...</div>
    <div itemscope itemtype="http://schema.org/Place">
        <div id="map_canvas" style="height:100%;" itemprop="hasMap" itemscope itemtype="https://schema.org/Map"></div>
            <div itemProp="itemListElement" itemtype="http://schema.org/ListItem" itemscope itemtype="http://schema.org/Hotel">...</div>
            <div itemProp="itemListElement" itemtype="http://schema.org/ListItem" itemscope itemtype="http://schema.org/Hotel">...</div>
            <div itemProp="itemListElement" itemtype="http://schema.org/ListItem" itemscope itemtype="http://schema.org/Hotel">...</div>
        </div>
    </div>
</div>

Also is there a good way to test some of this? The problem is it's a single page application and the testing tools need raw html (whilst the google bot will run js and render the dom).

Community
  • 1
  • 1
Aidan Ewen
  • 13,049
  • 8
  • 63
  • 88
  • Note that it has to be `potentialAction` (with a lowercase *p*), not `PotentialAction`. – unor May 18 '16 at 23:32

2 Answers2

3

I would say the Map is not really useful as "parent" type for the Hotel items, which isn’t possible anyway with Schema.org, because Map does not define a property that could refer to Place items contained in the map.

The most basic structure would be a Place item (the main topic of the page) and several Hotel items associated with the containsPlace property. The Map is specified in addition.

<body itemscope itemtype="http://schema.org/WebPage">
  <section itemprop="mainEntity" itemscope itemtype="http://schema.org/Place">

    <div itemprop="hasMap" itemscope itemtype="http://schema.org/Map">
      …
    </div>

    <ul>
      <li itemprop="containsPlace" itemscope itemtype="http://schema.org/Hotel">…</li>
      <li itemprop="containsPlace" itemscope itemtype="http://schema.org/Hotel">…</li>
      <li itemprop="containsPlace" itemscope itemtype="http://schema.org/Hotel">…</li>
    </ul>

  </section>
</body>

If you want to use ItemList for the Hotel items, it gets more complex.

It’s then no longer possible to use containsPlace, because ItemList can’t have this property (well, actually it can, but it’s not expected). You could use the inverse property containedInPlace and reference the Place item, but in my example it wouldn’t be possible to use Microdata’s itemref attribute for this purpose (because the mainEntity property would be also added to Hotel, which is not an expected property).

The more powerful (but maybe less supported) alternative is to use Microdata’s itemid attribute. It’s used to specify URIs for items (these URIs don’t necessarily have to point to a page, they only serve as identifier; but it’s strongly recommended to serve the page that contains the Microdata about it). Each of your items could get a URI, and then you can use this URI as value for properties that would usually expect another item as value.

Taking my example from above, but now with itemid (for Place), ItemList, and containedInPlace:

<body itemscope itemtype="http://schema.org/WebPage">
  <section itemprop="mainEntity" itemscope itemtype="http://schema.org/Place" itemid="#thing">

    <div itemprop="hasMap" itemscope itemtype="http://schema.org/Map">
      …
    </div>

    <!-- note that this list doesn’t have to be a child of the <section> element -->
    <ul itemscope itemtype="http://schema.org/ItemList">

      <li itemprop="itemListElement" itemscope itemtype="http://schema.org/Hotel">
        <link itemprop="containedInPlace" href="#thing" />
      </li>

      <li itemprop="itemListElement" itemscope itemtype="http://schema.org/Hotel">
        <link itemprop="containedInPlace" href="#thing" />
      </li>

      <li itemprop="itemListElement" itemscope itemtype="http://schema.org/Hotel">
        <link itemprop="containedInPlace" href="#thing" />
      </li>

    </ul>

  </section>
</body>

About itemid and the URI value

Let’s say the page about this Place has the URL http://example.com/places/amsterdam. As the itemid value is #thing, the full URI would be http://example.com/places/amsterdam#thing.

Whenever you refer to this Place on another page, you can use http://example.com/places/amsterdam#thing (and if you refer to it on the same page, you could use the full URI, too, or again #thing). This has the benefit that you don’t have to repeat data (you can refer to its "canonical" location where everything is specified), but it has the drawback that consumers have to visit another page (but hey, it’s their job).

To differentiate between /places/amsterdam, for the page, and /places/amsterdam#thing, for the place, can be important in the Semantic Web / Linked Data world – more details in my answer to the question Best practices for adding semantics to a website.

Community
  • 1
  • 1
unor
  • 92,415
  • 26
  • 211
  • 360
1

You are most of the way there by using an ID as an identifier.

For example, if you assign a unique ID to a hotel, you can use that ID in different structures, such as Place or ItemList.

You can test the structures on Google Structure Data Testing Tool (GSDTT): https://search.google.com/structured-data/testing-tool.

However, you'll need to fix your HTML in the top example as you have a dangling <div>.

Copy the completed structure above and paste it on GSDTT. The HTML page is not required; only the microdata structures.

Jay Gray
  • 1,706
  • 2
  • 20
  • 36