Version Description
- Remove HTML comments added in 5.4.1 to assist in troubleshooting some select site issues
Download this release
Release Info
Developer | Mike_Koepke |
Plugin | External Links |
Version | 5.5.4 |
Comparing to | |
See all releases |
Version 5.5.4
- anchor-utils/anchor-utils.php +9 -0
- external-links-anchor-utils.php +400 -0
- external.png +0 -0
- readme.txt +148 -0
- sem-external-links-admin.php +163 -0
- sem-external-links-info.php +4 -0
- sem-external-links.css +4 -0
- sem-external-links.php +356 -0
- sem-external-links.pot +102 -0
anchor-utils/anchor-utils.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
* Anchor Utils
|
4 |
+
* Author: Denis de Bernardy & Mike Koepke <http://www.semiologic.com>
|
5 |
+
* Version: 1.6.2
|
6 |
+
*/
|
7 |
+
|
8 |
+
// no longer used
|
9 |
+
|
external-links-anchor-utils.php
ADDED
@@ -0,0 +1,400 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
* External Links Anchor Utils
|
4 |
+
* Author: Denis de Bernardy & Mike Koepke <http://www.semiologic.com>
|
5 |
+
* Version: 1.6.1
|
6 |
+
*
|
7 |
+
* Forked from Anchor-Utils
|
8 |
+
*/
|
9 |
+
|
10 |
+
if ( @ini_get('pcre.backtrack_limit') <= 1000000 )
|
11 |
+
@ini_set('pcre.backtrack_limit', 1000000);
|
12 |
+
if ( @ini_get('pcre.recursion_limit') <= 250000 )
|
13 |
+
@ini_set('pcre.recursion_limit', 250000);
|
14 |
+
|
15 |
+
/**
|
16 |
+
* external_links_anchor_utils
|
17 |
+
*
|
18 |
+
* @packageExternal Links Anchor Utils
|
19 |
+
**/
|
20 |
+
|
21 |
+
class external_links_anchor_utils {
|
22 |
+
|
23 |
+
private $external_links = null;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* constructor
|
27 |
+
*/
|
28 |
+
public function __construct( external_links $external_links, $apply_globally = true, $inc_text_widgets = true ) {
|
29 |
+
|
30 |
+
$this->external_links = $external_links;
|
31 |
+
|
32 |
+
if ( $apply_globally ) {
|
33 |
+
add_action('template_redirect', array($this, 'ob_start'), 100);
|
34 |
+
}
|
35 |
+
else {
|
36 |
+
add_filter('the_content', array($this, 'filter'), 1000000);
|
37 |
+
add_filter('the_excerpt', array($this, 'filter'), 1000000);
|
38 |
+
add_filter('comment_text', array($this, 'filter'), 1000000);
|
39 |
+
if ( $inc_text_widgets )
|
40 |
+
add_filter('widget_text', array($this, 'filter'), 1000000);
|
41 |
+
}
|
42 |
+
|
43 |
+
} #external_links_anchor_utils
|
44 |
+
|
45 |
+
|
46 |
+
/**
|
47 |
+
* ob_start()
|
48 |
+
*
|
49 |
+
* @return void
|
50 |
+
**/
|
51 |
+
|
52 |
+
function ob_start() {
|
53 |
+
ob_start(array($this, 'ob_filter'));
|
54 |
+
add_action('wp_footer', array($this, 'ob_flush'), 1000000);
|
55 |
+
} # ob_start()
|
56 |
+
|
57 |
+
/**
|
58 |
+
* ob_filter()
|
59 |
+
*
|
60 |
+
* @param string $text
|
61 |
+
* @return string $text
|
62 |
+
**/
|
63 |
+
|
64 |
+
function ob_filter($text) {
|
65 |
+
global $escape_anchor_filter;
|
66 |
+
$escape_anchor_filter = array();
|
67 |
+
|
68 |
+
$text = $this->escape($text);
|
69 |
+
|
70 |
+
$text = preg_replace_callback("/
|
71 |
+
<\s*a\s+
|
72 |
+
([^<>]+)
|
73 |
+
>
|
74 |
+
(.*?)
|
75 |
+
<\s*\/\s*a\s*>
|
76 |
+
/isx", array($this, 'ob_filter_callback'), $text);
|
77 |
+
|
78 |
+
$text = $this->unescape($text);
|
79 |
+
|
80 |
+
return $text;
|
81 |
+
} # ob_filter()
|
82 |
+
|
83 |
+
|
84 |
+
/**
|
85 |
+
* ob_flush()
|
86 |
+
*
|
87 |
+
* @return void
|
88 |
+
**/
|
89 |
+
|
90 |
+
static function ob_flush() {
|
91 |
+
ob_end_flush();
|
92 |
+
} # ob_flush()
|
93 |
+
|
94 |
+
|
95 |
+
/**
|
96 |
+
* ob_filter_callback()
|
97 |
+
*
|
98 |
+
* @param array $match
|
99 |
+
* @return string $str
|
100 |
+
**/
|
101 |
+
|
102 |
+
function ob_filter_callback($match) {
|
103 |
+
# skip empty anchors
|
104 |
+
if ( !trim($match[2]) )
|
105 |
+
return $match[0];
|
106 |
+
|
107 |
+
# parse anchor
|
108 |
+
$anchor = $this->parse_anchor($match);
|
109 |
+
|
110 |
+
if ( !$anchor )
|
111 |
+
return $match[0];
|
112 |
+
|
113 |
+
# filter anchor
|
114 |
+
// $anchor = apply_filters( 'ob_filter_anchor', $anchor );
|
115 |
+
$anchor = $this->external_links->filter( $anchor );
|
116 |
+
|
117 |
+
# return anchor
|
118 |
+
return $this->build_anchor($anchor);
|
119 |
+
} # ob_filter_callback()
|
120 |
+
|
121 |
+
|
122 |
+
/**
|
123 |
+
* filter()
|
124 |
+
*
|
125 |
+
* @param string $text
|
126 |
+
* @return string $text
|
127 |
+
**/
|
128 |
+
|
129 |
+
function filter($text) {
|
130 |
+
global $escape_anchor_filter;
|
131 |
+
$escape_anchor_filter = array();
|
132 |
+
|
133 |
+
$text = $this->escape($text);
|
134 |
+
|
135 |
+
$text = preg_replace_callback("/
|
136 |
+
<\s*a\s+
|
137 |
+
([^<>]+)
|
138 |
+
>
|
139 |
+
(.*?)
|
140 |
+
<\s*\/\s*a\s*>
|
141 |
+
/isx", array($this, 'filter_callback'), $text);
|
142 |
+
|
143 |
+
$text = $this->unescape($text);
|
144 |
+
|
145 |
+
return $text;
|
146 |
+
} # filter()
|
147 |
+
|
148 |
+
|
149 |
+
/**
|
150 |
+
* filter_callback()
|
151 |
+
*
|
152 |
+
* @param array $match
|
153 |
+
* @return string $str
|
154 |
+
**/
|
155 |
+
|
156 |
+
function filter_callback($match) {
|
157 |
+
# skip empty anchors
|
158 |
+
if ( !trim($match[2]) )
|
159 |
+
return $match[0];
|
160 |
+
|
161 |
+
# parse anchor
|
162 |
+
$anchor = $this->parse_anchor($match);
|
163 |
+
|
164 |
+
if ( !$anchor )
|
165 |
+
return $match[0];
|
166 |
+
|
167 |
+
# filter anchor
|
168 |
+
// $anchor = apply_filters( 'filter_anchor', $anchor );
|
169 |
+
$anchor = $this->external_links->filter( $anchor );
|
170 |
+
|
171 |
+
# return anchor
|
172 |
+
return $this->build_anchor($anchor);
|
173 |
+
} # filter_callback()
|
174 |
+
|
175 |
+
|
176 |
+
/**
|
177 |
+
* parse_anchor()
|
178 |
+
*
|
179 |
+
* @param array $match
|
180 |
+
* @return array $anchor
|
181 |
+
**/
|
182 |
+
|
183 |
+
function parse_anchor($match) {
|
184 |
+
$anchor = array();
|
185 |
+
$anchor['attr'] = $this->parse_attrs($match[1]);
|
186 |
+
|
187 |
+
if ( !is_array($anchor['attr']) || empty($anchor['attr']['href']) # parser error or no link
|
188 |
+
|| trim($anchor['attr']['href']) != esc_url($anchor['attr']['href'], null, 'db') ) # likely a script
|
189 |
+
return false;
|
190 |
+
|
191 |
+
foreach ( array('class', 'rel') as $attr ) {
|
192 |
+
if ( !isset($anchor['attr'][$attr]) ) {
|
193 |
+
$anchor['attr'][$attr] = array();
|
194 |
+
} else {
|
195 |
+
$anchor['attr'][$attr] = explode(' ', $anchor['attr'][$attr]);
|
196 |
+
$anchor['attr'][$attr] = array_map('trim', $anchor['attr'][$attr]);
|
197 |
+
}
|
198 |
+
}
|
199 |
+
|
200 |
+
$anchor['body'] = $match[2];
|
201 |
+
|
202 |
+
$anchor['attr']['href'] = @html_entity_decode($anchor['attr']['href'], ENT_COMPAT, get_option('blog_charset'));
|
203 |
+
|
204 |
+
return $anchor;
|
205 |
+
} # parse_anchor()
|
206 |
+
|
207 |
+
|
208 |
+
/**
|
209 |
+
* build_anchor()
|
210 |
+
*
|
211 |
+
* @param array $anchor
|
212 |
+
* @return string $anchor
|
213 |
+
**/
|
214 |
+
|
215 |
+
function build_anchor($anchor) {
|
216 |
+
$anchor['attr']['href'] = esc_url($anchor['attr']['href']);
|
217 |
+
|
218 |
+
$str = '<a';
|
219 |
+
foreach ( $anchor['attr'] as $k => $v ) {
|
220 |
+
if ( is_array($v) ) {
|
221 |
+
$v = array_unique($v);
|
222 |
+
if ( $v )
|
223 |
+
$str .= ' ' . $k . '="' . implode(' ', $v) . '"';
|
224 |
+
} else {
|
225 |
+
if ($k)
|
226 |
+
$str .= ' ' . $k . '="' . $v . '"';
|
227 |
+
else
|
228 |
+
$str .= ' ' . $v;
|
229 |
+
}
|
230 |
+
}
|
231 |
+
$str .= '>' . $anchor['body'] . '</a>';
|
232 |
+
|
233 |
+
return $str;
|
234 |
+
} # build_anchor()
|
235 |
+
|
236 |
+
|
237 |
+
/**
|
238 |
+
* escape()
|
239 |
+
*
|
240 |
+
* @param string $text
|
241 |
+
* @return string $text
|
242 |
+
**/
|
243 |
+
|
244 |
+
function escape($text) {
|
245 |
+
global $escape_anchor_filter;
|
246 |
+
|
247 |
+
if ( !isset($escape_anchor_filter) )
|
248 |
+
$escape_anchor_filter = array();
|
249 |
+
|
250 |
+
foreach ( array(
|
251 |
+
'head' => "/
|
252 |
+
.*?
|
253 |
+
<\s*\/\s*head\s*>
|
254 |
+
/isx",
|
255 |
+
'blocks' => "/
|
256 |
+
<\s*(script|style|object|textarea)(?:\s.*?)?>
|
257 |
+
.*?
|
258 |
+
<\s*\/\s*\\1\s*>
|
259 |
+
/isx",
|
260 |
+
) as $regex ) {
|
261 |
+
$text = preg_replace_callback($regex, array($this, 'escape_callback'), $text);
|
262 |
+
}
|
263 |
+
|
264 |
+
return $text;
|
265 |
+
} # escape()
|
266 |
+
|
267 |
+
|
268 |
+
/**
|
269 |
+
* escape_callback()
|
270 |
+
*
|
271 |
+
* @param array $match
|
272 |
+
* @return string $text
|
273 |
+
**/
|
274 |
+
|
275 |
+
function escape_callback($match) {
|
276 |
+
global $escape_anchor_filter;
|
277 |
+
|
278 |
+
$tag_id = "----escape_external_links_anchor_utils:" . md5($match[0]) . "----";
|
279 |
+
$escape_anchor_filter[$tag_id] = $match[0];
|
280 |
+
|
281 |
+
return $tag_id;
|
282 |
+
} # escape_callback()
|
283 |
+
|
284 |
+
|
285 |
+
/**
|
286 |
+
* unescape()
|
287 |
+
*
|
288 |
+
* @param string $text
|
289 |
+
* @return string $text
|
290 |
+
**/
|
291 |
+
|
292 |
+
function unescape($text) {
|
293 |
+
global $escape_anchor_filter;
|
294 |
+
|
295 |
+
if ( !$escape_anchor_filter )
|
296 |
+
return $text;
|
297 |
+
|
298 |
+
$unescape = array_reverse($escape_anchor_filter);
|
299 |
+
|
300 |
+
return str_replace(array_keys($unescape), array_values($unescape), $text);
|
301 |
+
} # unescape()
|
302 |
+
|
303 |
+
/**
|
304 |
+
* Parse an attributes string into an array. If the string starts with a tag,
|
305 |
+
* then the attributes on the first tag are parsed. This parses via a manual
|
306 |
+
* loop and is designed to be safer than using DOMDocument.
|
307 |
+
*
|
308 |
+
* @param string|* $attrs
|
309 |
+
* @return array
|
310 |
+
*
|
311 |
+
* @example parse_attrs( 'src="example.jpg" alt="example"' )
|
312 |
+
* @example parse_attrs( '<img src="example.jpg" alt="example">' )
|
313 |
+
* @example parse_attrs( '<a href="example"></a>' )
|
314 |
+
* @example parse_attrs( '<a href="example">' )
|
315 |
+
*/
|
316 |
+
function parse_attrs($attrs) {
|
317 |
+
|
318 |
+
if ( !is_scalar($attrs) )
|
319 |
+
return (array) $attrs;
|
320 |
+
|
321 |
+
$attrs = str_split( trim($attrs) );
|
322 |
+
|
323 |
+
if ( '<' === $attrs[0] ) # looks like a tag so strip the tagname
|
324 |
+
while ( $attrs && ! ctype_space($attrs[0]) && $attrs[0] !== '>' )
|
325 |
+
array_shift($attrs);
|
326 |
+
|
327 |
+
$arr = array(); # output
|
328 |
+
$name = ''; # for the current attr being parsed
|
329 |
+
$value = ''; # for the current attr being parsed
|
330 |
+
$mode = 0; # whether current char is part of the name (-), the value (+), or neither (0)
|
331 |
+
$stop = false; # delimiter for the current $value being parsed
|
332 |
+
$space = ' '; # a single space
|
333 |
+
$paren = 0; # in parenthesis for js attrs
|
334 |
+
|
335 |
+
foreach ( $attrs as $j => $curr ) {
|
336 |
+
|
337 |
+
if ( $mode < 0 ) {# name
|
338 |
+
if ( '=' === $curr ) {
|
339 |
+
$mode = 1;
|
340 |
+
$stop = false;
|
341 |
+
} elseif ( '>' === $curr ) {
|
342 |
+
'' === $name or $arr[ $name ] = $value;
|
343 |
+
break;
|
344 |
+
} elseif ( !ctype_space($curr) ) {
|
345 |
+
if ( ctype_space( $attrs[ $j - 1 ] ) ) { # previous char
|
346 |
+
'' === $name or $arr[ $name ] = ''; # previous name
|
347 |
+
$name = $curr; # initiate new
|
348 |
+
} else {
|
349 |
+
$name .= $curr;
|
350 |
+
}
|
351 |
+
}
|
352 |
+
} elseif ( $mode > 0 ) {# value
|
353 |
+
if ( $paren ) {
|
354 |
+
$value .= $curr;
|
355 |
+
if ( $curr === "(")
|
356 |
+
$paren += 1;
|
357 |
+
elseif ( $curr === ")")
|
358 |
+
$paren -= 1;
|
359 |
+
}
|
360 |
+
else {
|
361 |
+
if ( $stop === false ) {
|
362 |
+
if ( !ctype_space($curr) ) {
|
363 |
+
if ( '"' === $curr || "'" === $curr ) {
|
364 |
+
$value = '';
|
365 |
+
$stop = $curr;
|
366 |
+
} else {
|
367 |
+
$value = $curr;
|
368 |
+
$stop = $space;
|
369 |
+
}
|
370 |
+
}
|
371 |
+
} elseif ( $stop === $space ? ctype_space($curr) : $curr === $stop ) {
|
372 |
+
$arr[ $name ] = $value;
|
373 |
+
$mode = 0;
|
374 |
+
$name = $value = '';
|
375 |
+
} else {
|
376 |
+
$value .= $curr;
|
377 |
+
if ( $curr === "(")
|
378 |
+
$paren += 1;
|
379 |
+
elseif ( $curr === ")")
|
380 |
+
$paren -= 1;
|
381 |
+
}
|
382 |
+
}
|
383 |
+
} else {# neither
|
384 |
+
|
385 |
+
if ( '>' === $curr )
|
386 |
+
break;
|
387 |
+
if ( !ctype_space( $curr ) ) {
|
388 |
+
# initiate
|
389 |
+
$name = $curr;
|
390 |
+
$mode = -1;
|
391 |
+
}
|
392 |
+
}
|
393 |
+
}
|
394 |
+
|
395 |
+
# incl the final pair if it was quoteless
|
396 |
+
'' === $name or $arr[ $name ] = $value;
|
397 |
+
|
398 |
+
return $arr;
|
399 |
+
}
|
400 |
+
} # external_links_anchor_utils
|
external.png
ADDED
Binary file
|
readme.txt
ADDED
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== External Links ===
|
2 |
+
Contributors: Denis-de-Bernardy, Mike_Koepke
|
3 |
+
Donate link: http://www.semiologic.com/partners/
|
4 |
+
Tags: external-links, nofollow, link-target, link-icon, semiologic
|
5 |
+
Requires at least: 2.8
|
6 |
+
Tested up to: 3.9
|
7 |
+
License: GPLv2 or later
|
8 |
+
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
+
|
10 |
+
The external links plugin for WordPress lets you process outgoing links differently from internal links.
|
11 |
+
|
12 |
+
|
13 |
+
== Description ==
|
14 |
+
|
15 |
+
The external links plugin for WordPress lets you process outgoing links differently from internal links.
|
16 |
+
|
17 |
+
Under Settings / External Links, you can configure the plugin to:
|
18 |
+
|
19 |
+
- Process all outgoing links, rather than only those within your entries' content and text widgets.
|
20 |
+
- Add an external link icon to outgoing links. You can use a class="no_icon" attribute on links to override this.
|
21 |
+
- Add rel=nofollow to the links. You can use a rel="follow" attribute on links to override this.
|
22 |
+
- Open outgoing links in new windows. Note that this can damage your visitor's trust towards your site in that they can think your site used a pop-under.
|
23 |
+
|
24 |
+
= Help Me! =
|
25 |
+
|
26 |
+
The [Semiologic forum](http://forum.semiologic.com) is the best place to report issues. Please note, however, that while community members and I do our best to answer all queries, we're assisting you on a voluntary basis.
|
27 |
+
|
28 |
+
If you require more dedicated assistance, consider using [Semiologic Pro](http://www.semiologic.com).
|
29 |
+
|
30 |
+
|
31 |
+
== Installation ==
|
32 |
+
|
33 |
+
1. Upload the plugin folder to the `/wp-content/plugins/` directory
|
34 |
+
2. Activate the plugin through the 'Plugins' menu in WordPress
|
35 |
+
|
36 |
+
|
37 |
+
== Change Log ==
|
38 |
+
|
39 |
+
= 5.5.4 =
|
40 |
+
|
41 |
+
- Remove HTML comments added in 5.4.1 to assist in troubleshooting some select site issues
|
42 |
+
|
43 |
+
= 5.5.3 =
|
44 |
+
|
45 |
+
- Use template_redirect hook and put ourselves after default hooks that most 404/redirect plugins want to use and Yoast's at priority 99999
|
46 |
+
|
47 |
+
= 5.5.2 =
|
48 |
+
|
49 |
+
- Fix compatibility with Yoast WP SEO plugin when Force Title Rewrite option is on and using the Apply Globally setting of this plugin.
|
50 |
+
|
51 |
+
= 5.5.1 =
|
52 |
+
|
53 |
+
- Additional tweak to global callback processing
|
54 |
+
|
55 |
+
= 5.5 =
|
56 |
+
|
57 |
+
- Use wp_print_footer_scripts hook instead of wp_footer as some themes fail to call wp_footer();
|
58 |
+
- Use own custom version of the anchor_utils class
|
59 |
+
- Content, excerpt and comment filters no longer called when Apply Globally is selected. Improves performance.
|
60 |
+
|
61 |
+
= 5.4.1 =
|
62 |
+
|
63 |
+
- Troubleshooting release. Adds a few html comments in the page source to ensure hooks are being called.
|
64 |
+
|
65 |
+
= 5.4 =
|
66 |
+
|
67 |
+
- Handle nested parenthesis in javascript event attributes on links and images
|
68 |
+
|
69 |
+
= 5.3.2 =
|
70 |
+
|
71 |
+
- Temporarily placeholders links - http:// and https:// (no other url components) are no longer processed.
|
72 |
+
|
73 |
+
= 5.3.1 =
|
74 |
+
|
75 |
+
- Fix localization
|
76 |
+
|
77 |
+
= 5.3 =
|
78 |
+
|
79 |
+
- Fix: Conflict with Auto Thickbox plugin that would result in text widgets still being filtered even though option was turned off
|
80 |
+
- Fix: Ensure this plugin filter is executed way back in the change to prevent other plugins/themes from reversing our changes
|
81 |
+
- Code refactoring
|
82 |
+
- WP 3.9 compat
|
83 |
+
|
84 |
+
= 5.2.1 =
|
85 |
+
|
86 |
+
- Checks for new sem_dofollow class to determine if Do Follow plugin is active
|
87 |
+
- WP 3.8 compat
|
88 |
+
|
89 |
+
= 5.2 =
|
90 |
+
|
91 |
+
- Further updates to the link attribute parsing code
|
92 |
+
- Fixed bug where external link was not processed if it was preceded by an empty text anchor link.
|
93 |
+
|
94 |
+
= 5.1 =
|
95 |
+
|
96 |
+
- Take two! With issues now with breaking google adsense code reverted back to 4.2 parsing code but added more advanced dom attribute parsing code to handle various link configurations.
|
97 |
+
|
98 |
+
= 5.0 =
|
99 |
+
|
100 |
+
- Completely replaced the mechanism for parsing links to resolve the various errors that have been occurring with different external services' link attributes
|
101 |
+
- Tested with WP 3.7
|
102 |
+
|
103 |
+
= 4.2 =
|
104 |
+
|
105 |
+
- WP 3.6 compat
|
106 |
+
- PHP 5.4 compat
|
107 |
+
- Fixed issue with parsing of links with non-standard (class, href, rel, target) attributes included in the <a> tag. This caused Twitter Widgets to break.
|
108 |
+
- Fixed issue where the external link icon was not added if the url specified by href had a preceding space href=" http://www.example.com"
|
109 |
+
- Fixed issue with links containing onClick (or other javascript event) attributes with embedded javascript code. WordPress' Threaded Comments does this
|
110 |
+
- Fixed issue with 2 spaces being injected between <a and class/href/rel/etc. i.e <a href="http://example.com">
|
111 |
+
|
112 |
+
= 4.1 =
|
113 |
+
|
114 |
+
- WP 3.5 compat
|
115 |
+
|
116 |
+
= 4.0.6 =
|
117 |
+
|
118 |
+
- WP 3.0.1 compat
|
119 |
+
|
120 |
+
= 4.0.5 =
|
121 |
+
|
122 |
+
- WP 3.0 compat
|
123 |
+
|
124 |
+
= 4.0.4 =
|
125 |
+
|
126 |
+
- Force a higher pcre.backtrack_limit and pcre.recursion_limit to avoid blank screens on large posts
|
127 |
+
|
128 |
+
= 4.0.3 =
|
129 |
+
|
130 |
+
- Improve case-insensitive handling of domains
|
131 |
+
- Improve image handling
|
132 |
+
- Switch back to using a target attribute: work around double windows getting opened in Vista/IE7
|
133 |
+
- Disable entirely in feeds
|
134 |
+
|
135 |
+
= 4.0.2 =
|
136 |
+
|
137 |
+
- Don't enforce new window pref in feeds
|
138 |
+
|
139 |
+
= 4.0.1 =
|
140 |
+
|
141 |
+
- Ignore case when comparing domains
|
142 |
+
|
143 |
+
= 4.0 =
|
144 |
+
|
145 |
+
- Allow to force a follow when the nofollow option is toggled
|
146 |
+
- Enhance escape/unescape methods
|
147 |
+
- Localization
|
148 |
+
- Code enhancements and optimizations
|
sem-external-links-admin.php
ADDED
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* external_links_admin
|
4 |
+
*
|
5 |
+
* @package External Links
|
6 |
+
**/
|
7 |
+
|
8 |
+
class external_links_admin {
|
9 |
+
/**
|
10 |
+
* external_links_admin()
|
11 |
+
*/
|
12 |
+
public function __construct() {
|
13 |
+
add_action('settings_page_external-links', array($this, 'save_options'), 0);
|
14 |
+
}
|
15 |
+
|
16 |
+
/**
|
17 |
+
* save_options()
|
18 |
+
*
|
19 |
+
* @return void
|
20 |
+
**/
|
21 |
+
|
22 |
+
function save_options() {
|
23 |
+
if ( !$_POST || !current_user_can('manage_options') )
|
24 |
+
return;
|
25 |
+
|
26 |
+
check_admin_referer('external_links');
|
27 |
+
|
28 |
+
foreach ( array('global', 'icon', 'target', 'nofollow', 'text_widgets') as $var )
|
29 |
+
$$var = isset($_POST[$var]);
|
30 |
+
|
31 |
+
update_option('external_links', compact('global', 'icon', 'target', 'nofollow', 'text_widgets'));
|
32 |
+
|
33 |
+
echo "<div class=\"updated fade\">\n"
|
34 |
+
. "<p>"
|
35 |
+
. "<strong>"
|
36 |
+
. __('Settings saved.', 'external-links')
|
37 |
+
. "</strong>"
|
38 |
+
. "</p>\n"
|
39 |
+
. "</div>\n";
|
40 |
+
} # save_options()
|
41 |
+
|
42 |
+
|
43 |
+
/**
|
44 |
+
* edit_options()
|
45 |
+
*
|
46 |
+
* @return void
|
47 |
+
**/
|
48 |
+
|
49 |
+
static function edit_options() {
|
50 |
+
echo '<div class="wrap">' . "\n"
|
51 |
+
. '<form method="post" action="">';
|
52 |
+
|
53 |
+
wp_nonce_field('external_links');
|
54 |
+
|
55 |
+
$options = external_links::get_options();
|
56 |
+
|
57 |
+
if ( $options['nofollow'] && ( function_exists('strip_nofollow') || class_exists('sem_dofollow') ) ) {
|
58 |
+
echo "<div class=\"error\">\n"
|
59 |
+
. "<p>"
|
60 |
+
. __('Note: Your rel=nofollow preferences is being ignored because the dofollow plugin is enabled on your site.', 'external-links')
|
61 |
+
. "</p>\n"
|
62 |
+
. "</div>\n";
|
63 |
+
}
|
64 |
+
|
65 |
+
echo '<h2>' . __('External Links Settings', 'external-links') . '</h2>' . "\n";
|
66 |
+
|
67 |
+
echo '<table class="form-table">' . "\n";
|
68 |
+
|
69 |
+
echo '<tr>' . "\n"
|
70 |
+
. '<th scope="row">'
|
71 |
+
. __('Apply Globally', 'external-links')
|
72 |
+
. '</th>' . "\n"
|
73 |
+
. '<td>'
|
74 |
+
. '<label>'
|
75 |
+
. '<input type="checkbox" name="global"'
|
76 |
+
. checked($options['global'], true, false)
|
77 |
+
. ' />'
|
78 |
+
. ' '
|
79 |
+
. __('Apply these settings to all outbound links on the site except those in scripts, styles and the html head section.', 'external-links')
|
80 |
+
. '</label>'
|
81 |
+
. '</td>' . "\n"
|
82 |
+
. '</tr>' . "\n";
|
83 |
+
|
84 |
+
echo '<tr>' . "\n"
|
85 |
+
. '<th scope="row">'
|
86 |
+
. __('Apply to Text Widgets', 'external-links')
|
87 |
+
. '</th>' . "\n"
|
88 |
+
. '<td>'
|
89 |
+
. '<label>'
|
90 |
+
. '<input type="checkbox" name="text_widgets"'
|
91 |
+
. checked($options['text_widgets'], true, false)
|
92 |
+
. ' />'
|
93 |
+
. ' '
|
94 |
+
. __('Apply these settings to all text widgets in addition to those in posts and comments.', 'external-links')
|
95 |
+
. '</label>'
|
96 |
+
. '</td>' . "\n"
|
97 |
+
. '</tr>' . "\n";
|
98 |
+
|
99 |
+
echo '<tr>' . "\n"
|
100 |
+
. '<th scope="row">'
|
101 |
+
. __('Add Icons', 'external-links')
|
102 |
+
. '</th>' . "\n"
|
103 |
+
. '<td>'
|
104 |
+
. '<label>'
|
105 |
+
. '<input type="checkbox" name="icon"'
|
106 |
+
. checked($options['icon'], true, false)
|
107 |
+
. ' />'
|
108 |
+
. ' '
|
109 |
+
. __('Mark outbound links with an icon.', 'external-links')
|
110 |
+
. '</label>'
|
111 |
+
. '<br />' . "\n"
|
112 |
+
. __('Note: You can override this behavior by adding a class="no_icon" to individual links.', 'external-links')
|
113 |
+
. '</td>' . "\n"
|
114 |
+
. '</tr>' . "\n";
|
115 |
+
|
116 |
+
echo '<tr>' . "\n"
|
117 |
+
. '<th scope="row">'
|
118 |
+
. __('Add No Follow', 'external-links')
|
119 |
+
. '</th>' . "\n"
|
120 |
+
. '<td>'
|
121 |
+
. '<label>'
|
122 |
+
. '<input type="checkbox" name="nofollow"'
|
123 |
+
. checked($options['nofollow'], true, false)
|
124 |
+
. ' />'
|
125 |
+
. ' '
|
126 |
+
. __('Add a rel=nofollow attribute to outbound links.', 'external-links')
|
127 |
+
. '</label>'
|
128 |
+
. '<br />' . "\n"
|
129 |
+
. __('Note: You can override this behavior by adding the attribute rel="follow" to individual links.', 'external-links')
|
130 |
+
. '</td>' . "\n"
|
131 |
+
. '</tr>' . "\n";
|
132 |
+
|
133 |
+
echo '<tr>' . "\n"
|
134 |
+
. '<th scope="row">'
|
135 |
+
. __('Open in New Windows', 'external-links')
|
136 |
+
. '</th>' . "\n"
|
137 |
+
. '<td>'
|
138 |
+
. '<label>'
|
139 |
+
. '<input type="checkbox" name="target"'
|
140 |
+
. checked($options['target'], true, false)
|
141 |
+
. ' />'
|
142 |
+
. ' '
|
143 |
+
. __('Open outbound links in new windows.', 'external-links')
|
144 |
+
. '</label>'
|
145 |
+
. '<br />' . "\n"
|
146 |
+
. __('Note: Some usability experts discourage this, claiming that <a href="http://www.useit.com/alertbox/9605.html">this can damage your visitors\' trust</a> towards your site. Others highlight that computer-illiterate users do not always know how to use the back button, and encourage the practice for that reason.', 'external-links')
|
147 |
+
. '</td>' . "\n"
|
148 |
+
. '</tr>' . "\n";
|
149 |
+
|
150 |
+
echo '</table>' . "\n";
|
151 |
+
|
152 |
+
echo '<p class="submit">'
|
153 |
+
. '<input type="submit"'
|
154 |
+
. ' value="' . esc_attr(__('Save Changes', 'external-links')) . '"'
|
155 |
+
. ' />'
|
156 |
+
. '</p>' . "\n";
|
157 |
+
|
158 |
+
echo '</form>' . "\n"
|
159 |
+
. '</div>' . "\n";
|
160 |
+
} # edit_options()
|
161 |
+
} # external_links_admin
|
162 |
+
|
163 |
+
$external_links_admin = new external_links_admin();
|
sem-external-links-info.php
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
__('External Links', 'external-links');
|
3 |
+
__('Marks outbound links as such, with various effects that are configurable under <a href="options-general.php?page=external-links">Settings / External Links</a>.', 'external-links');
|
4 |
+
?>
|
sem-external-links.css
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
1 |
+
a.external_icon {
|
2 |
+
background: url(external.png) center right no-repeat;
|
3 |
+
padding-right: 13px;
|
4 |
+
}
|
sem-external-links.php
ADDED
@@ -0,0 +1,356 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: External Links
|
4 |
+
Plugin URI: http://www.semiologic.com/software/external-links/
|
5 |
+
Description: Marks outbound links as such, with various effects that are configurable under <a href="options-general.php?page=external-links">Settings / External Links</a>.
|
6 |
+
Version: 5.5.4
|
7 |
+
Author: Denis de Bernardy & Mike Koepke
|
8 |
+
Author URI: http://www.getsemiologic.com
|
9 |
+
Text Domain: external-links
|
10 |
+
Domain Path: /lang
|
11 |
+
License: Dual licensed under the MIT and GPLv2 licenses
|
12 |
+
*/
|
13 |
+
|
14 |
+
/*
|
15 |
+
Terms of use
|
16 |
+
------------
|
17 |
+
|
18 |
+
This software is copyright Denis de Bernardy & Mike Koepke, and is distributed under the terms of the MIT and GPLv2 licenses.
|
19 |
+
|
20 |
+
**/
|
21 |
+
|
22 |
+
/**
|
23 |
+
* external_links
|
24 |
+
*
|
25 |
+
* @package External Links
|
26 |
+
**/
|
27 |
+
|
28 |
+
class external_links {
|
29 |
+
|
30 |
+
protected $opts;
|
31 |
+
|
32 |
+
protected $anchor_utils;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Plugin instance.
|
36 |
+
*
|
37 |
+
* @see get_instance()
|
38 |
+
* @type object
|
39 |
+
*/
|
40 |
+
protected static $instance = NULL;
|
41 |
+
|
42 |
+
/**
|
43 |
+
* URL to this plugin's directory.
|
44 |
+
*
|
45 |
+
* @type string
|
46 |
+
*/
|
47 |
+
public $plugin_url = '';
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Path to this plugin's directory.
|
51 |
+
*
|
52 |
+
* @type string
|
53 |
+
*/
|
54 |
+
public $plugin_path = '';
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Access this plugin’s working instance
|
58 |
+
*
|
59 |
+
* @wp-hook plugins_loaded
|
60 |
+
* @return object of this class
|
61 |
+
*/
|
62 |
+
public static function get_instance()
|
63 |
+
{
|
64 |
+
NULL === self::$instance and self::$instance = new self;
|
65 |
+
|
66 |
+
return self::$instance;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Loads translation file.
|
71 |
+
*
|
72 |
+
* Accessible to other classes to load different language files (admin and
|
73 |
+
* front-end for example).
|
74 |
+
*
|
75 |
+
* @wp-hook init
|
76 |
+
* @param string $domain
|
77 |
+
* @return void
|
78 |
+
*/
|
79 |
+
public function load_language( $domain )
|
80 |
+
{
|
81 |
+
load_plugin_textdomain(
|
82 |
+
$domain,
|
83 |
+
FALSE,
|
84 |
+
dirname(plugin_basename(__FILE__)) . '/lang'
|
85 |
+
);
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Constructor.
|
90 |
+
*
|
91 |
+
*
|
92 |
+
*/
|
93 |
+
public function __construct() {
|
94 |
+
$this->plugin_url = plugins_url( '/', __FILE__ );
|
95 |
+
$this->plugin_path = plugin_dir_path( __FILE__ );
|
96 |
+
$this->load_language( 'external-links' );
|
97 |
+
|
98 |
+
add_action( 'plugins_loaded', array ( $this, 'init' ) );
|
99 |
+
}
|
100 |
+
|
101 |
+
|
102 |
+
/**
|
103 |
+
* init()
|
104 |
+
*
|
105 |
+
* @return void
|
106 |
+
**/
|
107 |
+
|
108 |
+
function init() {
|
109 |
+
// more stuff: register actions and filters
|
110 |
+
if ( !is_admin() ) {
|
111 |
+
if ( !class_exists('external_links_anchor_utils') )
|
112 |
+
include $this->plugin_path . '/external-links-anchor-utils.php';
|
113 |
+
|
114 |
+
$o = external_links::get_options();
|
115 |
+
|
116 |
+
// add_filter(($o['global'] ? 'ob_' : '' ) . 'filter_anchor', array($this, 'filter'));
|
117 |
+
|
118 |
+
$inc_text_widgets = false;
|
119 |
+
if ( isset( $o['text_widgets'] ) && $o['text_widgets'] )
|
120 |
+
$inc_text_widgets = true;
|
121 |
+
|
122 |
+
$this->anchor_utils = new external_links_anchor_utils( $this, $o['global'], $inc_text_widgets );
|
123 |
+
|
124 |
+
if ( $o['icon'] )
|
125 |
+
add_action('wp_enqueue_scripts', array($this, 'styles'), 5);
|
126 |
+
|
127 |
+
unset($o);
|
128 |
+
}
|
129 |
+
else {
|
130 |
+
add_action('admin_menu', array($this, 'admin_menu'));
|
131 |
+
add_action('load-settings_page_external-links', array($this, 'external_links_admin'));
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* external_links_admin()
|
137 |
+
*
|
138 |
+
* @return void
|
139 |
+
**/
|
140 |
+
function external_links_admin() {
|
141 |
+
include_once $this->plugin_path . '/sem-external-links-admin.php';
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* styles()
|
146 |
+
*
|
147 |
+
* @return void
|
148 |
+
**/
|
149 |
+
|
150 |
+
function styles() {
|
151 |
+
$folder = plugin_dir_url(__FILE__);
|
152 |
+
wp_enqueue_style('external-links', $folder . 'sem-external-links.css', null, '20090903');
|
153 |
+
} # styles()
|
154 |
+
|
155 |
+
|
156 |
+
/**
|
157 |
+
* filter()
|
158 |
+
*
|
159 |
+
* @param $anchor
|
160 |
+
* @return string
|
161 |
+
*/
|
162 |
+
|
163 |
+
function filter($anchor) {
|
164 |
+
# disable in feeds
|
165 |
+
if ( is_feed() )
|
166 |
+
return $anchor;
|
167 |
+
|
168 |
+
# ignore local urls
|
169 |
+
if ( external_links::is_local_url($anchor['attr']['href']) )
|
170 |
+
return $anchor;
|
171 |
+
|
172 |
+
# no icons for images
|
173 |
+
$is_image = (bool) preg_match("/^\s*<\s*img\s.+?>\s*$/is", $anchor['body']);
|
174 |
+
|
175 |
+
$o = external_links::get_options();
|
176 |
+
|
177 |
+
if ( !in_array('external', $anchor['attr']['class']) )
|
178 |
+
$anchor['attr']['class'][] = 'external';
|
179 |
+
|
180 |
+
if ( !$is_image && $o['icon'] && !in_array('external_icon', $anchor['attr']['class'])
|
181 |
+
&& !in_array('no_icon', $anchor['attr']['class'])
|
182 |
+
&& !in_array('noicon', $anchor['attr']['class']) )
|
183 |
+
$anchor['attr']['class'][] = 'external_icon';
|
184 |
+
|
185 |
+
if ( $o['nofollow'] && !function_exists('strip_nofollow')
|
186 |
+
&& !in_array('nofollow', $anchor['attr']['rel'])
|
187 |
+
&& !in_array('follow', $anchor['attr']['rel']) )
|
188 |
+
$anchor['attr']['rel'][] = 'nofollow';
|
189 |
+
|
190 |
+
if ( $o['target'] && empty($anchor['attr']['target']) )
|
191 |
+
$anchor['attr']['target'] = '_blank';
|
192 |
+
|
193 |
+
return $anchor;
|
194 |
+
} # filter()
|
195 |
+
|
196 |
+
/**
|
197 |
+
* is_local_url()
|
198 |
+
*
|
199 |
+
* @param string $url
|
200 |
+
* @return bool $is_local_url
|
201 |
+
**/
|
202 |
+
|
203 |
+
function is_local_url($url) {
|
204 |
+
if ( in_array(substr($url, 0, 1), array('?', '#')) || strpos($url, '://') === false )
|
205 |
+
return true;
|
206 |
+
elseif ( $url == 'http://' || $url == 'https://' )
|
207 |
+
return true;
|
208 |
+
elseif ( preg_match("~/go(/|\.)~i", $url) )
|
209 |
+
return false;
|
210 |
+
|
211 |
+
static $site_domain;
|
212 |
+
|
213 |
+
if ( !isset($site_domain) ) {
|
214 |
+
$site_domain = get_option('home');
|
215 |
+
$site_domain = parse_url($site_domain);
|
216 |
+
$site_domain = $site_domain['host'];
|
217 |
+
if ($site_domain == false)
|
218 |
+
return false;
|
219 |
+
elseif (is_array($site_domain)) {
|
220 |
+
if (isset($site_domain['host']))
|
221 |
+
$site_domain = $site_domain['host'];
|
222 |
+
else
|
223 |
+
return false;
|
224 |
+
}
|
225 |
+
$site_domain = preg_replace("/^www\./i", '', $site_domain);
|
226 |
+
|
227 |
+
# The following is not bullet proof, but it's good enough for a WP site
|
228 |
+
if ( $site_domain != 'localhost' && !preg_match("/\d+(\.\d+){3}/", $site_domain) ) {
|
229 |
+
if ( preg_match("/\.([^.]+)$/", $site_domain, $tld) ) {
|
230 |
+
$tld = end($tld);
|
231 |
+
} else {
|
232 |
+
$site_domain = false;
|
233 |
+
return false;
|
234 |
+
}
|
235 |
+
|
236 |
+
$site_domain = substr($site_domain, 0, strlen($site_domain) - 1 - strlen($tld));
|
237 |
+
|
238 |
+
if ( preg_match("/\.([^.]+)$/", $site_domain, $subtld) ) {
|
239 |
+
$subtld = end($subtld);
|
240 |
+
if ( strlen($subtld) <= 4 ) {
|
241 |
+
$site_domain = substr($site_domain, 0, strlen($site_domain) - 1 - strlen($subtld));
|
242 |
+
$site_domain = explode('.', $site_domain);
|
243 |
+
$site_domain = array_pop($site_domain);
|
244 |
+
$site_domain .= ".$subtld";
|
245 |
+
} else {
|
246 |
+
$site_domain = $subtld;
|
247 |
+
}
|
248 |
+
}
|
249 |
+
|
250 |
+
$site_domain .= ".$tld";
|
251 |
+
}
|
252 |
+
|
253 |
+
$site_domain = strtolower($site_domain);
|
254 |
+
}
|
255 |
+
|
256 |
+
if ( !$site_domain )
|
257 |
+
return false;
|
258 |
+
|
259 |
+
$link_domain = @parse_url($url);
|
260 |
+
if ($link_domain === false)
|
261 |
+
return true;
|
262 |
+
elseif (is_array($link_domain)) {
|
263 |
+
if (isset($link_domain['host']))
|
264 |
+
$link_domain = $link_domain['host'];
|
265 |
+
else
|
266 |
+
return false;
|
267 |
+
}
|
268 |
+
$link_domain = preg_replace("/^www\./i", '', $link_domain);
|
269 |
+
$link_domain = strtolower($link_domain);
|
270 |
+
|
271 |
+
if ( $site_domain == $link_domain ) {
|
272 |
+
return true;
|
273 |
+
} elseif ( function_exists('is_multisite') && is_multisite() ) {
|
274 |
+
return false;
|
275 |
+
} else {
|
276 |
+
$site_elts = explode('.', $site_domain);
|
277 |
+
$link_elts = explode('.', $link_domain);
|
278 |
+
|
279 |
+
while ( ( $site_elt = array_pop($site_elts) ) && ( $link_elt = array_pop($link_elts) ) ) {
|
280 |
+
if ( $site_elt !== $link_elt )
|
281 |
+
return false;
|
282 |
+
}
|
283 |
+
|
284 |
+
return empty($link_elts) || empty($site_elts);
|
285 |
+
}
|
286 |
+
} # is_local_url()
|
287 |
+
|
288 |
+
|
289 |
+
/**
|
290 |
+
* get_options
|
291 |
+
*
|
292 |
+
* @return array $options
|
293 |
+
**/
|
294 |
+
|
295 |
+
static function get_options() {
|
296 |
+
static $o;
|
297 |
+
|
298 |
+
if ( !is_admin() && isset($o) )
|
299 |
+
return $o;
|
300 |
+
|
301 |
+
$o = get_option('external_links');
|
302 |
+
|
303 |
+
if ( $o === false || !isset($o['text_widgets']) )
|
304 |
+
$o = external_links::init_options();
|
305 |
+
|
306 |
+
return $o;
|
307 |
+
} # get_options()
|
308 |
+
|
309 |
+
|
310 |
+
/**
|
311 |
+
* init_options()
|
312 |
+
*
|
313 |
+
* @return array $options
|
314 |
+
**/
|
315 |
+
|
316 |
+
function init_options() {
|
317 |
+
$o = get_option('external_links');
|
318 |
+
|
319 |
+
$defaults = array(
|
320 |
+
'global' => false,
|
321 |
+
'icon' => true,
|
322 |
+
'target' => false,
|
323 |
+
'nofollow' => true,
|
324 |
+
'text_widgets' => true,
|
325 |
+
);
|
326 |
+
|
327 |
+
if ( !$o )
|
328 |
+
$o = $defaults;
|
329 |
+
else
|
330 |
+
$o = wp_parse_args($o, $defaults);
|
331 |
+
|
332 |
+
update_option('external_links', $o);
|
333 |
+
|
334 |
+
return $o;
|
335 |
+
} # init_options()
|
336 |
+
|
337 |
+
|
338 |
+
|
339 |
+
/**
|
340 |
+
* admin_menu()
|
341 |
+
*
|
342 |
+
* @return void
|
343 |
+
**/
|
344 |
+
|
345 |
+
function admin_menu() {
|
346 |
+
add_options_page(
|
347 |
+
__('External Links', 'external-links'),
|
348 |
+
__('External Links', 'external-links'),
|
349 |
+
'manage_options',
|
350 |
+
'external-links',
|
351 |
+
array('external_links_admin', 'edit_options')
|
352 |
+
);
|
353 |
+
} # admin_menu()
|
354 |
+
} # external_links
|
355 |
+
|
356 |
+
$external_links = external_links::get_instance();
|
sem-external-links.pot
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# External Links pot file.
|
2 |
+
# Copyright (C) 2010 Mesoconcepts <http://www.mesoconcepts.com>
|
3 |
+
# This file is distributed under the same license as the External Links package.
|
4 |
+
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
5 |
+
#
|
6 |
+
#, fuzzy
|
7 |
+
msgid ""
|
8 |
+
msgstr ""
|
9 |
+
"Project-Id-Version: 4.0.5\n"
|
10 |
+
"Report-Msgid-Bugs-To: https://tickets.semiologic.com\n"
|
11 |
+
"POT-Creation-Date: 2010-05-13 16:35+0200\n"
|
12 |
+
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
13 |
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
14 |
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
15 |
+
"MIME-Version: 1.0\n"
|
16 |
+
"Content-Type: text/plain; charset=CHARSET\n"
|
17 |
+
"Content-Transfer-Encoding: 8bit\n"
|
18 |
+
|
19 |
+
#: sem-external-links-admin.php:29
|
20 |
+
msgid "Settings saved."
|
21 |
+
msgstr ""
|
22 |
+
|
23 |
+
#: sem-external-links-admin.php:53
|
24 |
+
msgid ""
|
25 |
+
"Note: Your rel=nofollow preferences is being ignored because the dofollow "
|
26 |
+
"plugin is enabled on your site."
|
27 |
+
msgstr ""
|
28 |
+
|
29 |
+
#: sem-external-links-admin.php:60
|
30 |
+
msgid "External Links Settings"
|
31 |
+
msgstr ""
|
32 |
+
|
33 |
+
#: sem-external-links-admin.php:66
|
34 |
+
msgid "Apply Globally"
|
35 |
+
msgstr ""
|
36 |
+
|
37 |
+
#: sem-external-links-admin.php:74
|
38 |
+
msgid ""
|
39 |
+
"Apply these settings to all outbound links, including those in sidebars, "
|
40 |
+
"rather than to those in posts and comments."
|
41 |
+
msgstr ""
|
42 |
+
|
43 |
+
#: sem-external-links-admin.php:81
|
44 |
+
msgid "Add Icons"
|
45 |
+
msgstr ""
|
46 |
+
|
47 |
+
#: sem-external-links-admin.php:89
|
48 |
+
msgid "Mark outbound links with an icon."
|
49 |
+
msgstr ""
|
50 |
+
|
51 |
+
#: sem-external-links-admin.php:92
|
52 |
+
msgid ""
|
53 |
+
"Note: You can override this behavior by adding a class=\"no_icon\" to "
|
54 |
+
"individual links."
|
55 |
+
msgstr ""
|
56 |
+
|
57 |
+
#: sem-external-links-admin.php:98
|
58 |
+
msgid "Add No Follow"
|
59 |
+
msgstr ""
|
60 |
+
|
61 |
+
#: sem-external-links-admin.php:106
|
62 |
+
msgid "Add a rel=nofollow attribute to outbound links."
|
63 |
+
msgstr ""
|
64 |
+
|
65 |
+
#: sem-external-links-admin.php:109
|
66 |
+
msgid ""
|
67 |
+
"Note: You can override this behavior by adding a rel=\"follow\" to "
|
68 |
+
"individual links."
|
69 |
+
msgstr ""
|
70 |
+
|
71 |
+
#: sem-external-links-admin.php:115
|
72 |
+
msgid "Open in New Windows"
|
73 |
+
msgstr ""
|
74 |
+
|
75 |
+
#: sem-external-links-admin.php:123
|
76 |
+
msgid "Open outbound links in new windows."
|
77 |
+
msgstr ""
|
78 |
+
|
79 |
+
#: sem-external-links-admin.php:126
|
80 |
+
msgid ""
|
81 |
+
"Note: Some usability experts discourage this, claiming that <a href=\"http://"
|
82 |
+
"www.useit.com/alertbox/9605.html\">this can damage your visitors' trust</a> "
|
83 |
+
"towards your site. Others highlight that computer-illiterate users do not "
|
84 |
+
"always know how to use the back button, and encourage the practice for that "
|
85 |
+
"reason."
|
86 |
+
msgstr ""
|
87 |
+
|
88 |
+
#: sem-external-links-admin.php:134
|
89 |
+
msgid "Save Changes"
|
90 |
+
msgstr ""
|
91 |
+
|
92 |
+
#: sem-external-links-info.php:2 sem-external-links.php:216
|
93 |
+
#: sem-external-links.php:217
|
94 |
+
msgid "External Links"
|
95 |
+
msgstr ""
|
96 |
+
|
97 |
+
#: sem-external-links-info.php:3
|
98 |
+
msgid ""
|
99 |
+
"Marks outbound links as such, with various effects that are configurable "
|
100 |
+
"under <a href=\"options-general.php?page=external-links\">Settings / "
|
101 |
+
"External Links</a>."
|
102 |
+
msgstr ""
|