Do not prepend a mention the reply already carries - #3680
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes duplicate reply-context mentions in federated comment content by skipping auto-prepended mentions when the author already included them (common for C2S/API-composed replies), and stabilizes/extends PHPUnit coverage for this behavior.
Changes:
- Skip prepending a reply-context mention when the comment content already mentions the actor (by handle or link).
- Move the WebFinger HTTP mock to per-test setup/teardown and add a data-driven test for mention de-duplication.
- Add a Changelogger entry describing the user-visible fix.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
includes/transformer/class-comment.php |
Adds content_mentions() gating to avoid duplicating reply-context mention links in outgoing content. |
tests/phpunit/tests/includes/transformer/class-test-comment.php |
Makes the WebFinger mock deterministic per test and adds coverage for existing-mention scenarios. |
.github/changelog/fix-reply-mention-duplicate |
Documents the fix for release notes (patch/fixed). |
Suppressed comments (1)
tests/phpunit/tests/includes/transformer/class-test-comment.php:162
- If the parent actor URL includes a trailing slash, the auto-prepended mention href will include it as well. Update the expectation for the "no mention" case so it continues to validate the output while covering the trailing-slash variant.
'no mention' => array(
'thanks',
'<p><a rel="mention" class="u-url mention" href="https://remote.example/@author" title="@author@remote.example">@author</a> thanks</p>',
),
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
tests/phpunit/tests/includes/transformer/class-test-comment.php:54
- tear_down() also calls a WordPress global function without a leading backslash in a namespaced file. Prefix it with \ for consistency with the codebase's namespaced WordPress function style.
public function tear_down() {
remove_filter( 'pre_http_request', array( self::class, 'pre_http_request' ) );
parent::tear_down();
}
tests/phpunit/tests/includes/transformer/class-test-comment.php:141
- In this namespaced test file, the new code calls get_comment() without a leading backslash. Use \get_comment() to follow the project's namespaced WordPress function convention.
$object = ( new Comment( get_comment( $test_comment_id ) ) )->to_object();
$this->assertSame( $expected, $object->get_content() );
| public function set_up() { | ||
| parent::set_up(); | ||
|
|
||
| // Mock the WebFinger wp_safe_remote_get. | ||
| add_filter( 'pre_http_request', array( self::class, 'pre_http_request' ), 10, 3 ); | ||
| } |
|
Hi @pfefferle thanks for engaging with this.
Having given it some more thought, I think committing to the ActivityPub API would translate to bypassing the auto-mention of every actor in the reply chain, letting the client and user ultimately handle actor mentions. |
|
I think you are right, and that is how Mastodon treats client content: the client sent the mentions it meant, the server should not add to them. The reason this PR stops at removing the duplicate is that it cannot tell a client-authored reply apart from one typed into the WordPress comment form. A reply from the API is stored with a The fix for that is to mark comments created through the API at the point they are stored, and then skip the reply context for those. That is a storage change and a behaviour decision, so I opened it as its own issue rather than growing this one: #3683. WordPress-native replies would keep the auto-mention, since a comment form has no way to type one. This PR stays as the safety net for comments that already exist. |
|
I figured it was a temporary measure, thanks for confirming! |
Fixes #3646
Proposed changes:
Transformer\Comment::get_content()prepends a mention link for every actor in the reply chain, and it does so unconditionally: it never checks whether the content already mentions that actor. A reply written by hand in WordPress never does, so nobody noticed. A reply composed through the ActivityPub API usually does, because the client writes the mention itself, the way Mastodon does. So the federated object carries it twice.The reporter's own object shows it. Fetched from mediaformat.org, the content has two
rel="mention"links to the same actor: ours first, with thetitle="@user@host"attribute our template adds, then the client's, without it. Thetagarray had the actor once, so only the content prefix was wrong.The fix skips the prefix for an actor the content already mentions, matched the same way the tag side keys mentions: a link whose
hrefis the actor's URL, or the bare@user@hosthandle. The regular WordPress reply, where the author typed no mention, is unchanged.I read the report as a fix for the visible symptom rather than a decision on whether the server should add a mention to API replies at all. That larger question is open, and worth its own issue if we want to go the way Mastodon does and leave the content entirely to the client.
One test fix rode along: the class added its WebFinger mock in
wpSetUpBeforeClass, butWP_UnitTestCasesnapshots the hook table around every test, so that filter was only as durable as what an earlier class left behind, and the existing reply-context test passed by ordering luck. The mock now lives inset_up()/tear_down(), which is why the new test could be made to pass in the full suite at all.Other information:
Testing instructions:
test_content_does_not_duplicate_an_existing_mentioncovers three cases: mention as a link, mention as a handle, and no mention. The first two fail against trunk, the third passes on both, so the regular path is provably untouched.git show origin/trunk:includes/transformer/class-comment.php > includes/transformer/class-comment.phpwp-env run tests-cli --env-cwd="wp-content/plugins/activitypub" vendor/bin/phpunit --filter content_does_not_duplicate, see the two failures.git checkout -- includes/transformer/class-comment.php, all three pass.By hand: reply to a remote reply from an ActivityPub client and type the mention yourself. Before, the federated note shows the person twice. After, once.
Changelog entry
In the branch as
.github/changelog/fix-reply-mention-duplicate, patch / fixed.