Snippets using Hugo Shortcodes

Last modified: September 11th, 2024

CloudCannon supports embedding rich snippets in Markdown content when using the CloudCannon Content Editor. For sites built with Hugo, CloudCannon includes support for most of the built-in Hugo shortcodes without any configuration. Any existing shortcodes in your content will be presented as blocks in rich text views, with the ability to add the built-in shortcodes via the toolbar:

The CloudCannon Content Editor toolbar with a cursor hovering over the "Snippet" button

The builtin shortcodes can be configured via a _snippets_imports key in your CloudCannon global configuration file:

cloudcannon.config.yaml
copied
_snippets_imports:
  hugo: false

Exclude all builtin Hugo shortcodes.

cloudcannon.config.json
copied
{
  "_snippets_imports": {
    "hugo": false
  }
}

Exclude all builtin Hugo shortcodes.

cloudcannon.config.yaml
copied
_snippets_imports:
  hugo:
    include:
      - hugo_youtube
      - hugo_vimeo

Exclude all shortcodes by default, but import the youtube and vimeo shortcodes specifically.

cloudcannon.config.json
copied
{
  "_snippets_imports": {
    "hugo": {
      "include": [
        "hugo_youtube",
        "hugo_vimeo"
      ]
    }
  }
}

Exclude all shortcodes by default, but import the youtube and vimeo shortcodes specifically.

cloudcannon.config.yaml
copied
_snippets_imports:
  hugo:
    exclude:
      - hugo_embed

Import all shortcodes by default, but exclude the embed shortcode.

cloudcannon.config.json
copied
{
  "_snippets_imports": {
    "hugo": {
      "exclude": [
        "hugo_embed"
      ]
    }
  }
}

Import all shortcodes by default, but exclude the embed shortcode.

Hugo's instagram shortcode is excluded by default, as it is not functional without configuring an Instagram API key in your Hugo configuration. In other words, for sites configured to build with Hugo on CloudCannon, the following configuration will be applied by default:

cloudcannon.config.yaml
copied
_snippets_imports:
  hugo:
    exclude:
      - hugo_instagram

The default snippet import for Hugo sites.

cloudcannon.config.json
copied
{
  "_snippets_imports": {
    "hugo": {
      "exclude": [
        "hugo_instagram"
      ]
    }
  }
}

The default snippet import for Hugo sites.

To override this default and import all shortcodes, set hugo: true in your global _snippets_imports:

cloudcannon.config.yaml
copied
_snippets_imports:
  hugo: true

Force all shortcodes to be available.

cloudcannon.config.json
copied
{
  "_snippets_imports": {
    "hugo": true
  }
}

Force all shortcodes to be available.

Enabling snippets in the toolbar#

By default, CloudCannon will show the snippet toolbar action in the content editor if snippets are available.

If you have already customized which options are available via _editables in your CloudCannon config, you will need to include snippet: true for Snippets to be available. See the Editables options documentation for more details.

Custom Hugo Shortcodes#

By default, a custom shortcode in Hugo content will be displayed in the Content Editor as an Unknown shortcode or Unknown shortcode pair. This allows an editor to move and delete a shortcode, but prevents editing of its arguments or content:

A screenshot of an unknown shortcode displayed as a block in the CloudCannon Content Editor

To enable editing and provide the custom shortcode in the toolbar, your custom shortcode must be configured using the _snippets object in your CloudCannon global config file. CloudCannon Snippets can be built from scratch to support nearly any syntax or SSG, but a set of snippet templates are provided for Hugo shortcodes to cover most use cases in Hugo.

To help illustrate this configuration, we will first cover a few examples of custom shortcode configurations. First, let's look a custom tint shortcode on our Hugo site that takes a string and applies a color to it:

post.md
copied
# My Post

{{< tint "#ff0000" >}}This text should be red{{< /tint >}}

