Template Plugins
Overview
Plugins extend the capabilities of HyperTemplates with support for Javascript functions.
A plugin is a Javascript file that exports a default function.
The exported function can accept positional arguments supplied at run time.
Some plugins get predefined local bindings injected into the runtime environment (e.g. local const declarations).
All plugins are executed in an Immediately Invoked Function Expression (IIFE) for scope isolation.
NEW: Template plugins are available in
hyperctlversion 0.20.0 and newer.
Examples
This is an example template variable plugins, which can accept one or more positional arguments.
1// uppercase transforms strings to uppercase
2export default function uppercase(input="") {
3 return input.toUpperCase()
4};
This is an example computed namespace plugin, which does not accept arguments but does have access local data bindings, including: ht.*, build.*, env.*, data.*, theme.*, and site.* template data (including the full site.pages sitemap):
1// tags.js generates a data.tags object of unique website tags w/ tag counts
2// example output: {"html":{"count":3,"label":"HTML"},"css":{"count":1,"label":"CSS"},"rss":{"count":4,"label":"RSS"}}
3export default function tagcloud() {
4 var result = {}
5 for (let page of site.pages) {
6 let tags = page.tags || []
7 console.log(`${ page.path } has ${ tags.length } tags`)
8 for (let tag of tags) {
9 let id = tag.toLowerCase();
10 result[id] = (result[id] || { label: tag, count: 0 })
11 result[id].count += 1
12 }
13 }
14 return result
15};
Specification
Plugins kinds
HyperTemplates currently supports two kinds of plugins:
- Template variable plugins
- Add custom template variable functions with template variable plugins.
Learn more - Computed namespace plugins
- Add generated template data with computed namespace plugins.
Learn more
Plugin identifiers
HyperTemplates plugin identifiers are derived via file name.
For example, computed namespace plugin at <data_dir>/archive.js is named archive.
Plugin runtime environment
HyperTemplates plugins run in sandboxed JavaScript environments that support modern JavaScript: let, const, arrow functions, template literals, destructuring, classes, Promise, and async/await, on top of an ECMAScript 5.1+ baseline.
Think of it as "JavaScript the programming language" without "JavaScript the browser" or Node.js — there is no DOM (window, document, fetch) and none of the Node.js globals (require, process, Buffer, setTimeout).
Plugins can leverage plain functions, core JavaScript types like objects and arrays, plus standard built-ins including Object, Array, String, Number, Boolean, BigInt, Symbol, Date, RegExp, Map, Set, Promise, JSON, Math, Proxy, Reflect, undefined, Error, TypeError, RangeError, SyntaxError, ReferenceError, parseInt, parseFloat, NaN, isNaN, Infinity, isFinite, encodeURI, decodeURI, encodeURIComponent, decodeURIComponent, and more.
Plugins are executed inside Immediately Invoked Function Expressions (IIFEs), so each invocation runs in an isolated scope with no shared state.
Plugin logging
HyperTemplates plugins have access to a console object, including console.log, console.info, console.warn, console.error, and console.debug.
All console.* methods write to standard output with a [scripting] prefix.
A console.logger(name) function returns a console-shaped object that prefixes its output with the provided name (i.e. [name] ) which is useful for debugging output from a specific plugin.
Examples
In the following example we use console.log() directly.
The highlighted line will generate output like [scripting] /about/ has 4 tags.
1// tags.js generates a data.tags object of unique website tags w/ tag counts
2// example output: {"html":{"count":3,"label":"HTML"},"css":{"count":1,"label":"CSS"},"rss":{"count":4,"label":"RSS"}}
3export default function tagcloud() {
4 var result = {}
5 for (let page of site.pages) {
6 let tags = page.tags || []
7 console.log(`${ page.path } has ${ tags.length } tags`)
8 for (let tag of tags) {
9 let id = tag.toLowerCase();
10 result[id] = (result[id] || { label: tag, count: 0 })
11 result[id].count += 1
12 }
13 }
14 return result
15};
In this example we use console.logger("tags.js") to customize the log output.
The resulting call to logger.log() will generate output like [tags.js] /about/ has 4 tags.
1// tags.js generates a data.tags object of unique website tags w/ tag counts
2// example output: {"html":{"count":3,"label":"HTML"},"css":{"count":1,"label":"CSS"},"rss":{"count":4,"label":"RSS"}}
3const logger = console.logger("tags.js");
4export default function tagcloud() {
5 var result = {}
6 for (let page of site.pages) {
7 let tags = page.tags || []
8 logger.log(`${ page.path } has ${ tags.length } tags`)
9 for (let tag of tags) {
10 let id = tag.toLowerCase();
11 result[id] = (result[id] || { label: tag, count: 0 })
12 result[id].count += 1
13 }
14 }
15 return result
16};
Positional arguments
Some plugin kinds support positional arguments.
Example
For example, this template variable plugin accepts two positional arguments, date and format:
1// datefmt formats RFC3339 date strings using the Unicode LDML microsyntax for dates.
2//
3// Date Field Symbol Table: https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
4//
5// Format tokens:
6//
7// yyyy 4-digit year (2026)
8// yy 2-digit year (26)
9// MMMM Full month name (April)
10// MMM Abbreviated month (Apr)
11// MM 2-digit month (04)
12// M Numeric month (4)
13// dd 2-digit day (12)
14// d Numeric day (12)
15// EEEE Full weekday (Sunday)
16// EEE Abbreviated weekday (Sun)
17// HH 24-hour, padded (14)
18// hh 12-hour, padded (02)
19// mm Minute, padded (30)
20// ss Second, padded (05)
21// a AM/PM marker (PM)
22// ZZZZZ ISO 8601 w/ colon (-07:00)
23// Z ISO 8601 w/o colon (-0700)
24//
25// Usage: ${ datefmt page.created_at "EEEE, MMMM d, yyyy" }
26export default function datefmt(date="", format="") {
27 const datetime = new Date(date);
28 var out = ""
29 // apply formatting
30 return out
31}
If used in a template variable like ${ datefmt page.created_at "EEEE, MMMM d, yyyy" }, HyperTemplates will lookup the value of page.created_at (an RFC3339 string), and call datefmt(...["2026-05-08T11:00:00-07:00", "EEEE, MMMM d, yyyy"]).
When used in a template variable like ${ datefmt page.created_at "EEEE, MMMM d, yyyy" }, HyperTemplates resolves page.created_at from template data and invokes the plugin with the resulting value (an RFC3339 string), in the same order: datefmt("2026-05-08T11:00:00-07:00", "EEEE, MMMM d, yyyy").
Local variables
HyperTemplates plugins are executed inside Immediately Invoked Function Expressions (IIFEs) with optional predefined local const bindings.
For example, computed namespace plugins have access to ht, env, build, theme, site, and data as local variables.