Fragment id linking in wagtail's rich text content

wagtail anchor links
wagtail link to page

I have a bunch of content in a Wagtail 2.0 rich text field that looks like

Page heading
(intro blurb)

heading 1
(heading-1-relevant text)

heading 2
(heading-2-relevant text)

...

and I would like to give each heading an id so that any text can be made a link to jump to the relevant content. I can't seem to find an option to give headings an explicit id, and the "link" button in the rich text editor does not seem to let me pick active fragment identifiers in the content.

Is there a way to add fragment identifier based navigation on the same page work with Wagtail's rich text editor?

Revisiting my own question a year later because this is still something we need, the solution we came up with is to simply wrap the RichText html serialization, and putting fragment id injection on top:

import re
from django import template
from django.utils.text import slugify
from wagtail.core.rich_text import RichText

# We'll be wrapping the original RichText.__html__(), so make
# sure we have a reference to it that we can call.
__original__html__ = RichText.__html__

# This matches an h1/.../h6, using a regexp that is only
# guaranteed to work because we know that the source of
# the HTML code we'll be working with generates nice
# and predictable HTML code.
heading_re = r"<h(\d)[^>]*>([^<]*)</h\1>"


def add_id_attribute(match):
    """
    This is a regexp replacement function that takes
    in the above regex match results, and then turns:
        <h1>some text</h1>
    Into:
        <h1><a id="some-text"></a><a href="#some-text">some text</a></h1>
    where the id attribute value is generated by running
    the heading text through Django's slugify() function.
    """
    n = match.group(1)
    text_content = match.group(2)
    id = slugify(text_content)
    return f'<h{n}><a id="{id}""></a><a href="#{id}">{text_content}</a></h{n}>'


def with_heading_ids(self):
    """
    We don't actually change how RichText.__html__ works, we just replace
    it with a function that does "whatever it already did", plus a
    substitution pass that adds fragment ids and their associated link
    elements to any headings that might be in the rich text content.
    """
    html = __original__html__(self)
    return re.sub(heading_re, add_id_attribute, html)


# Rebind the RichText's html serialization function such that
# the output is still entirely functional as far as wagtail
# can tell, except with headings enriched with fragment ids.
RichText.__html__ = with_heading_ids

This works rather well, does not require any hacking in draftail or wagtail, and is very easy to enable/disable simply by loading this code as part of the server startup process (we have it living in our wagtailcustom_tags.py file, so when Django loads up all template tag sets, the RichText "enrichment" kicks in automatically).

We had initially tried to extend the ... | richtext template filter, but while that's entirely possible, that only works for custom blocks we ourselves wrote, with our own custom templates, and so turned out to not be a solution given the idea that it should "just work".

Not possible to add link with fragment identifier � Issue #1049 , Currently it is not possible to add fragment identifier to Wagtail rich text add a new text field in the link chooser UI, to enter a fragment ID - but� Wagtail is a fast CMS. It's built largely for performance, which is why a lot of beautiful features are not enabled by default. In this lesson we're going to take a look at database queries and template fragment caching to speed up our load times (page performance).

What about using RawHTMLBlock and StreamField? Make a page like this:

class BlogPage(Page):
    body = StreamField([
        ('tag', blocks.RawHTMLBlock(),
        ('body', blocks.RichTextBlock()),

Then In your admin you can make:

choose RawHTMLBlock: <h1 id="test">
choose RichTextBlock: your staff here
choose RawHTMLBlock: </h1>

Not possible to add link with fragment identifier - wagtail, Currently it is not possible to add fragment identifier to Wagtail rich text links: . com/questions/49415788/fragment-id-linking-in-wagtails-rich-text-content. For example, PageLinkHandler.get_instance might receive {'id': 123} and return the instance of the Wagtail Page class with ID 123. If left undefined, a default implementation of this method will query the id model field on the class returned by get_model using the provided id attribute; this can be overriden in your own handlers should you want

To have control over the structure of your page body, it's preferable to encourage users to use heading blocks, rather than headings within the rich text block. Then you can have a heading block type which has two fields, a 'text' and an 'id', and you can specify a template that outputs the h element with the id attribute.

class Heading2Block(blocks.StructBlock):
    heading = blocks.CharBlock(classname='full title')
    link_id = blocks.CharBlock(help_text='For making hyperlinks to this heading')

    class Meta:
        template = 'blocks/h2.html'

Put the following in blocks/h2.html:

<h1{% if value.link_id %} id="{{ value.link_id|slugify }}"{% endif %}>{{ value.heading }}</h1>

In earlier versions of Wagtail it was possible to remove the h widget from the Hallo.js rich text editor, and this was a good way of encouraging user adoption of the heading block. Similar restriction is not currently present in Draftail, but there is a pull request which reimplements it.

Wagtail list of Tips and Tricks! |, Tips and tricks in Wagtail that will help you tweak the appearance and href="# some-text">some text</a></h1> where the id attribute value is generated pass that adds fragment ids and their associated link elements to any� Second Fragment. An Identification field populated with the same ID number used for the first fragment; A reserved bit not set, the Don’t Fragment flag not set and a More Fragments flag of 1 in the Flags field, expressed in binary as: 001; The Fragment Offset field is set to 69 (552/8), expressed in binary as: 0 0000 0100 0101

How to add Template Fragment Caching to Your Wagtail Website , In this tutorial I'll show you how to enable template fragment caching, and in the video I'll posts %} {% cache 604800 blog_post_preview post.id %} <div class=" row mt-5 mb-5"> Here's the link to the entire GitHub commit:� Wagtail is a system for capturing and presenting information, Fragment id linking in wagtail's rich text content. 5. Adding HTML viewing to Draftail editor on

[PDF] v2.6.1 PDF - Wagtail's documentation, Wagtail is an open source CMS written in Python and built on the it to retrieve the Wagtail page with ID 123, and render a link to its URL sponding embeddable HTML fragment, has now been converted to a template tag. Hyperlinks can target a specific point in a document that has been created with a “fragment” identifier – an element with a unique identifying name assigned to an id attribute in its opening tag. Within the hyperlink, the fragment identifier is specified to a href attribute in the opening <a> tag prefixed by a # hash character.

Inserting links in a page — Wagtail 2.0 documentation, You can insert a link into the body text by clicking the Insert link button in the rich text toolbar. Whichever way you insert a link, you will be presented with the form� In the previous lesson we discovered how to save sections of a template and reduce the number of queries on any given page. But to delete the cache so that Wagtail CMS could update the page was a very manual task. In this tutorial, we'll learn how to use Wagtails save() method to delete specific template fragment cache from our site.

Comments
  • There are two separate questions here: how to add ids on headings in rich text, and how to add links with fragment identifiers. Neither of these have simple answers in Wagtail right now (sob), so they probably warrant separate questions. For the links with fragment identifiers, see github.com/wagtail/wagtail/issues/1049. I'll drop a comment there to explain how this could work
  • For id on the headings, Wagtail doesn't provide this level of customisation for rich text content at the moment. Your best bet "right now" is StreamField, as @nimasmi described, with the limitations you described for content creators. A way forward would be github.com/wagtail/wagtail/issues/4223 if what you want is auto-generated ids based on context, ref counting, or block text.
  • If what you want is user-controlled ids, then there is no way to customise the rich text editor heading blocks rendering to add a field there. Your best bet would be to create a custom entity (like in github.com/wagtail/wagtail/issues/1049#issuecomment-375815036, and the official docs "Stock") that would allow authors to place a tag with an id on arbitrary text, or without text at an arbitrary point in the content – eg. <h2><a id="my-anchor"></a> My heading</h2>.
  • A pretty terrible solution, since I'm trying to keep things simple for the people who actually need to write the content. They shouldn't have to learn to "program" that, they should simply be able to use the rich text field.
  • yeah, ok, then you need to customize draftail
  • As @Alexey points out, customising Draftail to do this instead is probably a better prospect than it ever was with hallo.js, but the above is less work.
  • I also realise I've simply assumed that you're using Stream Field and a Rich Text block, rather than a RichTextField directly on the page model.
  • Also in the spitit of the Zen of Wagtail, forcing content creators to break up their content is thinking with a dev hat on. Would be fine if the audience was other devs, but it very much isn't. Editing draftail to make fragment linking work seems the way forward.
  • I disagree with that interpretation. The editor should not be using the rich text field to generate page structure in a WYSIWYG fashion, merely formatted text. Making the headings (or images, or blockquotes) into their own block types takes the structure out of the rich text field, and as a bonus puts the markup in the hands of the developer. This particular case is a slightly greyer area. I'd say if the id attribute were auto-generated then a Draftail feature would cover it, but for something that the editor interacts with, a separate block is the better home.