The first thing we need to do is decide which shortcode template to use, which we can determine from the following aspects:

  • First, in Hugo terms this is a "paired" shortcode, since it has a start and end tag that wrap some content.
  • Next, this shortcode takes "positional" arguments, so rather than using keys and values (like color="#ff0000") we have the value #ff0000 in the first position.
  • Lastly, the fact that our shortcode uses the < and > characters means it outputs HTML, rather than the markdown that % characters would represent.

Looking at the list of shortcode templates further down this page, this means we should configure this snippet using the hugo_paired_shortcode_positional_args template. A full example configuration for this shortcode thus might look like the following:

cloudcannon.config.yaml
copied
_snippets:
  hugo_tint:
    template: hugo_paired_shortcode_positional_args
    inline: true
    preview:
      text: Tint
    definitions:
      shortcode_name: tint
      content_key: inner_text
      positional_args:
        - editor_key: tint_color
          type: string
    _inputs:
      tint_color:
        type: color
      inner_text:
        comment: This text will be tinted
cloudcannon.config.json
copied
{
  "_snippets": {
    "hugo_tint": {
      "template": "hugo_paired_shortcode_positional_args",
      "inline": true,
      "preview": {
        "text": "Tint"
      },
      "definitions": {
        "shortcode_name": "tint",
        "content_key": "inner_text",
        "positional_args": [
          {
            "editor_key": "tint_color",
            "type": "string"
          }
        ]
      },
      "_inputs": {
        "tint_color": {
          "type": "color"
        },
        "inner_text": {
          "comment": "This text will be tinted"
        }
      }
    }
  }
}

Each snippet definition lives under a top level key, hugo_tint in this example. This is the unique name that CloudCannon uses to identify this snippet, but is otherwise unused in the shortcode configuration itself.

We specify the template that this snippet should inherit from, and also specify that it is an inline snippet, since it can live anywhere in the content (such as in the middle of a sentence).

In the preview object we configure how this snippet is displayed while editing, using the CloudCannon card preview options.

In definitions we need to specify some values that are required for the template we picked. For the hugo_paired_shortcode_positional_args template, we need to specify:

  • The shortcode_name — in this case we're configuring our tint shortcode
  • The content_key — this controls the key that CloudCannon will use to edit the text in between the start and end tags of the shortcode.
  • The positional_args — for our tint shortcode we need to configure that the first argument should be captured with the key tint_color

Finally, we can specify any other keys from the CloudCannon configuration cascade here. In this example, we configure the inputs for the keys that this snippet will generate. With that in place, we can now add and edit our tint shortcode anywhere on our site.

A screenshot of the "tint" shortcode in the Content Editor, with the editing panel open showing the snippet data

Next, let's quickly look at a shortcode with a different syntax:

post.md
copied
# My Post

{{< callout type="info" message="This is my shortcode" >}}

This time, we have an unpaired shortcode that takes type and message argument keys. This syntax matches the hugo_shortcode_named_args template.

In CloudCannon, we could configure this snippet using the following global configuration:

cloudcannon.config.yaml
copied
_snippets:
  callout:
    template: hugo_shortcode_named_args
    inline: false
    preview:
      text: Callout
    definitions:
      shortcode_name: callout
      named_args:
        - source_key: type
          editor_key: label
          type: string
        - editor_key: message
          type: string
    _inputs:
      label:
        type: select
        options:
          values:
            - info
            - warning
            - error
cloudcannon.config.json
copied
{
  "_snippets": {
    "callout": {
      "template": "hugo_shortcode_named_args",
      "inline": false,
      "preview": {
        "text": "Callout"
      },
      "definitions": {
        "shortcode_name": "callout",
        "named_args": [
          {
            "source_key": "type",
            "editor_key": "label",
            "type": "string"
          },
          {
            "editor_key": "message",
            "type": "string"
          }
        ]
      },
      "_inputs": {
        "label": {
          "type": "select",
          "options": {
            "values": [
              "info",
              "warning",
              "error"
            ]
          }
        }
      }
    }
  }
}

