Plugin Structure and Metadata
Every plugin is a pair of files in its own directory: a compiled WASM module and
a TOML manifest that tells Accent CMS what the plugin can do. This page covers
the directory layout and every section of the plugin.toml file.
Plugin Directory Structure
Plugins live in site/plugins/, with each plugin in its own subdirectory:
site/
plugins/
syntax-highlight/
plugin.toml # Metadata (required)
plugin.wasm # Compiled WASM module (required)
contact-form/
plugin.toml
plugin.wasm
search/
plugin.toml
plugin.wasm
Each plugin directory must contain both files:
plugin.toml- Declares the plugin’s name, version, and capabilitiesplugin.wasm- The compiled WebAssembly module built with an Extism PDK
If either file is missing, the plugin is skipped with a warning. Invalid plugins do not prevent the server from starting.
Plugin Metadata (plugin.toml)
The plugin.toml file declares what a plugin can do. Here is a complete example:
[plugin]
name = "syntax-highlight"
version = "0.1.0"
api_version = "0.1.0"
description = "Syntax highlighting for code blocks"
[hooks]
on_render = true # Called after markdown-to-HTML rendering
on_page_load = false # Called before markdown processing
on_media_discover = false # Called during content scanning for media files
on_media_process = false # Called after image processing
[filters]
# filter_name = "exported_function_name"
highlight = "apply_highlight"
lang_name = "get_language_name"
[shortcodes]
# List of shortcode names this plugin handles
codes = ["code", "highlight"]
[routes]
# path = "HTTP method"
"/api/highlight" = "POST"
"/api/languages" = "GET"
[config]
# Plugin-specific settings (passed to the plugin as JSON)
theme = "monokai"
line_numbers = true
Required Fields
The [plugin] section is required:
| Field | Type | Description |
|---|---|---|
name | string | Unique plugin identifier (used as registry key) |
version | string | Semantic version of the plugin |
api_version | string | Host API version the plugin targets (checked against the host’s supported range; see Security) |
description | string | Human-readable description (optional) |
requires_fs | bool | Request WASI filesystem access (optional, default: false) |
Hooks
The [hooks] section declares which lifecycle hooks the plugin listens to:
| Hook | When it fires | Input | Output |
|---|---|---|---|
on_page_load | Before markdown processing | Raw markdown | Modified markdown |
on_render | After HTML rendering | Rendered HTML | Modified HTML |
on_media_discover | During content scanning | File path, MIME type | Metadata key-value pairs |
on_media_process | After image processing | Base64 image bytes, dimensions | Modified bytes, metadata |
Multiple plugins can register for the same hook. They are called in the order they were loaded.
The on_media_discover and on_media_process hooks are described in detail in the Media Hooks section.
Filters
The [filters] section maps template filter names to exported WASM function names:
[filters]
highlight = "apply_highlight" # {{ code | highlight("rust") }}
uppercase = "to_upper" # {{ text | uppercase }}
The key is the filter name used in templates; the value is the function exported by the WASM module.
Shortcodes
The [shortcodes] section lists shortcode names the plugin handles. Shortcodes are inline content components that authors embed in markdown using square-bracket notation (see Shortcodes for syntax details).
[shortcodes]
codes = ["note", "warning", "gallery"]
When Accent CMS encounters [note]...[/note] or [gallery/] in content, it calls the plugin’s handle_shortcode exported WASM function. The plugin receives the shortcode name, arguments, and body content as JSON and returns rendered HTML.
Plugin shortcodes are checked after built-in and theme shortcodes in the resolution chain. This means a theme can override a plugin shortcode by providing a template with the same name in its shortcodes/ directory.
Routes
The [routes] section registers custom HTTP endpoints:
[routes]
"/api/search" = "GET"
"/api/contact" = "POST"
Plugin Configuration
The [config] section holds plugin-specific settings. These values are passed to the plugin as JSON when its functions are called:
[config]
theme = "monokai"
line_numbers = true
max_results = 50
A minimal plugin.toml only needs the [plugin] section:
[plugin]
name = "my-plugin"
version = "0.1.0"
api_version = "0.1.0"