External Links - Version 6.0.1

Version Description

Download this release

Release Info

Developer Mike_Koepke
Plugin Icon wp plugin External Links
Version 6.0.1
Comparing to
See all releases

Code changes from version 6.0 to 6.0.1

external-links-anchor-utils.php CHANGED
@@ -25,20 +25,11 @@ class external_links_anchor_utils {
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
 
@@ -50,8 +41,15 @@ class external_links_anchor_utils {
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
  /**
@@ -62,24 +60,11 @@ class external_links_anchor_utils {
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()
@@ -87,314 +72,16 @@ class external_links_anchor_utils {
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
25
  /**
26
  * constructor
27
  */
28
+ public function __construct( sem_external_links $external_links ) {
29
 
30
  $this->external_links = $external_links;
31
 
32
+ add_action('template_redirect', array($this, 'ob_start'), 100);
 
 
 
 
 
 
 
 
 
33
 
34
  } #external_links_anchor_utils
35
 
41
  **/
42
 
43
  function ob_start() {
44
+ static $done = false;
45
+
46
+ if ($done)
47
+ return;
48
+
49
  ob_start(array($this, 'ob_filter'));
50
+ add_action('wp_footer', array($this, 'ob_flush'), 100000);
51
+
52
+ $done = true;
53
  } # ob_start()
54
 
55
  /**
60
  **/
61
 
62
  function ob_filter($text) {
 
 
 
 
63
 
64
+ $text = $this->external_links->process_content( $text );
 
 
 
 
 
 
 
 
65
 
66
  return $text;
67
+ }
 
68
 
69
  /**
70
  * ob_flush()
72
  * @return void
73
  **/
74
 
75
+ function ob_flush() {
76
+ static $done = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
+ if ($done)
79
+ return;
80
 
81
+ ob_end_flush();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
+ $done = true;
84
+ } # ob_flush()
 
 
 
 
 
 
 
85
 
 
 
86
 
 
 
87
  } # external_links_anchor_utils
readme.txt CHANGED
@@ -14,12 +14,35 @@ The external links plugin for WordPress lets you process outgoing links differen
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
 
@@ -34,8 +57,22 @@ If you require more dedicated assistance, consider using [Semiologic Pro](http:/
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
@@ -145,4 +182,5 @@ If you require more dedicated assistance, consider using [Semiologic Pro](http:/
145
  - Allow to force a follow when the nofollow option is toggled
146
  - Enhance escape/unescape methods
147
  - Localization
148
- - Code enhancements and optimizations
 
14
 
15
  The external links plugin for WordPress lets you process outgoing links differently from internal links.
16
 
17
+ = Usage =
18
+
19
  Under Settings / External Links, you can configure the plugin to:
20
 
21
  - Process all outgoing links, rather than only those within your entries' content and text widgets.
22
  - Add an external link icon to outgoing links. You can use a class="no_icon" attribute on links to override this.
23
+ - Add rel=nofollow to the links. (Note: You can use a rel="follow" attribute on links to override this.)
24
  - 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.
25
+ - Follow comment links (supersedes the nofollow setting in the comment area).
26
+ - Turn on "autolinks" functionality.
27
+
28
+
29
+ = Auto Links =
30
+
31
+ The Autolink functionaity automatically converts urls to hyperlinked urls in post/page content, excerpts and text widgets.
32
+
33
+ Before:
34
+
35
+ > www.semiologic.com
36
+
37
+ After:
38
+
39
+ > [www.semiologic.com](http://www.semiologic.com)
40
+
41
+
42
+ = Follow Comments =
43
+
44
+ The Follow Comments functionality lets you remove the evil nofollow attribute from your comments.
45
+
46
 
47
  = Help Me! =
48
 
57
  2. Activate the plugin through the 'Plugins' menu in WordPress
58
 
59
 
60
+ == Frequently Asked Questions ==
61
+
62
+ = How can I make some links still be followed? =
63
+
64
+ The plugin supports a non-started rel="follow" attribute on links to override this. If it detects rel="follow" it will not add the "nofollow" attribute to that link.
65
+
66
+
67
  == Change Log ==
68
 
69
+ = 6.0 =
70
+
71
+ - Fixed performance issues with the link processing. Really was poor.
72
+ - Embedded the functionality of the autolink uri and the dofollow plugins (off by default in Settings)
73
+ - New option on how to treat subdomains of installed plugin domain as local or external
74
+ - Fixed several php strict warnings
75
+
76
  = 5.5.4 =
77
 
78
  - Remove HTML comments added in 5.4.1 to assist in troubleshooting some select site issues
182
  - Allow to force a follow when the nofollow option is toggled
183
  - Enhance escape/unescape methods
184
  - Localization
185
+ - Code enhancements and optimizations
186
+
sem-autolink-uri.php ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Module Name: Sem Autolink URI
4
+ Description: Automatically wraps unhyperlinked uri with html anchors.
5
+ Version: 2.7
6
+ Author: Denis de Bernardy & Mike Koepke
7
+ Author URI: https://www.semiologic.com
8
+ License: Dual licensed under the MIT and GPLv2 licenses
9
+ */
10
+
11
+ /*
12
+ Terms of use
13
+ ------------
14
+
15
+ This software is copyright Denis de Bernardy & Mike Koepke, and is distributed under the terms of the MIT and GPLv2 licenses.
16
+ **/
17
+
18
+
19
+ /**
20
+ * autolink_uri
21
+ *
22
+ * @package Autolink URI
23
+ **/
24
+
25
+ class sem_autolink_uri {
26
+ /**
27
+ * Plugin instance.
28
+ *
29
+ * @see get_instance()
30
+ * @type object
31
+ */
32
+ protected static $instance = NULL;
33
+
34
+ /**
35
+ * URL to this plugin's directory.
36
+ *
37
+ * @type string
38
+ */
39
+ public $plugin_url = '';
40
+
41
+ /**
42
+ * Path to this plugin's directory.
43
+ *
44
+ * @type string
45
+ */
46
+ public $plugin_path = '';
47
+
48
+ /**
49
+ * Access this plugin’s working instance
50
+ *
51
+ * @wp-hook plugins_loaded
52
+ * @return object of this class
53
+ */
54
+ public static function get_instance()
55
+ {
56
+ NULL === self::$instance and self::$instance = new self;
57
+
58
+ return self::$instance;
59
+ }
60
+
61
+ /**
62
+ * Constructor.
63
+ *
64
+ *
65
+ */
66
+
67
+ public function __construct() {
68
+ $this->plugin_url = plugins_url( '/', __FILE__ );
69
+ $this->plugin_path = plugin_dir_path( __FILE__ );
70
+
71
+ $this->init();
72
+ }
73
+
74
+
75
+ /**
76
+ * init()
77
+ *
78
+ * @return void
79
+ **/
80
+
81
+ function init() {
82
+ // more stuff: register actions and filters
83
+ // after shortcodes
84
+ add_filter('the_content', array($this, 'filter'), 12);
85
+ add_filter('the_excerpt', array($this, 'filter'), 12);
86
+ add_filter('widget_text', array($this, 'filter'), 12);
87
+ }
88
+
89
+ /**
90
+ * filter()
91
+ *
92
+ * @param string $text
93
+ * @return string $text
94
+ **/
95
+
96
+ function filter($text) {
97
+ global $escape_autolink_uri;
98
+
99
+ $escape_autolink_uri = array();
100
+
101
+ $text = sem_autolink_uri::escape($text);
102
+
103
+ $text = preg_replace_callback("/
104
+ ((?<![\"']) # don't look inside quotes
105
+ (\b
106
+ ( # protocol or www.
107
+ [a-z]{3,}:\/\/
108
+ |
109
+ www\.
110
+ )
111
+ (?: # domain
112
+ [a-zA-Z0-9_\-]+
113
+ (?:\.[a-zA-Z0-9_\-]+)*
114
+ |
115
+ localhost
116
+ )
117
+ (?: # port
118
+ \:[0-9]+
119
+ )?
120
+ (?: # path (optional)
121
+ [\/|\?][\wa-z0-9#!:\.\?\+=&%@$!'~\*,;\/\(\)\[\]\-]*
122
+ )?
123
+ )
124
+ (?![\"']))
125
+ /ix", array($this, 'url_callback'), $text);
126
+
127
+ $text = sem_autolink_uri::unescape($text);
128
+
129
+ return $text;
130
+ } # filter()
131
+
132
+
133
+ /**
134
+ * url_callback()
135
+ *
136
+ * @param array $match
137
+ * @return string $text
138
+ **/
139
+
140
+ function url_callback($match) {
141
+ $url = $match[0];
142
+ $href = $url;
143
+
144
+ if ( strtolower($match[1]) === 'www.' )
145
+ $href = 'http://' . $href;
146
+
147
+ $href = esc_url($href);
148
+
149
+ return '<a href="' . $href . '">' . $url . '</a>';
150
+ } # url_callback()
151
+
152
+ /**
153
+ * escape()
154
+ *
155
+ * @param string $text
156
+ * @return string $text
157
+ **/
158
+
159
+ function escape($text) {
160
+ global $escape_autolink_uri;
161
+
162
+ if ( !isset($escape_autolink_uri) )
163
+ $escape_autolink_uri = array();
164
+
165
+ foreach ( array(
166
+ 'head' => "/
167
+ .*?
168
+ <\s*\/\s*head\s*>
169
+ /isx",
170
+ 'blocks' => "/
171
+ <\s*(script|style|object|textarea|code|pre)(?:\s.*?)?>
172
+ .*?
173
+ <\s*\/\s*\\1\s*>
174
+ /isx",
175
+ 'smart_links' => "/
176
+ \[.+?\]
177
+ /x",
178
+ 'anchors' => "/
179
+ <\s*a\s.+?>.+?<\s*\/\s*a\s*>
180
+ /isx",
181
+ 'tags' => "/
182
+ <[^<>]+?(?:src|href|codebase|archive|usemap|data|value|action|background|placeholder)=[^<>]+?>
183
+ /ix",
184
+ ) as $regex ) {
185
+ $text = preg_replace_callback($regex, array($this, 'escape_callback'), $text);
186
+ }
187
+
188
+ return $text;
189
+ } # escape()
190
+
191
+
192
+ /**
193
+ * escape_callback()
194
+ *
195
+ * @param array $match
196
+ * @return string $tag_id
197
+ **/
198
+
199
+ function escape_callback($match) {
200
+ global $escape_autolink_uri;
201
+
202
+ $tag_id = "----escape_sem_autolink_uri:" . md5($match[0]) . "----";
203
+ $escape_autolink_uri[$tag_id] = $match[0];
204
+
205
+ return $tag_id;
206
+ } # escape_callback()
207
+
208
+
209
+ /**
210
+ * unescape()
211
+ *
212
+ * @param string $text
213
+ * @return string $text
214
+ **/
215
+
216
+ function unescape($text) {
217
+ global $escape_autolink_uri;
218
+
219
+ if ( !$escape_autolink_uri )
220
+ return $text;
221
+
222
+ $unescape = array_reverse($escape_autolink_uri);
223
+
224
+ return str_replace(array_keys($unescape), array_values($unescape), $text);
225
+ } # unescape()
226
+ } # sem_autolink_uri
227
+
228
+ $sem_autolink_uri = sem_autolink_uri::get_instance();
sem-external-links-admin.php CHANGED
@@ -6,13 +6,67 @@
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
  *
@@ -23,12 +77,15 @@ class external_links_admin {
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>"
@@ -50,9 +107,9 @@ class external_links_admin {
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"
@@ -91,11 +148,47 @@ class external_links_admin {
91
  . checked($options['text_widgets'], true, false)
92
  . ' />'
93
  . '&nbsp;'
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')
@@ -109,7 +202,7 @@ class external_links_admin {
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
 
@@ -123,13 +216,32 @@ class external_links_admin {
123
  . checked($options['nofollow'], true, false)
124
  . ' />'
125
  . '&nbsp;'
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')
@@ -143,10 +255,10 @@ class external_links_admin {
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">'
@@ -160,4 +272,4 @@ class external_links_admin {
160
  } # edit_options()
161
  } # external_links_admin
162
 
163
- $external_links_admin = new external_links_admin();
6
  **/
7
 
8
  class external_links_admin {
9
+ /**
10
+ * Plugin instance.
11
+ *
12
+ * @see get_instance()
13
+ * @type object
14
+ */
15
+ protected static $instance = NULL;
16
+
17
+ /**
18
+ * URL to this plugin's directory.
19
+ *
20
+ * @type string
21
+ */
22
+ public $plugin_url = '';
23
+
24
+ /**
25
+ * Path to this plugin's directory.
26
+ *
27
+ * @type string
28
+ */
29
+ public $plugin_path = '';
30
+
31
+ /**
32
+ * Access this plugin’s working instance
33
+ *
34
+ * @wp-hook plugins_loaded
35
+ * @return object of this class
36
+ */
37
+ public static function get_instance()
38
+ {
39
+ NULL === self::$instance and self::$instance = new self;
40
+
41
+ return self::$instance;
42
+ }
43
+
44
+
45
+ /**
46
+ * Constructor.
47
+ *
48
+ *
49
+ */
50
+
51
  public function __construct() {
52
+ $this->plugin_url = plugins_url( '/', __FILE__ );
53
+ $this->plugin_path = plugin_dir_path( __FILE__ );
54
+
55
+ $this->init();
56
  }
57
 
58
+
59
+ /**
60
+ * init()
61
+ *
62
+ * @return void
63
+ **/
64
+
65
+ function init() {
66
+ // register actions and filters
67
+ add_action('settings_page_external-links', array($this, 'save_options'), 0);
68
+ }
69
+
70
  /**
71
  * save_options()
72
  *
77
  if ( !$_POST || !current_user_can('manage_options') )
78
  return;
79
 
80
+ check_admin_referer('sem_external_links');
81
 
82
+ foreach ( array('global', 'icon', 'target', 'nofollow', 'text_widgets', 'autolinks',
83
+ 'follow_comments', 'subdomains_local') as $var )
84
  $$var = isset($_POST[$var]);
85
+
86
+ $version = sem_external_links_version;
87
+ update_option('external_links', compact('global', 'icon', 'target', 'nofollow', 'text_widgets',
88
+ 'autolinks', 'follow_comments', 'subdomains_local', 'version'));
89
 
90
  echo "<div class=\"updated fade\">\n"
91
  . "<p>"
107
  echo '<div class="wrap">' . "\n"
108
  . '<form method="post" action="">';
109
 
110
+ wp_nonce_field('sem_external_links');
111
 
112
+ $options = sem_external_links::get_options();
113
 
114
  if ( $options['nofollow'] && ( function_exists('strip_nofollow') || class_exists('sem_dofollow') ) ) {
115
  echo "<div class=\"error\">\n"
148
  . checked($options['text_widgets'], true, false)
149
  . ' />'
150
  . '&nbsp;'
151
+ . __('Apply these settings to any text widgets in addition to post, page and comments content.', 'external-links')
152
  . '</label>'
153
  . '</td>' . "\n"
154
  . '</tr>' . "\n";
155
 
156
+ echo '<tr>' . "\n"
157
+ . '<th scope="row">'
158
+ . __('Treat Subdomains as Local', 'external-links')
159
+ . '</th>' . "\n"
160
+ . '<td>'
161
+ . '<label>'
162
+ . '<input type="checkbox" name="subdomains_local"'
163
+ . checked($options['subdomains_local'], true, false)
164
+ . ' />'
165
+ . '&nbsp;'
166
+ . __('Treat any subdomains for this site as a local link.', 'external-links')
167
+ . '</label>'
168
+ . '<br />' . "\n"
169
+ . '<i>' . __('Example: If your site is at domain.com and you also have store.domain.com, any link to store.domain.com will be treated as local.', 'external-links') . '<i>'
170
+ . '</td>' . "\n"
171
+ . '</tr>' . "\n";
172
+
173
+ echo '<tr>' . "\n"
174
+ . '<th scope="row">'
175
+ . __('Auto Convert Text Urls', 'external-links')
176
+ . '</th>' . "\n"
177
+ . '<td>'
178
+ . '<label>'
179
+ . '<input type="checkbox" name="autolinks"'
180
+ . checked($options['autolinks'], true, false)
181
+ . ' />'
182
+ . '&nbsp;'
183
+ . __('Automatically converts text urls into clickable urls.', 'external-links')
184
+ . '</label>'
185
+ . '<br />' . "\n"
186
+ . '<i>' . __('Note: If this option is enabled then if www.example.com is found in your text, it will be converted to an html &lt;a&gt; link."', 'external-links')
187
+ . '<br />' . "\n"
188
+ . __('This conversion will occur first so external link treatment for nofollow, icon and target will be applied to this auto links.', 'external-links') . '</i>'
189
+ . '</td>' . "\n"
190
+ . '</tr>' . "\n";
191
+
192
  echo '<tr>' . "\n"
193
  . '<th scope="row">'
194
  . __('Add Icons', 'external-links')
202
  . __('Mark outbound links with an icon.', 'external-links')
203
  . '</label>'
204
  . '<br />' . "\n"
205
+ . '<i>' .__('Note: You can override this behavior by adding a class="no_icon" to individual links.', 'external-links') . '</i>'
206
  . '</td>' . "\n"
207
  . '</tr>' . "\n";
208
 
216
  . checked($options['nofollow'], true, false)
217
  . ' />'
218
  . '&nbsp;'
219
+ . __('Add a rel="nofollow" attribute to outbound links.', 'external-links')
220
  . '</label>'
221
  . '<br />' . "\n"
222
+ . '<i>' . __('Note: You can override this behavior by adding the attribute rel="follow" to individual links.', 'external-links')
223
+ . '<br />' . "\n"
224
+ . __('Your rel="nofollow" preferences will be ignored for comments if the "Do Follow Comment Links" setting below is enabled or if the standalone Dofollow plugin is enabled on your site.', 'external-links') . '</i>'
225
  . '</td>' . "\n"
226
  . '</tr>' . "\n";
227
 
228
+ echo '<tr>' . "\n"
229
+ . '<th scope="row">'
230
+ . __('Do Follow Comment Links', 'external-links')
231
+ . '</th>' . "\n"
232
+ . '<td>'
233
+ . '<label>'
234
+ . '<input type="checkbox" name="follow_comments"'
235
+ . checked($options['follow_comments'], true, false)
236
+ . ' />'
237
+ . '&nbsp;'
238
+ . __('Override WordPress\' default behavior of adding rel="nofollow" to comment links.', 'external-links')
239
+ . '</label>'
240
+ . '<br />' . "\n"
241
+ . '<i>' . __('Note: You can override this behavior by adding the attribute rel="follow" to individual links.', 'external-links') . '</i>'
242
+ . '</td>' . "\n"
243
+ . '</tr>' . "\n";
244
+
245
  echo '<tr>' . "\n"
246
  . '<th scope="row">'
247
  . __('Open in New Windows', 'external-links')
255
  . __('Open outbound links in new windows.', 'external-links')
256
  . '</label>'
257
  . '<br />' . "\n"
258
+ . '<i>' . __('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') . '</i>'
259
  . '</td>' . "\n"
260
  . '</tr>' . "\n";
261
+
262
  echo '</table>' . "\n";
263
 
264
  echo '<p class="submit">'
272
  } # edit_options()
273
  } # external_links_admin
274
 
275
+ $external_links_admin = external_links_admin::get_instance();
sem-external-links.php CHANGED
@@ -3,7 +3,7 @@
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
@@ -19,13 +19,15 @@ This software is copyright Denis de Bernardy & Mike Koepke, and is distributed u
19
 
20
  **/
21
 
 
 
22
  /**
23
  * external_links
24
  *
25
  * @package External Links
26
  **/
27
 
28
- class external_links {
29
 
30
  protected $opts;
31
 
@@ -107,24 +109,39 @@ class external_links {
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'));
@@ -154,45 +171,335 @@ class external_links {
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
  *
@@ -201,7 +508,9 @@ class external_links {
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;
@@ -211,7 +520,7 @@ class external_links {
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)
@@ -265,27 +574,67 @@ class external_links {
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
  *
@@ -299,9 +648,9 @@ class external_links {
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()
@@ -313,29 +662,70 @@ class external_links {
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
  *
@@ -351,6 +741,8 @@ class external_links {
351
  array('external_links_admin', 'edit_options')
352
  );
353
  } # admin_menu()
 
 
354
  } # external_links
355
 
356
- $external_links = external_links::get_instance();
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: 6.0
7
  Author: Denis de Bernardy & Mike Koepke
8
  Author URI: http://www.getsemiologic.com
9
  Text Domain: external-links
19
 
20
  **/
21
 
22
+ define('sem_external_links_version', '6.0');
23
+
24
  /**
25
  * external_links
26
  *
27
  * @package External Links
28
  **/
29
 
30
+ class sem_external_links {
31
 
32
  protected $opts;
33
 
109
 
110
  function init() {
111
  // more stuff: register actions and filters
112
+ $this->opts = sem_external_links::get_options();
 
 
 
 
 
 
113
 
114
+ if ( !is_admin() ) {
115
  $inc_text_widgets = false;
116
+ if ( isset( $this->opts['text_widgets'] ) && $this->opts['text_widgets'] )
117
  $inc_text_widgets = true;
118
 
119
+ if ( $this->opts['icon'] )
 
 
120
  add_action('wp_enqueue_scripts', array($this, 'styles'), 5);
121
 
122
+ if ( $this->opts['follow_comments'] ) {
123
+ if ( !class_exists('sem_follow_comment') )
124
+ include $this->plugin_path . '/sem-follow_comment.php';
125
+ }
126
+
127
+ if ( $this->opts['autolinks'] ) {
128
+ if ( !class_exists('sem_autolink_uri') )
129
+ include $this->plugin_path . '/sem-autolink-uri.php';
130
+ }
131
+
132
+ if ( $this->opts['global'] ) {
133
+ if ( !class_exists('external_links_anchor_utils') )
134
+ include $this->plugin_path . '/external-links-anchor-utils.php';
135
+
136
+ $this->anchor_utils = new external_links_anchor_utils( $this );
137
+ }
138
+ else {
139
+ add_filter('the_content', array($this, 'process_content'), 1000000);
140
+ add_filter('the_excerpt', array($this, 'process_content'), 1000000);
141
+ add_filter('comment_text', array($this, 'process_content'), 1000000);
142
+ if ( $inc_text_widgets )
143
+ add_filter('widget_text', array($this, 'process_content'), 1000000);
144
+ }
145
  }
146
  else {
147
  add_action('admin_menu', array($this, 'admin_menu'));
171
 
172
 
173
  /**
174
+ * process_content()
175
+ *
176
+ * @param string $text
177
+ * @return string $text
178
+ **/
179
+
180
+ function process_content($text) {
181
+
182
+ // short circuit if there's no anchors at all in the text
183
+ if ( false === stripos($text, '<a ') )
184
+ return($text);
185
+
186
+ global $escape_anchor_filter;
187
+ $escape_anchor_filter = array();
188
+
189
+ $text = $this->escape($text);
190
+
191
+ // find all occurrences of anchors and fill matches with links
192
+ preg_match_all("/
193
+ <\s*a\s+
194
+ ([^<>]+)
195
+ >
196
+ (.*?)
197
+ <\s*\/\s*a\s*>
198
+ /isx", $text, $matches, PREG_SET_ORDER);
199
+
200
+ $raw_links = array();
201
+ $processed_links = array();
202
+
203
+ foreach ($matches as $match)
204
+ {
205
+ $updated_link = $this->process_link($match);
206
+ if ( $updated_link ) {
207
+ $raw_links[] = $match[0];
208
+ $processed_links[] = $updated_link;
209
+ }
210
+ }
211
+
212
+ if ( !empty($raw_links) && !empty($processed_links) )
213
+ $text = str_replace($raw_links, $processed_links, $text);
214
+
215
+ $text = $this->unescape($text);
216
+
217
+ return $text;
218
+ } # process_content()
219
+
220
+
221
+ /**
222
+ * escape()
223
+ *
224
+ * @param string $text
225
+ * @return string $text
226
+ **/
227
+
228
+ function escape($text) {
229
+ global $escape_anchor_filter;
230
+
231
+ if ( !isset($escape_anchor_filter) )
232
+ $escape_anchor_filter = array();
233
+
234
+ foreach ( array(
235
+ 'head' => "/
236
+ .*?
237
+ <\s*\/\s*head\s*>
238
+ /isx",
239
+ 'blocks' => "/
240
+ <\s*(script|style|object|textarea)(?:\s.*?)?>
241
+ .*?
242
+ <\s*\/\s*\\1\s*>
243
+ /isx",
244
+ ) as $regex ) {
245
+ $text = preg_replace_callback($regex, array($this, 'escape_callback'), $text);
246
+ }
247
+
248
+ return $text;
249
+ } # escape()
250
+
251
+
252
+ /**
253
+ * escape_callback()
254
+ *
255
+ * @param array $match
256
+ * @return string $text
257
+ **/
258
+
259
+ function escape_callback($match) {
260
+ global $escape_anchor_filter;
261
+
262
+ $tag_id = "----escape_sem_external_links:" . md5($match[0]) . "----";
263
+ $escape_anchor_filter[$tag_id] = $match[0];
264
+
265
+ return $tag_id;
266
+ } # escape_callback()
267
+
268
+
269
+ /**
270
+ * unescape()
271
+ *
272
+ * @param string $text
273
+ * @return string $text
274
+ **/
275
+
276
+ function unescape($text) {
277
+ global $escape_anchor_filter;
278
+
279
+ if ( !$escape_anchor_filter )
280
+ return $text;
281
+
282
+ $unescape = array_reverse($escape_anchor_filter);
283
+
284
+ return str_replace(array_keys($unescape), array_values($unescape), $text);
285
+ } # unescape()
286
+
287
+
288
+ /**
289
+ * filter_callback()
290
+ *
291
+ * @param array $match
292
+ * @return string $str
293
+ **/
294
+
295
+ function process_link($match) {
296
+ # skip empty anchors
297
+ if ( !trim($match[2]) )
298
+ return $match[0];
299
+
300
+ # parse anchor
301
+ $anchor = $this->parse_anchor($match);
302
+
303
+ if ( !$anchor )
304
+ return $match[0];
305
+
306
+ # filter anchor
307
+ $anchor = $this->filter_anchor( $anchor );
308
+
309
+ if ( $anchor )
310
+ $anchor = $this->build_anchor($match[0], $anchor);
311
+
312
+ return $anchor;
313
+ } # process_link()
314
+
315
+
316
+ /**
317
+ * parse_anchor()
318
+ *
319
+ * @param array $match
320
+ * @return array $anchor
321
+ **/
322
+
323
+ function parse_anchor($match) {
324
+ $anchor = array();
325
+ $anchor['attr'] = $this->parseAttributes( $match[1] );
326
+
327
+ if ( !is_array($anchor['attr']) || empty($anchor['attr']['href']) # parser error or no link
328
+ || trim($anchor['attr']['href']) != esc_url($anchor['attr']['href'], null, 'db') ) # likely a script
329
+ return false;
330
+
331
+ foreach ( array('class', 'rel') as $attr ) {
332
+ if ( !isset($anchor['attr'][$attr]) ) {
333
+ $anchor['attr'][$attr] = array();
334
+ } else {
335
+ $anchor['attr'][$attr] = explode(' ', $anchor['attr'][$attr]);
336
+ $anchor['attr'][$attr] = array_map('trim', $anchor['attr'][$attr]);
337
+ }
338
+ }
339
+
340
+ $anchor['body'] = $match[2];
341
+
342
+ $anchor['attr']['href'] = @html_entity_decode($anchor['attr']['href'], ENT_COMPAT, get_option('blog_charset'));
343
+
344
+ return $anchor;
345
+ } # parse_anchor()
346
+
347
+
348
+ /**
349
+ * build_anchor()
350
+ *
351
+ * @param $link
352
+ * @param array $anchor
353
+ * @return string $anchor
354
+ */
355
+
356
+ function build_anchor($link, $anchor) {
357
+
358
+ $attrs = array( 'class', 'rel', 'target');
359
+
360
+ foreach ( $attrs as $attr ) {
361
+ if ( isset($anchor['attr'][$attr]) ) {
362
+ $new_attr_value = null;
363
+ $values = $anchor['attr'][$attr];
364
+ if ( is_array($values) ) {
365
+ $values = array_unique($values);
366
+ if ( $values )
367
+ $new_attr_value = implode(' ', $values );
368
+ } else {
369
+ $new_attr_value = $values;
370
+ }
371
+
372
+ if ( $new_attr_value )
373
+ $link = $this->update_attribute($link, $attr, $new_attr_value);
374
+ }
375
+ }
376
+
377
+ return $link;
378
+ } # build_anchor()
379
+
380
+ /**
381
+ * Parse an attributes string into an array. If the string starts with a tag,
382
+ * then the attributes on the first tag are parsed. This parses via a manual
383
+ * loop and is designed to be safer than using DOMDocument.
384
+ *
385
+ * @param string|* $attrs
386
+ * @return array
387
+ *
388
+ * @example parse_attrs( 'src="example.jpg" alt="example"' )
389
+ * @example parse_attrs( '<img src="example.jpg" alt="example">' )
390
+ * @example parse_attrs( '<a href="example"></a>' )
391
+ * @example parse_attrs( '<a href="example">' )
392
+ */
393
+ function parseAttributes($text) {
394
+ $attributes = array();
395
+ $pattern = '#(?(DEFINE)
396
+ (?<name>[a-zA-Z][a-zA-Z0-9-:]*)
397
+ (?<value_double>"[^"]+")
398
+ (?<value_single>\'[^\']+\')
399
+ (?<value_none>[^\s>]+)
400
+ (?<value>((?&value_double)|(?&value_single)|(?&value_none)))
401
+ )
402
+ (?<n>(?&name))(=(?<v>(?&value)))?#xs';
403
+
404
+ if (preg_match_all($pattern, $text, $matches, PREG_SET_ORDER)) {
405
+ foreach ($matches as $match) {
406
+ $attributes[$match['n']] = isset($match['v'])
407
+ ? trim($match['v'], '\'"')
408
+ : null;
409
+ }
410
+ }
411
+
412
+ return $attributes;
413
+ }
414
+
415
+ /**
416
+ * Updates attribute of an HTML tag.
417
+ *
418
+ * @param $html
419
+ * @param $attr_name
420
+ * @param $new_attr_value
421
+ * @return string
422
+ */
423
+ function update_attribute($html, $attr_name, $new_attr_value) {
424
+
425
+ $attr_value = false;
426
+ $quote = false; // quotes to wrap attribute values
427
+
428
+ if (preg_match('/\s' . $attr_name . '="([^"]*)"/iu', $html, $matches)
429
+ || preg_match('/\s' . $attr_name . "='([^']*)'/iu", $html, $matches)
430
+ ) {
431
+ // two possible ways to get existing attributes
432
+ $attr_value = $matches[1];
433
+
434
+ $quote = false !== stripos($html, $attr_name . "='") ? "'" : '"';
435
+ }
436
+
437
+ if ($attr_value)
438
+ {
439
+ //replace current attribute
440
+ return str_ireplace("$attr_name=" . $quote . "$attr_value" . $quote,
441
+ $attr_name . '="' . esc_attr($new_attr_value) . '"', $html);
442
+ }
443
+ else {
444
+ // attribute does not currently exist, add it
445
+ return str_ireplace('>', " $attr_name=\"" . esc_attr($new_attr_value) . '">', $html);
446
+ }
447
+ } # update_attribute()
448
+
449
+
450
+ /**
451
+ * filter_anchor()
452
  *
453
  * @param $anchor
454
  * @return string
455
  */
456
 
457
+ function filter_anchor($anchor) {
458
  # disable in feeds
459
  if ( is_feed() )
460
+ return null;
461
 
462
  # ignore local urls
463
+ if ( sem_external_links::is_local_url($anchor['attr']['href']) )
464
+ return null;
465
 
466
  # no icons for images
467
  $is_image = (bool) preg_match("/^\s*<\s*img\s.+?>\s*$/is", $anchor['body']);
468
 
469
+ $updated = false;
470
+ if ( !in_array('external', $anchor['attr']['class']) ) {
 
471
  $anchor['attr']['class'][] = 'external';
472
+ $updated = true;
473
+ }
474
 
475
+ if ( !$is_image && $this->opts['icon'] && !in_array('external_icon', $anchor['attr']['class'])
476
  && !in_array('no_icon', $anchor['attr']['class'])
477
+ && !in_array('noicon', $anchor['attr']['class']) ) {
478
  $anchor['attr']['class'][] = 'external_icon';
479
+ $updated = true;
480
+ }
481
 
482
+ if ( $this->opts['nofollow'] && ( current_filter() == 'comment_text')
483
+ && !function_exists('strip_nofollow')
484
+ && !class_exists('sem_dofollow') && !class_exists('sem_follow_comment')
485
  && !in_array('nofollow', $anchor['attr']['rel'])
486
+ && !in_array('follow', $anchor['attr']['rel']) ) {
487
  $anchor['attr']['rel'][] = 'nofollow';
488
+ $updated = true;
489
+ }
490
 
491
+ if ( $this->opts['target'] && empty($anchor['attr']['target']) ) {
492
  $anchor['attr']['target'] = '_blank';
493
+ $updated = true;
494
+ }
495
+
496
+ if ( $updated )
497
+ return $anchor;
498
+ else
499
+ return null;
500
+ } # filter_anchor()
501
+
502
 
 
 
 
503
  /**
504
  * is_local_url()
505
  *
508
  **/
509
 
510
  function is_local_url($url) {
511
+ if ( in_array(substr($url, 0, 1), array('?', '#')) )
512
+ return true;
513
+ elseif ( (substr($url, 0, 2) != '//') && (strpos($url, 'http://') === false) && (strpos($url, 'https://') === false) )
514
  return true;
515
  elseif ( $url == 'http://' || $url == 'https://' )
516
  return true;
520
  static $site_domain;
521
 
522
  if ( !isset($site_domain) ) {
523
+ $site_domain = home_url();
524
  $site_domain = parse_url($site_domain);
525
  $site_domain = $site_domain['host'];
526
  if ($site_domain == false)
574
  else
575
  return false;
576
  }
577
+
578
  $link_domain = strtolower($link_domain);
579
+ $link_domain = str_replace('www.', '', $link_domain);
580
+ if ( $this->opts['subdomains_local'] ) {
581
+ $subdomains = $this->extract_subdomains($link_domain);
582
+ if ( $subdomains != '')
583
+ $link_domain = str_replace($subdomains . '.', '', $link_domain);
584
+ }
585
 
586
  if ( $site_domain == $link_domain ) {
587
  return true;
588
  } elseif ( function_exists('is_multisite') && is_multisite() ) {
589
  return false;
590
  } else {
591
+ return false;
592
  $site_elts = explode('.', $site_domain);
593
  $link_elts = explode('.', $link_domain);
594
+
595
  while ( ( $site_elt = array_pop($site_elts) ) && ( $link_elt = array_pop($link_elts) ) ) {
596
  if ( $site_elt !== $link_elt )
597
  return false;
598
  }
599
+
600
  return empty($link_elts) || empty($site_elts);
601
+
602
  }
603
  } # is_local_url()
604
 
605
+ /**
606
+ * extract_domain()
607
+ *
608
+ * @param string $domain
609
+ * @return string
610
+ **/
611
+ function extract_domain($domain)
612
+ {
613
+ if(preg_match("/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i", $domain, $matches))
614
+ {
615
+ return $matches['domain'];
616
+ } else {
617
+ return $domain;
618
+ }
619
+ } # extract_domain()
620
+
621
+ /**
622
+ * extract_subdomains()
623
+ *
624
+ * @param string $domain
625
+ * @return string
626
+ **/
627
+ function extract_subdomains($domain)
628
+ {
629
+ $subdomains = $domain;
630
+ $domain = $this->extract_domain($subdomains);
631
+
632
+ $subdomains = rtrim(strstr($subdomains, $domain, true), '.');
633
+
634
+ return $subdomains;
635
+ } # extract_subdomains()
636
+
637
+
638
  /**
639
  * get_options
640
  *
648
  return $o;
649
 
650
  $o = get_option('external_links');
651
+
652
+ if ( $o === false || !isset($o['text_widgets']) || !isset($o['autolinks']) || !isset($o['version']) )
653
+ $o = sem_external_links::init_options();
654
 
655
  return $o;
656
  } # get_options()
662
  * @return array $options
663
  **/
664
 
665
+ static function init_options() {
666
  $o = get_option('external_links');
667
 
668
  $defaults = array(
669
  'global' => false,
670
+ 'icon' => false,
671
  'target' => false,
672
  'nofollow' => true,
673
  'text_widgets' => true,
674
+ 'autolinks' => false,
675
+ 'follow_comments' => false,
676
+ 'subdomains_local' => true,
677
+ 'version' => sem_external_links_version,
678
  );
679
 
680
  if ( !$o )
681
+ $updated_opts = $defaults;
682
  else
683
+ $updated_opts = wp_parse_args($o, $defaults);
684
 
685
+ if ( !isset( $o['version'] )) {
686
+ if ( sem_external_links::replace_plugin('sem-dofollow/sem-dofollow.php') )
687
+ $updated_opts['follow_comments'] = true;
688
 
689
+ if ( sem_external_links::replace_plugin('sem-autolink-uri/sem-autolink-uri.php') )
690
+ $updated_opts['autolinks'] = true;
691
+ }
692
+
693
+ update_option('external_links', $updated_opts);
694
+
695
+ return $updated_opts;
696
  } # init_options()
697
 
698
+ /**
699
+ * replace_plugin()
700
+ *
701
+ * @param $plugin_name
702
+ * @return bool
703
+ */
704
+ static function replace_plugin( $plugin_name ) {
705
+ $active_plugins = get_option('active_plugins');
706
 
707
+ if ( !is_array($active_plugins) )
708
+ {
709
+ $active_plugins = array();
710
+ }
711
+
712
+ $was_active = false;
713
+ foreach ( (array) $active_plugins as $key => $plugin )
714
+ {
715
+ if ( $plugin == $plugin_name )
716
+ {
717
+ $was_active = true;
718
+ unset($active_plugins[$key]);
719
+ break;
720
+ }
721
+ }
722
+
723
+ sort($active_plugins);
724
+
725
+ update_option('active_plugins', $active_plugins);
726
+
727
+ return $was_active;
728
+ }
729
  /**
730
  * admin_menu()
731
  *
741
  array('external_links_admin', 'edit_options')
742
  );
743
  } # admin_menu()
744
+
745
+
746
  } # external_links
747
 
748
+ $sem_external_links = sem_external_links::get_instance();
sem-external-links.pot CHANGED
@@ -1,102 +1,149 @@
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 ""
1
+ # Copyright (C) 2014 External Links
 
2
  # This file is distributed under the same license as the External Links package.
 
 
 
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: External Links 6.0 dev\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/sem-external-links\n"
7
+ "POT-Creation-Date: 2014-11-01 18:01:56+00:00\n"
 
 
 
8
  "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2014-MO-DA HO:MI+ZONE\n"
12
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
+ "Language-Team: LANGUAGE <LL@li.org>\n"
14
 
15
+ #: sem-external-links-admin.php:93
16
  msgid "Settings saved."
17
  msgstr ""
18
 
19
+ #: sem-external-links-admin.php:117
20
+ msgid "Note: Your rel=nofollow preferences is being ignored because the dofollow plugin is enabled on your site."
 
 
21
  msgstr ""
22
 
23
+ #: sem-external-links-admin.php:122
24
  msgid "External Links Settings"
25
  msgstr ""
26
 
27
+ #: sem-external-links-admin.php:128
28
  msgid "Apply Globally"
29
  msgstr ""
30
 
31
+ #: sem-external-links-admin.php:136
32
+ msgid "Apply these settings to all outbound links on the site except those in scripts, styles and the html head section."
33
+ msgstr ""
34
+
35
+ #: sem-external-links-admin.php:143
36
+ msgid "Apply to Text Widgets"
37
+ msgstr ""
38
+
39
+ #: sem-external-links-admin.php:151
40
+ msgid "Apply these settings to any text widgets in addition to post, page and comments content."
41
+ msgstr ""
42
+
43
+ #: sem-external-links-admin.php:158
44
+ msgid "Treat Subdomains as Local"
45
+ msgstr ""
46
+
47
+ #: sem-external-links-admin.php:166
48
+ msgid "Treat any subdomains for this site as a local link."
49
+ msgstr ""
50
+
51
+ #: sem-external-links-admin.php:169
52
+ msgid "Example: If your site is at domain.com and you also have store.domain.com, any link to store.domain.com will be treated as local."
53
+ msgstr ""
54
+
55
+ #: sem-external-links-admin.php:175
56
+ msgid "Auto Convert Text Urls"
57
+ msgstr ""
58
+
59
+ #: sem-external-links-admin.php:183
60
+ msgid "Automatically converts text urls into clickable urls."
61
+ msgstr ""
62
+
63
+ #: sem-external-links-admin.php:186
64
+ msgid "Note: If this option is enabled then if www.example.com is found in your text, it will be converted to an html &lt;a&gt; link.\""
65
  msgstr ""
66
 
67
+ #: sem-external-links-admin.php:188
68
+ msgid "This conversion will occur first so external link treatment for nofollow, icon and target will be applied to this auto links."
69
+ msgstr ""
70
+
71
+ #: sem-external-links-admin.php:194
72
  msgid "Add Icons"
73
  msgstr ""
74
 
75
+ #: sem-external-links-admin.php:202
76
  msgid "Mark outbound links with an icon."
77
  msgstr ""
78
 
79
+ #: sem-external-links-admin.php:205
80
+ msgid "Note: You can override this behavior by adding a class=\"no_icon\" to individual links."
 
 
81
  msgstr ""
82
 
83
+ #: sem-external-links-admin.php:211
84
  msgid "Add No Follow"
85
  msgstr ""
86
 
87
+ #: sem-external-links-admin.php:219
88
+ msgid "Add a rel=\"nofollow\" attribute to outbound links."
89
  msgstr ""
90
 
91
+ #: sem-external-links-admin.php:222 sem-external-links-admin.php:241
92
+ msgid "Note: You can override this behavior by adding the attribute rel=\"follow\" to individual links."
93
+ msgstr ""
94
+
95
+ #: sem-external-links-admin.php:224
96
+ msgid "Your rel=\"nofollow\" preferences will be ignored for comments if the \"Do Follow Comment Links\" setting below is enabled or if the standalone Dofollow plugin is enabled on your site."
97
  msgstr ""
98
 
99
+ #: sem-external-links-admin.php:230
100
+ msgid "Do Follow Comment Links"
101
+ msgstr ""
102
+
103
+ #: sem-external-links-admin.php:238
104
+ msgid "Override WordPress' default behavior of adding rel=\"nofollow\" to comment links."
105
+ msgstr ""
106
+
107
+ #: sem-external-links-admin.php:247
108
  msgid "Open in New Windows"
109
  msgstr ""
110
 
111
+ #: sem-external-links-admin.php:255
112
  msgid "Open outbound links in new windows."
113
  msgstr ""
114
 
115
+ #: sem-external-links-admin.php:258
116
+ msgid "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."
 
 
 
 
 
117
  msgstr ""
118
 
119
+ #: sem-external-links-admin.php:266
120
  msgid "Save Changes"
121
  msgstr ""
122
 
123
+ #: sem-external-links-info.php:2 sem-external-links.php:732
124
+ #: sem-external-links.php:733
125
  msgid "External Links"
126
  msgstr ""
127
 
128
  #: sem-external-links-info.php:3
129
+ msgid "Marks outbound links as such, with various effects that are configurable under <a href=\"options-general.php?page=external-links\">Settings / External Links</a>."
130
+ msgstr ""
131
+ #. Plugin Name of the plugin/theme
132
+ msgid "External Links"
133
+ msgstr ""
134
+
135
+ #. Plugin URI of the plugin/theme
136
+ msgid "http://www.semiologic.com/software/external-links/"
137
+ msgstr ""
138
+
139
+ #. Description of the plugin/theme
140
+ msgid "Marks outbound links as such, with various effects that are configurable under <a href=\"options-general.php?page=external-links\">Settings / External Links</a>."
141
+ msgstr ""
142
+
143
+ #. Author of the plugin/theme
144
+ msgid "Denis de Bernardy & Mike Koepke"
145
+ msgstr ""
146
+
147
+ #. Author URI of the plugin/theme
148
+ msgid "http://www.getsemiologic.com"
149
  msgstr ""
sem-follow_comment.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Module Name: Sem Do Follow
4
+ Description: Removes the <a href="http://www.semiologic.com/2005/02/05/prepare-for-more-comment-spam-not-less/">evil nofollow attribute</a> that WordPress adds in comments.
5
+ Version: 4.2.1
6
+ Author: Denis de Bernardy, Mike Koepke
7
+ Author URI: https://getsemiologic.com
8
+ License: Dual licensed under the MIT and GPLv2 licenses
9
+ */
10
+
11
+ /*
12
+ Terms of use
13
+ ------------
14
+
15
+ This software is copyright Denis de Bernardy & Mike Koepke, and is distributed under the terms of the MIT and GPLv2 licenses.
16
+
17
+
18
+ Hat tips
19
+ --------
20
+
21
+ * Sebastian Herp <http://sebbi.de>
22
+ * Thomas Parisot <http://oncle-tom.net>
23
+ **/
24
+
25
+
26
+ class sem_follow_comment {
27
+ /**
28
+ * Plugin instance.
29
+ *
30
+ * @see get_instance()
31
+ * @type object
32
+ */
33
+ protected static $instance = NULL;
34
+
35
+ /**
36
+ * URL to this plugin's directory.
37
+ *
38
+ * @type string
39
+ */
40
+ public $plugin_url = '';
41
+
42
+ /**
43
+ * Path to this plugin's directory.
44
+ *
45
+ * @type string
46
+ */
47
+ public $plugin_path = '';
48
+
49
+ /**
50
+ * Access this plugin’s working instance
51
+ *
52
+ * @wp-hook plugins_loaded
53
+ * @return object of this class
54
+ */
55
+ public static function get_instance()
56
+ {
57
+ NULL === self::$instance and self::$instance = new self;
58
+
59
+ return self::$instance;
60
+ }
61
+
62
+
63
+ /**
64
+ * Constructor.
65
+ *
66
+ *
67
+ */
68
+
69
+ public function __construct() {
70
+ $this->plugin_url = plugins_url( '/', __FILE__ );
71
+ $this->plugin_path = plugin_dir_path( __FILE__ );
72
+
73
+ $this->init();
74
+ }
75
+
76
+
77
+ /**
78
+ * init()
79
+ *
80
+ * @return void
81
+ **/
82
+
83
+ function init() {
84
+ // more stuff: register actions and filters
85
+ add_filter('get_comment_author_link', array($this, 'strip_nofollow'), 15);
86
+ add_filter('comment_text', array($this, 'strip_nofollow'), 15);
87
+ remove_filter('pre_comment_content', 'wp_rel_nofollow', 15);
88
+ }
89
+
90
+ /**
91
+ * strip_nofollow()
92
+ *
93
+ * @param string $text
94
+ * @return string $text
95
+ **/
96
+
97
+ function strip_nofollow($text = '') {
98
+ return preg_replace_callback("/<\s*a\s+(.+?)>/is", array($this, 'strip_nofollow_callback'), $text);
99
+ } # strip_nofollow()
100
+
101
+
102
+ /**
103
+ * strip_nofollow_callback()
104
+ *
105
+ * @param array $match
106
+ * @return string $text
107
+ **/
108
+
109
+ function strip_nofollow_callback($match) {
110
+ $attr = $match[1];
111
+ $attr = " $attr ";
112
+ $attr = preg_replace("/
113
+ \s
114
+ rel\s*=\s*(['\"])
115
+ ([^\\1]*?\s+)?
116
+ nofollow
117
+ (\s+[^\\1]*?)?
118
+ \\1
119
+ /ix", " rel=$1$2$3$1", $attr);
120
+ $attr = preg_replace("/
121
+ \s
122
+ rel\s*=\s*(['\"])\s*\\1
123
+ /ix", '', $attr);
124
+ $attr = trim($attr);
125
+ return '<a ' . $attr . '>';
126
+ } # strip_nofollow_callback()
127
+ } // sem_follow_comment
128
+
129
+ $sem_follow_comment = sem_follow_comment::get_instance();