This should now be familiar, but with a few changes:

  • We want this snippet to be a block-level element in the editor, so we set inline to false.
  • Since this shortcode does not have an end tag, we have no content_key
  • Instead of positional_args we have named_args

Configuring our named arguments uses most of the same options as the positional arguments earlier, but here we can additionally specify source_key and editor_key separately. In this example, we want the key in our shortcode to be type, but tell CloudCannon to treat that value as the label key, which we then configure using our inputs configuration.

A screenshot of the "callout" shortcode in the Content Editor, with the editing panel open showing the snippet data

Snippet options#

The following options are available for Hugo shortcode snippets:

template — String#

The template that this snippet should inherit, out of the available Hugo Shortcode Templates.

definitions — Object#

The variables required for the selected template.

inline — Boolean#

Whether this shortcode can appear inline (within a sentence). Defaults to false, which will treat this shortcode as a block-level element in the content editor.

preview — Object#

A preview definition for displaying this shortcode in the CloudCannon editor. See the preview options documentation.

_inputs — Object#

Input configurations for the keys contained in this shortcode. See the input configuration documentation.

Hugo Shortcode Templates#

Hugo allows a range of shortcode syntaxes, and each has a matching shortcode template provided by CloudCannon.

The first step to configure your custom shortcode is to identify which shortcode template to use, as each shortcode template requires a set of definitions keys to be configured. The following shortcode templates are available:

Shortcode with positional arguments#

example.md
copied
# hugo_shortcode_positional_args
{{< custom_shortcode arg1 arg2 >}}

# hugo_markdown_shortcode_positional_args
{{% custom_shortcode arg1 arg2 %}}

Example config

cloudcannon.config.yaml
copied
_snippets:
  custom_snippet:
    template: hugo_shortcode_positional_args
    inline: false
    preview:
      text: My Custom Snippet
    definitions:
      shortcode_name: custom_shortcode
      positional_args:
        - editor_key: argument_one
          type: string
        - editor_key: argument_two
          type: string
cloudcannon.config.json
copied
{
  "_snippets": {
    "custom_snippet": {
      "template": "hugo_shortcode_positional_args",
      "inline": false,
      "preview": {
        "text": "My Custom Snippet"
      },
      "definitions": {
        "shortcode_name": "custom_shortcode",
        "positional_args": [
          {
            "editor_key": "argument_one",
            "type": "string"
          },
          {
            "editor_key": "argument_two",
            "type": "string"
          }
        ]
      }
    }
  }
}

Definitions

shortcode_name — String#

The name of your shortcode, as used in your Hugo content files.

positional_args — Array of argument options#

An ordered list of each argument the shortcode takes.

Paired shortcode with positional arguments#

example.md
copied
# hugo_paired_shortcode_positional_args
{{< custom_shortcode arg1 arg2 >}} content {{< /custom_shortcode >}}

# hugo_paired_markdown_shortcode_positional_args
{{% custom_shortcode arg1 arg2 %}} content {{% /custom_shortcode %}}

Example config

cloudcannon.config.yaml
copied
_snippets:
  custom_snippet:
    template: hugo_paired_shortcode_positional_args
    inline: false
    preview:
      text: My Custom Snippet
    definitions:
      shortcode_name: custom_shortcode
      content_key: custom_key
      positional_args:
        - editor_key: argument_one
          type: string
        - editor_key: argument_two
          type: string
cloudcannon.config.json
copied
{
  "_snippets": {
    "custom_snippet": {
      "template": "hugo_paired_shortcode_positional_args",
      "inline": false,
      "preview": {
        "text": "My Custom Snippet"
      },
      "definitions": {
        "shortcode_name": "custom_shortcode",
        "content_key": "custom_key",
        "positional_args": [
          {
            "editor_key": "argument_one",
            "type": "string"
          },
          {
            "editor_key": "argument_two",
            "type": "string"
          }
        ]
      }
    }
  }
}

