最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

the content - How to use wp_rel_nofollow to add nofollow to external links only?

programmeradmin4浏览0评论

I want to add nofollow attribute to only external links in the content of the post. Internal links should stay follow.

So, can I use wp_rel_nofollow() to make only external links nofollow? Or do I need to use another method?

I want to add nofollow attribute to only external links in the content of the post. Internal links should stay follow.

So, can I use wp_rel_nofollow() to make only external links nofollow? Or do I need to use another method?

Share Improve this question asked Nov 20, 2014 at 4:46 GixtyGixty 1,0972 gold badges19 silver badges37 bronze badges
Add a comment  | 

6 Answers 6

Reset to default 2

wp_rel_nofollow() add nofollow attribute to all links so we can not use it or may be I am not sure how.

You can use this function to add rel="nofollow" to all external links. This function will check all links in content against your blog/website URL (as internal domain) and add nofollow attribute if both does not match.

function add_nofollow_external_links( $content ) {
    return preg_replace_callback( '/<a>]+/', 'auto_nofollow_callback', $content );
}
function auto_nofollow_callback( $matches ) {
    $link = $matches[0];
    $site_link = get_bloginfo('url');
    if (strpos($link, 'rel') === false) {
        $link = preg_replace("%(href=S(?!$site_link))%i", 'rel="nofollow" $1', $link);
    } elseif (preg_match("%href=S(?!$site_link)%i", $link)) {
        $link = preg_replace('/rel=S(?!nofollow)S*/i', 'rel="nofollow"', $link);
    }
    return $link;
}
add_filter( 'the_content', 'add_nofollow_external_links' );

not tested.

I use the following function to add nofollow tags to external links:

add_filter( 'the_content', 'nofollow_enternal_links');

function nofollow_enternal_links( $content ) {

    $regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>";
    if(preg_match_all("/$regexp/siU", $content, $matches, PREG_SET_ORDER)) {
        if( !empty($matches) ) {

            $srcUrl = get_option('home');
            for ($i=0; $i < count($matches); $i++)
            {

                $tag = $matches[$i][0];
                $tag2 = $matches[$i][0];
                $url = $matches[$i][0];

                $noFollow = '';

                $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(']]>', ']]&gt;', $content);
    return $content;

}

This works site wide and targets all posts, even the published ones.

This approach is different to the other working one posted.

I'm posting this to check if anyone can confirm whether if this or the other approach is better for performance.

I am using following code to make all external links no follow and this code works.

add_filter('the_content', 'my_nofollow');
add_filter('the_excerpt', 'my_nofollow');

function my_nofollow($content) {
return preg_replace_callback('/<a[^>]+/', 'my_nofollow_callback', $content);
}
function my_nofollow_callback($matches) {
$link = $matches[0];
$site_link = get_bloginfo('url');

if (strpos($link, 'rel') === false) {
    $link = preg_replace("%(href=\S(?!$site_link))%i", 'rel="nofollow" $1', $link);
} elseif (preg_match("%href=\S(?!$site_link)%i", $link)) {
    $link = preg_replace('/rel=\S(?!nofollow)\S*/i', 'rel="nofollow"', $link);
}
return $link;
}

Based on @Robert hue's answer and the wordpress functions wp_rel_nofollow() and wp_rel_nofollow_callback I came up with this very similar solution that works for me because for some reason Robert's wasnt adding the nofollow attribute to the link.

function add_rel_nofollow( $text ) {
    // This is a pre save filter, so text is already escaped.
    $text = stripslashes($text);
    $text = preg_replace_callback('|<a (.+?)>|i', 'add_rel_nofollow_callback', $text);
    //$text = wp_slash($text); //I had to remove this because it was adding undesired backslashes to the output
    return $text;
}

function add_rel_nofollow_callback( $matches ) {
    $text = $matches[1];
    $site_link = get_bloginfo('url');

    if (strpos($text, 'rel') === false) {
        $text = preg_replace("%(href=S(?!$site_link))%i", 'rel="nofollow" $1', $text);
    } elseif (preg_match("%href=S(?!$site_link)%i", $link)) {
        $text = str_replace(array(' rel="nofollow"', " rel='nofollow'"), '', $text);
    }       

    return "<a $text rel=\"nofollow\">";
}
add_filter( 'the_content', 'add_rel_nofollow' );

This adds a rel="nofollow" attribute to all previously published and future posts.

Regarding performance, I asked @Roberthue the same question and this is what he said:

I don't know why it should. It's mostly the same as using wp_rel_nofollow() except it has a additional check for external domain. That's it but if you add tons of domains to check and exclude then it probably will. – Robert hue

Neither Gixty's nor Robert's code worked for me. Robert's one didn't even match correctly links, and even with the correct pattern didn't check whether the link was internal or external, and added the nofollow to all links, whereas Gixty's one correctly added the nofollow, but again to all links, not just internal ones.

This is my code, which works fine for me and only adds the rel nofollow to internal links. Also, notice that it doesn't touch links which do already have the rel attribute, whatever value it may have.

function add_nofollow_external_links( $content ) {
    return preg_replace_callback( '|<a (.+?)>|i', 'add_nofollow_callback', $content );
}

function add_nofollow_callback( $matches ) {
    $text = $matches[1];
    $site_link = get_bloginfo( 'url' );

    //If this is an internal link, don't touch it
    if( strpos( $text, $site_link ) ) {
        return "<a $text>";
    }     

    //If this doesn't have the rel attribute, append the nofollow
    if( strpos( $text, 'rel' ) === false ) {
        $text = preg_replace( "%(href=S(?!$site_link))%i", 'rel="nofollow" $1', $text );
    } 

    return "<a $text rel=\"nofollow\">";
}

The other answers don't work in all cases and/or change links when they shouldn't and/or don't reliably check for the rel attribute if it exists.

This solution is a bit more comprehensive and allows for more flexibility.

// Takes an string of html attr and adds an attribute value; if attr is present and $replace=false, space and the new value is added to end of the attribute; otherwise attr is added to end.
function inject_html_attr($attr_str, $new_attr_name, $attr_value, $replace=false) {
    return preg_replace_callback(
      '/(((?:^|\s)'.$new_attr_name.'=[\'"])(.*?))([\'"])|$/i', 
      function($m)use($new_attr_name,$attr_value, $replace){
        if( $m[0] ){
            $m[1] = $replace ? $m[2] : $m[1].($m[3]?' ':'');
        }else{
            $m[1] = ' '.$new_attr_name.'="'; 
            $m[4] = '"';
        }
        return $m[1].$attr_value.$m[4];
      }, 
    $attr_str, 1 );
}

add_filter('the_content', 'apply_external_link_markup');
function apply_external_link_markup($content) {
    // Assumes attributes are quoted (single or double)
    return preg_replace_callback(
      '/<a ([^>]*)(href=(["\'])(?:https?:)?\\/\\/([^\\/\'">]+)(.*?)\3)([^>]*)>/i', 
      function($m) {
        if( $m[4] === $_SERVER['HTTP_HOST'] )
            return $m[0];
        $attr = ' '.trim(trim($m[1]).' '.trim($m[6]));
        //$attr = inject_html_attr( $attr, 'class', 'external-link' );
        //$attr = inject_html_attr( $attr, 'target', '_blank', true );
        $attr = inject_html_attr( $attr, 'rel', 'nofollow', true );
        return '<a '.$m[2].$attr.'>';
      }, 
    $content );
}
发布评论

评论列表(0)

  1. 暂无评论