Rich text internals =================== At first glance, Wagtail's rich text capabilities appear to give editors direct control over a block of HTML content. In reality, it's necessary to give editors a representation of rich text content that is several steps removed from the final HTML output, for several reasons: * The editor interface needs to filter out certain kinds of unwanted markup; this includes malicious scripting, font styles pasted from an external word processor, and elements which would break the validity or consistency of the site design (for example, pages will generally reserve the ``
`` element", since various components of Wagtail - both client and server-side - need to agree on how to handle that feature, including how it should be exposed in the editor interface, how it should be represented within the database, and (if appropriate) how it should be translated when rendered on the front-end. The components involved in Wagtail's rich text handling are described below. Data format ----------- Rich text data (as handled by :ref:`RichTextField`, and ``RichTextBlock`` within :doc:`StreamField `) is stored in the database in a format that is similar, but not identical, to HTML. For example, a link to a page might be stored as: .. code-block:: html Contact us for more information.
Here, the ``linktype`` attribute identifies a rule that shall be used to rewrite the tag. When rendered on a template through the ``|richtext`` filter (see :ref:`rich-text-filter`), this is converted into valid HTML: .. code-block:: htmlContact us for more information.
In the case of ``RichTextBlock``, the block's value is a ``RichText`` object which performs this conversion automatically when rendered as a string, so the ``|richtext`` filter is not necessary. Likewise, an image inside rich text content might be stored as: .. code-block:: html which is converted into an ``img`` element when rendered: .. code-block:: htmlAgain, the ``embedtype`` attribute identifies a rule that shall be used to rewrite the tag. All tags other than ```` and ```` are left unchanged in the converted HTML. A number of additional constraints apply to ```` and ```` tags, to allow the conversion to be performed efficiently via string replacement: * The tag name and attributes must be lower-case * Attribute values must be quoted with double-quotes * ``embed`` elements must use XML self-closing tag syntax (i.e. end in ``/>`` instead of a closing ```` tag) * The only HTML entities permitted in attribute values are ``<``, ``>``, ``&`` and ``"`` The feature registry -------------------- Any app within your project can define extensions to Wagtail's rich text handling, such as new ``linktype`` and ``embedtype`` rules. An object known as the *feature registry* serves as a central source of truth about how rich text should behave. This object can be accessed through the :ref:`register_rich_text_features` hook, which is called on startup to gather all definitions relating to rich text: .. code-block:: python # my_app/wagtail_hooks.py from wagtail.core import hooks @hooks.register('register_rich_text_features') def register_my_feature(features): # add new definitions to 'features' here Link rewrite handlers --------------------- .. method:: FeatureRegistry.register_link_type(linktype, handler) The ``register_link_type`` method allows you to define a function to be called when an ```` tag with a given ``linktype`` attribute is encountered. This function receives a dictionary of attributes from the original ```` tag, and returns a string to replace that opening tag (which must be a valid HTML ```` tag). The link element content and closing ```` tag is left unchanged. .. code-block:: python from django.utils.html import escape from wagtail.core import hooks from myapp.models import Report def report_link_handler(attrs): # Handle a link of the form `` try: report = Report.objects.get(id=attrs['id']) except (Report.DoesNotExist, KeyError): return "" return '' % escape(report.url) @hooks.register('register_rich_text_features') def register_report_link(features): features.register_link_type('report', report_link_handler) Embed rewrite handlers ---------------------- .. method:: FeatureRegistry.register_embed_type(embedtype, handler) The ``register_embed_type`` method allows you to define a function to be called when an ```` tag with a given ``embedtype`` attribute is encountered. This function receives a dictionary of attributes from the original ``