只需要在 function.php 中添加以下代码即可,同时自动添加 target=”_blank”,如果链接中已有这两个属性,则不会重复添加。
我的这个版本不同于之前网上流传的那个版本,那个版本不知道是哪个菜鸟写的,虽然能实现功能,但那时间复杂度简直不能忍。。。
源代码带注释:
// 站外链接nofollow,targetadd_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_pos, strlen($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); if( count($match) < 1 ) $noFollow .= ' target="_blank" '; $pattern = '/rel\s*=\s*"\s*[n|d]ofollow\s*"/'; preg_match($pattern, $tag2, $match, PREG_OFFSET_CAPTURE); if( count($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”>,这样的链接。
是否使用这段代码是有待商榷的,因为一个正常的网站是不会没有出站链接的。全部都被添加上了 nofollow 属性,反而很不正常。