如何在Wagtail中官方支持地重写PageLinkHandler(非猴子补丁)
在Wagtail中为页面链接添加自定义onclick属性(无需猴子补丁)
场景背景
我做了个网站,用自定义JS实现页面局部刷新,同时保证音频播放不中断——这要求所有链接都得带onclick="navigate(event, 'url')"属性。网站里硬编码的链接都满足要求,但Wagtail CMS富文本内容生成的页面链接却没有这个属性。
我尝试用Wagtail的rewrite handlers方案,但发现标识为"page"的链接已经被默认的PageLinkHandler处理,自定义处理器被忽略。目前用猴子补丁实现了功能,但想找官方支持的非猴子补丁方案。
现有猴子补丁代码:
from wagtail.models import Page from wagtail.rich_text.pages import PageLinkHandler from django.utils.html import escape @classmethod def custom_expand_db_attributes(cls, attrs): try: page = cls.get_instance(attrs) return '<a onclick="navigate(event, \'{s}\')" href="{s}">'.format(s=escape(page.localized.specific.url)) except Page.DoesNotExist: return "<a>" PageLinkHandler.expand_db_attributes = custom_expand_db_attributes
官方支持的两种实现方式
方法一:替换默认的PageLinkHandler注册
Wagtail允许先取消默认的链接处理器注册,再注册自定义的处理器,这是最贴合Wagtail扩展机制的方案:
- 自定义继承自
PageLinkHandler的处理器:
from wagtail.rich_text.pages import PageLinkHandler from django.utils.html import escape from wagtail.models import Page class CustomPageLinkHandler(PageLinkHandler): @classmethod def expand_db_attributes(cls, attrs): try: page = cls.get_instance(attrs) url = escape(page.localized.specific.url) return f'<a onclick="navigate(event, \'{url}\')" href="{url}">' except Page.DoesNotExist: return '<a>'
- 在AppConfig的
ready方法中完成处理器的替换:
from django.apps import AppConfig from wagtail.rich_text import register_link_handler, unregister_link_handler class YourAppConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'your_app_name' # 替换成你的app名称 def ready(self): # 取消默认的"page"链接处理器 unregister_link_handler('page') # 注册自定义处理器 register_link_handler('page', CustomPageLinkHandler)
方法二:自定义RichText过滤器
通过添加RichText过滤器,在HTML输出阶段修改所有页面链接的属性:
- 创建自定义过滤器类:
from django.utils.html import escape from wagtail.rich_text import RichTextFilter from wagtail.models import Page from bs4 import BeautifulSoup class AddOnclickToPageLinksFilter(RichTextFilter): def apply(self, html): soup = BeautifulSoup(html, 'html.parser') for a_tag in soup.find_all('a', href=True): # 尝试通过链接URL匹配站内页面 try: page = Page.objects.get(url_path=a_tag['href']) url = escape(page.localized.specific.url) a_tag['onclick'] = f"navigate(event, '{url}')" except Page.DoesNotExist: # 非站内页面不处理 continue return str(soup)
- 在settings.py中配置启用该过滤器:
WAGTAIL_RICH_TEXT_EDITORS = { 'default': { 'WIDGET': 'wagtail.rich_text.widgets.RichTextEditor', 'OPTIONS': { 'features': ['h1', 'h2', 'h3', 'bold', 'italic', 'link', 'document-link'], # 保留你需要的编辑器功能 'filters': [ 'your_app_name.path.to.AddOnclickToPageLinksFilter', # 替换成过滤器的完整路径 ], }, }, }
方案对比
- 替换链接处理器:直接对接Wagtail的链接解析逻辑,性能更优,属于官方推荐的扩展方式,版本兼容性更好,优先选择。
- RichText过滤器:无需修改处理器注册,适合仅需调整HTML输出的场景,但需要解析整个HTML内容,性能略逊于前者。
内容的提问来源于stack exchange,提问作者Ada Fuge
相关产品推荐
相关产品推荐

