PluginProbe
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms / 3.6.2
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms v3.6.2
3.54.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 All 178 releases
simple-tags / inc / class.client.autolinks.php

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

908 lines 30.3 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 $html_exclusion[] = 'meta';
354 $html_exclusion[] = 'link';
355 $html_exclusion[] = 'head';
356
357 //auto link exclusion
358 $exclusion = '[not(ancestor::a)]';
359 if(count($html_exclusion) > 0){
360 foreach($html_exclusion as $exclude_ancestor){
361 $exclusion .= '[not(ancestor::'.strtolower($exclude_ancestor).')]';
362 }
363 }
364
365 // Prepare exclude terms array
366 $excludes_class = explode( ',', $exclude_class );
367 if ( !empty( $excludes_class ) ) {
368 $excludes_class = array_filter( $excludes_class );
369 $excludes_class = array_unique( $excludes_class );
370 if(count($excludes_class) > 0){
371 foreach($excludes_class as $idclass ){
372 if(substr( trim($idclass), 0, 1 ) === "#"){
373 $div_id = ltrim(trim($idclass), "#");
374 $exclusion .= "[not(ancestor::div/@id='$div_id')]";
375 }else{
376 $div_class = ltrim(trim($idclass), ".");
377 $exclusion .= "[not(ancestor::div/@class='$div_class')]";
378 }
379 }
380 }
381 }
382
383
384 $xpath = new DOMXPath( $dom );
385 $j = 0;
386 $replaced_count = 0;
387 foreach ( $xpath->query( '//text()'.$exclusion.'' ) as $node ) {
388
389 $substitute = '<a href="' . $replace . '" class="st_tag internal_tag '.$link_class.'" ' . $rel . ' title="' . esc_attr( sprintf( $title_attribute, $search ) ) . "\">$search</a>";
390 $link_openeing = '<a href="' . $replace . '" class="st_tag internal_tag '.$link_class.'" ' . $rel . ' title="' . esc_attr( sprintf( $title_attribute, $search ) ) . "\">";
391 $link_closing = '</a>';
392 $upperterm = strtoupper($search);
393 $lowerterm = strtolower($search);
394
395 $remaining_usage = $max_by_post-self::$tagged_link_count;
396 if( $same_usage_max > $remaining_usage){
397 $same_usage_max = $remaining_usage;
398 }
399
400 if($same_usage_max > 0 ){
401 if ( 'i' === $case ) {
402 if($autolink_case === 'none'){//retain case
403 $replaced = preg_replace('/(?<!\w)' . preg_quote($search, "/") . '(?!\w)/i', "$link_openeing$0$link_closing", $node->wholeText, $same_usage_max, $rep_count);
404 }elseif($autolink_case === 'uppercase'){//uppercase
405 $replaced = preg_replace('/(?<!\w)' . preg_quote($search, "/") . '(?!\w)/i', "$link_openeing$upperterm$link_closing", $node->wholeText, $same_usage_max, $rep_count);
406 }elseif($autolink_case === 'termcase'){//termcase
407 $replaced = preg_replace('/(?<!\w)' . preg_quote($search, "/") . '(?!\w)/i', "$link_openeing$search$link_closing", $node->wholeText, $same_usage_max, $rep_count);
408 }else {//lowercase
409 $replaced = preg_replace('/(?<!\w)' . preg_quote($search, "/") . '(?!\w)/i', "$link_openeing$lowerterm$link_closing", $node->wholeText, $same_usage_max, $rep_count);
410 }
411 } else {
412 $replaced = str_replace( $search, $substitute, $node->wholeText );
413 }
414
415 if($replaced && !empty(trim($replaced))){
416 $j ++;
417 if($rep_count > 0){
418 $replaced_count = $replaced_count+$rep_count;
419 self::$tagged_link_count = self::$tagged_link_count+$rep_count;
420 }
421 }
422 $newNode = $dom->createDocumentFragment();
423 $newNode->appendXML( $replaced );
424 $node->parentNode->replaceChild( $newNode, $node );
425 if ( $replaced_count >= $same_usage_max || 0 === (int) $same_usage_max ) {// Limit replacement at 1 by default, or options value !
426 break;
427 }
428 }else{
429 break;
430 }
431 }
432
433 // get only the body tag with its contents, then trim the body tag itself to get only the original content
434 $content = mb_substr( $dom->saveHTML( $xpath->query( '//body' )->item( 0 ) ), 6, - 7, "UTF-8" );
435 $content = str_replace('|--|','&#',$content);//https://github.com/TaxoPress/TaxoPress/issues/824
436 $content = str_replace('&#60;','<',$content);
437 $content = str_replace('&#62;','>',$content);
438 foreach(taxopress_html_character_and_entity(true) as $enity => $code){
439 $content = str_replace($enity, $code,$content);
440 }
441 $content = str_replace('&#38;','&',$content); //https://github.com/TaxoPress/TaxoPress/issues/770
442 $content = str_replace(';amp;',';',$content); //https://github.com/TaxoPress/TaxoPress/issues/810
443
444 }
445
446 /**
447 * Replace text by link, except HTML tag, and already text into link, use PregEXP.
448 *
449 * @param string $content
450 * @param string $search
451 * @param string $replace
452 * @param string $case
453 * @param string $rel
454 */
455 private static function replace_by_links_regexp( &$content, $search = '', $replace = '', $case = '', $rel = '', $options = false ) {
456
457 if($options){
458 $autolink_case = $options['autolink_case'];
459 $html_exclusion = $options['html_exclusion'];
460 $exclude_class = $options['autolink_exclude_class'];
461 $title_attribute = $options['autolink_title_attribute'];
462 $same_usage_max = $options['autolink_same_usage_max'];
463 $max_by_post = $options['autolink_usage_max'];
464 $link_class = isset($options['link_class']) ? taxopress_format_class($options['link_class']) : '';
465 }else{
466 $autolink_case = 'lowercase';
467 $html_exclusion = [];
468 $exclude_class = '';
469 $title_attribute = SimpleTags_Plugin::get_option_value( 'auto_link_title' );
470 $same_usage_max = SimpleTags_Plugin::get_option_value( 'auto_link_max_by_tag' );
471 $max_by_post = SimpleTags_Plugin::get_option_value( 'auto_link_max_by_post' );
472 $link_class = '';
473 }
474
475 $must_tokenize = true; // will perform basic tokenization
476 $tokens = null; // two kinds of tokens: markup and text
477
478 $j = 0;
479 $filtered = ''; // will filter text token by token
480
481 $match = '/(\PL|\A)(' . preg_quote( $search, '/' ) . ')(\PL|\Z)\b/u' . $case;
482 $substitute = '$1<a href="' . $replace . '" class="st_tag internal_tag '.$link_class.'" ' . $rel . ' title="' . esc_attr( sprintf( $title_attribute, $search ) ) . "\">$2</a>$3";
483
484 //$match = "/\b" . preg_quote($search, "/") . "\b/".$case;
485 //$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>";
486 // for efficiency only tokenize if forced to do so
487 if ( $must_tokenize ) {
488 // this regexp is taken from PHP Markdown by Michel Fortin: http://www.michelf.com/projects/php-markdown/
489 $comment = '(?s:<!(?:--.*?--\s*)+>)|';
490 $processing_instruction = '(?s:<\?.*?\?>)|';
491 $tag = '(?:<[/!$]?[-a-zA-Z0-9:]+\b(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*>)';
492
493 $markup = $comment . $processing_instruction . $tag;
494 $flags = PREG_SPLIT_DELIM_CAPTURE;
495 $tokens = preg_split( "{($markup)}", $content, - 1, $flags );
496 $must_tokenize = false;
497
498 }
499
500 // there should always be at least one token, but check just in case
501 $anchor_level = 0;
502
503 if ( isset( $tokens ) && is_array( $tokens ) && count( $tokens ) > 0 ) {
504 $i = 0;
505 $ancestor = '';
506 foreach ( $tokens as $token ) {
507 if ( ++ $i % 2 && $token !== '' )
508 { // this token is (non-markup) text
509
510
511 $pass_check = true;
512
513 if(!empty(trim($ancestor))){
514
515 //auto link exclusion
516 if(count($html_exclusion) > 0){
517 foreach($html_exclusion as $exclude_ancestor){
518 if(taxopress_starts_with( $ancestor, '<'.strtolower($exclude_ancestor).'' )){
519 $pass_check = false;
520 break;
521 }
522 }
523 }
524
525
526 // Prepare exclude terms array
527 $excludes_class = explode( ',', $exclude_class );
528 if ( !empty( $excludes_class ) ) {
529 $excludes_class = array_filter( $excludes_class );
530 $excludes_class = array_unique( $excludes_class );
531 if(count($excludes_class) > 0){
532 foreach($excludes_class as $idclass ){
533 if(substr( trim($idclass), 0, 1 ) === "#"){
534 $div_id = ltrim(trim($idclass), "#");
535 if ( preg_match_all('/<[a-z \'"]*id="'.$div_id.'"/i', $ancestor, $matches) || preg_match_all('/<[a-z \'"]*id=\''.$div_id.'\'/i', $ancestor, $matches)) {
536 $pass_check = false;
537 break;
538 }
539 }else{
540 $div_class = ltrim(trim($idclass), ".");
541 if ( preg_match_all('/<[a-z ]*class="'.$div_class.'"/i', $ancestor, $matches) || preg_match_all('/<[a-z ]*class=\''.$div_class.'\'/i', $ancestor, $matches)) {
542 $pass_check = false;
543 break;
544 }
545 }
546 }
547 }
548 }
549
550
551 }
552 if ( $anchor_level === 0 && $pass_check ) { // linkify if not inside anchor tags
553 if ( preg_match( $match, $token ) ) { // use preg_match for compatibility with PHP 4
554 $j ++;
555
556
557 $remaining_usage = $max_by_post-self::$tagged_link_count;
558 if( $same_usage_max > $remaining_usage){
559 $same_usage_max = $remaining_usage;
560 }
561
562
563 if ( $same_usage_max > 0 ) {// Limit replacement at 1 by default, or options value !
564 $token = preg_replace( $match, $substitute, $token, $same_usage_max, $rep_count ); // only PHP 5 supports calling preg_replace with 5 arguments
565 self::$tagged_link_count = self::$tagged_link_count+$rep_count;
566 }
567 $must_tokenize = true; // re-tokenize next time around
568 }
569 }
570 } else { // this token is markup
571 if ( preg_match( "#<\s*a\s+[^>]*>#i", $token ) ) { // found <a ...>
572 $ancestor = $token;
573 $anchor_level ++;
574 } elseif ( preg_match( "#<\s*/\s*a\s*>#i", $token ) ) { // found </a>
575 $anchor_level --;
576 }elseif(taxopress_starts_with( $token, "</" )){
577 $ancestor = '';
578 }else{
579 $ancestor = $token;
580 }
581 }
582 $filtered .= $token; // this token has now been filtered
583 }
584 $content = $filtered; // filtering completed for this link
585 }
586 }
587
588 /**
589 * Replace text of title by link to tag
590 *
591 * @param string $content
592 *
593 * @return string
594 */
595 public static function the_title( $title = '' ) {
596 global $post;
597
598 if ( 0 === (int) SimpleTags_Plugin::get_option_value( 'auto_link_title_excl' ) ) {
599 return $title;
600 }
601
602 // Show only on singular view ? Check context
603 if ( 'singular' === SimpleTags_Plugin::get_option_value( 'auto_link_views' ) && ! is_singular() ) {
604 return $title;
605 }
606
607 // Show only on single view ? Check context
608 if ( 'single' === SimpleTags_Plugin::get_option_value( 'auto_link_views' ) && ! is_single() ) {
609 return $title;
610 }
611
612 // user preference for this post ?
613 $meta_value = get_post_meta( $post->ID, '_exclude_autolinks', true );
614 if ( ! empty( $meta_value ) || is_admin() ) {
615 return $title;
616 }
617
618 // Get currents tags if no exists
619 self::prepare_auto_link_tags();
620
621 // Shuffle array
622 SimpleTags_Client::random_array( self::$link_tags );
623
624 // HTML Rel (tag/no-follow)
625 $rel = SimpleTags_Client::get_rel_attribut();
626
627 // only continue if the database actually returned any links
628 if ( ! isset( self::$link_tags ) || ! is_array( self::$link_tags ) || empty( self::$link_tags ) ) {
629 return $title;
630 }
631
632 // Case option ?
633 $case = ( 1 === (int) SimpleTags_Plugin::get_option_value( 'auto_link_case' ) ) ? 'i' : '';
634 $strpos_fnc = ( 'i' === $case ) ? 'stripos' : 'strpos';
635
636 // Prepare exclude terms array
637 $excludes_terms = explode( ',', SimpleTags_Plugin::get_option_value( 'auto_link_exclude' ) );
638 if ( empty( $excludes_terms ) ) {
639 $excludes_terms = array();
640 } else {
641 $excludes_terms = array_filter( $excludes_terms, '_delete_empty_element' );
642 $excludes_terms = array_unique( $excludes_terms );
643 }
644
645
646 $z = 0;
647 foreach ( (array) self::$link_tags as $term_name => $term_link ) {
648 // Force string for tags "number"
649 $term_name = (string) $term_name;
650
651 // Exclude terms ? next...
652 if ( in_array( $term_name, (array) $excludes_terms, true ) ) {
653 continue;
654 }
655
656 // Make a first test with PHP function, economize CPU with regexp
657 if ( false === $strpos_fnc( $title, $term_name ) ) {
658 continue;
659 }
660
661 if ( 1 === (int) SimpleTags_Plugin::get_option_value( 'auto_link_dom' ) && class_exists( 'DOMDocument' ) && class_exists( 'DOMXPath' ) ) {
662 self::replace_by_links_dom( $title, $term_name, $term_link, $case, $rel );
663 } else {
664 self::replace_by_links_regexp( $title, $term_name, $term_link, $case, $rel );
665 }
666
667 $z ++;
668
669 if ( $z > (int) SimpleTags_Plugin::get_option_value( 'auto_link_max_by_post' ) ) {
670 break;
671 }
672 }
673
674 return $title;
675 }
676
677
678 /**
679 * Replace text by link to tag
680 *
681 * @param string $content
682 *
683 * @return string
684 */
685 public static function taxopress_autolinks_the_content( $content = '' ) {
686 global $post;
687
688
689 if(!is_object($post) || is_admin() ){
690 return $content;
691 }
692
693 $post_tags = taxopress_get_autolink_data();
694
695
696 // user preference for this post ?
697 $meta_value = get_post_meta( $post->ID, '_exclude_autolinks', true );
698 if ( ! empty( $meta_value ) ) {
699 return $content;
700 }
701
702 if (count($post_tags) > 0) {
703
704 foreach ($post_tags as $post_tag) {
705
706 // Get option
707 $embedded = (isset($post_tag['embedded']) && is_array($post_tag['embedded']) && count($post_tag['embedded']) > 0) ? $post_tag['embedded'] : false;
708
709 if (!$embedded) {
710 continue;
711 }
712
713 if (!in_array($post->post_type, $embedded )) {
714 continue;
715 }
716
717 if ($post_tag['autolink_display'] === 'post_title') {
718 continue;
719 }
720
721 //reset added article link count
722 self::$tagged_link_count = 0;
723 //reset tags just in case
724 self::$link_tags = [];
725 // Get currents tags if no exists
726 self::prepare_auto_link_tags($post_tag);
727
728 // Shuffle array
729 SimpleTags_Client::random_array( self::$link_tags );
730
731 // HTML Rel (tag/no-follow)
732 $rel = SimpleTags_Client::get_rel_attribut();
733
734 // only continue if the database actually returned any links
735 if ( ! isset( self::$link_tags ) || ! is_array( self::$link_tags ) || empty( self::$link_tags ) ) {
736 $can_continue = false;
737 }else{
738 $can_continue = true;
739 }
740
741 if( $can_continue ){
742
743 // Case option ?
744 $case = ( 1 === (int) $post_tag['ignore_case'] ) ? 'i' : '';
745 $strpos_fnc = ( 'i' === $case ) ? 'stripos' : 'strpos';
746
747 // Prepare exclude terms array
748 $excludes_terms = explode( ',', $post_tag['auto_link_exclude'] );
749 if ( empty( $excludes_terms ) ) {
750 $excludes_terms = array();
751 } else {
752 $excludes_terms = array_filter( $excludes_terms, '_delete_empty_element' );
753 $excludes_terms = array_unique( $excludes_terms );
754 }
755
756 $z = 0;
757 foreach ( (array) self::$link_tags as $term_name => $term_link ) {
758 $z ++;
759 // Force string for tags "number"
760 $term_name = (string) $term_name;
761
762 // Exclude terms ? next...
763 if ( in_array( $term_name, (array) $excludes_terms, true ) ) {
764 continue;
765 }
766
767 // Make a first test with PHP function, economize CPU with regexp
768 if ( false === $strpos_fnc( $content, $term_name ) ) {
769 continue;
770 }
771
772 if ( 1 === (int) $post_tag['autolink_dom'] && class_exists( 'DOMDocument' ) && class_exists( 'DOMXPath' ) ) {
773 self::replace_by_links_dom( $content, $term_name, $term_link, $case, $rel, $post_tag );
774 }else if ( class_exists( 'DOMDocument' ) && class_exists( 'DOMXPath' ) ) {//force php dom if class exist for optimization purpose
775 self::replace_by_links_dom( $content, $term_name, $term_link, $case, $rel, $post_tag );
776 } else {
777 self::replace_by_links_regexp( $content, $term_name, $term_link, $case, $rel, $post_tag );
778 }
779 if ( self::$tagged_link_count >= (int) $post_tag['autolink_usage_max'] ) {
780 break;
781 }
782 }
783 }
784 }
785
786 }
787
788 return $content;
789 }
790
791
792
793
794 /**
795 * Replace text by link to tag
796 *
797 * @param string $title
798 *
799 * @return string
800 */
801 public static function taxopress_autolinks_the_title( $title = '' ) {
802 global $post;
803
804 if(!is_object($post) || is_admin() ){
805 return $title;
806 }
807
808 $post_tags = taxopress_get_autolink_data();
809
810
811 // user preference for this post ?
812 $meta_value = get_post_meta( $post->ID, '_exclude_autolinks', true );
813 if ( ! empty( $meta_value ) ) {
814 return $title;
815 }
816
817 if (count($post_tags) > 0) {
818
819 foreach ($post_tags as $post_tag) {
820
821 // Get option
822 $embedded = (isset($post_tag['embedded']) && is_array($post_tag['embedded']) && count($post_tag['embedded']) > 0) ? $post_tag['embedded'] : false;
823
824 if (!$embedded) {
825 continue;
826 }
827
828 if (!in_array($post->post_type, $embedded )) {
829 continue;
830 }
831
832 if ($post_tag['autolink_display'] === 'post_content') {
833 continue;
834 }
835 //reset added article link count
836 self::$tagged_link_count = 0;
837 //reset tags just in case
838 self::$link_tags = [];
839 // Get currents tags if no exists
840 self::prepare_auto_link_tags($post_tag);
841
842 // Shuffle array
843 SimpleTags_Client::random_array( self::$link_tags );
844
845 // HTML Rel (tag/no-follow)
846 $rel = SimpleTags_Client::get_rel_attribut();
847
848 // only continue if the database actually returned any links
849 if ( ! isset( self::$link_tags ) || ! is_array( self::$link_tags ) || empty( self::$link_tags ) ) {
850 $can_continue = false;
851 }else{
852 $can_continue = true;
853 }
854
855 if( $can_continue ){
856
857 // Case option ?
858 $case = ( 1 === (int) $post_tag['ignore_case'] ) ? 'i' : '';
859 $strpos_fnc = ( 'i' === $case ) ? 'stripos' : 'strpos';
860
861 // Prepare exclude terms array
862 $excludes_terms = explode( ',', $post_tag['auto_link_exclude'] );
863 if ( empty( $excludes_terms ) ) {
864 $excludes_terms = array();
865 } else {
866 $excludes_terms = array_filter( $excludes_terms, '_delete_empty_element' );
867 $excludes_terms = array_unique( $excludes_terms );
868 }
869
870 $z = 0;
871 foreach ( (array) self::$link_tags as $term_name => $term_link ) {
872 $z ++;
873 // Force string for tags "number"
874 $term_name = (string) $term_name;
875
876 // Exclude terms ? next...
877 if ( in_array( $term_name, (array) $excludes_terms, true ) ) {
878 continue;
879 }
880
881 // Make a first test with PHP function, economize CPU with regexp
882 if ( false === $strpos_fnc( $title, $term_name ) ) {
883 continue;
884 }
885
886 if ( 1 === (int) $post_tag['autolink_dom'] && class_exists( 'DOMDocument' ) && class_exists( 'DOMXPath' ) ) {
887 self::replace_by_links_dom( $title, $term_name, $term_link, $case, $rel, $post_tag );
888 }else if ( class_exists( 'DOMDocument' ) && class_exists( 'DOMXPath' ) ) {//force php dom if class exist for optimization purpose
889 self::replace_by_links_dom( $title, $term_name, $term_link, $case, $rel, $post_tag );
890 } else {
891 self::replace_by_links_regexp( $title, $term_name, $term_link, $case, $rel, $post_tag );
892 }
893
894 if ( self::$tagged_link_count >= (int) $post_tag['autolink_usage_max'] ) {
895 break;
896 }
897 }
898 }
899 }
900
901 }
902
903
904 return $title;
905 }
906
907 }
908