PluginProbe ʕ •ᴥ•ʔ
External Links – nofollow, noopener & new window / 2.66
External Links – nofollow, noopener & new window v2.66
2.66 0.31 0.32 0.33 0.34 0.35 1.01 1.02 1.03 1.10 1.20 1.21 1.30 1.31 1.40 1.41 1.50 1.51 1.52 1.53 1.54 1.55 1.56 1.60 1.61 1.62 1.70 1.80 1.81 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.1.0 2.1.1 2.1.2 2.1.3 2.2.0 2.3 2.32 2.35 2.40 2.42 2.43 2.45 2.46 2.47 2.48 2.50 2.51 2.55 2.56 2.57 2.58 2.59 2.60 2.61 2.62 2.63 2.64 2.65 trunk 0.10 0.11 0.12 0.20 0.21 0.30
wp-external-links / includes / class-wpel-front.php
wp-external-links / includes Last commit date
admin 2 months ago register-hooks 3 years ago class-wpel-front-ignore.php 3 years ago class-wpel-front.php 4 months ago class-wpel-link.php 3 years ago class-wpel-plugin.php 1 year ago class-wpel-register-scripts.php 2 months ago class-wpel-template-tags.php 3 years ago class-wpel-update.php 3 years ago index.php 6 years ago
class-wpel-front.php
469 lines
1 <?php
2 /**
3 * Class WPEL_Front
4 *
5 * @package WPEL
6 * @category WordPress Plugin
7 * @version 2.3
8 * @link https://www.webfactoryltd.com/
9 * @license Dual licensed under the MIT and GPLv2+ licenses
10 */
11 final class WPEL_Front extends WPRun_Base_1x0x0
12 {
13
14 /**
15 * @var WPEL_Settings_Page
16 */
17 private $settings_page = null;
18
19 /**
20 * Initialize
21 * @param WPEL_Settings_Page $settings_page
22 */
23 protected function init( WPEL_Settings_Page $settings_page )
24 {
25 $this->settings_page = $settings_page;
26
27 // load front ignore
28 WPEL_Front_Ignore::create( $settings_page );
29
30 // load template tags
31 WPEL_Template_Tags::create( $this );
32
33 // apply page sections
34 if ( $this->opt( 'apply_all' ) ) {
35 // create final_output filterhook
36 FWP_Final_Output_1x0x0::create();
37
38 add_action( 'final_output', $this->get_callback( 'scan' ), 10000000000 );
39 } else {
40 $filter_hooks = array();
41
42 if ( $this->opt( 'apply_post_content' ) ) {
43 array_push( $filter_hooks, 'the_title', 'the_content', 'the_excerpt', 'get_the_excerpt' );
44 }
45
46 if ( $this->opt( 'apply_comments' ) ) {
47 array_push( $filter_hooks, 'comment_text', 'comment_excerpt' );
48 }
49
50 if ( $this->opt( 'apply_widgets' ) ) {
51 // create widget_output filterhook
52 FWP_Widget_Output_1x0x0::create();
53
54 array_push( $filter_hooks, 'widget_output' );
55 }
56
57 foreach ( $filter_hooks as $hook ) {
58 add_filter( $hook, $this->get_callback( 'scan' ), 10000000000 );
59 }
60 }
61
62
63 }
64
65
66 /**
67 * Turn off output buffer for REST API calls
68 * @param type $wp_rest_server
69 */
70 protected function action_rest_api_init()
71 {
72 ob_end_flush();
73 }
74
75
76 /**
77 * Get option value
78 * @param string $key
79 * @param string|null $type
80 * @return string
81 * @triggers E_USER_NOTICE Option value cannot be found
82 */
83 protected function opt( $key, $type = null )
84 {
85 return $this->settings_page->get_option_value( $key, $type );
86 }
87
88 /**
89 * Action for "wp_enqueue_scripts"
90 */
91 protected function action_wp_enqueue_scripts()
92 {
93 $icon_type_int = $this->opt( 'icon_type', 'internal-links' );
94 $icon_type_ext = $this->opt( 'icon_type', 'external-links' );
95 $icon_type_excl = $this->opt( 'icon_type', 'excluded-links' );
96
97 if ( 'dashicon' === $icon_type_int || 'dashicon' === $icon_type_ext || 'dashicon' === $icon_type_excl ) {
98 wp_enqueue_style( 'dashicons' );
99 }
100
101 if ( 'fontawesome' === $icon_type_int || 'fontawesome' === $icon_type_ext || 'fontawesome' === $icon_type_excl) {
102 wp_enqueue_style( 'wpel-font-awesome' );
103 }
104
105 if ( $this->opt( 'icon_type', 'excluded-links' ) || $this->opt( 'icon_type', 'external-links' ) || $this->opt( 'icon_type', 'internal-links' ) ) {
106 wp_enqueue_style( 'wpel-style' );
107 }
108 }
109
110 /**
111 * Scan content for links
112 * @param string $content
113 * @return string
114 */
115 public function scan( $content )
116 {
117 /**
118 * Filter whether the plugin settings will be applied on links
119 * @param boolean $apply_settings
120 */
121 $apply_settings = apply_filters( 'wpel_apply_settings', true );
122
123 if ( false === $apply_settings ) {
124 return $content;
125 }
126
127 /**
128 * Filters before scanning content (for internal use)
129 * @param string $content
130 */
131 $content = apply_filters( '_wpel_before_filter', $content );
132
133 $regexp_link = '/<a[^A-Za-z>](.*?)>(.*?)<\/a[\s+]*>/is';
134
135 $content = preg_replace_callback( $regexp_link, $this->get_callback( 'match_link' ), $content );
136
137 /**
138 * Filters after scanning content (for internal use)
139 * @param string $content
140 */
141 $content = apply_filters( '_wpel_after_filter', $content );
142
143 return $content;
144 }
145
146 /**
147 * Pregmatch callback for handling link
148 * @param array $matches [ 0 ] => link, [ 1 ] => atts_string, [ 2 ] => label
149 * @return string
150 */
151 protected function match_link( $matches )
152 {
153 $original_link = $matches[ 0 ];
154 $atts = $matches[ 1 ];
155 $label = $matches[ 2 ];
156
157 if(strpos($atts,'href') === false){
158 return $original_link;
159 }
160
161 $created_link = $this->get_created_link( $label, $atts );
162
163 if ( false === $created_link ) {
164 return $original_link;
165 }
166
167 return $created_link;
168 }
169
170 /**
171 * Create html link
172 * @param string $label
173 * @param string $atts
174 * @return string
175 */
176 protected function get_created_link( $label, $atts )
177 {
178 $link = new WPEL_Link( 'a', $label );
179 $link->set_atts( $atts );
180
181 /**
182 * Action triggered before link settings will be applied
183 * @param WPEL_Link $link
184 * @return void
185 */
186 do_action( 'wpel_before_apply_link', $link );
187
188 // has ignore flag
189 if ( $link->is_ignore() ) {
190 return false;
191 }
192
193 $this->set_link( $link );
194
195 return $link->get_html( false );
196 }
197
198 /**
199 * Set link
200 * @param WPEL_Link $link
201 */
202 protected function set_link( WPEL_Link $link )
203 {
204 $url = $link->get_attr( 'href' );
205
206 $excludes_as_internal_links = $this->opt( 'excludes_as_internal_links' );
207
208 // internal, external or excluded
209 $is_excluded = $link->is_exclude() || $this->is_excluded_url( $url );
210 $is_internal = $link->is_internal() || ( $this->is_internal_url( $url ) && ! $this->is_included_url( $url ) ) || ( $is_excluded && $excludes_as_internal_links );
211 $is_external = $link->is_external() || ( ! $is_internal && ! $is_excluded );
212
213 if (strpos($url,'#') === 0) {
214 // skip anchors
215 } else if ( $is_external ) {
216 $link->set_external();
217 $this->apply_link_settings( $link, 'external-links' );
218 } else if ( $is_internal ) {
219 $link->set_internal();
220 $this->apply_link_settings( $link, 'internal-links' );
221 } else if ( $is_excluded ) {
222 $link->set_exclude();
223 $this->apply_link_settings( $link, 'excluded-links' );
224 }
225
226 /**
227 * Action for changing link object
228 * @param WPEL_Link $link
229 * @return void
230 */
231 do_action( 'wpel_link', $link );
232 }
233
234 /**
235 * @param WPEL_Link $link
236 * @param string $type
237 */
238 protected function apply_link_settings( WPEL_Link $link, $type )
239 {
240 if ( ! $this->opt( 'apply_settings', $type ) ) {
241 return;
242 }
243
244 // set target
245 $target = $this->opt( 'target', $type );
246 $target_overwrite = $this->opt( 'target_overwrite', $type );
247 $has_target = $link->has_attr( 'target' );
248
249 if ( $target && ( ! $has_target || $target_overwrite ) ) {
250 $link->set_attr( 'target', $target );
251 }
252
253 // add "follow" / "nofollow"
254 $follow = $this->opt( 'rel_follow', $type );
255 $follow_overwrite = $this->opt( 'rel_follow_overwrite', $type );
256 $has_follow = $link->has_attr_value( 'rel', 'follow' ) || $link->has_attr_value( 'rel', 'nofollow' );
257
258 if ( $follow && ( ! $has_follow || $follow_overwrite ) ) {
259 if ( $has_follow ) {
260 $link->remove_from_attr( 'rel', 'follow' );
261 $link->remove_from_attr( 'rel', 'nofollow' );
262 }
263
264 $link->add_to_attr( 'rel', $follow );
265 }
266
267 // add "external"
268 if ( 'external-links' === $type && $this->opt( 'rel_external', $type ) ) {
269 $link->add_to_attr( 'rel', 'external' );
270 }
271
272 // add "noopener"
273 if ( $this->opt( 'rel_noopener', $type ) ) {
274 $link->add_to_attr( 'rel', 'noopener' );
275 }
276
277 // add "noreferrer"
278 if ( $this->opt( 'rel_noreferrer', $type ) ) {
279 $link->add_to_attr( 'rel', 'noreferrer' );
280 }
281
282 // add "sponsored"
283 if ( 'external-links' === $type && $this->opt( 'rel_sponsored', $type ) ) {
284 $link->add_to_attr( 'rel', 'sponsored' );
285 }
286
287 // add "ugc"
288 if ( 'external-links' === $type && $this->opt( 'rel_ugc', $type ) ) {
289 $link->add_to_attr( 'rel', 'ugc' );
290 }
291
292 // set title
293 $title_format = $this->opt( 'title', $type );
294
295 if ( $title_format ) {
296 $title = $link->get_attr( 'title' );
297 $text = $link->get_content();
298 $new_title = str_replace( array( '{title}', '{text}', '{text_clean}' ), array( wp_strip_all_tags( $title ), wp_strip_all_tags( $text ), wp_strip_all_tags( $text ) ), $title_format );
299 if ( $new_title ) {
300 $link->set_attr( 'title', $new_title );
301 }
302 }
303
304 // add classes
305 $class = $this->opt( 'class', $type );
306
307 if ( $class ) {
308 $link->add_to_attr( 'class', $class );
309 }
310
311 // add icon
312 $icon_type = $this->opt( 'icon_type', $type );
313 $no_icon_for_img = $this->opt( 'no_icon_for_img', $type );
314 $has_img = preg_match( '/<img([^>]*)>/is', $link->get_content() );
315
316 if ( $icon_type && ! ( $has_img && $no_icon_for_img ) && ! $link->has_attr_value( 'class', 'wpel-no-icon' ) ) {
317 if ( 'dashicon' === $icon_type ) {
318 $dashicon = $this->opt( 'icon_dashicon', $type );
319 $icon = '<i class="wpel-icon dashicons-before '. $dashicon .'" aria-hidden="true"></i>';
320 } else if ( 'fontawesome' === $icon_type ) {
321 $fa = $this->opt( 'icon_fontawesome', $type );
322 $icon = '<i class="wpel-icon fa '. $fa .'" aria-hidden="true"></i>';
323 } else if ( 'image' === $icon_type ) {
324 $image = $this->opt( 'icon_image', $type );
325 $icon = '<span class="wpel-icon wpel-image wpel-icon-'. $image .'"></span>';
326 }
327
328 if ( 'left' === $this->opt( 'icon_position', $type ) ) {
329 $link->add_to_attr( 'class', 'wpel-icon-left' );
330 $link->set_content( $icon . $link->get_content() );
331 } else if ( 'right' === $this->opt( 'icon_position', $type ) ) {
332 $link->add_to_attr( 'class', 'wpel-icon-right' );
333 $link->set_content( $link->get_content() . $icon );
334 }
335 }
336 }
337
338 /**
339 * Check if url is included as external link
340 * @param string $url
341 * @return boolean
342 */
343 protected function is_included_url( $url )
344 {
345 // should be using private property, but static is more practical
346 static $include_urls_arr = null;
347
348 if ( null === $include_urls_arr ) {
349 $include_urls = $this->opt( 'include_urls' );
350 $include_urls = str_replace( "\n", ',', $include_urls );
351
352 if ( '' === trim( $include_urls ) ) {
353 $include_urls_arr = array();
354 } else {
355 $include_urls_arr = explode( ',', $include_urls );
356 }
357
358 $include_urls_arr = array_filter( $include_urls_arr, function ( $url ) {
359 return '' !== trim( $url );
360 } );
361 }
362
363 foreach ( $include_urls_arr as $include_url ) {
364 if ( false !== strpos( $url, $include_url ) ) {
365 return true;
366 }
367 }
368
369 return false;
370 }
371
372 /**
373 * Check if url is excluded as external link
374 * @param string $url
375 * @return boolean
376 */
377 protected function is_excluded_url( $url )
378 {
379 // should be using private property, but static is more practical
380 static $exclude_urls_arr = null;
381
382 if ( null === $exclude_urls_arr ) {
383 $exclude_urls = $this->opt( 'exclude_urls' );
384 $exclude_urls = str_replace( "\n", ',', $exclude_urls );
385
386 if ( '' === trim( $exclude_urls ) ) {
387 $exclude_urls_arr = array();
388 } else {
389 $exclude_urls_arr = explode( ',', $exclude_urls );
390 }
391
392 $exclude_urls_arr = array_filter( $exclude_urls_arr, function ( $url ) {
393 return '' !== trim( $url );
394 } );
395 }
396
397 foreach ( $exclude_urls_arr as $exclude_url ) {
398 if ( false !== strpos( $url, $exclude_url ) ) {
399 return true;
400 }
401 }
402
403 return false;
404 }
405
406 /**
407 * Check url is internal
408 * @param string $url
409 * @return boolean
410 */
411 protected function is_internal_url( $url )
412 {
413 // all relative url's are internal
414 if ( substr( $url, 0, 7 ) !== 'http://'
415 && substr( $url, 0, 8 ) !== 'https://'
416 && substr( $url, 0, 6 ) !== 'ftp://'
417 && substr( $url, 0, 2 ) !== '//' ) {
418 return true;
419 }
420
421 // is internal
422 $url_without_protocol = preg_replace('#^http(s)?://#', '', home_url( '' ));
423 $clean_home_url = preg_replace('/^www\./', '', $url_without_protocol);
424
425 if ( 0 === strpos( $url, 'http://'.$clean_home_url )
426 || 0 === strpos( $url, 'https://'.$clean_home_url )
427 || 0 === strpos( $url, 'http://www.'.$clean_home_url )
428 || 0 === strpos( $url, 'https://www.'.$clean_home_url )
429 ) {
430 return true;
431 }
432
433 // check subdomains
434 if ( $this->opt( 'subdomains_as_internal_links' ) && false !== strpos( $url, $this->get_domain() ) ) {
435 return true;
436 }
437
438 return false;
439 }
440
441 /**
442 * Get domain name
443 * @return string
444 */
445 protected function get_domain() {
446 // should be using private property, but static is more practical
447 static $domain_name = null;
448
449 if ( null === $domain_name ) {
450 preg_match(
451 '/[a-z0-9\-]{1,63}\.[a-z\.]{2,6}$/'
452 , parse_url( home_url(), PHP_URL_HOST )
453 , $domain_tld
454 );
455
456 if ( count( $domain_tld ) > 0 ) {
457 $domain_name = $domain_tld[ 0 ];
458 } else if(isset($_SERVER[ 'SERVER_NAME' ])){
459 $domain_name = sanitize_text_field(wp_unslash($_SERVER[ 'SERVER_NAME' ]));
460 } else {
461 $domain_name = '';
462 }
463 }
464
465 return $domain_name;
466 }
467
468 }
469