在 wagtail 中以新 window 打开外部链接

Making external links open in a new window in wagtail

我最近实现了将 target="_blank" 添加到外部链接,如下所示:

@hooks.register('after_edit_page')
def do_after_page_edit(request, page):
    if hasattr(page, "body"):
        soup = BeautifulSoup(page.body)
        for a in soup.findAll('a'):
            if hasattr(a, "href"):
            a["target"] = "_blank"
        page.body = str(soup)
        page.body = page.body.replace("<html><head></head><body>", "")
        page.body = page.body.replace("</body></html>", "")
        page.body = page.body.replace("></embed>", "/>")
        page.save()

@hooks.register('construct_whitelister_element_rules')
def whitelister_element_rules():
    return {
        'a': attribute_rule({'href': check_url, 'target': True}),
    }

问题:

  1. 美丽的汤弄乱了输出,添加了 html, head & body 标签 - Don't put html, head and body tags automatically, beautifulsoup

  2. 它还与嵌入标签混淆 - How to get BeautifulSoup 4 to respect a self-closing tag?

  3. 因此我糟糕的“fix”用空白字符串手动替换了部分输出。

问题:

执行此操作的正确和最佳方法是什么?

一直在努力解决同样的问题,无法使用 wagtailhooks 实现。我最初的解决方案是使用过滤器来处理 base.html 中的内容。用于剪切代码片段的过滤器放在内容块中时效果很好,例如:

{{ self.body|cut: ‘ href="http:’}}

上面的过滤器删除了部分内容,但不幸的是“替换”不能用作过滤器(我使用 Python 3.x)。因此,我的下一个方法是构建一个 custom_filter 来创建“替换”作为过滤器选项。长话短说:它部分起作用,但前提是内容从原始的“StreamValue”数据类型转换为“字符串”。此转换导致显示所有 html 标签的内容,因此替换没有导致工作 html。我无法再次将内容返回到 StreamValue,并且没有其他 Python 数据类型可以解决该问题。 最终 JQuery 帮我完成了工作:

$(document).ready(function(){
$('a[href^="http://"]').attr('target', '_blank');
});        

此代码将“target="_blank"”添加到每个包含“http://”的 link,因此所有内部 link 都保留在现有选项卡中。它需要放在 base.html(或类似的)的末尾,当然你需要在 运行 之前加载 JQuery。 从 here 得到了我的答案。 不知道 JQuery 是否是正确和最好的方法,但它对我来说就像一个魅力,只需最少的编码。

从 Wagtail v2.5 开始,作为 Wagtail 的富文本处理的一部分,有一个 API 可以进行这样的自定义:Rewrite handlers, with the register_rich_text_features 钩子。

下面是一个使用这个新的 API 来制作重写处理程序的示例,该处理程序将 target="_blank" 属性设置为所有外部链接:

from django.utils.html import escape
from wagtail.core import hooks
from wagtail.core.rich_text import LinkHandler


class NewWindowExternalLinkHandler(LinkHandler):
    # This specifies to do this override for external links only.
    # Other identifiers are available for other types of links.
    identifier = 'external'

    @classmethod
    def expand_db_attributes(cls, attrs):
        href = attrs["href"]
        # Let's add the target attr, and also rel="noopener" + noreferrer fallback.
        # See https://github.com/whatwg/html/issues/4078.
        return '<a href="%s" target="_blank" rel="noopener noreferrer">' % escape(href)


@hooks.register('register_rich_text_features')
def register_external_link(features):
    features.register_link_type(NewWindowExternalLinkHandler)

在此示例中,我还添加了 rel="noopener" 以修复 known security issuetarget="_blank"


与以前解决这个问题的方法相比,这个新方法是最可靠的:它完全在服务器端,只覆盖网站前端的链接呈现方式,而不是它们的存储方式,并且只依赖于记录了 APIs 而不是内部的/实现细节。