Comments

Comments support voting, ranking, threading, images, URL previews, mentions and notifications.

Adding Comments

// Adding a comment to an activity
$response = $feedsClient->addComment(
    new GeneratedModels\AddCommentRequest(
        id: 'comment_123', // id is optional, but must be unique. will be auto-generated if not provided
        comment: 'So great!',
        objectID: 'activity_123',
        objectType: 'activity',
        userID: 'user123',
        custom: (object)[
            'sentiment' => 'positive'
        ]
    )
);

// Adding a reply to a comment
$response = $feedsClient->addComment(
    new GeneratedModels\AddCommentRequest(
        comment: 'I agree!',
        parentID: 'comment_456',
        userID: 'user123'
    )
);

// Adding a comment without triggering push notifications
$response = $feedsClient->addComment(
    new GeneratedModels\AddCommentRequest(
        comment: 'Silent comment',
        objectID: 'activity_123',
        objectType: 'activity',
        userID: 'user123',
        skipPush: true
    )
);

// Adding a comment with attachments
$response = $feedsClient->addComment(
    new GeneratedModels\AddCommentRequest(
        comment: 'Check out this image!',
        objectID: 'activity_123',
        objectType: 'activity',
        userID: 'user123',
        attachments: [
            new GeneratedModels\Attachment(
                imageUrl: 'https://example.com/image.png',
                type: 'image',
                custom: (object)[]
            )
        ]
    )
);

You can use Stream's CDN for storing and quickly accessing files attached to comments.

Comment request options

Updating Comments

updateComment endpoint performs a partial update: only the fields you include in the request are changed, and each of those fields is completely overwritten.

// Update a comment
$response = $feedsClient->updateComment(
    'comment_123',
    new GeneratedModels\UpdateCommentRequest(comment: 'Updated comment')
);
echo 'Comment edited at: ' . $response->getComment()->getEditedAt();

Removing Comments

// Delete a comment (soft delete)
$response = $feedsClient->deleteComment('comment_123', false);

Reading Comments

You'll also want to show/return these comments. The most important is when reading the feed.

// Get comments for an activity
// activity id, object type, depth, sort, replies limit, limit, prev, next
$response = $feedsClient->getComments('activity_123', 'activity', 3, 'best', 10, 10, '', '');

echo json_encode($response->getData());

// Access comments from feed response
$feedResponse = $feedsClient->feed('user', 'eric')->getOrCreateFeed(
    new GeneratedModels\GetOrCreateFeedRequest(
        userID: 'eric'
    )
);
$comments = $feedResponse->getData()->activities[0]->comments;

// Reading a single comment
$comment = $feedsClient->getComment('123');

Sort options

The following sort options are supported when reading comments:

  • last: newest comment returned first
  • first: oldest comment returned first
  • top: highest score returned first - computed from upvote - downvote reaction types
  • controversial: controversial comment returned first - mixed reactions (upvote and downvote) and lots of comments
  • best: highest Wilson score returned first - Wilson score balances reaction score (upvote - downvote) with number of reactions (a comment with lower reaction score but more sum reactions is returned before a comment with higher score, but few sum reactions)

Search for Comments

You can also query the comments, the following examples show

  • how to search across all comments by text
  • query all comments of a given user
// Search in comment texts
$response = $feedsClient->queryComments(
    new GeneratedModels\QueryCommentsRequest(
        filter: (object)['comment_text' => ['$q' => 'oat']],
        limit: 10
    )
);

// Comments of a user
$response = $feedsClient->queryComments(
    new GeneratedModels\QueryCommentsRequest(
        filter: (object)['user_id' => 'jane'],
        limit: 20
    )
);

// Query comments for an activity
$response = $feedsClient->queryComments(
    new GeneratedModels\QueryCommentsRequest(
        filter: (object)['object_id' => 'activity_123'],
        limit: 10
    )
);

Comment Queryable Built-In Fields

