WordPress文章中自动为站外链接添加nofollow属性

只需要在 function.php 中添加以下代码即可,同时自动添加 target=”_blank”,如果链接中已有这两个属性,则不会重复添加。

我的这个版本不同于之前网上流传的那个版本,那个版本不知道是哪个菜鸟写的,虽然能实现功能,但那时间复杂度简直不能忍。。。

源代码带注释:

// 站外链接nofollow,target
add_filter( 'the_content''nofollow_a_links');
function nofollow_a_links ($content) {
    $regexp "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>";
    if (preg_match_all("/$regexp/siU"$content$matches, PREG_SET_ORDER)) {
        $srcUrl $_SERVER['SERVER_NAME'];
        $now_pos =0;
        for ($i = 0; $i count($matches); $i++) {
            //不包含本站域名,同时不是href="/dm/p/5" 这种形式
            if strpos($matches[$i][0], $srcUrl) === false && strpos($matches[$i][0], '//') !== false ) {
                $tag $matches[$i][0];
                $tag0 $matches[$i][0];
                $noFollow '';
                //添加 _blank
                $pattern '/target\s*=\s*"\s*_blank\s*"/';
                preg_match($pattern$tag2$match);
                if (count($match) < 1) $noFollow.= ' target="_blank" ';
                //添加nofollow
                $pattern '/rel\s*=\s*"\s*[n|d]ofollow\s*"/';
                preg_match($pattern$tag2$match);
                if (count($match) < 1) $noFollow.= ' rel="nofollow" ';
                //写入
                if($noFollow != ''){
                    //只进行单次替换,且使用$now_pos 记录$content的处理进度
                    $now_pos strpos($content$tag0$now_pos);
                    $tag = rtrim($tag'>'); $tag.= $noFollow '>';
                    $content = substr_replace( $content$tag$now_posstrlen($tag0) );
                }
            }
        }
    }
    return $content;
}

经历

以前用的都是下面这段代码,网上随便找的,但是啥也没想,直接粘贴后就开始用了,效果也还行,就没有多研究这段代码了:

add_filter( 'the_content''cn_nf_url_parse');
function cn_nf_url_parse( $content ) {
    $regexp "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>";
    if(preg_match_all("/$regexp/siU"$content$matches, PREG_SET_ORDER)) {
        if( !empty($matches) ) {
            $srcUrl = get_option('siteurl');
            for ($i=0; $i count($matches); $i++)
            {
                $tag $matches[$i][0];
                $tag2 $matches[$i][0];
                $url $matches[$i][0];
                $noFollow '';
                $pattern '/target\s*=\s*"\s*_blank\s*"/';
                preg_match($pattern$tag2$match, PREG_OFFSET_CAPTURE);
                ifcount($match) < 1 )
                    $noFollow .= ' target="_blank" ';
                $pattern '/rel\s*=\s*"\s*[n|d]ofollow\s*"/';
                preg_match($pattern$tag2$match, PREG_OFFSET_CAPTURE);
                ifcount($match) < 1 )
                    $noFollow .= ' rel="nofollow" ';
                $pos strpos($url,$srcUrl);
                if ($pos === false) {
                    $tag = rtrim ($tag,'>');
                    $tag .= $noFollow.'>';
                    $content str_replace($tag2,$tag,$content);
                }
            }
        }
    }
    $content str_replace(']]>'']]>'$content);
    return $content;
}

自动查找指向站外的链接,如果该链接指向站外,并且没有 nofollow_blank,则会自动添加,功能上到还是都实现了,没啥问题。

然后是近日发现,对于 <a href=”/i/zytbz”> 这种链接,这段代码也会识别成站外链接。于是,我就准备把这段代码改改。

不看不要紧,一看才发现这段代码简直是坑爹啊!是发布专门用来拖慢我们的服务器的吗?

特别是最后这句,安的究竟是什么心:

$content str_replace(']]>'']]>'$content);

 

除此之外,这段代码的逻辑似乎就有一点问题:

1、对每个链接对象,先进行一个镜像,镜像中添加 nofollow 属性。

2、在判断这个链接是否指向站外,如果是,将 $content 当中的源链接用 str_replace 替换成修改后的链接。

这么想这两步都反了,应该先判断是否是站外链接,再添加属性才对。

其次,每一次 str_replace,都会将 $content 全部扫描一遍(从头到尾),然而最后只替换掉当中的一条,这太浪费时间了!(时间复杂度为 N+1)

最佳算法当然是对于 $content,查找到一条 A 链接,判断处理一条,时间复杂度为 1。

但我查阅了很多资料,PHP 中的所有查找函数都只能返回查找后的结果,而不能返回找到目标的位置,总之是没法实现了,后来换了实现方法,让复杂度降为 2,大家可以去看代码,不细说了。

只想说 PHP 还是不够灵活啊。

我的代码的优势

大大优化运行效率。

可以识别 <a href=”/dm/top10″> & <a href=”//baidu.com”>,这样的链接。

1 条评论
  1. 是否使用这段代码是有待商榷的,因为一个正常的网站是不会没有出站链接的。全部都被添加上了 nofollow 属性,反而很不正常。

发表一条评论