Hugo Shortcode Github Button

By Erik Larson | August 22, 2020

Follow @statropy Sponsor Watch Star Fork Use this template Issue Download

GitHub provides a javascript library to add GitHub-related buttons to your website.

This website is generated using Hugo, a static site generator written in Go. A site is generated using a theme, which specifies the layout and look of the site. It also allows customization using .toml configuration files. Content (like this blog entry) is created using markdown. Hugo then generates the HTML and CSS for the site using the theme and content.

One way to provide features for a hugo site is with shortcodes. Shortcodes allow the content creator to add simple tags in a markdown file to create specific content. Hugo uses the shortcode and parameters to create html using snippets. The GitHub buttons can be used by adding a javascript source and a single anchor tag. Let’s create a shortcode to allow adding these buttons in hugo.

GitHub Button API

This is the html snippet for the follow button at the top of the page

<a 
  class="github-button"
  href="https://github.com/statropy" 
  aria-label="Follow @statropy on GitHub"
>
Follow @statropy
</a>

Create an anchor tag with class="github-button". The href links to the GitHub user page. The aria-label provides a description of the button.

Follow Button

To create a shortcode snippet for a follow button, create an html file and place it in the /layouts/shortcodes folder of either the hugo project or theme. The name of the html file is the name of the shortcode. github_follow_button.html

<a 
  class="github-button"
  href="https://github.com/{{.Get 0}}" 
  aria-label="Follow @{{.Get 0}} on GitHub"
>
Follow @{{.Get 0}}
</a>

Hugo uses {{ and }} to insert text into static files. The .Get hugo function is used to access the parameters provided with the shortcode. We are only going to use a single parameter, the GitHub username, so {{.Get 0}} will be replaced with the username provided in the markdown.

The javascript library also needs to be included in the <head> of the page. To only load a script when a specific shortcode is used, add this to the head.html snippet

{{ if .HasShortcode "github_follow_button" }}
  <script async defer src="https://buttons.github.io/buttons.js"></script>
{{ end }}

This calls the hugo function .HasShortCode, which will only insert the inner text into the file if the shortcode is on that page. Now we can add the shortcode to a markdown file.

{{< github_follow_button "statropy" >}}

And now we have a button!

Follow @statropy

Star Button

The Star button will allow a user to Star a given repo, so let’s add a shortcode for that also, github_star_button.html

<a 
  class="github-button"
  href="https://github.com/{{.Get 0}}/{{.Get 1}}" 
  aria-label="Star {{.Get 0}}/{{.Get 1}} on GitHub"
  data-show-count="{.Get 2}"
>
Star {{.Get 0}}/{{.Get 1}}
</a>

For the Star button, there is an option to display the star count along with the button. Now there are 3 parameters, user, repo and count.

{{< github_star_button "statropy" "github-button-hugo-shortcode" "true" >}}

Because it is a different shortcode, the script tag in head.html needs to be inserted for this one too

{{if or (.HasShortcode "github_follow_button") (.HasShortcode "github_star_button")}}
  <script async defer src="https://buttons.github.io/buttons.js"></script>
{{ end }}
Star

A Better Shortcode

We have 2 working buttons now, but there are some problems creeping in. There are 6 more buttons to add, which means 6 more shortcodes. The head.html snippet will have to be updated for each one, leading to a pretty big if statement. There are more parameters that can be added, such as color scheme and large button flags, but keeping track of them just by order is getting difficult. The code to implement those options is the same for each button, which leads to a lot of copy-and-paste. We should be able to combine these buttons into a single shortcode.

The github_button Shortcode

The new shortcode will be named github_button. The first change to make is switching from positional parameters (0, 1, 2, etc) to named parameters. The first parameter to define is button, which will be the type of button to display. The possible values for button will be

  • follow
  • sponsor
  • watch
  • star
  • fork
  • template
  • issue
  • download

For now only the follow and star types will be implemented, since we know how to do those already. Once those are working, the other types cand be added.

The next parameter is user, which is the GitHub username. The button and user parameters are used in every github_button.

The remaining parameters are repo, which is the GitHub repository name and count, which will add the appropriate number to the button.

Edit the head.html snippet so that it only checks for the new shortcode.

{{ if .HasShortcode "github_button" }}
  <script async defer src="https://buttons.github.io/buttons.js"></script>
{{ end }}

Create a new shortcode file named github_button.html.

 1{{ $button := .Get "button"}}
 2{{ $data_icon := "mark-github" }}
 3{{ $aria_label := "" }}
 4{{ $button_text := "" }}
 5{{ $href := "" }}
 6
 7{{if eq $button "follow"}}
 8    {{ $href = printf "%s" (.Get "user")}}
 9    {{ $aria_label = printf "Follow @%s on GitHub" (.Get "user") }}
