Plugins

The extensions directory, ext, is intended for plugins that extend or enhance Ark's functionality. Python modules or packages placed in this directory will be loaded automatically and can take advantage of Ark's extension hooks to inject their own code into the build process.

Ark makes three extension mechanisms available to plugins:

  1. Event and filter hooks.
  2. Pluggable rendering and parsing engines.
  3. WordPress-style shortcodes.

Much of Ark's builtin functionality is in fact implemented by a set of default plugins bundled in the ark/ext/ directory.

Installing Plugins

Extensions placed in a site's ext directory will be loaded automatically. Alternatively, extension modules installed on Python's standard import path can be activated by adding their names to an extensions list in the site's configuration file:

extensions = [
    'extension_one',
    'extension_two',
]

This method can be used to load extensions installed from the package index using pip.

Hooks

Ark exports a flexible framework of event and filter hooks. Plugins can extend Ark by registering callback functions on these hooks.

Events

Event callbacks accept zero or more arguments depending on the specific hook. They may modify their arguments in place but have no return value.

Here's a simple event callback that prints a count of the number of pages that have been written to disk:

import ark

@ark.hooks.register('exit')
def print_page_count():
    print(ark.site.written())

This callback is registered on the exit event hook which fires just before the application exits. (The exit hook can be found in the ark/__init__.py file.)

Filters

Filter callbacks accept at least one argument - the value to be filtered. They may accept additional arguments depending on the specific hook. Filter callbacks modify and return the value of their first argument.

Here's a simple filter callback that changes every instance of the word "foo" in records to "bar":

import ark

@ark.hooks.register('record_text')
def foo_to_bar(text, record):
    return text.replace('foo', 'bar')

This callback is registered on the record_text filter hook which fires just before a record's text is rendered into HTML. (The record_text hook can be found in the ark/records.py file).

Note that this hook supplies us with the Record instance itself as an additional argument which we here ignore.

Engines

Ark relies for most of its functionality on a suite of pluggable rendering and parsing engines, e.g. the Jinja template-engine for handling .jinja template files. Plugins can register support for additional rendering and parsing engines using a system of @register decorators.

Templates

Ark has builtin support for Jinja and Ibis templates. Plugins can register support for additional formats using the @templates.register() decorator. Template-engine callbacks are registered per file-extension, e.g.

import ark

@ark.templates.register('jinja')
def jinja_callback(page, filename):
    ...
    return html

A template-engine callback should accept a Page object and a template filename and return a string of HTML.

Records

Ark has builtin support for records written in Markdown and Syntex. Plugins can register support for additional formats using the @renderers.register() decorator. Rendering-engine callbacks are registered per file-extension, e.g.

import ark

@ark.renderers.register('md')
def markdown_callback(text):
    ...
    return html

A rendering-engine callback should accept a single string argument containing plain text and return a string of HTML.

Shortcodes

Ark has builtin support for WordPress-style shortcodes with space-separated positional and keyword arguments:

[% tag arg1 key=arg2 %] ... [% endtag %]

Plugins can register shortcode tags using the @shortcodes.register() decorator:

import shortcodes

@shortcodes.register('tag')
def handler(record, content, pargs, kwargs):
    ...
    return replacement_text

Handler functions should accept four arguments:

  1. The Record object for the source file containing the shortcode.
  2. A string containing the shortcode's content, if the shortcode has block scope.
  3. A list of positional arguments.
  4. A dictionary of keyword arguments.

Positional and keyword arguments are passed as strings. The handler function itself should return a string.

Note that shortcodes are processed before the record text is rendered into HTML.

Ark ships with a single builtin shortcode, [% code %], which uses the Pygments package to add syntax highlighting to code samples:

[% code python %]
def hello():
    print('hello world!')
[% endcode %]

The shortcode accepts a single optional argument specifying the language. If no language is specified, Pygments will attempt to guess the correct lexer to use.

If the Pygments package is not available or if an appropriate lexer cannot be found the shortcode will return the wrapped content with any HTML special characters escaped.