Definitions

shortcode_name — String#

The name of your shortcode, as used in your Hugo content files.

content_key — String#

The key to use in the data panel for editing the inner contents of the shortcode.

positional_args — Array of argument options#

An ordered list of each argument the shortcode takes.

Shortcode with named arguments#

example.md
copied
# hugo_shortcode_named_args
{{< custom_shortcode arg="value" >}}

# hugo_markdown_shortcode_named_args
{{% custom_shortcode arg="value" %}}

Example config

cloudcannon.config.yaml
copied
_snippets:
  custom_snippet:
    template: hugo_shortcode_named_args
    inline: false
    preview:
      text: My Custom Snippet
    definitions:
      shortcode_name: custom_shortcode
      named_args:
        - editor_key: arg
          type: string
cloudcannon.config.json
copied
{
  "_snippets": {
    "custom_snippet": {
      "template": "hugo_shortcode_named_args",
      "inline": false,
      "preview": {
        "text": "My Custom Snippet"
      },
      "definitions": {
        "shortcode_name": "custom_shortcode",
        "named_args": [
          {
            "editor_key": "arg",
            "type": "string"
          }
        ]
      }
    }
  }
}

Definitions

shortcode_name — String#

The name of your shortcode, as used in your Hugo content files.

named_args — Array of argument options#

A list of each key-value pair the shortcode takes.

Paired shortcode with named arguments#

example.md
copied
# hugo_paired_shortcode_named_args
{{< custom_shortcode arg="value" >}} content {{< /custom_shortcode >}}

# hugo_paired_markdown_shortcode_named_args
{{% custom_shortcode arg="value" %}} content {{% /custom_shortcode %}}

Example config

cloudcannon.config.yaml
copied
_snippets:
  custom_snippet:
    template: hugo_paired_shortcode_named_args
    inline: false
    preview:
      text: My Custom Snippet
    definitions:
      shortcode_name: custom_shortcode
      content_key: custom_key
      named_args:
        - editor_key: arg
          type: string
cloudcannon.config.json
copied
{
  "_snippets": {
    "custom_snippet": {
      "template": "hugo_paired_shortcode_named_args",
      "inline": false,
      "preview": {
        "text": "My Custom Snippet"
      },
      "definitions": {
        "shortcode_name": "custom_shortcode",
        "content_key": "custom_key",
        "named_args": [
          {
            "editor_key": "arg",
            "type": "string"
          }
        ]
      }
    }
  }
}

Definitions

shortcode_name — String#

The name of your shortcode, as used in your Hugo content files.

content_key — String#

The key to use in the data panel for editing the inner contents of the shortcode.

named_args — Array of argument options#

A list of each key-value pair the shortcode takes.

Argument options#

The following options are available for positional and named argument option objects:

editor_key — String#

Determines the key that will be used for this argument in the CloudCannon data panel.

source_key — String#

Determines the key of the key-value pair as it appears in the shortcode.

Only used for named arguments, and will default to the editor_key if unset.

default — Any#

The default value that should be used for this argument when creating a new snippet in the CloudCannon editor.

type — String#

Restrict this argument to parse as the specified type. Useful to ensure booleans get parsed as the boolean value, rather than a string such as "true".

One of:

  • string
  • boolean
  • number
  • array
optional — Boolean#

Whether this argument is required for the shortcode. If false, shortcodes in your templates missing this argument will not match this snippet definition.

Defaults to false.

remove_empty — Boolean#

Whether this argument should be omitted from the output shortcode if the value is empty.

Only used for named arguments, defaults to false.

allowed_values — Array of values#

A list of values that this argument must be in order to match this snippet definition. Allows you to match different usages of the same shortcode to separate snippet definitions based on the value of an argument.

implied_boolean — Boolean#

Output a boolean for whether this argument is present, rather than the value of the argument itself.

Only used for positional arguments.

Related Articles

Open in a new tab