I really frustrated, I am a novice in wordpress I am trying to Limit Maximum Numbers of Tag Links to appear within post content article. Below is my code. I don't know how to fix it up.
function link_words( $text ) {
$replace = array();
$tags = get_tags();
$count=0;
if ( $tags ) {
foreach ( $tags as $tag ) {
$count++;
$replace[ $tag->name ] = sprintf( '<a href="%s">%s</a>', esc_url( get_term_link( $tag ) ), esc_html( $tag->name ) );
if( $count > 2 ) break;
}
}
$text = str_replace( array_keys($replace), $replace, $text );
return $text;
}
add_filter( 'the_content', 'link_words' );
If your tags are comma-separated, this might work for you:
function limit_tags($tags) {
$tags = substr($tags, 0, strpos($tags, ',', strpos($tags, ',')+1));
return $tags;
}
add_filter('the_tags','limit_tags');
The $tags variable is actually a string...
You mention your function works the way you want it to (linking tags) so I won't mess with that. If you look at the docs for get_tags()
, you'll see it accepts a few arguments including number
which will limit it. This way you won't have a $counter
type variable to mess with.
You can also just check to see if the $tags
variable gets set to a truthy value, you don't need to define it first.
Your str_replace
is also occurring whether or not $tags
is defined, which can cause issues if none are found, so you should move that up into the if statement.
For semantic clarity, I've also changed the $text
variable to $content
since you're using the_content
filter.
add_filter( 'the_content', 'link_tags_in_content' );
function link_tags_in_content( $content ){
if( $tags = get_tags( array( 'number' => 2 ) ) ){
foreach( $tags as $tag ){
$tag_link = sprintf( '<a href="%s">%s</a>', esc_url( get_term_link( $tag ) ), esc_html( $tag->name ) );
$content = str_replace( $tag->name, $tag_link, $content );
}
}
return $content;
}
Ok, so I think I understand what you want better now...
function link_words( $text ) {
$tags = get_tags();
if ( $tags ) {
foreach ( $tags as $tag ) {
$from = '!<h2>[^<>]*<\/h2>(*SKIP)(*F)|<b>[^<>]*<\/b>(*SKIP)(*F)|<a\b[^>]*>.*?</a>(*SKIP)(*F)|(\b'.$tag->name.'\b)(?=[^>]*(?:<|$))!';
$to = sprintf( ' <a href="%s">%s</a> ', esc_url( get_term_link( $tag ) ), esc_html( $tag->name ) );
$text = preg_replace($from, $to , $text, 2);
}
}
return $text;
}
add_filter( 'the_content', 'link_words' );
Because of the limit on preg_replace (2), and it being inside the tag-loop, this replaces two instances of a tag name in the text for every tag... Is this along the lines of what you want? Be aware that this is not case-insensitive, so it will not match if your tag is the first word in a sentence, and is capitalized. To do something like that, maybe take a look at this thread:
PHP preg_replace: Case insensitive match with case sensitive replacement