@mentions, #hashtag link conversion

So I have this nice little function that converts hastags to clickable links (URLs), anyone is free to use this if they please btw.

<?php
if (!function_exists('convertHashtags')) {
	function convertHashtags($str) {
		$regex = "/#+([a-zA-Z0-9_]+)/";
		$str = preg_replace($regex, '<a href="hashtag?tag=$1">$0</a>', $str);
		return($str);
	}
}
$convert_hashtag = convertHashtags("#Sitepoint is the best forum");
echo $convert_hashtag;
?>

When I modify this function to have the @ sign instead of the # sign it converts @username to a clickable link.

<?php
if (!function_exists('convertMention')) {
	function convertMention($str) {
		$regex = "/@+([a-zA-Z0-9_]+)/";
		$str = preg_replace($regex, '<a href="profile?username=$1">$0</a>', $str);
		return($str);
	}
}
$convert_mention = convertMention("@Sitepoint is the best forum");
echo $convert_mention;
?>

Is there any way I can merge the two so that I can turn both the #hashtags and the @mentions into clickable links? I’m not a “pro” PHP programmer but if anyone can help that’d be great :slight_smile:.

It depends on how you want it to work.
You could pass the type of conversion into the function as a variable:-

function convertTags($string, $tagType){}

Or possibly alter the regex to pick out either symbol in the string.

1 Like

The easiest way would be to just pipe the result of the one convert function to the next convert function, like

function convertAll($str) {
    return convertHashtags(convertMention($str));
}

Or you could map the replacements in an associative array, and insert the href part corresponding to the first character of the match in a callback:

function convertAll($str) {
    $regex = "/[@#](\w+)/";

    $hrefs = [
        '#' => 'hashtag?tag',
        '@' => 'profile?username'
    ];
    
    $result = preg_replace_callback($regex, function($matches) use ($hrefs) {
         return sprintf(
             '<a href="%s=%s">%s</a>',
             $hrefs[$matches[0][0]],
             $matches[1], 
             $matches[0]
         );
    }, $str);
        
    return($result);
}

The advantage of the former approach is that you can still use the individual converters in isolation – it’s generally better to have a function do exactly one thing. The disadvantage however is that you’d also parse some already replaced parts. This should be no problem in this case, but if the links would themselves contain hashes (for example), it would result in garbage; so the latter approach is probably cleaner.

2 Likes

Fantastic :smile: :kissing_heart: :kissing_heart: :kissing_heart:, Thank you for all your help, works like a charm.

1 Like

This was a great help but I found a little flaw in this code. I am using this code for a comment system, and the people who are using the @mentionusername feature said that it does not allow the following: @mention.username.

Notice the subtle " . "

It’ll allow everything else but it won’t allow something like @mention.username. It does this @mention.username. It links the @mention but not the .username part.

All in all thank you guys for your help :slight_smile:

Just a matter of adjusting the regular expression, so that it accepts word-characters as well as dots…

$regex = "/[@#]([\w\.]+)/";
1 Like

I did something like that lol, I was putting the period after the w but I never added the back slash so it looked like this

$regex = "/[@#]([\w.]+)/";
then I also tried
$regex = "/[@#]([\w\].\+)/";

Thank you very much for your help

A period is one of the characters that has a special meaning in regex, so it must be escaped with the backslash to say you are using that character as an actual character.

I need some more help,.

What I’m trying to do: pull all posts that have the same hashtags.

So ex: If there are 20 posts in my database and out of the 20, 10 of them have the same hashtag (#firstpost), I’d like to get all 10 posts that have the hashtag (#firstpost) and display them on the page.

So when the user visits the link http://www.yoursite.com/hashtag/firstpost/

I’d like to get all the hashtags for (#firstpost) and display them.

This has been solved, it was a problem with my sql code that wasn’t working. Thank you guys for your help

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.