Wagtail Dev Notes

Updated Sep 8, 2025

Extending Wagtail RichText features

Using the method described in the Wagtail docs with a helper function register_block_feature to make adding multiple features cleaner.

Add to wagtail_hooks.py. I added it to a settings app that is installed before my other apps so that the new rich text features are added globally.

import wagtail.admin.rich_text.editors.draftail.features as draftail_features
from wagtail.admin.rich_text.converters.html_to_contentstate import BlockElementHandler
from wagtail import hooks

# https://docs.wagtail.org/en/stable/extending/extending_draftail.html
def register_block_feature(features, name, type_, element, label, description, css_class=None):
    """
    Register a custom block-level Draftail feature.
    """
    control = {
        'type': type_,
        'label': label,
        'description': description,
        'element': element,
    }

    # Register the block feature
    features.register_editor_plugin(
        'draftail', name, draftail_features.BlockFeature(control)
    )

    # Map stored HTML to editor state with CSS class
    from_db_selector = f'{element}[class={css_class}]' if css_class else element

    # Map editor state back to HTML if CSS class
    to_db_props = {'element': element}
    if css_class:
        to_db_props['props'] = {'class': css_class}

    features.register_converter_rule('contentstate', name, {
        'from_database_format': {from_db_selector: BlockElementHandler(type_)},
        'to_database_format': {'block_map': {type_: to_db_props}},
    })

    # Add to default features so it's available everywhere
    features.default_features.append(name)

# Add features with custom CSS classes to style output
@hooks.register('register_rich_text_features')
def register_custom_block_features(features):
    register_block_feature(features, 'blue-text', 'BLUE-TEXT', 'p', '🟦', 'Blue Text', css_class='richtext__blue-text')
    register_block_feature(features, 'blue-text-large', 'BLUE-TEXT-LARGE', 'p', 'LG:🟦', 'Blue Text Large', css_class='richtext__blue-text-large')