When it fires: Filters the single-comment response.
Serves the endpoint the portal calls when deep-linking to a comment and when opening one for editing. With context=edit the payload has been reshaped first: meta is unset and any attached images are lifted onto a media_images property, or a non-uploader preview is put back under meta.media_preview. Access is verified against the parent post before the filter runs.
When it fires: Filters the comment sort options a space administrator can choose from as that space's default.
Defaults to oldest (labelled "Earliest"), latest, popular and most_replied. It reaches the portal as comment_order_by_options, and the only consumer is the space settings form. The reader-facing sort dropdown is hard-coded in the Vue components and the sorting itself is done client-side, so adding a key here makes it selectable as a space default but nothing will know how to apply it. Removing keys is the safe direction. $context is comment at the only current call site.
When it fires: Filters the attributes a new comment is about to be created from.
The pre-save hook for comments, applied immediately after the read-only fluent_community/before_comment_create action. Setting status to something other than published here diverts the request into the held-comment branch — that is how Pro's moderation holds a comment back. There is no WP_Error contract: unlike the post-side filters, whatever you return is passed straight to Comment::create(), so throw if you need to abort.
When it fires: Filters the response returned when a new comment is not published.
Only applied on the held-for-moderation branch. The success path returns its payload without any filter at all, so this is not a general "comment created" response hook — it exists so Pro can explain to the author why their comment is pending. The comment value is the raw model with its relations loaded.
When it fires: Filters the response of the comment patch endpoint.
The patch endpoint handles the pin toggle only and is restricted to moderators and admins. The filter is applied whether or not anything changed, and receives four arguments — note that the request data is last, not second as in most response filters.
When it fires: Filters the attributes an edited comment is about to be saved with.
The update-side twin of fluent_community/comment/comment_data, with two extra arguments. What you return is filled onto the model and determines the dirty check, so returning the attributes unchanged makes the edit a silent no-op that fires neither fluent_community/comment_updated nor its type-scoped twin. Pro uses it to re-flag an edited comment.
When it fires: Filters the comment listing response for one post.
The endpoint returns every comment on the post in one go — there is no paging, and sorting is done client side — so on a busy thread the payload can be large. Replies are flat in the list, distinguished by parent_id. When fluent_community/can_view_comments_{type} denies access the endpoint returns an empty list early and this filter never runs.
When it fires: Filters the comment collection for a post before the viewer's likes are marked on it.
Receives an Eloquent collection of Comment models, not an array and not a response payload — return a collection or the each() call that follows will fail. It runs after moderation-status scoping and after inactive-profile comments have been excluded, which makes it the right place to drop or reorder comments; fluent_community/comments_api_response is the place to reshape the response.
When it fires: Filters whether the identical-comment guard is skipped for this submission.
By default a comment whose body exactly matches an earlier comment by the same user on the same post is rejected with "No duplicate comment please!". The check only runs when the comment has text, so image-only replies bypass it regardless. Return true to skip it — useful for short affirmations such as "thanks" in busy spaces.
When it fires: Filters whether users are barred from reacting to their own comments.
The name reads as a switch that is on by default, but it is not: it defaults to false, meaning self-reacting is permitted. Return true to block it, at which point the API responds with an error. It applies to comment reactions only — reactions on the user's own posts are unaffected.
When it fires: Filters the maximum number of characters allowed in a comment or reply.
Defaults to 10000 and, like the post limit, is measured with strlen() on the Markdown source, so it is a byte count. Exceeding it throws a 422 before the comment is stored. It applies to both new comments and edits, since both run through the same validation routine.
When it fires: Filters the comment listing shown on a member profile.
Scoped to comments on plain text posts the viewer may access, newest first, and paginated. The payload carries the paginator plus the profile itself. The parent posts of the listed comments have already been run through FeedsHelper::transformFeedsCollection(), so they are hydrated in place on each comment's post relation.
When it fires: Filters how many comments a member may post in a rolling one-minute window.
Defaults to 5. The comparison is count > limit against comments created in the last 60 seconds, so the effective allowance is one more than the number returned — the default lets six through before the sixth attempt is refused. Site administrators are exempt before the filter is reached, and exceeding the limit throws rather than returning a structured error.
Comments Filters
13 unique filter hooks currently map to this category, across 13 call sites.
Hook Inventory
fluent_community/comment_api_responsefluent-community/app/Http/Controllers/CommentsController.php:734fluent_community/comment_order_optionsfluent-community/app/Services/Helper.php:2273fluent_community/comment/comment_datafluent-community/app/Http/Controllers/CommentsController.php:140fluent_community/comment/new_comment_responsefluent-community/app/Http/Controllers/CommentsController.php:177fluent_community/comment/patch_comment_responsefluent-community/app/Http/Controllers/CommentsController.php:334fluent_community/comment/update_comment_datafluent-community/app/Http/Controllers/CommentsController.php:225fluent_community/comments_api_responsefluent-community/app/Http/Controllers/CommentsController.php:71fluent_community/comments_query_responsefluent-community/app/Http/Controllers/CommentsController.php:52fluent_community/disable_duplicate_comment_checkfluent-community/app/Http/Controllers/CommentsController.php:94fluent_community/disable_self_comment_reactfluent-community/app/Http/Controllers/CommentsController.php:633fluent_community/max_comment_char_lengthfluent-community/app/Http/Controllers/CommentsController.php:448fluent_community/profile_comments_api_responsefluent-community/app/Http/Controllers/ProfileController.php:713fluent_community/rate_limit/comments_per_minutefluent-community/app/Hooks/Handlers/RateLimitHandler.php:49fluent_community/comment_api_responseServes the endpoint the portal calls when deep-linking to a comment and when opening one for editing. With
context=editthe payload has been reshaped first:metais unset and any attached images are lifted onto amedia_imagesproperty, or a non-uploader preview is put back undermeta.media_preview. Access is verified against the parent post before the filter runs.Parameters
$dataarraycommentkey.$requestDataarraycontext.Return: The response payload array.
Call Sites
fluent-community/app/Http/Controllers/CommentsController.php:734$data(mixed)$request->all()(array)Example
Related:
fluent_community/comments_api_responsefluent_community/comment_order_optionsDefaults to
oldest(labelled "Earliest"),latest,popularandmost_replied. It reaches the portal ascomment_order_by_options, and the only consumer is the space settings form. The reader-facing sort dropdown is hard-coded in the Vue components and the sorting itself is done client-side, so adding a key here makes it selectable as a space default but nothing will know how to apply it. Removing keys is the safe direction.$contextiscommentat the only current call site.Parameters
$optionsarray$contextstringcommenttoday.Return:
array— an associative map of sort key to label, preserving order.Call Sites
fluent-community/app/Services/Helper.php:2273$options(mixed)$context(mixed)Example
Related:
fluent_community/portal_varsfluent_community/comment/comment_dataThe pre-save hook for comments, applied immediately after the read-only
fluent_community/before_comment_createaction. Settingstatusto something other thanpublishedhere diverts the request into the held-comment branch — that is how Pro's moderation holds a comment back. There is noWP_Errorcontract: unlike the post-side filters, whatever you return is passed straight toComment::create(), so throw if you need to abort.Parameters
$commentDataarraypost_id,message,message_rendered,parent_id,is_admin,meta,status.$feed\FluentCommunity\App\Models\FeedReturn:
array— the attribute map. It is not validated, so unknown keys will reach the model.Call Sites
fluent-community/app/Http/Controllers/CommentsController.php:140$commentData(mixed)$feed(Feed)Example
Related:
fluent_community/comment/update_comment_data·fluent_community/before_comment_createfluent_community/comment/new_comment_responseOnly applied on the held-for-moderation branch. The success path returns its payload without any filter at all, so this is not a general "comment created" response hook — it exists so Pro can explain to the author why their comment is pending. The
commentvalue is the raw model with its relations loaded.Parameters
$responsearraycommentandmessage.$comment\FluentCommunity\App\Models\CommentReturn: The response payload array.
Call Sites
fluent-community/app/Http/Controllers/CommentsController.php:177$response(mixed)$comment(Comment)Example
Related:
fluent_community/comment/new_comment_{comment}·fluent_community/comment/patch_comment_responsefluent_community/comment/patch_comment_responseThe patch endpoint handles the pin toggle only and is restricted to moderators and admins. The filter is applied whether or not anything changed, and receives four arguments — note that the request data is last, not second as in most response filters.
Parameters
$responsearraycommentandmessage.$comment\FluentCommunity\App\Models\Comment$feed\FluentCommunity\App\Models\Feed$requestDataarrayReturn: The response payload array.
Call Sites
fluent-community/app/Http/Controllers/CommentsController.php:334array (2 keys: comment, message)(array)$comment(Comment)$feed(Feed)$request->all()(array)Example
Related:
fluent_community/comment/updatedfluent_community/comment/update_comment_dataThe update-side twin of
fluent_community/comment/comment_data, with two extra arguments. What you return is filled onto the model and determines the dirty check, so returning the attributes unchanged makes the edit a silent no-op that fires neitherfluent_community/comment_updatednor its type-scoped twin. Pro uses it to re-flag an edited comment.Parameters
$commentDataarray$feed\FluentCommunity\App\Models\Feed$requestDataarrayis_admin.$comment\FluentCommunity\App\Models\CommentReturn:
array— the attribute map.Call Sites
fluent-community/app/Http/Controllers/CommentsController.php:225$commentData(mixed)$feed(Feed)$requestData(array)$comment(Comment)Example
Related:
fluent_community/comment/comment_datafluent_community/comments_api_responseThe endpoint returns every comment on the post in one go — there is no paging, and sorting is done client side — so on a busy thread the payload can be large. Replies are flat in the list, distinguished by
parent_id. Whenfluent_community/can_view_comments_{type}denies access the endpoint returns an empty list early and this filter never runs.Parameters
$dataarraycommentscollection.$requestDataarrayReturn: The response payload array.
Call Sites
fluent-community/app/Http/Controllers/CommentsController.php:71$data(mixed)$request->all()(array)Example
Related:
fluent_community/comments_query_response·fluent_community/can_view_comments_{feed}fluent_community/comments_query_responseReceives an Eloquent collection of
Commentmodels, not an array and not a response payload — return a collection or theeach()call that follows will fail. It runs after moderation-status scoping and after inactive-profile comments have been excluded, which makes it the right place to drop or reorder comments;fluent_community/comments_api_responseis the place to reshape the response.Parameters
$comments\FluentCommunity\Framework\Database\Orm\Collectionxprofileeager-loaded.$requestDataarrayReturn: The comment collection.
Call Sites
fluent-community/app/Http/Controllers/CommentsController.php:52$comments(mixed)$request->all()(array)Example
Related:
fluent_community/comments_api_responsefluent_community/disable_duplicate_comment_checkBy default a comment whose body exactly matches an earlier comment by the same user on the same post is rejected with "No duplicate comment please!". The check only runs when the comment has text, so image-only replies bypass it regardless. Return
trueto skip it — useful for short affirmations such as "thanks" in busy spaces.Parameters
$skipCheckboolfalseby default.$userIdint$feedIdintReturn:
bool—trueto allow the duplicate through.Call Sites
fluent-community/app/Http/Controllers/CommentsController.php:94false(bool)get_current_user_id()(int)$feed->id(int)Example
Related:
fluent_community/rate_limit/comments_per_minutefluent_community/disable_self_comment_reactThe name reads as a switch that is on by default, but it is not: it defaults to
false, meaning self-reacting is permitted. Returntrueto block it, at which point the API responds with an error. It applies to comment reactions only — reactions on the user's own posts are unaffected.Parameters
$disabledboolfalseby default, so self-reacting is allowed.$feed\FluentCommunity\App\Models\FeedReturn:
bool—trueto reject a reaction on the user's own comment.Call Sites
fluent-community/app/Http/Controllers/CommentsController.php:633false(bool)$feed(Feed)Example
fluent_community/max_comment_char_lengthDefaults to 10000 and, like the post limit, is measured with
strlen()on the Markdown source, so it is a byte count. Exceeding it throws a 422 before the comment is stored. It applies to both new comments and edits, since both run through the same validation routine.Parameters
$maxLengthintReturn:
int— the maximum length.Call Sites
fluent-community/app/Http/Controllers/CommentsController.php:44810000(int)Example
Related:
fluent_community/max_post_lengthfluent_community/profile_comments_api_responseScoped to comments on plain
textposts the viewer may access, newest first, and paginated. The payload carries the paginator plus the profile itself. The parent posts of the listed comments have already been run throughFeedsHelper::transformFeedsCollection(), so they are hydrated in place on each comment'spostrelation.Parameters
$dataarraycommentspaginator andxprofile.$requestDataarrayReturn: The response payload array.
Call Sites
fluent-community/app/Http/Controllers/ProfileController.php:713$data(mixed)$request->all()(array)Example
Related:
fluent_community/comments_api_responsefluent_community/rate_limit/comments_per_minuteDefaults to 5. The comparison is
count > limitagainst comments created in the last 60 seconds, so the effective allowance is one more than the number returned — the default lets six through before the sixth attempt is refused. Site administrators are exempt before the filter is reached, and exceeding the limit throws rather than returning a structured error.Parameters
$limitPerMinuteintReturn:
int— the limit. A very large value effectively disables comment rate limiting.Call Sites
fluent-community/app/Hooks/Handlers/RateLimitHandler.php:495(int)Example
Related:
fluent_community/disable_duplicate_comment_check