Docs » Template rules and filters

Before you dig deep
Webhook uses the Swig JS templating language. It is very similar to Django, Jinja and Twig. Webhook also adds some extra filters, tags and functions to Swig's base functionality.

Calling data from the CMS onto the page

Data from the CMS is available on any Webhook page simply by invoking the content type id prefaced by cms.. At it's simplist, it can look something like this.

{# This would be an array of our "video games" from the CMS. #}
{# Note that we call the id "videogames", not the name "video games" #}
{{ cms.videogames }}

It is also possible to chain content types into one list.

{% set editorial = merge(cms.articles, cms.podcasts, cms.video) %}

The two styles of content types

Remember when you created your CMS form and we asked you whether there were multiple or just one version of the thing you added? That's important. We generate scaffolding for the multiple items type in your /templates/ directory. For the single item type we generate a single page in your /pages/ directory.

Hot tip
If you're confused about which type your form is, just look on your Add / Edit Content Types page. There you can find not only the ID, but the form type for any content type you created.

Example: Making a list from a multiple items form

In the following example we're going to put a list of video games onto the home page. We could copy this code anywhere though.

{# Grabbing content for list based CMS content #}

{# cms.videogames is our array from the CMS. Let's sort it by genre.#}
{% set action_games = cms.videogames|where('genre','action') %}

{# When you want to paginate the above data, use the following format. #}
{% set action_games = paginate(games, 5) %}

{# A simple forloop listing our games. #}
<ul>
  {% for game in action_games %}
    <li>
      <a href="{{ url(game) }}">{{ game.name }} ({{ game.genre }})</a>
      {# Resize the boxart to a max of 50x50 pixels #}
      <img src="{{ game.box_art|imageSize(50, 50) }}" />
    </li>
  {% endfor %}
</ul>

{# The actual pagination template, feel free to edit or replace the default one. #}
{% include "templates/partials/paginator.html" %}

Example: Outputting data from a single item form

Calling data from a single item form is similar, except the variable we set doesn't come out as a looped array. You just call it directly.

{# Grabbing content for non-list CMS content #}

{# We made a form called "About us". That means we can call the data at cms.aboutus #}

{# Because the about us content-type only has one object, we call it directly, rather than looping through it. #}
{{ cms.aboutus.name }}

{# This time, let's also crop the original image, rather than just resize it like before #}
{{ cms.aboutus.team_image|imageCrop(200, 200) }}

{# Since this field was a wysiwyg, we'll want to pass the filter of safe to say it's OK to load the HTML #}
{{ cms.aboutus.body|safe }}

Functions

In addition to the standard template filters and tags provided by Swig, Webhook ships with several helper functions to grab and interact with data from the CMS.

get()

Pro tip:
This is the formal, advanced way to pull content in through a function. You can also call {{ cms.articles }} directly as a varaible rather than using get(articles) and assigning it. Using the function simply allows you to pass options as described below.

Grabs data from the listed content types in the CMS.

{# Grab all articles, videos and podcasts from the CMS. Assign them to the editorial variable #}
{% set editorial = get(articles) %}

{# List all editorial, sort alphabetically #}
<ul>
  {% for object in editorial|sort("name") %}
    <li>
      <a href="{{ url(object) }}">
        {{ object._type }} {# Outputs article, video or podcast #}
        {{ object.image }}
        {{ object.name }}
      </a>
    </li>
  {% endfor %}
</ul>

Get can also be used to grab all the items in a type, even unpublished ones, by passing the boolean true as the last parameter.

{% set all_articles = get('articles', true) %}

getCurrentUrl()

Returns the URL of the page you're viewing.

{# Set class active if the URL you're on is the same as the article you're linking to. #}
<a href="{{ url(article) }}" {% if getCurrentUrl() == url(article) %}class="active" {% endif %}>{{ article.name }}</a>

getItem()

getItem() can be used to grab the data for any item in the CMS. Doing so requires you know the ID of the item you're looking for. The ID is the long string shown in the URL of that item in the CMS. You can also print out {{ item._id }} in your templates to find it.

{# Get the CMS data for a single movie we know exists #}
{# Setting true as the third parameter allows you to grab the data even if the content has not yet been published. #}
{% set star_wars = getItem('movie', 'xyn1873nsld87', true) %}

{{ star_wars.release_date|date('M d Y') }}

getItems()

Deprecated
This works, but we've made it so you can now call relationships directly. In the below example we could simply say {% for actor in movie.actors %} directly without the use of getItems() function.

Similar to getItem() above, but is used when multiple objects are allowed to be linked in a relationship.

{{ movie.name }}
{# In our movie form, we linked to some people actors. #}
{% for actor in getItems(movie.actors) %}
  {# Because we used getItems, we now have access to all the fields on that object. #}
  {{ actor.name }}
  {{ actor.gender }}
{% endfor %}

getSetting()

Returns the values from the global settings files that you set in the CMS.

{# Site Name #}
{{ getSetting('site_name') }}

{# Site Description #}
{{ getSetting('site_description') }}

{# Site Keywords #}
{{ getSetting('site_keywords') }}

{# Site URL #}
{{ getSetting('site_url') }}

{# Site Analytics ID #}
{{ getSetting('analytics_id') }}

{# Site Twitter #}
{{ getSetting('site_twitter') }}

{# Site Facebook #}
{{ getSetting('site_facebook') }}

getTypes()

Pro tip:
This is the formal, advanced way to grab an array of your content types. You can also use the global variable {{ cms_types }} as a shortcut.

Grabs all the content types in the CMS that are not singular types. An optional boolean parameter determines if it returns One Off types, defaults to not returning One Offs.

{# Return all types including one offs with true #}
{% set types = getTypes(true) %}
{# Link to content types you've created in the CMS so far. #}

<ul>
  {% for type in types %}
    <li><a href="{{ url(type) }}">{{ type.name }}</a></li>
  {% endfor %}
</ul>

merge(array1, array2, array3, .....)

Merges the arrays passed into a single array and returns the result.

{% set editorial = merge(cms.articles, cms.videos) %}

{% for item in editorial %}
  {{ item.name }}
{% endfor%}

nextItem(item, sort_field, reverse)

prevItem(item, sort_field, reverse)

Returns the next/previous item in the given content type. sort_field is the optional field to sort all the items on. If reverse is true, the sort will be reversed.

{# Assuming item is the current pages object #}

{% set prev = prevItem(item, 'publish_date', true) %}
{% set next = nextItem(item, 'publish_date', true) %}

<a href="{{ url(prev) }}">Prev</a>
<a href="{{ url(next) }}">Next</a>

paginate(data, perPage, urlPrefix)

Tells the templating system to paginate the content provided. This will tell Webhook to build multiple pages from this URL (example: http://www.yoursite.com/articles/page-2/).

  • data is the content you want paginated from the CMS.
  • perPage is the number of items per page.
  • urlPrefix is the prefix you want to use for the page url (default is /page-<pageNum>/).
Warning

You can only paginate once per page. If you try to add two paginators to a page things will blow up.

{% set articles = paginate(cms.articles, 10) %}

{# List all articles #}
{% for game in articles %}
  <li>
    <a href="{{ url(article) }}">
      {{ article.name }}
    </a>
  </li>
{% endfor %}

{# Outputs Webhook's default paginator buttons. Feel free to make your own. #}
{% include "templates/partials/paginator.html "%}

a

random()

Returns a random item out of an array. Note that because Webhook deploys static websites, this random action will only happen when you build your site (after a save or deploy). It will not randomize based on page refresh. To do that, you'll want to use a client side solution.

{% set random_game = random(cms.videogames) %}

{{ random_game.name }}

url(object)

Outputs the URL of the object passed to it.

{% for article in cms.articles %}
  <a href="{{ url(article) }}">{{ article.name }}</a>
{% endfor %}

Alternatively, you can pass the function a string and it will return the url of the list page of that content type.

<a href="{{ url('articles') }}">View all articles</a>

Filters

|date(format, offset)

Formats the given date according to the php style format string.

Offset is optional, specifies offset from GMT in minutes. The offset is positive if the timezone is negative, negative if the timezone is positive. (i.e. -06:00 === 360, +01:00 == -60)

If offset is not specified then the time is displayed in the timezone it was saved in.

{# January 01 2014 #}
{{ article.publish_date|date('M d Y') }}

{# Displayed in time zone the item was saved in #}
{{ article.publish_date|date('H:ia') }}

{# Date converted to timezone +02:00 #}
{{ article.create_date|date('H:ia', -120) }}

|addslashes

Backslash-escape characters that need to be escaped.

{{ "\"quoted string\""|addslashes }}
// => \"quoted string\"

|capitalize

Upper-case the first letter of the input and lower-case the rest.

{{ "i like Burritos"|capitalize }}
// => I like burritos

|default

If the input is undefined, null, or false, a default return value can be specified.

{{ null_value|default('Tacos') }}
// => Tacos

{{ "Burritos"|default("Tacos") }}
// => Burritos

|duration

Displays the seconds given in 'hours:minutes:seconds' format. Only shows hours if hours > 0. Useful for duration properties on audio files

{# Displays the seconds in hh:mm:ss format #}
{{ audio.duration|duration }}

|endsWith(string)

Returns true if the string passed in ends with the given string, false otherwise

{% set curUrl = getCurrentUrl() %}
{% if curUrl|endsWith('/some-ending/') %}
   This url ends in /some-ending/!
{% endif %}

|escape(type)

Force escape the output of the variable. Optionally use e as a shortcut filter name. This filter will be applied by default if autoescape is turned on.

{{ "<blah>"|escape }}
// => <blah>

{{ "<blah>"|e("js") }}
// => \u003Cblah\u003E

|exclude(property, filter)

Returns an array of data that does not include the provided filter.

Note: Does not work with relations. The opposite of this filter is the |where filter.

{# Will get all podcasts where the category is not 'comedy' #}
{% set not_comedy = cms.podcasts|exclude('category', 'comedy') %}

{# Can take multiple values. Just separate with commas. #}
{% set not_coming = cms.guest_list|exclude('RSVP', 'yes', 'maybe' %}

The exclude filter also accepts arrays as a filter, if an array is passed then every item in the array will have the specified property compared to the objects property. This can be used to exclude subsets of arrays.

{% set some_subset = cms.podcasts|slice(0, 3) %}
{# This will remove all items that match any of the ids of the objects in some_subset #}
{% set the_rest = cms.podcasts|exclude('_id', some_subset %}

|first

Get the first item in an array or character in a string. All other objects will attempt to return the first value available.

// my_arr = ['a', 'b', 'c']
{{ my_arr|first }}
// => a

// my_val = 'Tacos'
{{ my_val|first }}
// T

|groupBy(key)

Group an array of objects by a common key. If an array is not provided, the input value will be returned untouched.

// people = [{ age: 23, name: 'Paul' }, { age: 26, name: 'Jane' }, { age: 23, name: 'Jim' }];
{% for agegroup in people|groupBy('age') %}
  <h2>{{ loop.key }}</h2>
  <ul>
    {% for person in agegroup %}
    <li>{{ person.name }}</li>
    {% endfor %}
  </ul>
{% endfor %}

|imageSize(width, height)

Takes the passed image url and returns a new resized url based upon the dimensions provided.

If only width is specified, then the image is resized to to a bounding box of that size.

To resize by only one dimension you can use the keyword 'auto' for the dimension that you want to resize automatically.

Retains the original aspect ratio.

{# Resize the article image and output one that is max 200 width or 200 height #}
<img src="{{ article.image|imageSize(200) }}" />

{# Resize the article image and output one that is max 200 width or 400 height #}
<img src="{{ article.image|imageSize(200, 400) }}" />

{# Resize the article image and output one that is max 200 width #}
<img src="{{ article.image|imageSize(200, 'auto') }}" />

{# Resize the article image and output one that is max 400 height #}
<img src="{{ article.image|imageSize('auto', 400) }}" />

|imageCrop(width, height)

Takes the passed image url and returns a new resized url based upon the size provided.

If only width is provided then the image is cropped to a square of the given size.

To crop by only one dimension you can use the keyword 'auto' to specify the dimension you do not wish to crop.

{# Resize the article image to be a square 50 width x 50 height #}
<img src="{{ article.image|imageCrop(50) }}" />

{# Resize the article image to be a square 50 width x 25 height #}
<img src="{{ article.image|imageCrop(50, 25) }}" />

{# Crop the article image to have 50 width #}
<img src="{{ article.image|imageCrop(50, 'auto') }}" />

{# Crop the article image to have 25 height #}
<img src="{{ article.image|imageCrop('auto', 25) }}" />

|join

Join the input with a string.

// my_array = ['foo', 'bar', 'baz']
{{ my_array|join(', ') }}
// => foo, bar, baz

// my_key_object = { a: 'foo', b: 'bar', c: 'baz' }
{{ my_key_object|join(' and ') }}
// => foo and bar and baz

|json

Returns the object passed as JSON. When used in combination with sub-templates, this gives you a fast http: endpoint for your data.

{# Let's say this is a file I make at /templates/article/json.html #}

{{ item|json }}

{# Now all my article pages can give me json if I go to /articles/article-name/json/ #}

|last

Get the last item in an array or character in a string. All other objects will attempt to return the last value available.

// my_arr = ['a', 'b', 'c']
{{ my_arr|last }}
// => c

// my_val = 'Tacos'
{{ my_val|last }}
// s

|lower

Return the input in all lowercase letters.

{{ "FOOBAR"|lower }}
// => foobar

// myObj = { a: 'FOO', b: 'BAR' }
{{ myObj|lower|join('') }}
// => foobar

|markdown

Coverts the content to HTML from Markdown syntax

// content = '**This is bold**'
{{ content|markdown }}
// => <strong>This is bold</strong>

|pluralize

Returns a plural suffix if the value is not 1. By default, this suffix is 's'.

You have {{ cms.articles|size }} message{{ cms.articles|pluralize }}.

If num_messages is 1, the output will be You have 1 message. If num_messages is 2 the output will be You have 2 messages.

For words that require a suffix other than 's', you can provide an alternate suffix as a parameter to the filter.

You have {{ cms.walrus|size }} walrus{{ num_walruses|pluralize("es") }}.

For words that don’t pluralize by simple suffix, you can specify both a singular and plural suffix, separated by a comma.

You have {{ cms.cherries }} cherr{{ cms.cherries|pluralize:"y,ies" }}.

|replace(search, replacement, flags)

Returns a new string with the matched search pattern replaced by the given replacement string. Uses JavaScript's built-in String.replace() method.

  • search String or pattern to replace from the input.
  • replacement String to replace matched pattern.
  • flags Regular Expression flags. 'g': global match, 'i': ignore case, 'm': match over multiple lines
// my_var = 'foobar';
{{ my_var|replace('o', 'e', 'g') }}
// => feebar

// my_var = "farfegnugen";
{{ my_var|replace('^f', 'p') }}
// => parfegnugen

// my_var = 'a1b2c3';
{{ my_var|replace('\w', '0', 'g') }}
// => 010203

|reverse

Reverse sort the input. This is an alias for {{ input|sort(true) }}.

// val = [1, 2, 3];
{{ val|reverse }}
// => 3,2,1

|safe

Forces the input to not be auto-escaped. Use this only on content that you know is safe to be rendered on your page. This should be used on all WYSIWYG content to make it display properly.

// my_var = "<p>Stuff</p>";
{{ my_var|safe }}
// => <p>Stuff</p>

|size

Returns the number of items in an array.

{% set editorial = merge(cms.articles, cms.podcasts)%}

There are a total of {{ editorial|size }} articles and podcasts.

|slice(offset, limit)

Slices the array passed, returning only those items between the offset and the limit.

{# Output only 10 articles, starting with the 5th one. #}
{% for article in cms.articles|slice(5,10) %}
  {{ article.name }}
{% endfor %}

|sort(property, reverseOrder)

Sorts an array by the property. By default all arrays sorted by create date.

{# Sort articles alphabetically by name #}
{% for article in cms.articles|sort('name') %}
  {{ article.name }}
{% endfor %}

{# Sort articles by publish date, newest first #}
{% for article in cms.articles|sort('publish_date', true) %}
  {{ article.name }}
{{ article.publish_date|date('F d Y') }}
{% endfor %}
Tip when sorting within pagination
If you're attempting to sort something you plan on paginating, make sure you run your |sort before you paginate and not in the forloop itself. Example of proper usage below.
{# First, sort articles by the publish date, newest first. #}
{% set articles = cms.articles|sort('publish_date', true) %}

{# Finally paginate the sorted list #}
{% set articles = paginate(data, 5) %}

{# Sort articles by publish date, newest first #}
{% for article in articles %}
  {{ article.name }}
{{ article.publish_date|date('F d Y') }}
{% endfor %}

{# The actual pagination template, feel free to edit or replace the default one. #}
{% include "templates/partials/paginator.html" %}

###|startsWith(string)

Returns true if the string passed in starts with the given string, false otherwise

{% set curUrl = getCurrentUrl() %}
{% if curUrl|startsWith('/some/prefix/') %}
  This is a sub page of /some/prefix/!
{% endif %}

|striptags

Strip HTML from tags.

// stuff = '<p>foobar</p>';
{{ stuff|striptags }}
// => foobar

|title

Capitalizes every word given and lower-cases all other letters.

// my_str = 'this is soMe text';
{{ my_str|title }}
// => This Is Some Text

// my_arr = ['hi', 'this', 'is', 'an', 'array'];
{{ my_arr|title|join(' ') }}
// => Hi This Is An Array

|truncate(size)

Truncates the returned string by the the number of characters passed. Also makes sure not to stop mid word.

{# Strips any HTML out of the body content and truncates to 100 characters. #}
{{ article.body|striptags|truncate(100) }}

|where(property, filter)

Filters an array of objects down to objects where the property on the object is equal to filter. If filter is not provided, then it filters the array to objects where property exists.

Note: Does not work with relations. The opposite of this filter is the |exclude filter.

{# Will get all podcasts where the category is 'comedy' #}
{% set funny = cms.podcasts|where('category', 'comedy') %}

{# Can take multiple values. Just separate with commas. #}
{% set possible = cms.guest_list|where('RSVP', 'yes', 'maybe' %}

|uniq

Remove all duplicate items from an array.

// my_arr = [1, 2, 3, 4, 4, 3, 2, 1];
{{ my_arr|uniq|join(',') }}
// => 1,2,3,4

|upper

Convert the input to all uppercase letters. If an object or array is provided, all values will be uppercased.

// my_str = 'tacos';
{{ my_str|upper }}
// => TACOS

// my_arr = ['tacos', 'burritos'];
{{ my_arr|upper|join(' & ') }}
// => TACOS & BURRITOS

|url_encode

URL-encode a string. If an object or array is passed, all values will be URL-encoded.

// my_str = 'param=1&anotherParam=2';
{{ my_str|url_encode }}
// => param%3D1%26anotherParam%3D2

|url_decode

URL-decode a string. If an object or array is passed, all values will be URL-decoded.

// my_str = 'param%3D1%26anotherParam%3D2';
{{ my_str|url_decode }}
// => param=1&anotherParam=2

Tags

autoescape

Control auto-escaping of variable output from within your templates.

// myvar = '<foo>';
{% autoescape true %}{{ myvar }}{% endautoescape %}
// => &lt;foo&gt;
{% autoescape false %}{{ myvar }}{% endautoescape %}
// => <foo>

block

Defines a block in a template that can be overridden by a template extending this one and/or will override the current template's parent template block of the same name. See the template inheritance docs for proper usage.

{% block body %}...{% endblock %}

else

Used within an {% if %} tag, the code block following this tag up until {% endif %} will be rendered if the if statement returns false.

{% if false %}
  statement1
{% else %}
  statement2
{% endif %}
// => statement2

elseif

Like {% else %}, except this tag can take more conditional statements.

{% if false %}
  Tacos
{% elseif true %}
  Burritos
{% else %}
  Churros
{% endif %}
// => Burritos

extends

Makes the current template extend a parent template. This tag must be the first item in your template. See the template inheritance docs for proper usage.

{% extends "templates/partials/base.html" %}

filter

Apply a filter to an entire block of template.

{% filter uppercase %}oh hi, {{ name }}{% endfilter %}
// => OH HI, PAUL

{% filter replace(".", "!", "g") %}Hi. My name is Paul.{% endfilter %}
// => Hi! My name is Paul!

for

Loop over CMS objects and arrays. Has the following variables within the loop itself:

  • loop.index: The current iteration of the loop (1-indexed)
  • loop.index0: The current iteration of the loop (0-indexed)
  • loop.revindex: The number of iterations from the end of the loop (1-indexed)
  • loop.revindex0: The number of iterations from the end of the loop (0-indexed)
  • loop.key: If the iterator is an object, this will be the key of the current item, otherwise it will be the same as the loop.index.
  • loop.first: True if the current object is the first in the object or array.
  • loop.last: True if the current object is the last in the object or array.
// obj = { one: 'hi', two: 'bye' };
{% for x in obj %}
  {% if loop.first %}<ul>{% endif %}
  <li>{{ loop.index }} - {{ loop.key }}: {{ x }}</li>
  {% if loop.last %}</ul>{% endif %}
{% endfor %}
// => <ul>
//    <li>1 - one: hi</li>
//    <li>2 - two: bye</li>
//    </ul>


// arr = [1, 2, 3]
// Reverse the array, shortcut the key/index to `key`
{% for key, val in arr|reverse %}
{{ key }} -- {{ val }}
{% endfor %}
// => 0 -- 3
//    1 -- 2
//    2 -- 1

if

Used to create conditional statements in templates. Accepts most JavaScript valid comparisons.

Can be used in conjunction with {% elseif ... %} and {% else %} tags.

{% if x %}{% endif %}
{% if !x %}{% endif %}
{% if not x %}{% endif %}

{% if x and y %}{% endif %}
{% if x && y %}{% endif %}
{% if x or y %}{% endif %}
{% if x || y %}{% endif %}
{% if x || (y && z) %}{% endif %}

{% if x [operator] y %}
  Operators: ==, !=, <, <=, >, >=, ===, !==
{% endif %}

{% if x == 'five' %}
  The operands can be also be string or number literals
{% endif %}

{% if x|lower === 'tacos' %}
  You can use filters on any operand in the statement.
{% endif %}

{% if x in y %}
  If x is a value that is present in y, this will return true.
{% endif %}

include

Includes a template partial in place. The template is rendered within the current locals variable context. Can also have the following parameters.

  • file The path, relative to the template root, to render into the current context.
  • with Literally, "with".
  • context Local variable key-value object context to provide to the included file.
  • only Restricts to only passing the with context as local variables the included template will not be aware of any other local variables in the parent template. For best performance, usage of this option is recommended if possible.
  • ignore missing Will output empty string if not found instead of throwing an error.
// food = 'burritos';
// drink = 'lemonade';
{% include "templates/partials/partial.html" %}
// => I like burritos and lemonade.

// my_obj = { food: 'tacos', drink: 'horchata' };
{% include "templates/partials/partial.html" with my_obj only %}
// => I like tacos and horchata.

{% include "/this/file/does/not/exist" ignore missing %}
// => (Nothing! empty string)

parent

Inject the content from the parent template's block of the same name into the current block. See the template inheritance docs for proper usage.

{% extends "./foo.html" %}
{% block content %}
  My content.
  {% parent %}
{% endblock %}

raw

Forces the content to not be auto-escaped. All swig instructions will be ignored and the content will be rendered exactly as it was given.

// foobar = '<p>'
{% raw %}{{ foobar }}{% endraw %}
// => {{ foobar }}

set

Set a variable for re-use in the current context. This will over-write any value already set to the context for the given varname.

{% set foo = "anything!" %}
{{ foo }}
// => anything!

// index = 2;
{% set bar = 1 %}
{% set bar += index|default(3) %}
// => 3

// foods = {};
// food = 'chili';
{% set foods[food] = "con queso" %}
{{ foods.chili }}
// => con queso

// foods = { chili: 'chili con queso' }
{% set foods.chili = "guatamalan insanity pepper" %}
{{ foods.chili }}
// => guatamalan insanity pepper

spaceless

Attempts to remove whitespace between HTML tags. Use at your own risk.

{% spaceless %}
  {% for num in foo %}
  <li>{{ loop.index }}</li>
  {% endfor %}
{% endspaceless %}
// => <li>1</li><li>2</li><li>3</li>

Global and hidden variables

Globals

Webhook creates the following global variables for every site. They can be called directly on any page.

{{ cms_types }}          // An array of your multi-item content-types. You can use the function getTypes(true) to pull in single-item types as well.
{{ cmsSocketPort }}      // The port the local runserver is on.
{{ cmsVersion }}         // The version number of the latest CMS. Used on cms.html.
{{ cms.contenttypeid }}  // An array of data for the content type id you provide. Ex: A "video games" content type can be called with {{ cms.videogames }}.
{{ firebase_conf }}      // Values for your site's Firebase settings.
{{ production }}         // Boolean. True if on the live website, False if being run locally.

Hidden values

Webhook also stores the following hidden values on any item within a multi-item content type.

{{ item._id }}           // A hashed string. This corresponds with the URL in the CMS for that item.
{{ item._type }}         // A string value of the item's content type. Ex: "articles".
{{ item._relationname }} // Where relationname = the name of the field you created for relations. Using this version will also output items that have yet to be published (which we normally filter out).

Make your own globals

It's extremely easy to create your own global variables with Webhook. Simply create a new, single-item content-type (let's assume "Global Variables"). Then create some fields to store those values. Now you can call {{ cms.globalvariables.my_field_name }} on any page.