Skip to content

Social Media Cards

Tomos Hillman edited this page Dec 9, 2021 · 6 revisions

Social Media Cards

⚠️ WARNING
This page contains documentation for a feature in preparation for history.state.gov

Social Media Cards[^1] provide a way of controlling preview metadata for links shared on social media, including preview images, titles, and descriptions. This page described how hsg-project generates this metadata, and how that generation can be controlled, over-written, or extended.

[^1]: Sometimes referred by other names, such as "Social Previews" or "Social Media Previews"

About Social Media Cards and Open Graph

Social Media Cards are generated by social media sites such as Twitter and Facebook when links are shared. Linked pages can define images, link titles, descriptions and more by providing the relevant metadata properties as <meta/> elements in the HTML header.

Generally, this metadata conforms to the Open Graph Protocol, or is at least based on the same conventions[^2]; we will differentiate it from other types of metadata in this document as Open Graph metadata.

Open Graph metadata is normally provided as a meta element with a key defined by a CURIE[^3] as the @property and the value defined using @content:

<meta property="og:type" content="website"/>

[^2]: see "Twitter Cards and Open Graph" on Twitter's Getting Started documentation. [^3]: Compact URIs

Default HSG Open Graph metadata

Population

The HTML head element is generated for all hsg-project pages by the same site.xml template using exist-db's HTML templating module and resulting in a call to config:app-meta:

  <meta data-template="config:app-meta"/>

The config:app-meta function populates the Open Graph metadata using a set of strings representing the metadata CURIEs (by default the sequence in $config:OPEN_GRAPH_KEYS), and a mapping from CURIEs to functions (by default the map $config:OPEN_GRAPH).

The set of strings or open graph keys define which metadata properties are to be populated; the corresponding entries in the open graph map define the functions which do so. This allows for some flexibility in customising how the metadata is populated for a particular page.

og:type[^4]

One of the required Open Graph properties, the default value for hsg-project is website. Using other values may require additional properties to be defined.

<meta property="og:type" content="website"/>

twitter:card[^5]

This property is required by Twitter, and has the default value of summary. There should not be more than one twitter:card property per page, but if there is, the last will take priority.

<meta property="twitter:card" content="summary">

twitter:site[^5]

This property specifies the Twitter username of the website, @HistoryAtState.

<meta property="twitter:site" content="@HistoryAtState">

og:site_name[^4]

This property specifies the human readable name of the web site:

<meta property="og:site_name" content="Office of the Historian">

og:title[^4]

One of the required Open Graph properties, this is the title of the page or resource; for hsg-project, the title may come from a number of possible sources:

  • The static title of the page as defined by div[@id='static-title']
  • $config:PUBLICATIONS?publication-id?title
  • The first HTML heading on the page (h1|h2|h3)
  • The default fallback text of Office of the Historian
<meta property="og:title" content="Latest News">

og:description[^4]

A one to two sentence description of the object. The default value is currently hard-coded.

<meta property="og:description" content="Office of the Historian">

og:url[^4]

One of the required Open Graph properties, this is the canonical URL of the object/page:

<meta property="og:url" content="https://history.state.gov">

og:image[^4]

One of the required Open Graph properties, this specifies one or more images that will be displayed with the link when shared in social media posts. A number of optional (but useful) metadata properties can follow each image:

Image width : og:image:width in pixels

Image height : og:image:height in pixels

Image MIME type : og:image:type

Image alt text : og:image:alt

By default, images will be taken from the associated TEI document for the page, if there is one. The default Office of the Historian logo is also provided as a fallback.

<meta property="og:image" content="https://static.history.state.gov/images/avatar_big.jpg">
<meta property="og:image:width" content="400">
<meta property="og:image:height" content="400">
<meta property="og:image:alt" content="Department of State heraldic Shield"/>

[^4]: Open Graph Specification [^5]: Twitter Cards Markup Tag Reference

