Hi all,
I was hopping I could get some help on my extension. I created this extension, which worked fine on my local machine but does not work on our production server. It uses regular expressions to find links, check if the href points to an external url, then adds a target attribute to the link.
here is an outline:
foreach ($this->fields as $field_id => $field)
{
if (!preg_match_all('/<a(.*)>.*<\/a>/iU', $field['content'], $matches, PREG_SET_ORDER))
{
continue;
}
...
foreach ($matches as $i => $match)
{
if (!preg_match_all('/([^\s]*)=[\'\"]??([^\'^\"]*?)[\'\"]/iU', $match[1], $attr))
{
unset($matches[$i]);
continue;
}
...
// --------------------------------------
// make attribute names lowercase
// --------------------------------------
foreach ($attr[1] as $k => $v)
{
$attr[1][$k] = strtolower($v);
}
// --------------------------------------
// create attributes associative array
// --------------------------------------
foreach ($attr[1] AS $index => $name)
{
$attributes[$i][$name] = $attr[2][$index];
}
// --------------------------------------
// check for the href attribute
// --------------------------------------
if (!isset($attributes[$i]['href']))
{
unset($matches[$i]);
unset($attributes[$i]);
continue;
}
// --------------------------------------
// get the value of href
// --------------------------------------
$url = $attributes[$i]['href'];
// --------------------------------------
// check the value of href
// --------------------------------------
if (substr($url, 0, 7) != 'http://' && substr($url, 0, 8) != 'https://')
{
if (substr($url, 0, 1) == '/')
{
$url = $IN->GBL('HTTP_HOST', 'SERVER').$url;
}
$url = 'http://'.$url;
}
// --------------------------------------
// get the host part of the href
// --------------------------------------
$host = @parse_url($url, PHP_URL_HOST);
// --------------------------------------
// check the host
// --------------------------------------
if ($host == $IN->GBL('HTTP_HOST', 'SERVER'))
{
continue;
}
// --------------------------------------
// check the attributes
// -------------------------------------
$attributes[$i]['target'] = '_blank';
if (!isset($attributes[$i]['class']))
{
$attributes[$i]['class'] = $this->settings['class_name'];
}
else
{
if (stripos($attributes[$i]['class'], $this->settings['class_name']) === false)
{
$attributes[$i]['class'] = $this->settings['class_name'].' '.$attributes[$i]['class'];
}
}
// --------------------------------------
// rebuild the element attributes
// --------------------------------------
$new_attr = '';
foreach ($attributes[$i] as $k => $v)
{
$new_attr .= ' '.$k.'="'.$v.'"';
}
// --------------------------------------
// create the new link element and add to the queue
// --------------------------------------
$new_link = str_replace($match[1], $new_attr, $match[0]);
$this->target[] = array($i, $new_link);
// --------------------------------------
// if there is nothing in the queue, stop
// --------------------------------------
if (count($this->target) == 0)
{
return false;
}
// --------------------------------------
// Replace links in the custom field
// --------------------------------------
for ($i = 0; $i < count($this->target); $i++)
{
$this->fields[$field_id]['new_content'] = str_replace($matches[$this->target[$i][0]][0], $this->target[$i][1], $field['content']);
}
This worked fine on my local MAMP setup but didn’t work on the production server at RackSpace.
Can anyone point me any clues?
I have attached the original file for your convenience.
Thank you.
I thought of using javascript for this. But it’s actually a way to enforce a rule. Editors are supposed to make external links target=”_blank”, but they don’t. This would only be active for editorial content and not for user submitted content (which are only comments). We tried to discuss this with the editors but they don’t want more to do. To tell you the truth, they want as much automation as possible. There is so much we already automated for them and now they want this too. I wonder what will be next.
Also, wouldn’t javascript slowdown the page? We already have Glam and Dart ads clogging the download pipes.
Thanks for taking your time to reply. If you do look at it, I have a feeling it’s a problem with the second regular expression. I’m not versed in regex and I actually threw that together.
Thanks again Derek
Well, my suggestion still stands. Let’s assume that it has been explained to the client what the pros are of not opening links in new windows are (not irritating visitors, retaining back button functionality, etc.), but that they knowingly insist. Using appropriate markup and javascript, you can prevent this from being applied site wide by only targeting links within “article content containers” and then drilling down as necessary to dynamically target only the links you wish to be affected. So if your articles are in an “article” class <div>, you can target with .article a {}, etc.
I actually just did this in javascript and worked great. I use prototype and came out like this:
$$('div.entry a[href]').each(function(node) {
var host = window .location .hostname; // spaced out to avoid being stripped from post
if (node.href.indexOf(host) == -1 && node.href != '') {
node.addClassName('external');
node.writeAttribute('target', '_blank');
};
});
Thanks again.
Yeah I can’t believe I went through all the trouble of making that extension before trying this. Literally took me less than 5 minutes to write that.
Blankwin is another standalone script that works nicely for this also.
Very neat as well. Good thing about it is that it is not library dependent.
Packet Tide owns and develops ExpressionEngine. © Packet Tide, All Rights Reserved.