How can I add no-follow to all links in a WordPress site in one go? - wordpress

I'm coding a WordPress website in which I want all the external links to be "no-follow" by default.
It is quite long to go and edit each single link to add the "no-follow", is there a way to code it once for all?
Thank you

IMHO, the best way to do so is using a custom filter. Being generated dinamically by PHP, you can edit links on post and pages server-side even before a user visit them: WordPress used to add rel="nofollow" to each link by default in the past, but I see it doesn’t happen anymore. Then, I found a solution by Debjit Saha you may try on functions.php.
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;
}
Please, notice that some plugins could break this code and I’ve never tried this on newer WordPress versions.

One way you can do it is using JavaScript:
var hrefToCheck = "mysite.com" // change this string
noFollowExternalLinks(hrefToCheck); // call to run the function below
function noFollowExternalLinks(siteHref) {
document.querySelectorAll('a').forEach(function(link) {
if (!link.href.includes(siteHref)) {
link.setAttribute("rel", "nofollow");
}
})
}
So, you can change hrefToCheck variable to a piece of your site URL that will be checked inside each link inside the page.
The function will loop to check every link in the page and apply rel="nofollow" to all external links (that don't match the text in the variable).

Related

Replace Wordpress URL domain in HTML output (for SEO optimisation) [duplicate]

WordPress has great filter support for getting at all sorts of specific bits of content and modifying it before output. Like the_content filter, which lets you access the markup for a post before it's output to the screen.
I'm trying to find a catch-all filter that gives me one last crack at modifying the final markup in its entirety before output.
I've browsed the list of filters a number of times, but nothing jumps out at me:
https://codex.wordpress.org/Plugin_API/Filter_Reference
Anyone know of one?
WordPress doesn't have a "final output" filter, but you can hack together one. The below example resides within a "Must Use" plugin I've created for a project.
Note: I haven't tested with any plugins that might make use of the "shutdown" action.
The plugin works by iterating through all the open buffer levels, closing them and capturing their output. It then fires off the "final_output" filter, echoing the filtered content.
Sadly, WordPress performs almost the exact same process (closing the open buffers), but doesn't actually capture the buffer for filtering (just flushes it), so additional "shutdown" actions won't have access to it. Because of this, the below action is prioritized above WordPress's.
wp-content/mu-plugins/buffer.php
<?php
/**
* Output Buffering
*
* Buffers the entire WP process, capturing the final output for manipulation.
*/
ob_start();
add_action('shutdown', function() {
$final = '';
// We'll need to get the number of ob levels we're in, so that we can iterate over each, collecting
// that buffer's output into the final output.
$levels = ob_get_level();
for ($i = 0; $i < $levels; $i++) {
$final .= ob_get_clean();
}
// Apply any filters to the final output
echo apply_filters('final_output', $final);
}, 0);
An example of hooking into the final_output filter:
<?php
add_filter('final_output', function($output) {
return str_replace('foo', 'bar', $output);
});
Edit:
This code uses anonymous functions, which are only supported in PHP 5.3 or newer. If you're running a website using PHP 5.2 or older, you're doing yourself a disservice. PHP 5.2 was released in 2006, and even though Wordpress (edit: in WP version < 5.2) STILL supports it, you should not use it.
The question is may be old, but I have found a better way to do it:
function callback($buffer) {
// modify buffer here, and then return the updated code
return $buffer;
}
function buffer_start() { ob_start("callback"); }
function buffer_end() { ob_end_flush(); }
add_action('wp_head', 'buffer_start');
add_action('wp_footer', 'buffer_end');
Explanation
This plugin code registers two actions – buffer_start and buffer_end.
buffer_start is executed at the end of the header section of the html. The parameter, the callback function, is called at the end of the output buffering. This occurs at the footer of the page, when the second registered action, buffer_end, executes.
The callback function is where you add your code to change the value of the output (the $buffer variable). Then you simply return the modified code and the page will be displayed.
Notes
Be sure to use unique function names for buffer_start, buffer_end, and callback, so they do not conflict with other functions you may have in plugins.
AFAIK, there is no hook for this, since the themes uses HTML which won't be processed by WordPress.
You could, however, use output buffering to catch the final HTML:
<?php
// example from php.net
function callback($buffer) {
// replace all the apples with oranges
return (str_replace("apples", "oranges", $buffer));
}
ob_start("callback");
?>
<html><body>
<p>It's like comparing apples to oranges.</p>
</body></html>
<?php ob_end_flush(); ?>
/* output:
<html><body>
<p>It's like comparing oranges to oranges.</p>
</body></html>
*/
#jacer, if you use the following hooks, the header.php also gets included.
function callback($buffer) {
$buffer = str_replace('replacing','width',$buffer);
return $buffer;
}
function buffer_start() { ob_start("callback"); }
function buffer_end() { ob_end_flush(); }
add_action('after_setup_theme', 'buffer_start');
add_action('shutdown', 'buffer_end');
I was using the top solution of this post (by kfriend) for a while. It uses an mu-plugin to buffer the whole output.
But this solution breaks the caching of wp-super-cache and no supercache-files are generated when i upload the mu-plugin.
So: If you are using wp-super-cache, you can use the filter of this plugin like this:
add_filter('wp_cache_ob_callback_filter', function($buffer) {
$buffer = str_replace('foo', 'bar', $buffer);
return $buffer;
});
Modified https://stackoverflow.com/users/419673/kfriend answer.
All code will be on functions.php. You can do whatever you want with the html on the "final_output" filter.
On your theme's 'functions.php'
//we use 'init' action to use ob_start()
add_action( 'init', 'process_post' );
function process_post() {
ob_start();
}
add_action('shutdown', function() {
$final = '';
// We'll need to get the number of ob levels we're in, so that we can iterate over each, collecting
// that buffer's output into the final output.
$levels = ob_get_level();
for ($i = 0; $i < $levels; $i++) {
$final .= ob_get_clean();
}
// Apply any filters to the final output
echo apply_filters('final_output', $final);
}, 0);
add_filter('final_output', function($output) {
//this is where changes should be made
return str_replace('foo', 'bar', $output);
});
You might try looking in the wp-includes/formatting.php file. For example, the wpautop function.
If you are looking for doing something with the entire page, look at the Super Cache plugin. That writes the final web page to a file for caching. Seeing how that plug-in works may give you some ideas.
Indeed there was a discusussion recently on the WP-Hackers mailing list about the topic of full page modification and it seems the consensus was that output buffering with ob_start() etc was the only real solution. There was also some discussion about the upsides and downsides of it: http://groups.google.com/group/wp-hackers/browse_thread/thread/e1a6f4b29169209a#
To summarize: It works and is the best solution when necessary (like in the WP-Supercache plugin) but slows down overall speeds because your content isn't allowed to be sent to the browser as its ready, but instead has to wait for the full document to be rendered (for ob_end() ) before it can be processed by you and sent to the browser.
To simplify previous answers, just use this in functions.php:
ob_start();
add_action('shutdown', function () {
$html = ob_get_clean();
// ... modify $html here
echo $html;
}, 0);
I've been testing the answers here now for a while, and since the cache breaking thing is still an issue, I came up with a slightly different solution. In my tests no page cache broke. This solution has been implemented into my WordPress plugin OMGF (which has 50k+ users right now) and no issues with page cache breaking has been reported.
First, we start an output buffer on template redirect:
add_action('template_redirect', 'maybe_buffer_output', 3);
function maybe_buffer_output()
{
/**
* You can run all sorts of checks here, (e.g. if (is_admin()) if you don't want the buffer to start in certain situations.
*/
ob_start('return_buffer');
}
Then, we apply our own filter to the HTML.
function return_buffer($html)
{
if (!$html) {
return $html;
}
return apply_filters('buffer_output', $html);
}
And then we can hook into the output by adding a filter:
add_filter('buffer_output', 'parse_output');
function parse_output($html)
{
// Do what you want. Just don't forget to return the $html.
return $html;
}
Hope it helps anyone.
I have run into problems with this code, as I end up with what seems to be the original source for the page so that some plugins has no effect on the page. I am trying to solve this now - I haven't found much info regarding best practises for collecting the output from WordPress.
Update and solution:
The code from KFRIEND didnt work for me as this captures unprocessed source from WordPress, not the same output that ends up in the browser in fact. My solution is probably not elegant using a globals variable to buffer up the contents - but at least I know get the same collected HTML as is delivered to the browser. Could be that different setups of plugins creates problems but thanks to code example by Jacer Omri above I ended up with this.
This code is in my case located typically in functions.php in theme folder.
$GLOBALS['oldschool_buffer_variable'] = '';
function sc_callback($data){
$GLOBALS['final_html'] .= $data;
return $data;
}
function sc_buffer_start(){
ob_start('sc_callback');
}
function sc_buffer_end(){
// Nothing makes a difference in my setup here, ob_get_flush() ob_end_clean() or whatever
// function I try - nothing happens they all result in empty string. Strange since the
// different functions supposedly have very different behaviours. Im guessing there are
// buffering all over the place from different plugins and such - which makes it so
// unpredictable. But that's why we can do it old school :D
ob_end_flush();
// Your final HTML is here, Yeeha!
$output = $GLOBALS['oldschool_buffer_variable'];
}
add_action('wp_loaded', 'sc_buffer_start');
add_action('shutdown', 'sc_buffer_end');
If you want to modify the output, you can use template_include:
add_filter( 'template_include', static function ( $template ) {
if ( basename( $template ) === 'foo-template.php' ) {
echo str_replace( 'foo', 'bar', file_get_contents( $template ) );
}
return null;
} );
If instead you want to override the output completely, you can use the action template_redirect.
add_action( 'template_redirect', static function () {
wp_head();
echo 'My output.';
wp_footer();
exit;
} );

switching templates dynamically in wordpress

Right now I'm trying to switch the template that Wordpress uses depending on the device that is viewing the site.
The exact issue here is that the ONLY thing that seems to be switching are the scripts and stylesheets. The actual templates them selves (index, header, footer) stay the same.
Here is the function I'm using to do this:
<?
function fxn_change_theme($device) {
$header = $_SERVER['HTTP_X_UA_DEVICE'];
if ($header === 'mobile') {
$theme = 'jankness-mobile';
} elseif ($header === 'tablet') {
$theme = 'jankness-tablet';
} else {
$theme = 'jankness-desktop';
}
return $theme;
}
add_filter('template', 'fxn_change_theme');
add_filter('option_template', 'fxn_change_theme');
add_filter('option_stylesheet', 'fxn_change_theme');
?>
Also, the only filter that's doing anything seems to be 'template', the option filters don't do much. I've tried looking up what they do and it's not clear to me at the moment.
What might be the issue here?
Basically, since the code I was using was sitting in functions.php it was not able to manipulate the theme content earlier enough in the Wordpress core process. So the solution was to move the code into a very simple plugin exactly as it is, and hook in to the theme_setup point using the same code I used here.

Add rel="nofollow" and target="_blank" for external links permanently

I would like to add rel="nofollow" and target="_blank" for all external links in my Wordpress posts and pages permanently. I am aware, that there are plugins, which do the same, but as soon as they get disabled, all changes will be reversed and the articles are the same as from the beginning.
I do not know how to differ between internal or external links nor how to check if there is already a rel="nofollow" or target="_blank" attribute.
I guess the best way of doing this would be using PHP instead of MySQL. I already searched the web for guides, tutorials or plugins, without success.
May someone help me? I appreciate your support.
I have got a solution for applying nofollow to all existing and new external links.
Copy the code into your functions.php of your activated theme
function add_nofollow_content($content) {
$content = preg_replace_callback('/]*href=["|\']([^"|\']*)["|\'][^>]*>([^<]*)<\/a>/i', function($m) {
if (strpos($m[1], "YOUR_DOMAIN_ADDRESS") === false)
return ''.$m[2].'';
else
return ''.$m[2].'';
}, $content);
return $content;
}
add_filter('the_content', 'add_nofollow_content');
You can also call the function home_url() instead of "YOUR_DOMAIN_ADDRESS" in the space provided to avoid hard coding of the domain name.
The code is tested and it works.
Hope this one helps.
You can use following snippet:
http://wpsnipp.com/index.php/functions-php/nofollow-external-links-only-the_content-and-the_excerpt/
This great little snippet that will add rel=”nofollow” to external
links within both the_content and the_excerpt. Add this snippet to the
functions.php of your wordpress theme to enable nofollow external
links.
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;
}
I think adding rel"nofollow" and target="_blank" to outgoing links permanently is more work than it can be shown here. You will have to rebuild the functions of plugins like External Links so that even links in your wp_nav_menus can be rewritten.
I have a suggestion that adds the desired attributes via JavaScript when the page is loaded. You can add this script directly to your theme header or you can keep it in a seperate file enqueing the script in your themes' functions.php:
$(document).ready(function () {
$( "a:not(a[href^='http://www.your-domain-name.com'],a[href^='javascript'],a[href^='#'])" ).attr({
rel: "nofollow",
target: "_blank"
});
});
I took the answer of #rony-samuel and adjusted few things you might find useful.
Use the built-in make_clickable function to wrap links automatically. (E.g. useful when creating posts via API) - then check if the user has added additional classes to a link, (like a button to have a different styling) – we don't want to overwrite that, so just return the given markup with $m[0].
Last thing is the regex. In combination with make_clickable it would output <a <a href... so a link in a link. I corrected the regex to avoid that.
// Auto warp links within content
add_filter( 'the_content', 'make_clickable' );
// Add target blank and nofollow to external links
// Do not overwrite links that probably have been placed manually in the content
// and contain classes like "button" or whatever etc. Since they were placed manually
// with additional styling, the editor can add target="_blank" manually as well if needed.
function external_links ($content) {
$content = preg_replace_callback(
'/<a[^>]*href=["|\']([^"|\']*)["|\'][^>]*>([^<]*)<\/a>/i',
function($m) {
$hasClass = (bool) preg_match('/class="[^"]*[^"]*"/', $m[0]);
if (strpos($m[1], home_url()) === false && $hasClass === false)
return ''.$m[2].'';
else
return $m[0];
},
$content);
return $content;
}
// set a very low priority to ensure,
// all the content and shortcode things has been completed already
add_filter('the_content', 'external_links', 999);

