Add Structure Data JSON-LD in Hugo Website Pages Add Structure Data JSON-LD in Hugo Website Pages

Guide to create a Site Schema partial in Hugo

Page content

When you add structure data to your website, it helps google, bing or other website indexers to understand the content for your website and pages which leads to better search results for your website and eventually helps in SEO ranking.

Mark up schema is based on website type and its content. Suppose you have a blog website, then schema of your web pages will be of type “Article” or “BlogPosting”. You can go through the google’s example of adding structure data using JSON-LD for “Article” type of website pages.

Schema of structure data for all type of websites and web pages can be found in documentation of schema.org

Microdata and JSON-LD are two ways to add mark up in order to structure your data. Google recommends using JSON-LD as it is more cleaner approach to express the structure of the data in JSON format embedded as a <script> in the <head> tag of your HTML. Its a clear separation of structure from HTML elements as compare to Microdata where you add special properties like itemprop, itemtype in HTML element tags everywhere.

Now we know that JSON-LD is way to go. There are the steps to add structure data using JSON-LD in hugo website:

Create site_schema.html Partial

First of all we are going to create a partial called site_schema.html which is responsible to generate structure data JSON-LD for hugo website and hugo blog pages. All you need to do is copy the below code snippet and save it under $hugo/layouts/partials/site_schema.html.

{{ if .IsHome -}}
<script type="application/ld+json">
{
    "@context": "http://schema.org",
    "@type": "WebSite",
    "name": "{{ .Site.Title }}",
    "url": "{{ .Site.BaseURL }}",
    "description": "{{ .Site.Params.description }}",
    "thumbnailUrl": "{{ .Site.Params.Logo | absURL }}",
    "license": "{{ .Site.Params.Copyright }}"
}
</script>
{{ else if .IsPage }}
{{ $author :=  or (.Params.author) (.Site.Author.name) }}
{{ $org_name :=  .Site.Title }}
<script type="application/ld+json">
{
    "@context": "http://schema.org",
    "@type": "BlogPosting",
    "articleSection": "{{ .Section }}",
    "name": "{{ .Title | safeJS }}",
    "headline": "{{ .Title | safeJS }}",
    "alternativeHeadline": "{{ .Params.lead }}",
    "description": "{{ if .Description }}{{ .Description | safeJS }}{{ else }}{{if .IsPage}}{{ .Summary  }}{{ end }}{{ end }}",
    "inLanguage": {{ .Site.LanguageCode | default "en-us" }},
    "isFamilyFriendly": "true",
    "mainEntityOfPage": {
        "@type": "WebPage",
        "@id": "{{ .Permalink }}"
    },
    "author" : {
        "@type": "Person",
        "name": "{{ $author }}"
    },
    "creator" : {
        "@type": "Person",
        "name": "{{ $author }}"
    },
    "accountablePerson" : {
        "@type": "Person",
        "name": "{{ $author }}"
    },
    "copyrightHolder" : "{{ $org_name }}",
    "copyrightYear" : "{{ .Date.Format "2006" }}",
    "dateCreated": "{{ .Date.Format "2006-01-02T15:04:05.00Z" | safeHTML }}",
    "datePublished": "{{ .PublishDate.Format "2006-01-02T15:04:05.00Z" | safeHTML }}",
    "dateModified": "{{ .Lastmod.Format "2006-01-02T15:04:05.00Z" | safeHTML }}",
    "publisher":{
        "@type":"Organization",
        "name": {{ $org_name }},
        "url": {{ .Site.BaseURL }},
        "logo": {
            "@type": "ImageObject",
            "url": "{{ .Site.Params.logo | absURL }}",
            "width":"32",
            "height":"32"
        }
    },
    "image": {{ if .Params.images }}[{{ range $i, $e := .Params.images }}{{ if $i }}, {{ end }}{{ $e | absURL }}{{ end }}]{{ else}}{{.Site.Params.logo | absURL }}{{ end }},
    "url" : "{{ .Permalink }}",
    "wordCount" : "{{ .WordCount }}",
    "genre" : [ {{ range $index, $tag := .Params.tags }}{{ if $index }}, {{ end }}"{{ $tag }}" {{ end }}],
    "keywords" : [ {{ range $index, $keyword := .Params.keywords }}{{ if $index }}, {{ end }}"{{ $keyword }}" {{ end }}]
}
</script>
{{ end }}

Note: I am using hugo as a static site generator for this blog website and after spending so much time here and there, i came up with this partial. You can do the changes in this partial as per your need.

The data to generate structure data json using this partial comes from the front-matter of the blog post and config.toml file. I have tried to feed in most of the data from front-matter and fallback as config.toml so that most of the blog post pages have their specific data.