10    {{ $button_text = printf "Follow @%s" (.Get "user") }}
11{{else if eq $button "star"}}
12    {{ $href = printf "%s/%s/" (.Get "user") (.Get "repo")}}
13    {{ $data_icon = "star" }}
14    {{ $aria_label = printf "Star %s/%s on GitHub" (.Get "user") (.Get "repo")}}
15    {{ $button_text = "Star" }}
16{{end}}
17
18<a 
19    class="github-button" 
20    href="https://github.com/{{$href}}"
21    data-icon="octicon-{{$data_icon}}"
22    aria-label="{{$aria_label}}"
23    {{ with .Get "count"}} data-show-count="{{.}}"{{ end }} 
24>
25{{$button_text}}
26</a>

Lines 1-5 define the variables to be used. The $button variable is the button type, which is set by using the .Get function, this time with the parameter name instead of the position number. mark-github is the default icon, so $data_icon is set to that. The other variables will be set based on the button type.

To build the strings from variables and parameters, the printf function is used. Notice that the variable declaration syntax $var := "value" is different from assigning to an existing variable $var = "new value". Lines 7-16 make the string assignments for each button type.

For the anchor tag, the class is always the same. The href always begins with https://github.com/, so the $href variable only contains the rest of the URL. The data-icon and aria-label are set also.

The data-show-count uses some new syntax. The with function is useful for checking if the parameter exists. If the shortcode tag in the markdown includes the count parameter, then the text inside the block (until {{ end }}) is inserted, and the value of .Get "count" is accessed using {{.}}. If the count parameter isn’t used, then the block is skipped. This makes adding optional parameters pretty simple and compact.

Finally the $button_text is inserted, the tag is closed, and we have our new shortcode.

Edit the markdown file to use the new shortcode.

{{< github_button button="follow" user="statropy" >}}
{{< github_button button="star"   user="statropy" repo="github-button-hugo-shortcode" count="true" >}}

Follow @statropy Star

Adding more options

Now that new parameters only need to be added in one place, adding color scheme and size options should be easy.

 1{{ $button := .Get "button"}}
 2{{ $data_icon := "mark-github" }}
 3{{ $aria_label := "" }}
 4{{ $button_text := "" }}
 5{{ $href := "" }}
 6
 7{{if eq $button "follow"}}
 8    {{ $href = printf "%s" (.Get "user")}}
 9    {{ $aria_label = printf "Follow @%s on GitHub" (.Get "user") }}
10    {{ $button_text = printf "Follow @%s" (.Get "user") }}
11{{else if eq $button "star"}}
12    {{ $href = printf "%s/%s/" (.Get "user") (.Get "repo")}}
13    {{ $data_icon = "star" }}
14    {{ $aria_label = printf "Star %s/%s on GitHub" (.Get "user") (.Get "repo")}}
15    {{ $button_text = "Star" }}
16{{end}}
17
18<a 
19    class="github-button" 
20    href="https://github.com/{{$href}}"
21    data-icon="octicon-{{$data_icon}}"
22    aria-label="{{$aria_label}}"
23    {{ with .Get "count"}} data-show-count="{{.}}"{{ end }} 
24    {{if eq "true" (.Get "dark")}}data-color-scheme="dark"{{ end }}
25    {{if eq "true" (.Get "large")}}data-size="large"{{ end }}
26>
27{{$button_text}}
28</a>

For the color-scheme, light is the default. To use the dark color scheme, a new optional parameter dark is added. For the shortcode user, this is a true/false flag, with false being the default. Specifying dark="true" will add data-color-scheme="dark" to the anchor tag. To do this, the eq function compares the value of dark to true. Any other value, or no value specified, will omit data-color-scheme.

The large parameter works the same way. data-size="large" is only added if the large parameter is set to true

{{< github_button button="follow" user="statropy" large="true" >}}
{{< github_button button="star"   user="statropy" repo="github-button-hugo-shortcode" count="true" dark="true" >}}

Follow @statropy Star

Finishing github_button

 1{{ $button := .Get "button"}}
 2{{ $data_icon := "mark-github" }}
 3{{ $aria_label := "" }}
 4{{ $button_text := "" }}
 5{{ $href := "" }}
 6
 7{{if eq $button "follow"}}
 8    {{ $href = printf "%s" (.Get "user")}}
 9    {{ $aria_label = printf "Follow @%s on GitHub" (.Get "user") }}