WordPress / CF7 - Customising the Contact Form 7 ajax loader gif, depending on location

I am using the Contact Form 7 plugin on a web site, which has a contact form in the footer of every page and also a contact form in the main area of a dedicated Contact page.
I know how to customise the ajax loader gif in CF7...
function my_wpcf7_ajax_loader () {
return get_stylesheet_directory_uri() . '/images/my-loader-image.gif';
}
add_filter('wpcf7_ajax_loader', 'my_wpcf7_ajax_loader');
...but my problem is that I need to specify two different loader images - one for the footer form and one for the Contact page form. (The reason for this is because one form is on a white background and the other is on a red background, and despite experimenting with different loader gifs I don't think it is possible to have a loader gif that looks good on both.)
Here's the solution: https://gist.github.com/tctc91/8271205
add_filter('wpcf7_ajax_loader', 'my_wpcf7_ajax_loader');
function my_wpcf7_ajax_loader () {
return network_home_url() . '/assets/themes/ips-helpdesk/images/ajax-loader.gif';
}
As loading image is an img element with src attribute, css methods will not be helpful.
It would be required to change src attribute of img tag through JavaScript and without modifying the core js of contact 7 form plugin (to allow plugin upgrades in future), I have come with following JavaScript solution to apply this change by bruteforce method.
(function($) {
setInterval(function() {
if(typeof $.fn.wpcf7InitForm != "undefined") {
//Contact Form 7 is loaded and initialized
$loaderImage = $("#wpcf7-f52-o2 img.ajax-loader"); // modify your selector accordingly
if(!$loaderImage.data("pathChanged")) {
$loaderImage.attr("src", "ALTERNATIVE_IMAGE_PATH");
$loaderImage.data("pathChanged", true);
}
}
}, 2000);
})(jQuery);
Though it may not be the best way, See if it helps.
I read an article with a solid solution for your problem. They gave this solution:
// Change the URL to the ajax-loader image
function change_wpcf7_ajax_loader($content) {
if ( is_page('contact') ) {
$string = $content;
$pattern = '/(<img class="ajax-loader" style="visibility: hidden;" alt="ajax loader" src=")(.*)(" \/>)/i';
$replacement = "$1".get_template_directory_uri()."/images/ajax-loader.gif$3";
$content = preg_replace($pattern, $replacement, $string);
}
return $content;
}
add_filter( 'the_content', 'change_wpcf7_ajax_loader', 100 );
link to the article here:
Note: We're using a heavily modified twenty twenty theme and NONE of these solutions worked. Tried them all. Updated to latest version of plugin, still the same issue. Can't disabled plugins one at a time and test by practical means because there are dozens and because we need the ones that we have.

Wordpress Plug-ins: How-to add custom URL Handles

I'm trying to write a Wordpress Plug-in but can't seem to figure out how you would modify how a URL gets handled, so for example: any requests made for:
<url>/?myplugin=<pageID>
will get handled by a function in my plug-in. I'm sure this is a very simple to do, but I'm pretty new to working with Wordpress and couldn't find it in the documentation.
In order to handle just a specific URL use the code below:
add_action('parse_request', 'my_custom_url_handler');
function my_custom_url_handler() {
if(isset($_GET['myplugin']) && $_SERVER["REQUEST_URI"] == '/custom_url') {
echo "<h1>TEST</h1>";
exit();
}
}
add_action('parse_request', 'my_custom_url_handler');
function my_custom_url_handler() {
if( isset($_GET['myplugin']) ) {
// do something
exit();
}
}
That should set you on the right direction. parse_request happens before WordPress runs any of the complicated WordPress queries used to get the posts for the current URL.

Resources