{"id":1833,"date":"2016-05-30T00:00:00","date_gmt":"2016-05-29T22:00:00","guid":{"rendered":"https:\/\/wwwneu.strehle.de\/tim\/weblog\/archives\/2016\/05\/30\/1593-2\/"},"modified":"2025-07-31T21:57:14","modified_gmt":"2025-07-31T19:57:14","slug":"1593-2","status":"publish","type":"post","link":"https:\/\/www.strehle.de\/tim\/weblog\/archives\/2016\/05\/30\/1593-2\/","title":{"rendered":"Where do I put search result context in schema.org?"},"content":{"rendered":"\n<p>I\u2019ve been advocating <a href=\"\/tim\/weblog\/archives\/2015\/05\/08\/1762\">schema.org for DAM interoperability<\/a> for a while now, but mostly from a theoretical perspective \u2013 I didn\u2019t have any implementation experience to back my claims up. This is supposed to change now as we\u2019re trying to base parts of our new DAM UI on the <a href=\"https:\/\/schema.org\/\">schema.org<\/a> vocabulary.<\/p>\n\n\n\n<p>But of course, where the rubber meets the road, there\u2019s unexpected challenges. I had already figured out how to express <a href=\"\/tim\/weblog\/archives\/2015\/12\/04\/1577\">core asset data using schema.org<\/a>, but a real DAM UI\u2019s central aspect is search. And searches don\u2019t just consist of the found objects\u2019 data, but also of context and controls (to borrow a phrase from Ruben Verborgh\u2019s excellent <a href=\"http:\/\/ruben.verborgh.org\/blog\/2015\/10\/06\/turtles-all-the-way-down\/\">Turtles all the way down<\/a>).<\/p>\n\n\n\n<p>Here\u2019s some things I need to know to render a good search UI (along with related <a href=\"http:\/\/www.opensearch.org\/Specifications\/OpenSearch\/1.1\">OpenSearch<\/a> and <a href=\"http:\/\/www.hydra-cg.com\/spec\/latest\/core\/\">Hydra<\/a> property names where available):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>total number of results (<code>opensearch:totalResults<\/code>, <code>hydra:totalItems<\/code>)<\/li>\n\n\n\n<li>pagination info: page size (<code>opensearch:itemsPerPage<\/code>), current page number (<code>opensearch:startIndex<\/code>), links to first, previous, next, and last page (<code>hydra:first<\/code>, <code>hydra:previous<\/code>, <code>hydra:next<\/code>, <code>hydra:last<\/code>)<\/li>\n\n\n\n<li>human-readable search description of the submitted search criteria; for example: <em>&#8218;peppa pig&#8216; in Books, date published: 2016<\/em><br><\/li>\n\n\n\n<li>links (with labels) to related searches: <em>Did you mean: \u2026<\/em> or <em>See also: \u2026<\/em><br><\/li>\n\n\n\n<li>data for filters \/ <a href=\"http:\/\/alistapart.com\/article\/design-patterns-faceted-navigation\">faceted navigation<\/a>: available attributes and their values with labels, counts and links<\/li>\n<\/ul>\n\n\n\n<p>The problem starts with me not knowing where to put this search result metadata in a valid schema.org response. (I\u2019ve asked on <a href=\"https:\/\/lists.w3.org\/Archives\/Public\/public-schemaorg\/2016May\/0064.html\">public-schemaorg@w3.org<\/a> and <a href=\"https:\/\/www.linkedin.com\/groups\/4201699\/4201699-6141131688157147137\">LinkedIn<\/a> already, no replies so far.)<\/p>\n\n\n\n<p><em>Update:<\/em> I did get helpful replies, see the bottom of this post for the final version.<\/p>\n\n\n\n<p>schema.org has a pretty clever concept, the <a href=\"https:\/\/schema.org\/SearchAction\">SearchAction<\/a>, and it seems you can stuff search results into its <a href=\"https:\/\/schema.org\/result\">result<\/a> property in JSON-LD syntax like this (I\u2019m not 100% sure it\u2019s okay to have <code>result<\/code> point to multiple things; haven\u2019t found a schema.org validator yet):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"@context\": \"http:\/\/schema.org\",\n  \"@type\": \"SearchAction\",\n  \"actionStatus\": \"CompletedActionStatus\",\n  \"query\": \"john doe\",\n  \"result\": &#91;\n    {\n      \"@type\": \"ImageObject\",\n      \"name\": \"Photo of Jane Doe\"\n    },\n    {\n      \"@type\": \"ImageObject\",\n      \"name\": \"Photo of John Doe\"\n    }\n  ]\n}\n<\/code><\/pre>\n\n\n\n<p>schema.org actions can have \u201coutput constraints\u201d (see <a href=\"http:\/\/schema.org\/docs\/actions.html\">Potential Actions<\/a>) but as far as I can see, they only specify the properties returned for resulting objects, not additional metadata.<\/p>\n\n\n\n<p>My best guess so far is something like this (not including the faceted navigation data):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"@context\":\n  {\n     \"@vocab\": \"http:\/\/schema.org\/\",\n     \"opensearch\": \"http:\/\/a9.com\/-\/spec\/opensearch\/1.1\/\"\n  },\n  \"@type\": \"SearchAction\",\n  \"actionStatus\": \"CompletedActionStatus\",\n  \"query\": \"john doe\",\n  \"description\": \"'john doe' in 'Images'\",\n  \"potentialAction\": \n  &#91;\n    {\n      \"@type\": \"SearchAction\",\n      \"name\": \"Did you mean 'jane doe'?\",\n      \"target\": \"http:\/\/example.com\/?q=jane+doe\"\n    },\n    {\n      \"@type\": \"SearchAction\",\n      \"name\": \"See also: 'dole'\",\n      \"target\": \"http:\/\/example.com\/?q=dole\"\n    },\n    {\n      \"@type\": \"SearchAction\",\n      \"name\": \"next\",\n      \"target\": \"http:\/\/example.com\/?q=john+doe&amp;p=2\"\n    }\n  ],\n  \"opensearch:totalResults\": 35,\n  \"opensearch:startIndex\": 1,\n  \"opensearch:itemsPerPage\": 2,\n  \"result\": \n  &#91;\n    {\n      \"@type\": \"ImageObject\",\n      \"name\": \"Photo of Jane Doe\"\n    },\n    {\n      \"@type\": \"ImageObject\",\n      \"name\": \"Photo of John Doe\"\n    }\n  ]\n}\n<\/code><\/pre>\n\n\n\n<p>Does that make sense to you? (The <code>potentialAction<\/code> names aren\u2019t suitable for machine interpretation yet.) Any help is appreciated!<\/p>\n\n\n\n<p>P.S.: What\u2019s the difference between <a href=\"http:\/\/schema.org\/SearchAction\">SearchAction<\/a> and <a href=\"http:\/\/schema.org\/FindAction\">FindAction<\/a>? Am I supposed to use the latter for search results?<\/p>\n\n\n\n<p><em>Update:<\/em> <a href=\"https:\/\/twitter.com\/jarnovandriel\">Jarno van Driel<\/a> proposed using <a href=\"http:\/\/schema.org\/ItemList\">ItemList<\/a> (which has a numberOfItems property) in <a href=\"https:\/\/lists.w3.org\/Archives\/Public\/public-schemaorg\/2016May\/0069.html\">his mailing list reply<\/a>, and a <a href=\"https:\/\/lists.w3.org\/Archives\/Public\/public-schemaorg\/2016May\/0071.html\">follow-up<\/a>. Thanks! I\u2019ll use this approach then (sadly, the <a href=\"https:\/\/schema.org\/itemListElement\">itemListElement<\/a> requires wrapping items in an additional ListItem for ordered lists):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"@context\":\n  {\n     \"@vocab\": \"http:\/\/schema.org\/\",\n     \"opensearch\": \"http:\/\/a9.com\/-\/spec\/opensearch\/1.1\/\"\n  },\n  \"@type\": \"SearchAction\",\n  \"actionStatus\": \"CompletedActionStatus\",\n  \"query\": \"john doe\",\n  \"description\": \"'john doe' in 'Images'\",\n  \"potentialAction\": \n  &#91;\n    {\n      \"@type\": \"SearchAction\",\n      \"name\": \"Did you mean 'jane doe'?\",\n      \"target\": \"http:\/\/example.com\/?q=jane+doe\"\n    },\n    {\n      \"@type\": \"SearchAction\",\n      \"name\": \"See also: 'dole'\",\n      \"target\": \"http:\/\/example.com\/?q=dole\"\n    },\n    {\n      \"@type\": \"SearchAction\",\n      \"name\": \"next\",\n      \"target\": \"http:\/\/example.com\/?q=john+doe&amp;p=2\"\n    }\n  ],\n  \"result\": \n  {\n    \"@type\": \"ItemList\",\n    \"numberOfItems\": 35,\n    \"opensearch:startIndex\": 1,\n    \"opensearch:itemsPerPage\": 2,\n    \"itemListElement\":\n    &#91;\n      {\n        \"@type\": \"ListItem\",\n        \"position\": 1,\n        \"item\":\n        {\n          \"@type\": \"ImageObject\",\n          \"name\": \"Photo of Jane Doe\"\n        }\n      },\n      {\n        \"@type\": \"ListItem\",\n        \"position\": 2,\n        \"item\":\n        {\n          \"@type\": \"ImageObject\",\n          \"name\": \"Photo of John Doe\"\n        }\n      }\n    ]\n  }\n}\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I\u2019ve been advocating schema.org for DAM interoperability for a while now, but mostly from a theoretical perspective \u2013 I didn\u2019t have any implementation experience to back my claims up. This is supposed to change now as we\u2019re trying to base parts of our new DAM UI on the schema.org vocabulary. But of course, where the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_share_on_mastodon":"0"},"categories":[1],"tags":[],"class_list":["post-1833","post","type-post","status-publish","format-standard","hentry","category-weblog"],"share_on_mastodon":{"url":"","error":""},"_links":{"self":[{"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/posts\/1833","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/comments?post=1833"}],"version-history":[{"count":1,"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/posts\/1833\/revisions"}],"predecessor-version":[{"id":1911,"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/posts\/1833\/revisions\/1911"}],"wp:attachment":[{"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/media?parent=1833"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/categories?post=1833"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/tags?post=1833"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}