10    {{ $button_text = printf "Follow @%s" (.Get "user") }}
11{{else if eq $button "sponsor"}}
12    {{ $href = printf "sponsors/%s/" (.Get "user")}}
13    {{ $data_icon = "heart" }}
14    {{ $aria_label = printf "Sponsor @%s on GitHub" (.Get "user") }}
15    {{ $button_text = "Sponsor" }}
16{{else if eq $button "watch"}}
17    {{ $href = printf "%s/%s/subscription" (.Get "user") (.Get "repo")}}
18    {{ $data_icon = "eye" }}
19    {{ $aria_label = printf "Watch %s/%s on GitHub" (.Get "user") (.Get "repo")}}
20    {{ $button_text = "Watch" }}
21{{else if eq $button "star"}}
22    {{ $href = printf "%s/%s/" (.Get "user") (.Get "repo")}}
23    {{ $data_icon = "star" }}
24    {{ $aria_label = printf "Star %s/%s on GitHub" (.Get "user") (.Get "repo")}}
25    {{ $button_text = "Star" }}
26{{else if eq $button "fork"}}
27    {{ $href = printf "%s/%s/fork" (.Get "user") (.Get "repo")}}
28    {{ $data_icon = "repo-forked" }}
29    {{ $aria_label = printf "Fork %s/%s on GitHub" (.Get "user") (.Get "repo")}}
30    {{ $button_text = "Fork" }}
31{{else if eq $button "template"}}
32    {{ $href = printf "%s/%s/generate" (.Get "user") (.Get "repo")}}
33    {{ $data_icon = "repo-template" }}
34    {{ $aria_label = printf "Use this template %s/%s on GitHub" (.Get "user") (.Get "repo")}}
35    {{ $button_text = "Use this template" }}
36{{else if eq $button "issue"}}
37    {{ $href = printf "%s/%s/issues" (.Get "user") (.Get "repo")}}
38    {{ $data_icon = "issue-opened" }}
39    {{ $aria_label = printf "Issue %s/%s on GitHub" (.Get "user") (.Get "repo")}}
40    {{ $button_text = "Issue" }}
41{{else if eq $button "download"}}
42    {{ $branch := default "master" (.Get "branch")}}
43    {{ $href = printf "%s/%s/archive/%s.zip" (.Get "user") (.Get "repo") $branch}}
44    {{ $data_icon = "download" }}
45    {{ $aria_label = printf "Download %s/%s on GitHub" (.Get "user") (.Get "repo")}}
46    {{ $button_text = "Download" }}
47{{end}}
48
49<a 
50    class="github-button" 
51    href="https://github.com/{{$href}}"
52    data-icon="octicon-{{$data_icon}}"
53    aria-label="{{$aria_label}}"
54    {{ with .Get "count"}} data-show-count="{{.}}"{{ end }} 
55    {{if eq "true" (.Get "dark")}}data-color-scheme="dark"{{ end }}
56    {{if eq "true" (.Get "large")}}data-size="large"{{ end }}
57>
58{{$button_text}}
59</a>

Adding the 6 remaining buttons only requires setting the existing variables for each new button type. The anchor tag doesn’t change! There is one new optional parameter, branch, that is only used with the download button. Specifying branch in the shortcode will choose that branch for the zip file to download. If not specified, the default master branch is used.

The shortcodes used to generate the buttons at the top of the page.

{{< github_button button="follow"   user="statropy" >}}
{{< github_button button="sponsor"  user="statropy" >}}
{{< github_button button="watch"    user="statropy" repo="github-button-hugo-shortcode" count="true" >}}
{{< github_button button="star"     user="statropy" repo="github-button-hugo-shortcode" count="true" >}}
{{< github_button button="fork"     user="statropy" repo="github-button-hugo-shortcode" count="true" >}}
{{< github_button button="template" user="statropy" repo="github-button-hugo-shortcode" >}}
{{< github_button button="issue"    user="statropy" repo="github-button-hugo-shortcode" count="true" >}}
{{< github_button button="download" user="statropy" repo="github-button-hugo-shortcode" >}}

More Customization

Software is never finished, only abandoned. Not ready to abandon this just yet, this shortcode can have more customizations.

View button type

github-button-hugo-shortcode

Add a new button type that, by default, displays the repo name and links to the repo. All that’s needed is another else if block.

{{else if eq $button "view"}}
    {{ $href = printf "%s/%s" (.Get "user") (.Get "repo")}}
    {{ $data_icon = "mark-github" }}
    {{ $aria_label = printf "View %s/%s on GitHub" (.Get "user") (.Get "repo")}}
    {{ $button_text = .Get "repo" }}
{{end}}

There are some more parameters that can be exposed for customization.

What?

icon parameter

Change the icon from the default, if specified.

{{ with .Get "icon" }}
    {{ $data_icon = . }}
{{ end }}

text parameter

Change the button text from the default, if specified.

{{ with .Get "text" }}
    {{ $button_text = . }}
{{ end }}

aria_label parameter

Change the aria-label from the default, if specified.

{{ with .Get "aria_label" }}
    {{ $aria_label = . }}
{{ end }}

Conclusion

Adding a shortcode to hugo, as we’ve shown, is actually pretty easy. If you like this shortcode, then give it a Star ! Have an idea for improving this shortcode? Then Fork it and submit a pull-request. Just want to use the shortcode in your own hugo project? Then Download it. If you find a bug, please submit an Issue .

If interested in other things I’m working on?

Follow @statropy