Relevant front-matter

These are the relevant front-matter properties which are being used in generating JSON-LD schema for your blog page:-

blog-page.md
---
title: I am the name and headline of blog post structure data
lead: I am alternativeHeadline of blog post structure data
description: I am description of blog post structure data
author: I am author, creator and accountablePerson of blog post structure data. I come from config.toml if not specified here
date: I am copyrightYear, dateCreated and datePublished of blog post structure data
lastmod: I am dateModified of blog post structure data. I am same as "date" if not specified. 
images:
  - "/img/image-1.png"
  - "/img/image-2.png"
tags:
  - "genre 1 of blog post structure data"
  - "genre 2 of blog post structure data"
keywords:
  - "keyword 1 of blog post structure data"
  - "keyword 2 of blog post structure data "
---

Relevant config.toml

These are the relevant config.toml configuration properties which are being used in generating JSON-LD schema for your website:-

config.toml
baseURL = "I am url of website structure data"
languageCode = "en-us"
title = "I am name of website structure data"
[Author]
  name = "I am fallback author of blog post structure data"
[Params]
  description = "I am description of website structure data"
  logo = "favicon-32x32.png"
  copyright = "I am license of website structure data"

Add partial to the <head> tag of baseof.html

Once you created a partial, you need to add this partial in the <head> tag of html page under _default folder which generates your hugo website and blog HTML pages.

If you are using any theme in hugo website then this HTML page could be $hugo/themes/layouts/_default/baseof.html. If you have designed hugo website on your own then this HTML page could be $hugo/layouts/_default/baseof.html depending upon your naming convention. Just add the partial in HTML head tag like below:

baseof.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    ...
    ...

    {{ partial "site_schema.html" . }}
  </head>
  <body>
  </body>
</html>

Generated Structure Data JSON-LD

The following structure data are generated in JSON-LD format.

Website Main Page
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    ...
    ...
    ...

    <script type="application/ld+json">
    {
        "@context": "http://schema.org",
        "@type": "WebSite",
        "name": "Coding N Concepts",
        "url": "https://codingnconcepts.com/",
        "description": "Coding N Concepts is a technical blog for developers by developers to help you with coding problems, puzzle solving, interview preparation, learning concepts in simplified way.",
        "thumbnailUrl": "https://codingnconcepts.com/favicon-32x32.png",
        "license": "Ashish Lahoti"
    }
    </script>
  </head>
  <body>
  </body>
</html>
Blog Post Page
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    ...
    ...
    ...

    <script type="application/ld+json">
    {
        "@context": "http://schema.org",
        "@type": "BlogPosting",
        "articleSection": "hugo",
        "name": "Structure Data Using JSON-LD for Hugo",
        "headline": "Structure Data Using JSON-LD for Hugo",
        "alternativeHeadline": "",
        "description": "Structure Data Using JSON-LD for Hugo",
        "inLanguage": "en-us",
        "isFamilyFriendly": "true",
        "mainEntityOfPage": {
            "@type": "WebPage",
            "@id": "https://codingnconcepts/hugo/structure-data-json-ld"
        },
        "author" : {
            "@type": "Person",
            "name": "Ashish Lahoti"
        },
        "creator" : {
            "@type": "Person",
            "name": "Ashish Lahoti"
        },
        "accountablePerson" : {
            "@type": "Person",
            "name": "Ashish Lahoti"
        },
        "copyrightHolder" : "Coding N Concepts",
        "copyrightYear" : "2020",
        "dateCreated": "2020-05-04T00:00:00.00Z",
        "datePublished": "2020-05-04T00:00:00.00Z",
        "dateModified": "2020-05-04T00:00:00.00Z",
        "publisher":{
            "@type":"Organization",
            "name": "Coding N Concepts",
            "url": "http://localhost:1313/",
            "logo": {
                "@type": "ImageObject",
                "url": "https://codingnconcepts/favicon-32x32.png",
                "width":"32",
                "height":"32"
            }
        },
        "image": "https://codingnconcepts/favicon-32x32.png",
        "url" : "https://codingnconcepts/hugo/structure-data-json-ld",
        "wordCount" : "857",
        "genre" : [ "Hugo" , "SEO" ],
        "keywords" : [ "Schema markup using JSON-LD in hugo website", "SEO optimization for hugo" ]
    }
    </script>
  </head>
  <body>
  </body>
</html>

Verify Structure Data JSON-LD

You can verify the structure data using Structured Data Testing Tool provided by Google where either you give a URL of your page or just copy paste whole HTML to verify. Look for the errors and correct them.