Working with Templates

(excerpt from lua-resty-templates documentation)

You may use the following tags in templates:

  • {{expression}}, writes result of expression - html escaped
  • {% lua code %}, executes Lua code
  • {(path-to-partial)}, include partial file by path, you may also supply context for the file {(partials/header.html, { message = "Hello, World" } )}

  • {-block-}...{-block-}, wraps inside of a {-block-} to a value stored in a blocks table with a key block (in this case), see . Don’t use predefined block names verbatim and raw.

  • {-verbatim-}...{-verbatim-} and {-raw-}...{-raw-} are predefined blocks whose inside is not processed by the lua-resty-template but the content is outputted as is.
  • {# comments #} everything between {# and #} is considered to be commented out (i.e., not outputted or executed).

Show custom properties

You may work with custom properties in your OpenAPI spec. To expose custom properties in Dev Portal, change the property showExtensions to true in the spec-renderer.html file. By default, showExtensions is false.

Partials are snippets of html that layouts can reference. Partials have access to all the same data that its layout does, and can even call other partials. Breaking your code into partials can help organize large pages, as well as allow different layouts share common page elements.

layouts/index.html

  1. {(partials/header.html)}
  2. <div class="content">
  3. {(partials/hero.html)}
  4. </div>
  5. {(partials/footer.html)}

partials/header.html

  1. <header class="row">
  2. <div class="column">
  3. <img src="{{page.header_logo}}"/>
  4. </div>
  5. <div class="column">
  6. {(partials/header_nav.html)}
  7. </div>
  8. </header>

partials/header_nav.html

  1. <ul>
  2. {% for title, href in each(page.header_nav_items) do %}
  3. <li><a href="{{href}}">{{title}}</a></li>
  4. {% end %}
  5. </ul>

partials/hero.html

  1. <h1>{{page.hero_title}}</h1>
  2. <p>{{page.hero_description}}</p>

partials/hero.html

  1. <footer>
  2. <p>footer</p>
  3. </footer>

Output:

  1. <header class="row">
  2. <div class="column">
  3. <img src="assets/images/example.jpeg"/>
  4. </div>
  5. <div class="column">
  6. <ul>
  7. <li><a href="/about">about</a></li>
  8. <li><a href="/guieds">guides</a></li>
  9. </ul>
  10. </div>
  11. </header>
  12. <h1>Partials Info</h1>
  13. <p>Partials are wicked sick!</p>
  14. <footer>
  15. <p>footer</p>
  16. </footer>

Blocks

Blocks can be used to embed a view or partial into another template. Blocks are particularly useful when you want different templates to share a common wrapper.

In the example below, notice that the content file is referencing index.html, and not wrapper.html.

content/index.txt

  1. ---
  2. layout: index.html
  3. title: Blocks
  4. description: Blocks are the future!
  5. ---

layouts/index.html

  1. {% layout = "layouts/wrapper.html" %} <- syntax declaring where to find the block
  2. {-main-} <- delimiter describing what content renders in block
  3. <div class="content">
  4. <h1>{{page.title}}</h1>
  5. <p>{{page.description}}<p>
  6. </div>
  7. {-main-}
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Testing lua-resty-template blocks</title>
  5. </head>
  6. <body>
  7. <header>
  8. <p>header</p>
  9. </header>
  10. {*main*} <- syntax indicating where to place the block
  11. <footer>
  12. <p>footer</p>
  13. </footer>
  14. </body>
  15. </html>

Output:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Testing lua-resty-template blocks</title>
  5. </head>
  6. <body>
  7. <header>
  8. <p>header</p>
  9. </header>
  10. <div class="content">
  11. <h1>Blocks</h1>
  12. <p>Blocks are the future!<p>
  13. </div>
  14. <footer>
  15. <p>footer</p>
  16. </footer>
  17. </body>
  18. </html>

Collections are a powerful tool enabling you to render sets of content as a group. Content rendered as a collection share a configurable route pattern, as well as a layout. Collections are configured in your portals portal.conf.yaml file.

The example below shows all the necessary configuration/files needed to render a basic blog collection made up of individual posts.

portal.conf.yaml

  1. name: Kong Portal
  2. theme:
  3. name: base
  4. collections:
  5. posts:
  6. output: true
  7. route: /:stub/:collection/:name
  8. layout: post.html

Above you can see a collections object was declared, which is made up of individual collection configurations. In this example, you are configuring a collection called posts. The renderer looks for a root directory called _posts within the content folder for individual pages to render. If you created another collection conf called animals, the renderer would look for a directory called _animals for content files to render.

Each configuration item is made up of a few parts:

  • output
    • required: false
    • type: boolean
    • description: This optional attribute determines whether the collections should render or not. When set to false, virtual routes for the collection are not created.
  • route
    • required: true
    • type: string
    • default: none
    • description: The route attribute is required and tells the renderer what pattern to generate collection routes from. A collection route should always include at least one valid dynamic namespace that uniquely identifies each collection member.
      • Any namespace in the route declaration which begins with : is considered dynamic.
      • Only certain dynamic namespaces are recognized by Kong as valid:
        • :title: Replaces namespace with a contents title, declared in headmatter.
        • :name: Replaces namespace with the filename of a piece of content.
        • :collection: Replaces namespace with name of current collection.
        • :stub: Replaces namespace with value of headmatter.stub in each contents headmatter.
  • layout
    • required: true
      • type: boolean
      • description: The layout attribute determines what HTML layout the collections use to render. The path root is accessed from within the current themes layouts directory.

content/_posts/post1.md

  1. ---
  2. title: Post One
  3. stub: blog
  4. This is my first post!

content/_posts/post2.md

  1. ---
  2. title: Post Two
  3. stub: blog
  4. ---
  5. This is my second post!

themes/base/layouts/post.html

  1. <h1>{{ page.title }}</h1>
  2. <p>{* page.body *}</p>

Output:

From <kong_portal_gui_url>/blog/posts/post1:

  1. <h1>Post One</h1>
  2. <p>This is my first post!</p>

From <kong_portal_gui_url>/blog/posts/post2:

  1. <h1>Post Two</h1>
  2. <p>This is my second post!</p>

Kong Template Helpers - Lua API

Kong Template Helpers are a collection of objects that give access to your portal data at the time of render and provide powerful integrations into Kong.

Globals:

  • l - Locale helper, first version, gets values from the currently active page.
  • - Commonly used helper to iterate over lists or tables.
  • print - Commonly used helper to print lists / tables.
  • - Commonly used helper to print lists / tables.
  • json_decode - Decode JSON to Lua table.
  • - Encode Lua table to JSON.

Objects:

  • portal - The portal object refers to the current workspace portal being accessed.
  • - The page object refers to the currently active page and its contents.
  • user - The user object represents the currently logged in developer accessing the Kong Portal.
  • - The theme object represents the currently active theme and its variables.
  • tbl = Table helper methods. Examples: map, filter, find, sort.
  • = String helper methods. Examples: lower, upper, reverse, endswith.
  • helpers - Helper functions simplify common tasks or provide easy shortcuts to Kong Portal methods.

Terminology / Definitions:

  • list - Also referred to commonly as an array ([1, 2, 3]) in Lua is a table-like object ({1, 2, 3}). Lua list index starts at 1 not 0. Values can be accessed by array notation (list[1]).
  • table - Also commonly known as an object or hashmap ({1: 2}) in Lua looks like ({1 = 2}). Values can be accessed by array or dot notation (table.one or table["one"]).

l(key, fallback)

Returns the current translation by key from the currently active page.

Return Type

  1. string

Usage

Using content/en/example.txt:

  1. ---
  2. layout: example.html
  3. locale:
  4. title: Welcome to {{portal.name}}
  5. slogan: The best developer portal ever created.
  6. ---

Using content/es/example.txt:

  1. ---
  2. layout: example.html
  3. locale:
  4. title: Bienvenido a {{portal.name}}
  5. slogan: El mejor portal para desarrolladores jamás creado.
  6. ---

Using layouts/example.html:

  1. <h1>{* l("title", "Welcome to" .. portal.name) *}</h1>
  2. <p>{* l("slogan", "My amazing developer portal!") *}</p>
  3. <p>{* l("powered_by", "Powered by Kong.") *}</p>

Output:

For en/example:

  1. <h1>Welcome to Kong Portal</h1>
  2. <p>The best developer portal ever created.</p>
  3. <p>Powered by Kong.</p>

For es/example:

  1. <h1>Bienvenido a Kong Portal</h1>
  2. <p>El mejor portal para desarrolladores jamás creado.</p>
  3. <p>Powered by Kong.</p>

Notes

  • l(...) is a helper from the page object. It can be also accessed via page.l. However, page.l does not support template interpolation (for example, `` will not work.)

each(list_or_table)

Returns the appropriate iterator depending on what type of argument is passed.

Return Type

  1. Iterator

Usage

Template (List):

  1. {% for index, value in each(table) do %}
  2. <ul>
  3. <li>Index: {{index}}</li>
  4. <li>Value: {{ print(value) }}</li>
  5. </ul>
  6. {% end %}

Template (Table):

  1. {% for key, value in each(table) do %}
  2. <ul>
  3. <li>Key: {{key}}</li>
  4. <li>Value: {{ print(value) }}</li>
  5. </ul>
  6. {% end %}

print(any)

Returns stringified output of input value.

Return Type

  1. string

Usage

Template (Table):

  1. <pre>{{print(page)}}</pre>

markdown(string)

Returns HTML from the markdown string passed as an argument. If a string argument is not valid markdown, the function will return the string as is. To render properly, the helper should be used with raw {* *} delimiters.

Return Type

  1. string

Usage

Template (string as arg):

  1. <pre>{* markdown("##This is Markdown") *}</pre>

Template (content val as arg):

  1. <pre>{* markdown(page.description) *}</pre>

JSON encodes Lua table passed as argument

Return Type

    Usage

    Template:

    1. <pre>{{ json_encode({ dog = cat }) }}</pre>

    json_decode(string)

    Decodes JSON string argument to Lua table

    Return Type

    1. table

    Usage

    Template:

    1. <pre>{{ print(json_encode('{"dog": "cat"}')) }}</pre>

    portal

    portal gives access to data relating to the current portal, this includes things like portal configuration, content, specs, and layouts.

    You can access the current workspace’s portal config directly on the portal object like so:

    For example portal.auth is a portal config value. You can find a list of config values by reading the portal section of kong.conf.

    From kong.conf

    Some configuration values are modified or customized, these customizations are documented under the Portal Members section.

    portal.workspace

    Returns the current portal’s workspace.

    Return Type
    1. string
    Usage

    Template:

    1. {{portal.workspace}}

    Output:

    1. default

    portal.url

    Returns the current portal’s url with workspace.

    Return Type
    1. string
    Usage

    Template:

    1. {{portal.url}}

    Output:

    1. http://127.0.0.1:8003/default

    portal.api_url

    Returns the configuration value for portal_api_url with the current workspace appended.

    Return Type
    1. string or nil
    Usage

    Template:

    1. {{portal.api_url}}

    Output when portal_api_url = http://127.0.0.1:8004:

    1. http://127.0.0.1:8004/default

    portal.auth

    Returns the current portal’s authentication type.

    Return Type
    1. string
    Usage

    Printing a value

    Input:

    1. {{portal.auth}}

    Output when portal_auth = basic-auth:

    1. basic-auth

    Checking if authentication is enabled

    Input:

    1. {% if portal.auth then %}
    2. Authentication is enabled!
    3. {% end %}

    Output when portal_auth = basic-auth:

    1. Authentication is endabled!

    portal.specs

    Returns an array of specification files contained within the current portal.

    Return type
    1. array
    Usage

    Viewing a content value

    Template:

    1. <pre>{{ print(portal.specs) }}</pre>

    Output:

    1. {
    2. {
    3. "path" = "content/example1_spec.json",
    4. "content" = "..."
    5. },
    6. {
    7. "path" = "content/documentation/example1_spec.json",
    8. "content" = "..."
    9. },
    10. ...
    11. }

    Looping through values

    Template:

    1. {% for _, spec in each(portal.specs) %}
    2. <li>{{spec.path}}</li>
    3. {% end %}

    Output:

    1. <li>content/example1_spec.json</li>
    2. <li>content/documentation/example1_spec.json</li>

    Filter by path

    Template:

    1. {% for _, spec in each(helpers.filter_by_path(portal.specs, "content/documentation")) %}
    2. <li>{{spec.path}}</li>
    3. {% end %}

    Output:

    1. <li>content/documentation/example1_spec.json</li>

    portal.developer_meta_fields

    Returns an array of developer meta fields available/required by Kong to register a developer.

    Return Type

    1. array
    Usage

    Printing a value

    Template:

    1. {{ print(portal.developer_meta_fields) }}

    Output:

    1. {
    2. {
    3. label = "Full Name",
    4. name = "full_name",
    5. type = "text",
    6. required = true,
    7. },
    8. ...

    Looping through values

    Template:

    1. {% for i, field in each(portal.developer_meta_fields) do %}
    2. <ul>
    3. <li>Label: {{field.label}}</li>
    4. <li>Name: {{field.name}}</li>
    5. <li>Type: {{field.type}}</li>
    6. <li>Required: {{field.required}}</li>
    7. </ul>
    8. {% end %}

    Output:

    1. <ul>
    2. <li>Label: Full Name</li>
    3. <li>Name: full_name</li>
    4. <li>Type: text</li>
    5. <li>Required: true</li>
    6. </ul>
    7. ...

    page

    page gives access to data relating to the current page, which includes things like page url, path, breadcrumbs, and more.

    When you create a new content page, you are able to define key-values. Here you are going to learn how to access those values and a few other interesting things.

    You can access the key-values you define directly on the page object like so:

    1. page[key_name] or page.key_name

    You can also access nested keys like so:

    1. page.key_name.nested_key

    Be careful! To avoid output errors, make sure that the key_name exists before accessing nested_key as shown below:

    1. {{page.key_name and page.key_name.nested_key}}

    page.route

    Returns the current page’s route/path.

    Return Type
    1. string
    Usage

    Template:

    1. {{page.route}}

    Output, given url is http://127.0.0.1:8003/default/guides/getting-started:

    1. guides/getting-started

    page.url

    Returns the current page’s url.

    Return Type
    1. string
    Usage
    1. {{page.url}}

    Output, given url is http://127.0.0.1:8003/default/guides/getting-started:

    page.breadcrumbs

    Returns the current page’s breadcrumb collection.

    Return Type
    1. table[]
    Item Properties
    • item.path - Full path to item, no forward-slash prefix.
    • item.display_name - Formatted name.
    • item.is_first - Is this the first item in the list?
    • item.is_last - Is this the last item in the list?
    Usage

    Template:

    1. <div id="breadcrumbs">
    2. <a href="">Home</a>
    3. {% for i, crumb in each(page.breadcrumbs) do %}
    4. {% if crumb.is_last then %}
    5. / {{ crumb.display_name }}
    6. {% else %}
    7. / <a href="{{crumb.path}}">{{ crumb.display_name }}</a>
    8. {% end %}
    9. {% end %}
    10. </div>

    page.body

    Returns the body of the current page as a string. If the route’s content file has a .md or .markdown extension, the body will be parsed from markdown to html.

    Return Type
    1. string
    Usage for .txt, .json, .yaml, .yml templates

    index.txt:

    1. This is text content.

    Template:

    1. <h1>This is a title</h1>
    2. <p>{{ page.body) }}</p>

    Output:

    1. > # This is a title
    2. > This is text content.
    Usage for .md, .markdown templates

    Template (markdown): Use the raw delimiter syntax {* *} to render markdown within a template.

    index.txt

    1. # This is a title
    2. This is text content.

    Template:

    1. {* page.body *}

    Output:

    1. > # This is a title
    2. > This is text content.

    user

    user gives access to data relating to the currently authenticated user. User object is only applicable when KONG_PORTAL_AUTH is enabled.

    user.is_authenticated

    Returns boolean value as to the current user’s authentication status.

    Return Type
    1. boolean
    Usage

    Template:

    1. {{print(user.is_authenticated)}}

    Output:

    1. true

    user.has_role

    Returns true if a user has a role given as an argument.

    Return Type
    1. boolean
    Usage

    Template:

    1. {{print(user.has_role("blue"))}}

    Output:

    1. true

    user.get

    Takes developer attribute as an argument and returns value if present.

    Return Type
    1. any
    Usage

    Template:

    1. {{user.get("email")}}
    2. {{print(user.get("meta"))}}

    Output:

    1. example123@konghq.com
    2. { "full_name" = "example" }

    theme

    The theme object exposes values set in your theme.conf.yaml file. In addition, any variable overrides contained in portal.conf.yaml will be included as well.

    theme.colors

    Returns a table of color variables and their values as key-value pairs.

    Return Type
    1. table
    Usage

    theme.conf.yaml:

    1. name: Kong
    2. colors:
    3. primary:
    4. value: '#FFFFFF'
    5. description: 'Primary Color'
    6. secondary:
    7. value: '#000000'
    8. description: 'Secondary Color'
    9. tertiary:
    10. value: '#1DBAC2'
    11. description: 'Tertiary Color'

    Template:

    1. {% for k,v in each(theme.colors) do %}
    2. <p>{{k}}: {{v}}</p>
    3. {% end %}

    Output:

    1. <p>primary: #FFFFFF</p>
    2. <p>secondary: #000000</p>
    3. <p>tertiary: #1DBAC2</p>

    theme.color

    Description

    Takes color var by string argument, returns value.

    Return Type
    1. string
    Usage

    theme.conf.yaml:

    1. name: Kong
    2. colors:
    3. primary:
    4. value: '#FFFFFF'
    5. description: 'Primary Color'
    6. secondary:
    7. value: '#000000'
    8. description: 'Secondary Color'
    9. tertiary:
    10. value: '#1DBAC2'
    11. description: 'Tertiary Color'

    Template:

    1. <p>primary: {{theme.color("primary")}}</p>
    2. <p>secondary: {{theme.color("secondary")}}</p>
    3. <p>tertiary: {{theme.color("tertiary")}}</p>

    Output:

    1. <p>primary: #FFFFFF</p>
    2. <p>secondary: #000000</p>
    3. <p>tertiary: #1DBAC2</p>

    theme.fonts

    Returns table of font vars and their values as key-value pairs.

    Return Type
    1. table
    Usage

    theme.conf.yaml:

    1. name: Kong
    2. fonts:
    3. base: Roboto
    4. code: Roboto Mono
    5. headings: Lato

    Template:

    1. {% for k,v in each(theme.fonts) do %}
    2. <p>{{k}}: {{v}}</p>
    3. {% end %}

    Output:

    1. <p>base: Roboto</p>
    2. <p>code: Roboto Mono</p>
    3. <p>headings: Lato</p>

    theme.font

    Takes font name by string argument, returns value.

    Return Type
    1. string
    Usage

    theme.conf.yaml:

    1. name: Kong
    2. fonts:
    3. base: Roboto
    4. code: Roboto Mono
    5. headings: Lato

    Template:

    1. <p>base: {{theme.font("base")}}</p>
    2. <p>code: {{theme.font("code")}}</p>
    3. <p>headings: {{theme.font("headings")}}</p>

    Output:

    1. <p>base: #FFFFFF</p>
    2. <p>code: #000000</p>
    3. <p>headings: #1DBAC2</p>

    str

    Table containing useful string helper methods.

    Usage

    .upper() example:

    Methods

    str.byte
    str.char
    str.dump
    str.find
    str.format
    str.gfind
    str.gmatch
    str.gsub
    str.len
    str.lower
    str.match
    str.rep
    str.reverse
    str.sub
    str.upper
    str.isalpha
    str.isdigit
    str.isalnum
    str.isspace
    str.islower
    str.isupper
    str.startswith
    str.endswith
    str.join
    str.splitlines
    str.split
    str.expandtabs
    str.lfind
    str.rfind
    str.replace
    str.count
    str.ljust
    str.rjust
    str.center
    str.lstrip
    str.rstrip
    str.strip
    str.splitv
    str.partition
    str.rpartition
    str.at
    str.lines
    str.title
    str.shorten
    str.quote_string

    tbl

    Table containing useful table helper methods

    Usage

    .map() example:

    1. {% tbl.map({"dog", "cat"}, function(item) %}
    2. {% if item ~= "dog" then %}
    3. {% return true %}
    4. {% end) %}

    Methods

    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.
    tbl.