The Product Reviews Component renders a list of reviews for a product. It is typically used on product detail pages, but it can also power recent‑reviews widgets, sidebar lists, or threaded review sections.
Activate the component by adding:
data-v-component-reviews
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 reviews to display | 4 |
| page | data-v-page |
Page number for pagination | 1 |
| order | data-v-order |
Sort field (review_id, user_id, created_at, updated_at) |
created_at |
| direction | data-v-direction |
Sort direction (asc, desc) |
desc |
| image size | data-v-image_size |
xlarge, large, medium, thumb |
thumb |
Filtering
| Option | Attribute | Description | Default |
|---|---|---|---|
| status | data-v-status |
Review status: 1 = published, 0 = pending, 2 = spam, 3 = trash |
1 |
| product_id | data-v-product_id |
Filter by product ID | null |
| slug | data-v-slug |
Filter by product 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 review content and product title | Current language |
| product_title | data-v-product_title |
Include product title (useful for recent‑reviews widgets) | false |
Component Properties
Each review is wrapped in:
data-v-review
The following fields are available inside each review element.
Author Information
| Property | Attribute | Description |
|---|---|---|
| username | data-v-review-username |
Username of the reviewer |
data-v-review-email |
Email address | |
| first_name | data-v-review-first_name |
First name |
| last_name | data-v-review-last_name |
Last name |
| display_name | data-v-review-display_name |
Display name |
| author | data-v-review-author |
Full author name |
| avatar | data-v-review-avatar |
Avatar filename |
| avatar_url | data-v-review-avatar_url |
Full avatar URL |
| bio | data-v-review-bio |
Author biography |
| subscribe | data-v-review-subscribe |
Whether the user subscribed to replies |
Review Metadata
| Property | Attribute | Description |
|---|---|---|
| review_id | data-v-review-review_id |
Unique review ID |
| product_id | data-v-review-product_id |
ID of the product the review belongs to |
| user_id | data-v-review-user_id |
ID of the user who producted the review |
| url | data-v-review-url |
Author’s website URL |
| ip | data-v-review-ip |
IP address (if stored) |
| status | data-v-review-status |
Review status |
| rating | data-v-review-rating |
Rating 1 to 5 |
| type | data-v-review-type |
Review type (empty for standard reviews) |
| parent_id | data-v-review-parent_id |
Parent review ID (for threaded replies) |
| level | data-v-review-level |
Nesting level for threaded reviews |
| created_at | data-v-review-created_at |
Creation timestamp |
| updated_at | data-v-review-updated_at |
Last update timestamp |
Review Content
| Property | Attribute | Description |
|---|---|---|
| content | data-v-review-content |
Review text |
Product Information (Optional)
Displayed only when data-v-product_title="true" is used.
| Property | Attribute | Description |
|---|---|---|
| name | data-v-review-name |
Title of the product the review belongs to |
| slug | data-v-review-slug |
Slug of the product the review belongs to |
HTML Example
<div data-v-component-reviews data-v-product_id="url">
<ol data-v-if="count > 0">
<li data-v-review>
<div class="review-wrap">
<figure class="author-avatar me-2">
<img data-v-review-avatar_url
alt="user"
width="60"
loading="lazy"
src="/media/vvveb.svg"
data-v-if="review.avatar_url">
</figure>
<div class="review-author">
<a rel="external nofollow ugc" data-v-if="review.url">
<span data-v-review-author>John Doe<</span>
</a>
<div class="review-meta">
<span data-v-review-created_at data-filter-friendly_date>3 year ago</span>
</div>
</div>
</div>
<div data-v-review-content>This is an approved review.</div>
<div class="reply">
<a href="#review-form"
class="reply-btn"
data-v-vvveb-action="replyTo"
data-review_id
data-review_author>
Reply <i class="la la-reply"></i>
</a>
</div>
</li>
</ol>
<div class="alert" role="alert" data-v-if-not="this.default_review_status">
<div data-v-notification-text>
<span>Reviews are closed</span>
</div>
</div>
This example displays a threaded review list with avatars, author names, timestamps, content, and reply actions.
Product Review Form Component
The Review Form handles review submission on product pages. It works together with the Product Reviews Component, allowing users to submit new reviews or reply to existing ones. The form supports logged‑in users, anonymous reviewers (if enabled), CSRF protection, and threaded replies.
To use javascript to product the review without refreshing the page add the following attributes:
data-v-vvveb-action="addReview"
data-v-vvveb-on="submit"
These attributes instruct Vvveb CMS to process the form submission through javascript fetch.
How the Review Form Works
The form products 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 review in the database
- Assigns the review to the correct product
- Handles threaded replies via
parent_id - Returns success or error notifications
If reviews require moderation, the submitted review 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 review submission.
Hidden System Fields
| Field | Purpose |
|---|---|
| product_id | Identifies the product the review belongs to |
| slug | Product slug (used for redirects and validation) |
| parent_id | ID of the parent review (0 for top‑level reviews) |
| 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 reviewer |
| Yes | Email address of the reviewer |
When the user is logged in, these fields are omitted because the system already knows the user’s identity.
Review Content
| Field | Required | Description |
|---|---|---|
| content | Yes | The actual review text |
This is the main body of the review.
Replying to Reviews
The reply links in the review list use:
data-v-vvveb-action="replyTo"
This action:
- Scrolls to the review form
- Sets the hidden
parent_idfield to the ID of the review being replied to - Optionally displays the name of the user being replied to
This enables threaded/nested reviews.
Anonymous Reviews
The form includes:
data-v-if="this.global.user_id || this.anonymous_reviews"
This means:
- If the user is logged in → show the form
- If the user is not logged in but anonymous reviews are allowed → show the form
- Otherwise → hide the form
Anonymous review settings are controlled in the site configuration.
Validation & Security
The review 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, reviews may not appear immediately.
HTML Example
<form id="review-form"
method="post"
action=""
data-v-vvveb-action="addReview"
data-v-vvveb-on="submit"
data-v-if="this.global.user_id || this.anonymous_reviews">
<input type="hidden" name="product_id" data-v-product-product_id>
<input type="hidden" name="slug" data-v-product-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>
<!-- Review text -->
<div class="mb-3">
<textarea name="content" rows="5" class="form-control" placeholder="Review" 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>Producting...</span>
</span>
<span class="button-text">
<span>Product review</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.