如何用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=""nofollow nofollow noopener" noopener="" target=""_blank"">External Link</a></p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p><a href="%5C%22//microsoft.com%5C%22%5C%22" rel="""noopener" nofollow noopener" nofollow="" noopener="" target=""_blank"">No Opener</a></p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p><a href="%5C%22//yahoo.com%5C%22%5C%22" rel="""dofollow" nofollow noopener" nofollow="" noopener="" target=""_blank"">dofollow</a></p> <!-- /wp:paragraph -->
问题原因
原代码使用DOMDocument处理古腾堡块内容存在两个核心问题:
DOMDocument::loadHTML()会自动为内容添加完整的HTML骨架(如<html><body>),并破坏古腾堡的块注释结构- 对属性值进行过度转义,同时未正确处理
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
相关产品推荐
相关产品推荐

