Skip to main content

Tagging in Umbraco

The following article describes an example of tagging implementation for content in Umbraco, and how to filter source entities by tag in Enterspeed.

As an example, we are going to build a basic news portal about sports, named "Sports Central".

Content preparation in Umbraco

In order to build the site's content structure and filter it in Enterspeed, we have to do some groundwork as - creating document types, data types and adding some articles as content.

Umbraco Content Structure

Document types

Article

Used for article content nodes themselves, with the following properties:

PropertyData typeDescription
titleTextstringTitle for the article
subheaderTextstringSubheader for the article
publishedAtDatePickerPublished display date for the article
tagsTags PickerRelated tags for the article

Period Group

Is a document type without any properties, in the content tree, it will be used a grouping folder for articles per month, e.g. 09/2021.

Articles

Is a document type for grouping all 'Period group' content nodes.

Settings

Document type contains various settings for the site and different data types.

Tags

Used as container node for listing all possible tags underneath it in the content tree.

Tag

Tag, that can be news article can be associated with.

Articles By Tag

Is an Element Type document type, describing a block for displaying articles by a specific tag. Will be used on the front page of the site.

PropertyData typeDescription
titleTextstringTitle used for the block, f.x. - 'Latest from football world'.
tagSingle Tag PickerA tag that you want to include articles for.
topNumericDefine how many articles you want to see.

Site

Document type representing site instance.

PropertyData typeDescription
blocksFrontpage Block ListOur front page will consist of different blocks as - articles by tag, and potentially many others.

Data types

Single Tag Picker

Is a data type extending Umbraco default 'Content Picker', where we specify 'Tags' content node as a start node.

Frontpage Block List

Is a data type extending Umbraco default 'Block List', where we add a single available block - 'Articles By Tag', that we have created previously as part of Document types.

Adding blocks to frontpage

On the site node, we are going to add some blocks for displaying articles by different tags.

Umbraco blocks

Each of them configured with their own criteria for display of articles:

Umbraco blocks Content

Umbraco blocks Content basketball

Defining schemas in Enterspeed

Creating a Site schema

Site schema will work with source entities of type - 'site' since those are the ones where we have defined our blocks (in Umbraco) to describe what blocks we want to display.

This schema doesn't contain much of the logic, its responsibility is to iterate over blocks defined on the source entity and pass each of the blocks in partial view, with matching name.

{
"route": {
"url": "{url}"
},
"triggers": {
"umbraco": ["site"]
},
"properties": {
"blocks": {
"type": "array",
"input": "{p.blocks}",
"items": {
"type": "partial",
"input": "{item}",
"alias": "Block-{item.contentType}"
}
}
}
}

The only tricky part to remember is that now we have defined an alias match for partial schema view, where 'item.contentType' value is an alias of our current block Element document type in Umbraco - 'articlesByTag'.

Creating a partial schema - Articles By Tag Block

We are halfway through. The previous schema iterated through blocks, this schema will handle a specific type of block - Block-articlesByTag.

As result, we want to display the following properties - alias and title of this block and collection of articles matching criteria defined on this block along with basic information about them - title, subheader, publishedAt date and a list of tags associated.

{
"alias": "Block-articlesByTag",
"properties": {
"alias": "{item.contentType}",
"title": "{item.content.title}",
"articles": {
"type": "array",
"input": {
"$lookup": {
"filter": "type eq 'article' and properties.tags/any(t: t.id eq '{item.content.tag}')",
"top": "{item.content.top}",
"orderBy": {
"property": "p.publishedAt",
"sort": "desc"
}
}
},
"items": {
"type": "object",
"properties": {
"title": "{item.p.title ?? item.p.metaData.name}",
"subheader": "{item.p.subheader}",
"publishedAt": "{item.p.publishedAt}",
"tags": {
"type": "array",
"input": "{item.p.tags}",
"var": "tag",
"items": "{tag.name}"
}
}
}
}
}
}

Notice how we are using $lookup in combination with filter, top, and orderBy. In simple words, we want to lookup all source entities that match our filter, meaning where the type of source entity is an article and it has a current block selected tag associated with it.

On our front page, we want to show the latest published news first. That is what we define in our sorting criteria for all filters found in source entities. Lastly, regarding lookup, we defined a limit on how many articles will be displayed for the current block.

Outcome

After updating and deploying previously mentioned schemas and publishing all content data to Enterspeed, the outcome from the Delivery API would look like this:

{
"meta": {
"status": 200,
"redirect": null
},
"route": {
"blocks": [
{
"alias": "articlesByTag",
"title": "Hey Vancouver",
"articles": [
{
"title": "Canucks camp notebook: Sporting new look, Boeser striving for consistency",
"subheader": "Dan Murphy and Iain MacIntyre discuss the latest news surrounding Elias Pettersson and Quinn Hughes, as well as what's happening with Travis Hamonic",
"publishedAt": "09/28/2021 00:00:00",
"tags": ["Vancouver Canucks", "Ice hockey"]
},
{
"title": "Canucks Sign Forward Jason Dickinson",
"subheader": "...to a three-year contract",
"publishedAt": "09/02/2021 00:00:00",
"tags": ["Ice hockey", "Vancouver Canucks"]
},
{
"title": "NHL expects full capacity in all cities except Vancouver and Montreal",
"subheader": "",
"publishedAt": "08/30/2021 00:00:00",
"tags": ["Vancouver Canucks", "Ice hockey"]
}
]
},
{
"alias": "articlesByTag",
"title": "What is happening in #basketball?",
"articles": [
{
"title": "Position breakdown: Maximizing Porzingis a priority among big men",
"subheader": "When you have one of the tallest players in the NBA, one with a rare skill set of inside and outside capabilities, it makes sense to maximize his assets.",
"publishedAt": "09/27/2021 00:00:00",
"tags": ["Basketball"]
},
{
"title": "Will Kidd get the best out of Doncic?",
"subheader": "The savvy former guard looks to bring his Hall of Fame expertise to Dallas.",
"publishedAt": "09/14/2021 00:00:00",
"tags": ["Basketball"]
}
]
}
]
},
"views": {}
}