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
email 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
email 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_id field 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.