Customising Open Graph metadata by HSG page

As the population of Open Graph metadata is triggered from the same template function for every page, providing information for custom graph metadata for a given page needs to be done using the $model application data map provided by exist-db's templating mechanism. This can be provided by any templating function in the page template that occurs as an ancestor of the site template:surround templating function:

<div data-template="pages:load">
  <div data-template="templates:surround" data-template-with="templates/site.xml" data-template-at="content">
    <!-- Open Graph parameters could be provided here for the pages:load function-->
  </div>
</div>

Any templating function that supports customising the Open Graph for this page must support parameters given by attributes in the HTML template file: data-template-open-graph-keys, data-template-open-graph-keys-exclude, and data-template-open-graph-keys-add.

Specifying hard-coded Open Graph properties

The most straightforward way of customising Open Graph generation for a page is to provide the properties within a div element with id static-open-graph:

<div data-template="pages:load">
  <div id="static-open-graph" data-template="pages:suppress">
    <meta property="og:description" content="Custom hard-coded description goes here."/>
  </div>
  <div data-template="templates:surround" data-template-with="templates/site.xml" data-template-at="content">
    <!-- Open Graph parameters could be provided here for the pages:load function-->
  </div>
</div>

The provided properties are excluded from generation from the Open Graph map keys, and are copied to the page's HTML head instead of the corresponding function. NB: if the Open Graph property in question is generated using a key that doesn't match the property name, it may be necessary to use data-template-open-graph-keys-exclude to prevent duplicate properties; see below.

Customizing the Open Graph Map

If unique functions to populate one or more of the open graph properties is required, the $config:OPEN_GRAPH map can be replaced or extended by adding it to the $model map with the key open-graph.

For example, let's consider the case where the time the last article was changed was particularly important: we could replace the open graph map as follows:

open-graph: map:merge((
  $config:OPEN_GRAPH,
  map {
    "article:modified_time": function($node, $model) {<meta property="article:modified_time" content="{current-dateTime()}"/>}
  }
))

Note that this approach may not be the best: most functions that generate Open Graph properties will have good re-use value, and it may be more appropriate to add the functionality to the default $config:OPEN_GRAPH map instead, and simply specify different/additional Open Graph keys.

Even if you do decide to customize the Open Graph map, the functions added will have no effect unless the corresponding curie (in our example article:modified_time) is also specified in the sequence of Open Graph keys

Specifying a new set of Open Graph keys

A new set of Open Graph keys can be specified as a whitespace separated list of values in the data-template-open-graph-keys parameter:

<div data-template="pages:load" data-template-open-graph-keys="og:title og:type og:image og:url article:modified_time">
  <div data-template="templates:surround" data-template-with="templates/site.xml" data-template-at="content">...</div>
</div>

Although it may often be more desirable to simply specify any additional keys using the data-template-open-graph-keys-add parameter:

<div data-template="pages:load" data-template-open-graph-keys-add="article:modified_time">
  <div data-template="templates:surround" data-template-with="templates/site.xml" data-template-at="content">...</div>
</div>

The effect of which is to add any keys specified to the current list of Open Graph keys, either defined by data-template-open-graph-keys if present, or else using the default $config:OPEN_GRAPH_KEYS.

It may be desirable to remove the generation of a default open graph property, which can be done in a similar way using data-template-open-graph-keys-exclude:

<div data-template="pages:load" data-template-open-graph-keys-exclude="og:locale">
  <div data-template="templates:surround" data-template-with="templates/site.xml" data-template-at="content">...</div>
</div>

And it is also possible to combine 'add' and 'exclude' to replace one function with another; 'exclude' is always processed first:

<div data-template="pages:load" data-template-open-graph-keys-exclude="twitter:card" data-template-open-graph-keys-add="twitter:card_large">
  <div data-template="templates:surround" data-template-with="templates/site.xml" data-template-at="content">...</div>
</div>