nametypedescriptionsupported operationsexample
idstring or list of stringsThe ID of the comment$in, $eq{ id: { $in: [ 'comment_123', 'comment_456' ] } }
user_idstring or list of stringsThe ID of the user who created the comment$in, $eq{ user_id: { $eq: 'user_123' } }
object_typestring or list of stringsThe type of object being commented on$eq, $ne, $in, $nin{ object_type: { $in: [ 'activity', 'post' ] } }
object_idstring or list of stringsThe ID of the object being commented on$in, $eq{ object_id: { $eq: 'activity_123' } }
parent_idstring or list of stringsThe parent comment ID for replies$in, $eq{ parent_id: { $eq: 'comment_parent_123' } }
comment_textstringThe text content of the comment$q{ comment_text: { $q: 'search terms' } }
reply_countnumberThe number of replies to this comment$gt, $gte, $lt, $lte{ reply_count: { $gte: 5 } }
upvote_countnumberThe number of upvotes on the comment$gt, $gte, $lt, $lte{ upvote_count: { $gte: 10 } }
downvote_countnumberThe number of downvotes on the comment$gt, $gte, $lt, $lte{ downvote_count: { $lt: 5 } }
scorenumberThe overall score of the comment$gt, $gte, $lt, $lte{ score: { $gte: 0 } }
confidence_scorenumberThe confidence score of the comment$gt, $gte, $lt, $lte{ confidence_score: { $gte: 0.5 } }
controversy_scorenumberThe controversy score of the comment$gt, $gte, $lt, $lte{ controversy_score: { $lt: 0.8 } }
created_atstring, must be formatted as an RFC3339 timestampThe time the comment was created$eq, $gt, $gte, $lt, $lte{ created_at: { $gte: '2023-12-04T09:30:20.45Z' } }
custom.<key>string, number, boolean, or JSON (as stored)Values from the comment custom object. Enterprise only.$eq, $gt, $gte, $lt, $lte, $in, $exists, $contains{ 'custom.priority': { $gte: 10 } }

Comment sort options

All fields support 1 and -1 directions.

Comment Reactions

When adding reactions and the enforce_unique flag is set to true, the existing reaction of a user will be overridden with the new reaction. Use this flag if you want to ensure users have a single reaction per each comment/activity. The default value is false, in which case users can have multiple reactions.

// Add a reaction to a comment
$response = $feedsClient->addCommentReaction(
    $response->getData()->comment->id,
    new GeneratedModels\AddCommentReactionRequest(
      type: 'like',
      userID: 'user123',
      // Optionally override existing reaction
      enforceUnique: true
    )
);

// Remove a reaction from a comment
$response = $feedsClient->deleteCommentReaction(
  $response->getData()->comment->id,
  'like',
  userID: 'user123'
);

Overview of the reaction model

Comment Threading

// Get comments for an activity with threading
// activity id, object type, depth, sort, replies limit, limit, prev, next
$response = $feedsClient->getComments('activity_123', 'activity', 3, 'best', 20, 20, '', '');

// Get replies of a specific parent comment
// parent id, depth, sort, replies limit, limit, prev, next
$response = $feedsClient->getCommentReplies('parent_123', 3, 'best', 20, 20, '', '');

Reading comment replies supports the same sort parameters as reading comments does.

Restricting comment replies

Set who can add comments

When creating an activity it's possible to set who can add comments. Possible options:

  • Everyone (this is the default setting)
  • Only people I follow
  • Nobody

The activity author is always allowed to add comments regardless of the reply settings.

$activity = new GeneratedModels\AddActivityRequest(
    type: 'post',
    feeds: ['user:1'],
    text: 'apple stock will go up',
    userID: '<user id>',
    restrictReplies: 'people_i_follow' // Options: 'everyone', 'people_i_follow', 'nobody'
);
$response = $feedsClient->addActivity($activity);

Show/hide comment input

If a user isn't allowed to add comments, it's a good idea to hide the comment input.

When everyone/nobody can comment this is straightforward. However if only people the activity author follows can comment, we have to check if there are any feeds owned by the current user that is followed by the activity author, the code snippet below shows how to check this:

const activity: ActivityResponse = /* fetch a single activity or read a feed */;

// Lists follow relationships where
// - target feed is owned by current user
// - source feed is owned by activity author
const feed = client.feed(
  activity.current_feed.group_id,
  activity.current_feed.id,
);
console.log(feed.currentState.own_followings);

own_followings is only set when reading a feed/activity from client-side, for server-side requests it will be empty.

  • When fetching a single activity, own_followings is set by default
  • When reading a feed, you have to explicitly enable fetching own_followings:
feed.getOrCreate({ enrichment_options: { enrich_own_followings: true } });

Overview of the comment model

Add comments in batch

$response = $feedsClient->addCommentsBatch(
    new GeneratedModels\AddCommentsBatchRequest(
        comments: [
            new GeneratedModels\AddCommentRequest(
                id: 'comment_123', // id is optional, but must be unique. will be auto-generated if not provided
                comment: 'So great!',
                objectID: 'activity_123',
                objectType: 'activity',
                userID: 'user123',
                custom: (object)[
                    'sentiment' => 'positive'
                ]
            ),
        ]
    )
);