Skip to main content

Bug report: a mention followed by a period is not recognised

Product: FluentCommunity 2.9.1 (Pro 2.9.1), WordPress 7.1, PHP 8.3

What happens

A mention at the end of a sentence is not resolved:

  • Thanks @ pcl, renders as a link to the profile. Correct.
  • Thanks @ pcl. renders as plain text. No link, no notification.

Every other punctuation mark works. Only the period fails.

It is not limited to the one mention: getMentions() returns null for the
whole post as soon as no candidate resolves, so a second, correctly written
mention in the same post is dropped as well.

Why

app/Services/FeedsHelper.php:

public static function getMentions($text, $spaceId = null, $withUsers = false)
{
    // the mention may have . or _ or - in the username
    preg_match_all('/@([a-zA-Z0-9_.-]+)/', $text, $matches);

The period is part of the character class, so @pcl. yields the candidate
pcl., and XProfile::whereIn('username', ['pcl.']) finds nobody.

The comment above the pattern does not hold. Every path that assigns a user
name goes through CustomSanitizer::sanitizeUserName():

$username = sanitize_user($username);
$username = preg_replace('/[^a-zA-Z0-9_]/', '', $username);

Neither a period nor a hyphen survives that. Callers are
ProfileHelper (2x), ProfileController (2x) and PortalHandler, which even
compares the stored name against the sanitised one. Measured on a live site
with 236 profiles: 0 contain a period, 0 contain a hyphen.

The affected mention paths are FeedsController::store,
FeedsController::update, FeedsHelper::createFeed, CommentsController::store
and CommentsController::update. Beyond the missing link, the post also loses
meta.mentioned_user_ids, and with it the bell notification
(NotificationEventHandler::maybeHandleMentionedUserIds), the mention e-mail
(EmailNotificationHandler) and the Pro FollowHandler.

Suggested fix

Drop the period and the hyphen from the character class, matching what
sanitizeUserName() allows:

preg_match_all('/@([a-zA-Z0-9_]+)/', $text, $matches);

If older installations may carry imported names with a period, a fallback that
retries the candidate with trailing periods trimmed would cover both.

Related, same function

strtr() replaces substrings anywhere in the text, so a mention that resolves
also rewrites an e-mail address that happens to contain the same name:

$t = 'Thanks @ anna, write to hello@ anna.de please.';
strtr($t, ['@ anna' => '<a>Anna</a>']);
// Thanks <a>Anna</a>, write to hello<a>Anna</a>.de please.

A replacement anchored on a word boundary before the @ would avoid it.

Raiyan Marzan

Peter Claus Lamprecht We will have a look into it. Thanks for the details report!