The Post Comments Component renders a list of comments for a post. It is typically used on post detail pages, but it can also power recent‑comments widgets, sidebar lists, or threaded comment sections.
Activate the component by adding:
data-v-component-comments
The component supports filtering, sorting, pagination, and nested replies.
Component Options
Options are added as HTML attributes using the data-v-* syntax.
Pagination & Sorting
| Option | Attribute | Description | Default |
|---|---|---|---|
| start | data-v-start |
Starting offset for pagination | 0 |
| limit | data-v-limit |
Number of comments to display | 4 |
| page | data-v-page |
Page number for pagination | 1 |
| order | data-v-order |
Sort field (comment_id, user_id, created_at, updated_at) |
created_at |
| direction | data-v-direction |
Sort direction (asc, desc) |
desc |
Filtering
| Option | Attribute | Description | Default |
|---|---|---|---|
| status | data-v-status |
Comment status: 1 = published, 0 = pending, 2 = spam, 3 = trash |
1 |
| post_id | data-v-post_id |
Filter by post ID | null |
| slug | data-v-slug |
Filter by post slug | null |
| user_id | data-v-user_id |
Filter by user ID | null |
Additional Options
| Option | Attribute | Description | Default |
|---|---|---|---|
| language_id | data-v-language_id |
Language for comment content and post title | Current language |
| post_title | data-v-post_title |
Include post title (useful for recent‑comments widgets) | false |
Component Properties
Each comment is wrapped in:
data-v-comment
The following fields are available inside each comment element.
Author Information
| Property | Attribute | Description |
|---|---|---|
| username | data-v-comment-username |
Username of the commenter |
data-v-comment-email |
Email address | |
| first_name | data-v-comment-first_name |
First name |
| last_name | data-v-comment-last_name |
Last name |
| display_name | data-v-comment-display_name |
Display name |
| author | data-v-comment-author |
Full author name |
| avatar | data-v-comment-avatar |
Avatar filename |
| avatar_url | data-v-comment-avatar_url |
Full avatar URL |
| bio | data-v-comment-bio |
Author biography |
| subscribe | data-v-comment-subscribe |
Whether the user subscribed to replies |
Comment Metadata
| Property | Attribute | Description |
|---|---|---|
| comment_id | data-v-comment-comment_id |
Unique comment ID |
| post_id | data-v-comment-post_id |
ID of the post the comment belongs to |
| user_id | data-v-comment-user_id |
ID of the user who posted the comment |
| url | data-v-comment-url |
Author’s website URL |
| ip | data-v-comment-ip |
IP address (if stored) |
| status | data-v-comment-status |
Comment status |
| votes | data-v-comment-votes |
Upvotes/downvotes |
| type | data-v-comment-type |
Comment type (empty for standard comments) |
| parent_id | data-v-comment-parent_id |
Parent comment ID (for threaded replies) |
| level | data-v-comment-level |
Nesting level for threaded comments |
| created_at | data-v-comment-created_at |
Creation timestamp |
| updated_at | data-v-comment-updated_at |
Last update timestamp |
Comment Content
| Property | Attribute | Description |
|---|---|---|
| content | data-v-comment-content |
Comment text |
Post Information (Optional)
Displayed only when data-v-post_title="true" is used.
| Property | Attribute | Description |
|---|---|---|
| name | data-v-comment-name |
Title of the post the comment belongs to |
| slug | data-v-comment-slug |
Slug of the post the comment belongs to |
HTML Example
<div data-v-component-comments data-v-post_id="url">
<ol data-v-if="count > 0">
<li data-v-comment>
<div class="comment-wrap">
<figure class="author-avatar me-2">
<img data-v-comment-avatar_url
alt="user"
width="60"
loading="lazy"
src="/media/vvveb.svg"
data-v-if="comment.avatar_url">
</figure>
<div class="comment-author">
<a rel="external nofollow ugc" data-v-if="comment.url">
<span data-v-comment-author>John Doe<</span>
</a>
<div class="comment-meta">
<span data-v-comment-created_at data-filter-friendly_date>3 year ago</span>
</div>
</div>
</div>
<div data-v-comment-content>This is an approved comment.</div>
<div class="reply">
<a href="#comment-form"
class="reply-btn"
data-v-vvveb-action="replyTo"
data-comment_id
data-comment_author>
Reply <i class="la la-reply"></i>
</a>
</div>
</li>
</ol>
<div class="alert" role="alert" data-v-if-not="this.default_comment_status">
<div data-v-notification-text>
<span>Comments are closed</span>
</div>
</div>
This example displays a threaded comment list with avatars, author names, timestamps, content, and reply actions.
Post Comment Form Component
The Comment Form handles comment submission on post pages. It works together with the Post Comments Component, allowing users to submit new comments or reply to existing ones. The form supports logged‑in users, anonymous commenters (if enabled), CSRF protection, and threaded replies.
To use javascript to post the comment without refreshing the page add the following attributes:
data-v-vvveb-action="addComment"
data-v-vvveb-on="submit"
These attributes instruct Vvveb CMS to process the form submission through javascript fetch.
How the Comment Form Works
The form posts data to the current page and is intercepted by the Vvveb action handler. The handler:
- Validates required fields
- Checks CSRF token
- Determines whether the user is logged in or anonymous
- Creates a new comment in the database
- Assigns the comment to the correct post
- Handles threaded replies via
parent_id - Returns success or error notifications
If comments require moderation, the submitted comment may be stored with status = 0 (pending).
Form Fields
The form includes a mix of visible and hidden fields. These fields are required for proper comment submission.
Hidden System Fields
| Field | Purpose |
|---|---|
| post_id | Identifies the post the comment belongs to |
| slug | Post slug (used for redirects and validation) |
| parent_id | ID of the parent comment (0 for top‑level comments) |
| csrf | CSRF token for security |
| firstname-empty | Honeypot anti‑spam field (must remain empty) |
| subject-empty | Honeypot anti‑spam field |
| lastname-empty | Honeypot anti‑spam field |
Honeypot fields help block bots without affecting real users.
User Identity Fields
These fields are shown only when the user is not logged in:
| Field | Required | Description |
|---|---|---|
| author | Yes | Name of the commenter |
| Yes | Email address of the commenter |
When the user is logged in, these fields are omitted because the system already knows the user’s identity.
Comment Content
| Field | Required | Description |
|---|---|---|
| content | Yes | The actual comment text |
This is the main body of the comment.
Replying to Comments
The reply links in the comment list use:
data-v-vvveb-action="replyTo"
This action:
- Scrolls to the comment form
- Sets the hidden
parent_idfield to the ID of the comment being replied to - Optionally displays the name of the user being replied to
This enables threaded/nested comments.
Anonymous Comments
The form includes:
data-v-if="this.global.user_id || this.anonymous_comments"
This means:
- If the user is logged in → show the form
- If the user is not logged in but anonymous comments are allowed → show the form
- Otherwise → hide the form
Anonymous comment settings are controlled in the site configuration.
Validation & Security
The comment form includes several built‑in protections:
- CSRF token (
data-v-csrf) - Honeypot fields (
firstname-empty,subject-empty,lastname-empty) - Server‑side validation of required fields
- Status filtering (pending, spam, trash)
If moderation is enabled, comments may not appear immediately.
HTML Example
<form id="comment-form"
method="post"
action=""
data-v-vvveb-action="addComment"
data-v-vvveb-on="submit"
data-v-if="this.global.user_id || this.anonymous_comments">
<input type="hidden" name="post_id" data-v-post-post_id>
<input type="hidden" name="slug" data-v-post-slug>
<input type="hidden" name="parent_id" value="0">
<input type="hidden" name="csrf" data-v-csrf>
<!-- Honeypot anti-spam fields -->
<input type="hidden" name="firstname-empty">
<input type="text" class="visually-hidden" name="lastname-empty" tabindex="-1">
<input type="text" class="d-none" name="subject-empty">
<!-- Anonymous user fields -->
<div data-v-if-not="this.global.user_id">
<div class="mb-3">
<label class="form-label">Name</label>
<input type="text" name="author" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">Email address</label>
<input type="email" name="email" class="form-control" required>
</div>
</div>
<!-- Comment text -->
<div class="mb-3">
<textarea name="content" rows="5" class="form-control" placeholder="Comment" required></textarea>
</div>
<!-- Submit -->
<button type="submit" class="btn btn-primary btn-submit">
<span class="loading d-none">
<span class="spinner-border spinner-border-sm"></span>
<span>Posting...</span>
</span>
<span class="button-text">
<span>Post comment</span>
<i class="la la-long-arrow-alt-right ms-1"></i>
</span>
</button>
</form>
This example includes all required fields, anonymous user handling, CSRF protection, and reply support.