Create extensions
Grow has a powerful extension system that enables you to extend the functionality of Grow with extensions.
Example extension
As an example of a simple Grow extension see the html min extension.
Anatomy of an extension
Grow extensions work by creating hooks to bind to events that happen within Grow. For example, a hook to change the contents of a page after it has already been rendered. Each extension can bind to any number of hooks.
Extensions are provided with a configuration optionally defined in the
podspec.yaml
that can be used to control the extension's functionality:
# podspec.yaml ext: - extensions.html_min.HtmlMinExtension: options: remove_comments: true reduce_boolean_attributes: false
For complex extensions specific hooks can be enabled or disabled piecemeal:
# podspec.yaml ext: - extensions.complex.ComplexExtension: enabled: - post_render disabled: - dev_file_change
Extension hooks
Base hooks are defined by Grow and can be extended in the extension. When hooks
are triggered in Grow (ex: after the content is rendered) it calls the trigger
method on the hook.
Hook triggers follow some basic conventions:
- The first argument is the
previous_result
from any hooks already triggered. - Arguments change depending on the hook and are documented below.
- Each trigger method should have
*_args, **_kwargs
as the last two arguments.
For hooks that are expecting a specific result a result object will be provided
in the previous_result
argument and should just be updated as needed. If there
is a specific return type it will be documented with the hook.
Even if your extension doesn't change the previous_result
, the
previous_result
should be returned to continue the chain of extensions.
By using the *_args, **_kwargs
on all trigger methods it allows Grow to add
additional arguments to the hook without breaking existing extensions.
from grow.extensions import hooks class MyPostRenderHook(hooks.PostRenderHook): """Handle the post-render hook.""" def trigger(self, previous_result, doc, raw_content, *_args, **_kwargs): """Execute post-render modification.""" content = previous_result if previous_result else raw_content # Do something to modify the contents. return content
Extensions
A simple extension only needs to extend the BaseExtension
and define the
available_hooks
property.
from grow import extensions class MyExtension(extensions.BaseExtension): """Example Extension.""" @property def available_hooks(self): """Returns the available hook classes.""" return [MyPostRenderHook]
For special cases when you need to have additional arguments to the hook class you can create hook getters in the extension to control how the hook is created.
from grow import extensions class MyExtension(extensions.BaseExtension): """Example Extension.""" @property def available_hooks(self): """Returns the available hook classes.""" return [MyPostRenderHook] def post_render_hook(self): """Returns the hook object.""" return MyPostRenderHook(self, other_arg=True)
Grow Hooks
The following hooks are currently available for extensions.
hooks.DevFileChangeHook
When a file is changed when running the development server this hook is triggered.
def trigger(self, previous_result, pod_path, *_args, **_kwargs): return previous_result
pod_path
– path of the file that changed in the pod.
See the core routes extension for an example of the dev file change.
hooks.DevHandlerHook
When running the local development server the dev handler hook allows for adding custom handlers for the development server.
def trigger(self, previous_result, routes, *_args, **_kwargs): return previous_result
routes
– The routes object for adding the handler.
See the core routes extension for an example of the dev handler.
hooks.PostRenderHook
def trigger(self, previous_result, doc, raw_content, *_args, **_kwargs): return previous_result
doc
– The document being rendered. This can be a normal document or a static document.raw_content
– The raw rendered content.
See the html min extension for an example of the dev handler.
hooks.PreprocessHook
def trigger(self, previous_result, config, names, tags, run_all, rate_limit, *_args, **_kwargs): return previous_result
config
– Configuration for the preprocessor from the podspec.names
– Names of the preprocessors being run.tags
– Tags of the preprocessors being run.run_all
- If all preprocessors are being run.rate_limit
- Time in seconds when rate limiting should be used between bulk processing.
hooks.PreRenderHook
def trigger(self, previous_result, doc, original_body, *_args, **_kwargs): return previous_result
doc
– The document being rendered. This can be a normal document or a static document.original_body
– The original content before being rendered.