You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用PHP为WordPress古腾堡编辑器的外部链接添加nofollow标签

适配WordPress古腾堡编辑器的外部链接处理解决方案

问题背景

需要实现WordPress古腾堡编辑器内容保存到数据库前自动修改链接,满足以下要求:

  • 区分内部/外部链接
  • 外部链接的rel属性追加nofollow,若已包含dofollow或nofollow则跳过
  • 未设置target属性的链接,自动设置为_blank

但原有代码执行后出现链接格式混乱、转义错误的问题,导致属性值被错误编码(如href变成%5C%22//google.com%5C%22%5C%22)。

原问题代码

add_filter('content_save_pre', 'modify_links_before_saving', 10, 1);

function modify_links_before_saving($content) {
    $site_url = get_site_url();
    $dom = new DOMDocument;
    libxml_use_internal_errors(true);  // Suppress errors (due to HTML5 tags etc.)
    $dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8'));
    libxml_clear_errors();

    $links = $dom->getElementsByTagName('a');
    foreach ($links as $link) {
        // Check if the link is external
        $href = $link->getAttribute('href');
        if (strpos($href, $site_url) === false) {  // External link
            // Add 'nofollow' to 'rel' attribute
            $rel = $link->getAttribute('rel');
            if (!empty($rel)) {
                $rel .= ' nofollow';
            } else {
                $rel = 'nofollow';
            }
            $link->setAttribute('rel', $rel);
        }

        // Add 'target="_blank"' if not already set
        $target = $link->getAttribute('target');
        if (empty($target)) {
            $link->setAttribute('target', '_blank');
        }
    }

    $html = $dom->saveHTML();
    return $html;
}

原输入内容

<!-- wp:paragraph -->
<p><a href="http://google.com">External Link</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><a href="http://microsoft.com" rel="noopener">No Opener</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><a href="http://yahoo.com" rel="dofollow">dofollow</a></p>
<!-- /wp:paragraph -->

错误输出示例

<!-- wp:paragraph -->
<p><a href="%5C%22//google.com%5C%22%5C%22" rel="&quot;nofollow nofollow noopener" noopener="" target="&quot;_blank&quot;">External Link</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><a href="%5C%22//microsoft.com%5C%22%5C%22" rel="&quot;&quot;noopener&quot; nofollow noopener" nofollow="" noopener="" target="&quot;_blank&quot;">No Opener</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><a href="%5C%22//yahoo.com%5C%22%5C%22" rel="&quot;&quot;dofollow&quot; nofollow noopener" nofollow="" noopener="" target="&quot;_blank&quot;">dofollow</a></p>
<!-- /wp:paragraph -->

问题原因

原代码使用DOMDocument处理古腾堡块内容存在两个核心问题:

  1. DOMDocument::loadHTML()会自动为内容添加完整的HTML骨架(如<html><body>),并破坏古腾堡的块注释结构
  2. 对属性值进行过度转义,同时未正确处理rel属性的去重与条件判断逻辑,导致输出格式错乱

正确解决方案

使用WordPress 6.2+内置的WP_HTML_Tag_Processor类,这是官方专门为处理HTML内容(尤其是古腾堡块)设计的工具,不会破坏块结构,且能正确处理属性编码。

最终代码

add_filter('content_save_pre', 'modify_gutenberg_links_before_saving', 10, 1);

function modify_gutenberg_links_before_saving($content) {
    // 仅处理古腾堡块内容,避免影响经典编辑器
    if (strpos($content, '<!-- wp:') === false) {
        return $content;
    }

    $site_url = get_site_url();
    $processor = new WP_HTML_Tag_Processor($content);

    while ($processor->next_tag('a')) {
        $href = $processor->get_attribute('href');
        if (empty($href)) {
            continue;
        }

        // 准确判断是否为外部链接(包含相对路径的本地链接排除)
        $is_external = (strpos($href, $site_url) === false && !wp_is_local_html_uri($href));

        if ($is_external) {
            // 处理rel属性:仅当未包含dofollow/nofollow时添加nofollow
            $rel = $processor->get_attribute('rel');
            $rel_values = $rel ? array_map('trim', explode(' ', $rel)) : [];
            
            // 检查是否已存在目标属性值
            if (!in_array('dofollow', $rel_values) && !in_array('nofollow', $rel_values)) {
                $rel_values[] = 'nofollow';
                $processor->set_attribute('rel', implode(' ', $rel_values));
            }
        }

        // 处理target属性:未设置时默认设为_blank
        if (!$processor->get_attribute('target')) {
            $processor->set_attribute('target', '_blank');
        }
    }

    return $processor->get_updated_html();
}

代码说明

  • 古腾堡内容判断:通过检查块注释标识<!-- wp:,仅处理古腾堡生成的内容
  • 外部链接判断:结合get_site_url()和wp_is_local_html_uri(),准确区分本地/外部链接(包括相对路径的内部链接)
  • rel属性处理:拆分已有属性值,避免重复添加nofollow,同时跳过已包含dofollow的链接
  • 属性安全处理:WP_HTML_Tag_Processor会自动处理属性值的编码,不会出现转义错误,且保留古腾堡块的原始结构

预期输出

<!-- wp:paragraph -->
<p><a href="http://google.com" rel="nofollow" target="_blank">External Link</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><a href="http://microsoft.com" rel="noopener nofollow" target="_blank">No Opener</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><a href="http://yahoo.com" rel="dofollow" target="_blank">dofollow</a></p>
<!-- /wp:paragraph -->

内容的提问来源于stack exchange,提问作者Abhishek R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 02:17:41