PluginProbe
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms / 3.4.0
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms v3.4.0
3.53.0 3.52.0 3.51.0 3.50.0 3.45.0 3.38.0 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.40.0 3.40.1 3.41.0 3.42.0 3.43.0 3.44.0 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 All 177 releases
simple-tags / inc / class.client.autolinks.php

class.client.autolinks.php in Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms 3.4.0, at inc/class.client.autolinks.php

904 lines 30.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class SimpleTags_Client_Autolinks {
4
5 public static $posts = array();
6 public static $link_tags = array();
7 public static $tagged_link_count = 0;
8
9 /**
10 * Constructor
11 *
12 * @return void
13 * @author WebFactory Ltd
14 */
15 public function __construct() {
16
17 if ( 1 === (int) SimpleTags_Plugin::get_option_value( 'active_auto_links' ) ) {
18
19 $auto_link_priority = SimpleTags_Plugin::get_option_value( 'auto_link_priority' );
20 if ( 0 === (int) $auto_link_priority ) {
21 $auto_link_priority = 12;
22 }
23
24 // Auto link tags
25 add_filter( 'the_posts', array( __CLASS__, 'the_posts' ), 10 );
26
27 //legacy
28 if ( 'no' !== SimpleTags_Plugin::get_option_value( 'auto_link_views' ) && (int)SimpleTags_Plugin::get_option_value( 'auto_link_tags' ) > 0 ) {
29 add_filter( 'the_content', array( __CLASS__, 'the_content' ), $auto_link_priority );
30 add_filter( 'the_title', array( __CLASS__, 'the_title' ) );
31 }
32
33 //new UI
34 add_filter('the_content', array( __CLASS__, 'taxopress_autolinks_the_content'), 12);
35 add_filter('the_title', array( __CLASS__, 'taxopress_autolinks_the_title'), 12);
36 }
37
38 }
39
40 /**
41 * Stock posts ID as soon as possible
42 * TODO: test if post_type allow post_tag before keep post ID
43 *
44 * @param array $posts
45 *
46 * @return array
47 */
48 public static function the_posts( $posts ) {
49 if ( ! empty( $posts ) && is_array( $posts ) ) {
50 foreach ( (array) $posts as $post ) {
51 self::$posts[] = (int) $post->ID;
52 }
53
54 self::$posts = array_unique( self::$posts );
55 }
56
57 return $posts;
58 }
59
60 /**
61 * Get tags from current post views
62 *
63 * @return array
64 */
65 public static function get_tags_from_current_posts($options = false) {
66
67 if ( is_array( self::$posts ) && count( self::$posts ) > 0 ) {
68 // Generate SQL from post id
69 $postlist = implode( "', '", self::$posts );
70
71 // Generate key cache
72 $key = md5( maybe_serialize( $postlist ) );
73
74 $results = array();
75
76 if($options){
77 $term_taxonomy = $options['taxonomy'];
78 }else{
79 $term_taxonomy = 'post_tag';
80 }
81
82 // Get cache if exist
83 $cache = wp_cache_get( 'generate_keywords', 'simple-tags' );
84 if ( $options || false === $cache )
85 {
86 foreach ( self::$posts as $object_id ) {
87 // Get terms
88 $terms = get_object_term_cache( $object_id, $term_taxonomy );
89 if ( false === $terms || is_wp_error( $terms ) ) {
90 $terms = wp_get_object_terms( $object_id, $term_taxonomy );
91 }
92
93 if ( false !== $terms && ! is_wp_error( $terms ) ) {
94 $results = array_merge( $results, $terms );
95 }
96 }
97
98 $cache[ $key ] = $results;
99 wp_cache_set( 'generate_keywords', $cache, 'simple-tags' );
100 } else {
101 if ( isset( $cache[ $key ] ) ) {
102 return $cache[ $key ];
103 }
104 }
105
106 return $results;
107 }
108
109 return array();
110 }
111
112 /**
113 * Get all available local tags
114 *
115 * @return array
116 */
117 public static function get_all_post_tags($options = false) {
118 if ( is_array( self::$posts ) && count( self::$posts ) > 0 ) {
119 // Generate SQL from post id
120 $postlist = implode( "', '", self::$posts );
121
122 // Generate key cache
123 $key = md5( maybe_serialize( $postlist ) );
124
125 if($options){
126 $term_taxonomy = $options['taxonomy'];
127 }else{
128 $term_taxonomy = 'post_tag';
129 }
130 $results = get_tags(['taxonomy' => $term_taxonomy]);
131 // Get cache if exist
132 $cache = wp_cache_get( 'generate_keywords', 'simple-tags' );
133 if ( $options || false === $cache ) {
134 foreach ( self::$posts as $object_id ) {
135 // Get terms
136 $terms = get_object_term_cache( $object_id, $term_taxonomy );
137 if ( false === $terms || is_wp_error( $terms ) ) {
138 $terms = wp_get_object_terms( $object_id, $term_taxonomy );
139 }
140
141 if ( false !== $terms && ! is_wp_error( $terms ) ) {
142 $results = array_merge( $results, $terms );
143 }
144 }
145
146 $cache[ $key ] = $results;
147 wp_cache_set( 'generate_keywords', $cache, 'simple-tags' );
148 } else {
149 if ( isset( $cache[ $key ] ) ) {
150 return $cache[ $key ];
151 }
152 }
153
154 return $results;
155 }
156
157 return array();
158 }
159
160 /**
161 * Get links for each tag for auto link feature
162 *
163 */
164 public static function prepare_auto_link_tags($options = false) {
165 global $post;
166 if($options){
167 $auto_link_min = (int) $options['autolink_usage_min'];
168 $unattached_terms = (int) $options['unattached_terms'];
169 $autolink_min_char = (int) $options['autolink_min_char'];
170 $autolink_max_char = (int) $options['autolink_max_char'];
171 $ignore_attached = (int) $options['ignore_attached'];
172 $term_taxonomy = $options['taxonomy'];
173 }else{
174 $auto_link_min = (int) SimpleTags_Plugin::get_option_value( 'auto_link_min' );
175 $unattached_terms = (int) SimpleTags_Plugin::get_option_value( 'auto_link_all' );
176 $autolink_min_char = 0;
177 $autolink_max_char = 0;
178 $ignore_attached = 0;
179 $term_taxonomy = 'post_tag';
180 }
181
182 if ( 0 === $auto_link_min ) {
183 $auto_link_min = 1;
184 }
185 if( 1 === $unattached_terms ){
186 $terms = self::get_all_post_tags($options);
187 }else{
188 $terms = self::get_tags_from_current_posts($options);
189 }
190
191 foreach ( (array) $terms as $term ) {
192 if($ignore_attached > 0){
193 if(has_term( $term->term_id, $term_taxonomy, $post )){
194 continue;
195 }
196 }
197
198 //min character check
199 $min_char_pass = true;
200 if($autolink_min_char > 0){
201 $min_char_pass = strlen($term->name) >= $autolink_min_char ? true : false;
202 }
203 //max character check
204 $max_char_pass = true;
205 if($autolink_max_char > 0){
206 $max_char_pass = strlen($term->name) <= $autolink_max_char ? true : false;
207 }
208
209 if ( $term->count >= $auto_link_min && $min_char_pass && $max_char_pass ) {
210 self::$link_tags[ $term->name ] = esc_url( get_term_link( $term, $term->taxonomy ) );
211 }
212 }
213
214 return true;
215 }
216
217 /**
218 * Replace text by link to tag
219 *
220 * @param string $content
221 *
222 * @return string
223 */
224 public static function the_content( $content = '' ) {
225 global $post;
226
227 // Show only on singular view ? Check context
228 if ( 'singular' === SimpleTags_Plugin::get_option_value( 'auto_link_views' ) && ! is_singular() ) {
229 return $content;
230 }
231
232 // Show only on single view ? Check context
233 if ( 'single' === SimpleTags_Plugin::get_option_value( 'auto_link_views' ) && ! is_single() ) {
234 return $content;
235 }
236
237 // user preference for this post ?
238 $meta_value = get_post_meta( $post->ID, '_exclude_autolinks', true );
239 if ( ! empty( $meta_value ) || is_admin() ) {
240 return $content;
241 }
242
243 // Get currents tags if no exists
244 self::prepare_auto_link_tags();
245
246 // Shuffle array
247 SimpleTags_Client::random_array( self::$link_tags );
248
249 // HTML Rel (tag/no-follow)
250 $rel = SimpleTags_Client::get_rel_attribut();
251
252 // only continue if the database actually returned any links
253 if ( ! isset( self::$link_tags ) || ! is_array( self::$link_tags ) || empty( self::$link_tags ) ) {
254 return $content;
255 }
256
257 // Case option ?
258 $case = ( 1 === (int) SimpleTags_Plugin::get_option_value( 'auto_link_case' ) ) ? 'i' : '';
259 $strpos_fnc = ( 'i' === $case ) ? 'stripos' : 'strpos';
260
261 // Prepare exclude terms array
262 $excludes_terms = explode( ',', SimpleTags_Plugin::get_option_value( 'auto_link_exclude' ) );
263 if ( empty( $excludes_terms ) ) {
264 $excludes_terms = array();
265 } else {
266 $excludes_terms = array_filter( $excludes_terms, '_delete_empty_element' );
267 $excludes_terms = array_unique( $excludes_terms );
268 }
269
270 $z = 0;
271 foreach ( (array) self::$link_tags as $term_name => $term_link ) {
272 // Force string for tags "number"
273 $term_name = (string) $term_name;
274
275 // Exclude terms ? next...
276 if ( in_array( $term_name, (array) $excludes_terms, true ) ) {
277 continue;
278 }
279
280 // Make a first test with PHP function, economize CPU with regexp
281 if ( false === $strpos_fnc( $content, $term_name ) ) {
282 continue;
283 }
284
285 if ( 1 === (int) SimpleTags_Plugin::get_option_value( 'auto_link_dom' ) && class_exists( 'DOMDocument' ) && class_exists( 'DOMXPath' ) ) {
286 self::replace_by_links_dom( $content, $term_name, $term_link, $case, $rel );
287 } else {
288 self::replace_by_links_regexp( $content, $term_name, $term_link, $case, $rel );
289
290
291 }
292
293 $z ++;
294
295 if ( $z > (int) SimpleTags_Plugin::get_option_value( 'auto_link_max_by_post' ) ) {
296 break;
297 }
298 }
299
300
301 return $content;
302 }
303
304 /**
305 * Replace text by link, except HTML tag, and already text into link, use DOMdocument.
306 * https://stackoverflow.com/questions/4044812/regex-domdocument-match-and-replace-text-not-in-a-link
307 *
308 * @param string $content
309 * @param string $search
310 * @param string $replace
311 * @param string $case
312 * @param string $rel
313 *
314 * @return void
315 */
316 private static function replace_by_links_dom( &$content, $search = '', $replace = '', $case = '', $rel = '', $options = false ) {
317 $dom = new DOMDocument();
318
319 //replace html entity with their entity code
320 foreach(taxopress_html_character_and_entity() as $enity => $code){
321 $content = str_replace($enity, $code,$content);
322 }
323 $content = str_replace('&#','|--|',$content);//https://github.com/TaxoPress/TaxoPress/issues/824
324 $content = str_replace('&','&#38;',$content); //https://github.com/TaxoPress/TaxoPress/issues/770*/
325 //$content = utf8_decode($content);
326
327 libxml_use_internal_errors(true);
328 // loadXml needs properly formatted documents, so it's better to use loadHtml, but it needs a hack to properly handle UTF-8 encoding
329 $result = $dom->loadHtml( mb_convert_encoding( $content, 'HTML-ENTITIES', "UTF-8" ) );
330
331 if ( false === $result ) {
332 return;
333 }
334
335 if($options){
336 $autolink_case = $options['autolink_case'];
337 $html_exclusion = $options['html_exclusion'];
338 $exclude_class = $options['autolink_exclude_class'];
339 $title_attribute = $options['autolink_title_attribute'];
340 $same_usage_max = $options['autolink_same_usage_max'];
341 $max_by_post = $options['autolink_usage_max'];
342 $link_class = isset($options['link_class']) ? taxopress_format_class($options['link_class']) : '';
343 }else{
344 $autolink_case = 'lowercase';
345 $html_exclusion = [];
346 $exclude_class = '';
347 $title_attribute = SimpleTags_Plugin::get_option_value( 'auto_link_title' );
348 $same_usage_max = SimpleTags_Plugin::get_option_value( 'auto_link_max_by_tag' );
349 $max_by_post = SimpleTags_Plugin::get_option_value( 'auto_link_max_by_post' );
350 $link_class = '';
351 }
352
353 //auto link exclusion
354 $exclusion = '[not(ancestor::a)]';
355 if(count($html_exclusion) > 0){
356 foreach($html_exclusion as $exclude_ancestor){
357 $exclusion .= '[not(ancestor::'.strtolower($exclude_ancestor).')]';
358 }
359 }
360
361 // Prepare exclude terms array
362 $excludes_class = explode( ',', $exclude_class );
363 if ( !empty( $excludes_class ) ) {
364 $excludes_class = array_filter( $excludes_class );
365 $excludes_class = array_unique( $excludes_class );
366 if(count($excludes_class) > 0){
367 foreach($excludes_class as $idclass ){
368 if(substr( trim($idclass), 0, 1 ) === "#"){
369 $div_id = ltrim(trim($idclass), "#");
370 $exclusion .= "[not(ancestor::div/@id='$div_id')]";
371 }else{
372 $div_class = ltrim(trim($idclass), ".");
373 $exclusion .= "[not(ancestor::div/@class='$div_class')]";
374 }
375 }
376 }
377 }
378
379
380 $xpath = new DOMXPath( $dom );
381 $j = 0;
382 $replaced_count = 0;
383 foreach ( $xpath->query( '//text()'.$exclusion.'' ) as $node ) {
384
385 $substitute = '<a href="' . $replace . '" class="st_tag internal_tag '.$link_class.'" ' . $rel . ' title="' . esc_attr( sprintf( $title_attribute, $search ) ) . "\">$search</a>";
386 $link_openeing = '<a href="' . $replace . '" class="st_tag internal_tag '.$link_class.'" ' . $rel . ' title="' . esc_attr( sprintf( $title_attribute, $search ) ) . "\">";
387 $link_closing = '</a>';
388 $upperterm = strtoupper($search);
389 $lowerterm = strtolower($search);
390
391 $remaining_usage = $max_by_post-self::$tagged_link_count;
392 if( $same_usage_max > $remaining_usage){
393 $same_usage_max = $remaining_usage;
394 }
395
396 if($same_usage_max > 0 ){
397 if ( 'i' === $case ) {
398 if($autolink_case === 'none'){//retain case
399 $replaced = preg_replace('/(?<!\w)' . preg_quote($search, "/") . '(?!\w)/i', "$link_openeing$0$link_closing", $node->wholeText, $same_usage_max, $rep_count);
400 }elseif($autolink_case === 'uppercase'){//uppercase
401 $replaced = preg_replace('/(?<!\w)' . preg_quote($search, "/") . '(?!\w)/i', "$link_openeing$upperterm$link_closing", $node->wholeText, $same_usage_max, $rep_count);
402 }elseif($autolink_case === 'termcase'){//termcase
403 $replaced = preg_replace('/(?<!\w)' . preg_quote($search, "/") . '(?!\w)/i', "$link_openeing$search$link_closing", $node->wholeText, $same_usage_max, $rep_count);
404 }else {//lowercase
405 $replaced = preg_replace('/(?<!\w)' . preg_quote($search, "/") . '(?!\w)/i', "$link_openeing$lowerterm$link_closing", $node->wholeText, $same_usage_max, $rep_count);
406 }
407 } else {
408 $replaced = str_replace( $search, $substitute, $node->wholeText );
409 }
410
411 if($replaced && !empty(trim($replaced))){
412 $j ++;
413 if($rep_count > 0){
414 $replaced_count = $replaced_count+$rep_count;
415 self::$tagged_link_count = self::$tagged_link_count+$rep_count;
416 }
417 }
418 $newNode = $dom->createDocumentFragment();
419 $newNode->appendXML( $replaced );
420 $node->parentNode->replaceChild( $newNode, $node );
421 if ( $replaced_count >= $same_usage_max || 0 === (int) $same_usage_max ) {// Limit replacement at 1 by default, or options value !
422 break;
423 }
424 }else{
425 break;
426 }
427 }
428
429 // get only the body tag with its contents, then trim the body tag itself to get only the original content
430 $content = mb_substr( $dom->saveHTML( $xpath->query( '//body' )->item( 0 ) ), 6, - 7, "UTF-8" );
431 $content = str_replace('|--|','&#',$content);//https://github.com/TaxoPress/TaxoPress/issues/824
432 $content = str_replace('&#60;','<',$content);
433 $content = str_replace('&#62;','>',$content);
434 foreach(taxopress_html_character_and_entity(true) as $enity => $code){
435 $content = str_replace($enity, $code,$content);
436 }
437 $content = str_replace('&#38;','&',$content); //https://github.com/TaxoPress/TaxoPress/issues/770
438 $content = str_replace(';amp;',';',$content); //https://github.com/TaxoPress/TaxoPress/issues/810
439
440 }
441
442 /**
443 * Replace text by link, except HTML tag, and already text into link, use PregEXP.
444 *
445 * @param string $content
446 * @param string $search
447 * @param string $replace
448 * @param string $case
449 * @param string $rel
450 */
451 private static function replace_by_links_regexp( &$content, $search = '', $replace = '', $case = '', $rel = '', $options = false ) {
452
453 if($options){
454 $autolink_case = $options['autolink_case'];
455 $html_exclusion = $options['html_exclusion'];
456 $exclude_class = $options['autolink_exclude_class'];
457 $title_attribute = $options['autolink_title_attribute'];
458 $same_usage_max = $options['autolink_same_usage_max'];
459 $max_by_post = $options['autolink_usage_max'];
460 $link_class = isset($options['link_class']) ? taxopress_format_class($options['link_class']) : '';
461 }else{
462 $autolink_case = 'lowercase';
463 $html_exclusion = [];
464 $exclude_class = '';
465 $title_attribute = SimpleTags_Plugin::get_option_value( 'auto_link_title' );
466 $same_usage_max = SimpleTags_Plugin::get_option_value( 'auto_link_max_by_tag' );
467 $max_by_post = SimpleTags_Plugin::get_option_value( 'auto_link_max_by_post' );
468 $link_class = '';
469 }
470
471 $must_tokenize = true; // will perform basic tokenization
472 $tokens = null; // two kinds of tokens: markup and text
473
474 $j = 0;
475 $filtered = ''; // will filter text token by token
476
477 $match = '/(\PL|\A)(' . preg_quote( $search, '/' ) . ')(\PL|\Z)\b/u' . $case;
478 $substitute = '$1<a href="' . $replace . '" class="st_tag internal_tag '.$link_class.'" ' . $rel . ' title="' . esc_attr( sprintf( $title_attribute, $search ) ) . "\">$2</a>$3";
479
480 //$match = "/\b" . preg_quote($search, "/") . "\b/".$case;
481 //$substitute = '<a href="'.$replace.'" class="st_tag internal_tag '.$link_class.'" '.$rel.' title="'. esc_attr( sprintf( __('Posts tagged with %s', 'simple-tags'), $search ) )."\">$0</a>";
482 // for efficiency only tokenize if forced to do so
483 if ( $must_tokenize ) {
484 // this regexp is taken from PHP Markdown by Michel Fortin: http://www.michelf.com/projects/php-markdown/
485 $comment = '(?s:<!(?:--.*?--\s*)+>)|';
486 $processing_instruction = '(?s:<\?.*?\?>)|';
487 $tag = '(?:<[/!$]?[-a-zA-Z0-9:]+\b(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*>)';
488
489 $markup = $comment . $processing_instruction . $tag;
490 $flags = PREG_SPLIT_DELIM_CAPTURE;
491 $tokens = preg_split( "{($markup)}", $content, - 1, $flags );
492 $must_tokenize = false;
493
494 }
495
496 // there should always be at least one token, but check just in case
497 $anchor_level = 0;
498
499 if ( isset( $tokens ) && is_array( $tokens ) && count( $tokens ) > 0 ) {
500 $i = 0;
501 $ancestor = '';
502 foreach ( $tokens as $token ) {
503 if ( ++ $i % 2 && $token !== '' )
504 { // this token is (non-markup) text
505
506
507 $pass_check = true;
508
509 if(!empty(trim($ancestor))){
510
511 //auto link exclusion
512 if(count($html_exclusion) > 0){
513 foreach($html_exclusion as $exclude_ancestor){
514 if(taxopress_starts_with( $ancestor, '<'.strtolower($exclude_ancestor).'' )){
515 $pass_check = false;
516 break;
517 }
518 }
519 }
520
521
522 // Prepare exclude terms array
523 $excludes_class = explode( ',', $exclude_class );
524 if ( !empty( $excludes_class ) ) {
525 $excludes_class = array_filter( $excludes_class );
526 $excludes_class = array_unique( $excludes_class );
527 if(count($excludes_class) > 0){
528 foreach($excludes_class as $idclass ){
529 if(substr( trim($idclass), 0, 1 ) === "#"){
530 $div_id = ltrim(trim($idclass), "#");
531 if ( preg_match_all('/<[a-z \'"]*id="'.$div_id.'"/i', $ancestor, $matches) || preg_match_all('/<[a-z \'"]*id=\''.$div_id.'\'/i', $ancestor, $matches)) {
532 $pass_check = false;
533 break;
534 }
535 }else{
536 $div_class = ltrim(trim($idclass), ".");
537 if ( preg_match_all('/<[a-z ]*class="'.$div_class.'"/i', $ancestor, $matches) || preg_match_all('/<[a-z ]*class=\''.$div_class.'\'/i', $ancestor, $matches)) {
538 $pass_check = false;
539 break;
540 }
541 }
542 }
543 }
544 }
545
546
547 }
548 if ( $anchor_level === 0 && $pass_check ) { // linkify if not inside anchor tags
549 if ( preg_match( $match, $token ) ) { // use preg_match for compatibility with PHP 4
550 $j ++;
551
552
553 $remaining_usage = $max_by_post-self::$tagged_link_count;
554 if( $same_usage_max > $remaining_usage){
555 $same_usage_max = $remaining_usage;
556 }
557
558
559 if ( $same_usage_max > 0 ) {// Limit replacement at 1 by default, or options value !
560 $token = preg_replace( $match, $substitute, $token, $same_usage_max, $rep_count ); // only PHP 5 supports calling preg_replace with 5 arguments
561 self::$tagged_link_count = self::$tagged_link_count+$rep_count;
562 }
563 $must_tokenize = true; // re-tokenize next time around
564 }
565 }
566 } else { // this token is markup
567 if ( preg_match( "#<\s*a\s+[^>]*>#i", $token ) ) { // found <a ...>
568 $ancestor = $token;
569 $anchor_level ++;
570 } elseif ( preg_match( "#<\s*/\s*a\s*>#i", $token ) ) { // found </a>
571 $anchor_level --;
572 }elseif(taxopress_starts_with( $token, "</" )){
573 $ancestor = '';
574 }else{
575 $ancestor = $token;
576 }
577 }
578 $filtered .= $token; // this token has now been filtered
579 }
580 $content = $filtered; // filtering completed for this link
581 }
582 }
583
584 /**
585 * Replace text of title by link to tag
586 *
587 * @param string $content
588 *
589 * @return string
590 */
591 public static function the_title( $title = '' ) {
592 global $post;
593
594 if ( 0 === (int) SimpleTags_Plugin::get_option_value( 'auto_link_title_excl' ) ) {
595 return $title;
596 }
597
598 // Show only on singular view ? Check context
599 if ( 'singular' === SimpleTags_Plugin::get_option_value( 'auto_link_views' ) && ! is_singular() ) {
600 return $title;
601 }
602
603 // Show only on single view ? Check context
604 if ( 'single' === SimpleTags_Plugin::get_option_value( 'auto_link_views' ) && ! is_single() ) {
605 return $title;
606 }
607
608 // user preference for this post ?
609 $meta_value = get_post_meta( $post->ID, '_exclude_autolinks', true );
610 if ( ! empty( $meta_value ) || is_admin() ) {
611 return $title;
612 }
613
614 // Get currents tags if no exists
615 self::prepare_auto_link_tags();
616
617 // Shuffle array
618 SimpleTags_Client::random_array( self::$link_tags );
619
620 // HTML Rel (tag/no-follow)
621 $rel = SimpleTags_Client::get_rel_attribut();
622
623 // only continue if the database actually returned any links
624 if ( ! isset( self::$link_tags ) || ! is_array( self::$link_tags ) || empty( self::$link_tags ) ) {
625 return $title;
626 }
627
628 // Case option ?
629 $case = ( 1 === (int) SimpleTags_Plugin::get_option_value( 'auto_link_case' ) ) ? 'i' : '';
630 $strpos_fnc = ( 'i' === $case ) ? 'stripos' : 'strpos';
631
632 // Prepare exclude terms array
633 $excludes_terms = explode( ',', SimpleTags_Plugin::get_option_value( 'auto_link_exclude' ) );
634 if ( empty( $excludes_terms ) ) {
635 $excludes_terms = array();
636 } else {
637 $excludes_terms = array_filter( $excludes_terms, '_delete_empty_element' );
638 $excludes_terms = array_unique( $excludes_terms );
639 }
640
641
642 $z = 0;
643 foreach ( (array) self::$link_tags as $term_name => $term_link ) {
644 // Force string for tags "number"
645 $term_name = (string) $term_name;
646
647 // Exclude terms ? next...
648 if ( in_array( $term_name, (array) $excludes_terms, true ) ) {
649 continue;
650 }
651
652 // Make a first test with PHP function, economize CPU with regexp
653 if ( false === $strpos_fnc( $title, $term_name ) ) {
654 continue;
655 }
656
657 if ( 1 === (int) SimpleTags_Plugin::get_option_value( 'auto_link_dom' ) && class_exists( 'DOMDocument' ) && class_exists( 'DOMXPath' ) ) {
658 self::replace_by_links_dom( $title, $term_name, $term_link, $case, $rel );
659 } else {
660 self::replace_by_links_regexp( $title, $term_name, $term_link, $case, $rel );
661 }
662
663 $z ++;
664
665 if ( $z > (int) SimpleTags_Plugin::get_option_value( 'auto_link_max_by_post' ) ) {
666 break;
667 }
668 }
669
670 return $title;
671 }
672
673
674 /**
675 * Replace text by link to tag
676 *
677 * @param string $content
678 *
679 * @return string
680 */
681 public static function taxopress_autolinks_the_content( $content = '' ) {
682 global $post;
683
684
685 if(!is_object($post) || is_admin() ){
686 return $content;
687 }
688
689 $post_tags = taxopress_get_autolink_data();
690
691
692 // user preference for this post ?
693 $meta_value = get_post_meta( $post->ID, '_exclude_autolinks', true );
694 if ( ! empty( $meta_value ) ) {
695 return $content;
696 }
697
698 if (count($post_tags) > 0) {
699
700 foreach ($post_tags as $post_tag) {
701
702 // Get option
703 $embedded = (isset($post_tag['embedded']) && is_array($post_tag['embedded']) && count($post_tag['embedded']) > 0) ? $post_tag['embedded'] : false;
704
705 if (!$embedded) {
706 continue;
707 }
708
709 if (!in_array($post->post_type, $embedded )) {
710 continue;
711 }
712
713 if ($post_tag['autolink_display'] === 'post_title') {
714 continue;
715 }
716
717 //reset added article link count
718 self::$tagged_link_count = 0;
719 //reset tags just in case
720 self::$link_tags = [];
721 // Get currents tags if no exists
722 self::prepare_auto_link_tags($post_tag);
723
724 // Shuffle array
725 SimpleTags_Client::random_array( self::$link_tags );
726
727 // HTML Rel (tag/no-follow)
728 $rel = SimpleTags_Client::get_rel_attribut();
729
730 // only continue if the database actually returned any links
731 if ( ! isset( self::$link_tags ) || ! is_array( self::$link_tags ) || empty( self::$link_tags ) ) {
732 $can_continue = false;
733 }else{
734 $can_continue = true;
735 }
736
737 if( $can_continue ){
738
739 // Case option ?
740 $case = ( 1 === (int) $post_tag['ignore_case'] ) ? 'i' : '';
741 $strpos_fnc = ( 'i' === $case ) ? 'stripos' : 'strpos';
742
743 // Prepare exclude terms array
744 $excludes_terms = explode( ',', $post_tag['auto_link_exclude'] );
745 if ( empty( $excludes_terms ) ) {
746 $excludes_terms = array();
747 } else {
748 $excludes_terms = array_filter( $excludes_terms, '_delete_empty_element' );
749 $excludes_terms = array_unique( $excludes_terms );
750 }
751
752 $z = 0;
753 foreach ( (array) self::$link_tags as $term_name => $term_link ) {
754 $z ++;
755 // Force string for tags "number"
756 $term_name = (string) $term_name;
757
758 // Exclude terms ? next...
759 if ( in_array( $term_name, (array) $excludes_terms, true ) ) {
760 continue;
761 }
762
763 // Make a first test with PHP function, economize CPU with regexp
764 if ( false === $strpos_fnc( $content, $term_name ) ) {
765 continue;
766 }
767
768 if ( 1 === (int) $post_tag['autolink_dom'] && class_exists( 'DOMDocument' ) && class_exists( 'DOMXPath' ) ) {
769 self::replace_by_links_dom( $content, $term_name, $term_link, $case, $rel, $post_tag );
770 }else if ( class_exists( 'DOMDocument' ) && class_exists( 'DOMXPath' ) ) {//force php dom if class exist for optimization purpose
771 self::replace_by_links_dom( $content, $term_name, $term_link, $case, $rel, $post_tag );
772 } else {
773 self::replace_by_links_regexp( $content, $term_name, $term_link, $case, $rel, $post_tag );
774 }
775 if ( self::$tagged_link_count >= (int) $post_tag['autolink_usage_max'] ) {
776 break;
777 }
778 }
779 }
780 }
781
782 }
783
784 return $content;
785 }
786
787
788
789
790 /**
791 * Replace text by link to tag
792 *
793 * @param string $title
794 *
795 * @return string
796 */
797 public static function taxopress_autolinks_the_title( $title = '' ) {
798 global $post;
799
800 if(!is_object($post) || is_admin() ){
801 return $title;
802 }
803
804 $post_tags = taxopress_get_autolink_data();
805
806
807 // user preference for this post ?
808 $meta_value = get_post_meta( $post->ID, '_exclude_autolinks', true );
809 if ( ! empty( $meta_value ) ) {
810 return $title;
811 }
812
813 if (count($post_tags) > 0) {
814
815 foreach ($post_tags as $post_tag) {
816
817 // Get option
818 $embedded = (isset($post_tag['embedded']) && is_array($post_tag['embedded']) && count($post_tag['embedded']) > 0) ? $post_tag['embedded'] : false;
819
820 if (!$embedded) {
821 continue;
822 }
823
824 if (!in_array($post->post_type, $embedded )) {
825 continue;
826 }
827
828 if ($post_tag['autolink_display'] === 'post_content') {
829 continue;
830 }
831 //reset added article link count
832 self::$tagged_link_count = 0;
833 //reset tags just in case
834 self::$link_tags = [];
835 // Get currents tags if no exists
836 self::prepare_auto_link_tags($post_tag);
837
838 // Shuffle array
839 SimpleTags_Client::random_array( self::$link_tags );
840
841 // HTML Rel (tag/no-follow)
842 $rel = SimpleTags_Client::get_rel_attribut();
843
844 // only continue if the database actually returned any links
845 if ( ! isset( self::$link_tags ) || ! is_array( self::$link_tags ) || empty( self::$link_tags ) ) {
846 $can_continue = false;
847 }else{
848 $can_continue = true;
849 }
850
851 if( $can_continue ){
852
853 // Case option ?
854 $case = ( 1 === (int) $post_tag['ignore_case'] ) ? 'i' : '';
855 $strpos_fnc = ( 'i' === $case ) ? 'stripos' : 'strpos';
856
857 // Prepare exclude terms array
858 $excludes_terms = explode( ',', $post_tag['auto_link_exclude'] );
859 if ( empty( $excludes_terms ) ) {
860 $excludes_terms = array();
861 } else {
862 $excludes_terms = array_filter( $excludes_terms, '_delete_empty_element' );
863 $excludes_terms = array_unique( $excludes_terms );
864 }
865
866 $z = 0;
867 foreach ( (array) self::$link_tags as $term_name => $term_link ) {
868 $z ++;
869 // Force string for tags "number"
870 $term_name = (string) $term_name;
871
872 // Exclude terms ? next...
873 if ( in_array( $term_name, (array) $excludes_terms, true ) ) {
874 continue;
875 }
876
877 // Make a first test with PHP function, economize CPU with regexp
878 if ( false === $strpos_fnc( $title, $term_name ) ) {
879 continue;
880 }
881
882 if ( 1 === (int) $post_tag['autolink_dom'] && class_exists( 'DOMDocument' ) && class_exists( 'DOMXPath' ) ) {
883 self::replace_by_links_dom( $title, $term_name, $term_link, $case, $rel, $post_tag );
884 }else if ( class_exists( 'DOMDocument' ) && class_exists( 'DOMXPath' ) ) {//force php dom if class exist for optimization purpose
885 self::replace_by_links_dom( $title, $term_name, $term_link, $case, $rel, $post_tag );
886 } else {
887 self::replace_by_links_regexp( $title, $term_name, $term_link, $case, $rel, $post_tag );
888 }
889
890 if ( self::$tagged_link_count >= (int) $post_tag['autolink_usage_max'] ) {
891 break;
892 }
893 }
894 }
895 }
896
897 }
898
899
900 return $title;
901 }
902
903 }
904