commentThreads
This component fetches a threaded list of Comments (and star ratings) assigned to a given module item along with the Comment submission form and author edit links for logged-in members.
{% component type: "commentThreads", moduleItemId:"1234" %}
Parameters and Options
commentThreads
This is the name of the entity that needs to be used for the component retrieving function.
<ItemID>
<path/to/layout>
If an empty string, nothing will be rendered.
If paramater is not included, the default virtual layout will be rendered (see below).
If using your own custom layout here you must also specify a custom layout for the below comment layout.
<path/to/layout>
If an empty string or if the paramater is not included, the default virtual layout will be rendered (see below).
If using your own custom layout here you must also specify a custom layout for the above container layout.
<path/to/layout>
If an empty string or if the paramater is not included, the default virtual layout will be rendered (see below).
If using your own custom layout here you must also specify a custom layout for the above container layout.
10 (default)
<integer>
limit
is less than the total number of items, pagination will be displayed in the form of a 'SHOW MORE' link with the next number of items loaded to the list via AJAX.10 (default)
<integer>
commentLimit
is less than the total number of threaded items, pagination will be displayed for that thread in the form of a 'SHOW MORE' link with the next number of threaded items loaded to the thread via AJAX.collection (default)
collection
.<yourLiquidVariableName>
Your collectionVariable value must only contain English letters, numbers or underscores. Spaces or special characters are not supported.
Liquid Output
The below example has 2 top-level sample items
(with additional threaded/sub-level items) but is otherwise the default structure you will get from this Component.
{
"ModuleItemId": 2280,
"ThreadLayout": "cms-assets/layouts/comment_threads/thread_default.layout",
"CommentLayout": "cms-assets/layouts/comment_threads/comment_default.layout",
"Pagination": {
"CurrentPage": 1,
"ItemsPerPage": 10,
"NumberOfPages": 1,
"TotalItemsCount": 2
},
"Items": [
{
"ModuleItemId": 2280,
"ParentId": null,
"ThreadId": 113918,
"Rating": 100,
"Body": "Love the writing style. Keep it up.",
"DateAdded": "2024-01-12T23:19:41.075521",
"AuthorId": 1442,
"AuthorFirstName": "Alex",
"AuthorLastName": "Smith",
"AuthorEmail": "alextest@test.com",
"AuthorIsAdmin": false,
"Author": {
"Id": 1442,
"FirstName": "Alex",
"LastName": "Smith",
"Email": "alextest@test.com",
"IsAdmin": false
},
"Id": 113918,
"Items": [
{
"ModuleItemId": 2280,
"ParentId": 113919,
"ThreadId": 113918,
"Rating": 0,
"Body": "You're welcome :)",
"DateAdded": "2024-01-12T23:21:29.73719",
"AuthorId": 1442,
"AuthorFirstName": "Alex",
"AuthorLastName": "Smith",
"AuthorEmail": "alextest@test.com",
"AuthorIsAdmin": false,
"Author": {
"Id": 1442,
"FirstName": "Alex",
"LastName": "Smith",
"Email": "alextest@test.com",
"IsAdmin": false
},
"Id": "113920"
},
{
"ModuleItemId": 2280,
"ParentId": 113918,
"ThreadId": 113918,
"Rating": 0,
"Body": "Thank you for the nice words of encouragement.",
"DateAdded": "2024-01-12T23:20:43.6798",
"AuthorId": 1366,
"AuthorFirstName": "Admin Name",
"AuthorLastName": null,
"AuthorEmail": "admin@test.com",
"AuthorIsAdmin": true,
"Author": {
"Id": 1366,
"FirstName": "Admin Name",
"LastName": null,
"Email": "admin@test.com",
"IsAdmin": true
},
"Id": "113919"
}
],
"TotalItemsCount": 2
},
{
"ModuleItemId": 2280,
"ParentId": null,
"ThreadId": 113916,
"Rating": 80,
"Body": "Great post! Thanks for writing it.",
"DateAdded": "2024-01-12T23:17:29.720378",
"AuthorId": 1430,
"AuthorFirstName": "Joe",
"AuthorLastName": "Test",
"AuthorEmail": "joetest@test.com",
"AuthorIsAdmin": false,
"Author": {
"Id": 1430,
"FirstName": "Joe",
"LastName": "Test",
"Email": "joetest@test.com",
"IsAdmin": false
},
"Id": 113916,
"Items": [],
"TotalItemsCount": 0
}
],
"Params": {
"moduleitemid": "2280",
"limit": "10",
"layout": "",
"type": "commentThreads",
"collectionvariable": "commentsData"
}
}
Virtual Layout
Based on the above example, if not using any custom layout or collection, the default virtual layout will output with the overall container logic with an include layout for the threaded comments list, which in turn renders the individual comments list, eg:
Container Layout
<div class="cms_style_holder">
<div class="cms_container">
<div class="cms_comments cmsCommentsHolder">
<div class="comment-list">
<div class="cms_add_comment_form">
{% if request.is_logged %}
<form class="cmsCreateThreadForm cms_comments-form" action="/public/api/comment/{{this.moduleItemId}}?layout={{this.ThreadLayout}}&threadLayout={{this.ThreadLayout}}&commentLayout={{this.commentLayout}}">
<div class="cms_add_comment_form__top">
<h3 class="cms_add_comment_form__heading">Add a Comment</h3>
<div class="cms_star cms_star__holder cms_star__holder--right">
<label for="r1" class="cms_star__title">Rating</label>
<div class="cms_star__rating">
<input type="radio" value="100" name="rating" id="r5">
<label for="r5"></label>
<input type="radio" value="80" name="rating" id="r4">
<label for="r4"></label>
<input type="radio" value="60" name="rating" id="r3">
<label for="r3"></label>
<input type="radio" value="40" name="rating" id="r2">
<label for="r2"></label>
<input type="radio" value="20" name="rating" id="r1">
<label for="r1"></label>
</div>
</div>
</div>
<div class="cms_comments-form__body">
<textarea name="postComment" placeholder="Comment" class="cms_comments-form__textarea"></textarea>
<input type="submit" class="system_button" value="Post"/>
</div>
</form>
{% endif %}
</div>
<hr>
<div class="cmsCommentsThreadsHolder">
{% if this.Items.size > 0 %}
{% include "/{{this.threadLayout}}" %}
{% else %}
<p class="cmsNoCommentsMessage">No comments yet</p>
{% endif %}
</div>
{% if this.Pagination.CurrentPage < this.Pagination.NumberOfPages %}
<a href="/public/api/comment/load-more/{{this.moduleItemId}}" data-current_page="{{ this.Pagination.CurrentPage }}" data-total_items_count="{{ this.Pagination.TotalItemsCount }}" data-page="2" data-limit="{{this.params.limit}}" data-thread_layout="{{ this.ThreadLayout }}" data-comment_layout="{{ this.commentlayout }}" data-comment_limit="{{this.params.commentlimit}}" class="cms_comment__button cms_comment__button cms_comment__button--indent cmsLoadMoreThreadButton">
<svg width="14" height="14" aria-hidden="true" focusable="false" data-prefix="fas"
data-icon="caret-down" class="svg-inline--fa fa-caret-down fa-w-10" role="img"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
<path fill="currentColor"
d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"></path>
</svg>
SHOW MORE</a>
{% endif %}
</div>
</div>
</div>
</div>
Threaded Comment Layout
{% for thread in this.items %}
<div class="cms_comment cmsThreadHolder">
<div class="cmsCommentHolder">
<div class="cms_comment__top">
<div class="cms_comment__title">
<h3 class="cms_comment__user">{{ thread.AuthorFirstName }} {{ thread.AuthorLastName }}</h3>
<time class="cms_comment__date" datetime="2020-02-04">{{ thread.DateAdded | date: '%B %d, %Y at %l:%M %P' }}</time>
</div>
<div class="cms_star cms_star__holder cms_star__holder--right" >
<label for="comment-r1" class="cms_star__title">Rating</label>
<div class="cms_star__rating cms_star__rating--onlyread">
<input type="radio" value="100" name="rating-{{thread.Id}}" id="comment-r5-{{thread.Id}}" {% if thread.Rating == 100 %} checked {% endif %} >
<label for="comment-r5-{{thread.Id}}"></label>
<input type="radio" value="80" name="rating-{{thread.Id}}" id="comment-r4-{{thread.Id}}" {% if thread.Rating == 80 %} checked {% endif %} >
<label for="comment-r4-{{thread.Id}}"></label>
<input type="radio" value="60" name="rating-{{thread.Id}}" id="comment-r3-{{thread.Id}}" {% if thread.Rating == 60 %} checked {% endif %} >
<label for="comment-r3-{{thread.Id}}"></label>
<input type="radio" value="40" name="rating-{{thread.Id}}" id="comment-r2-{{thread.Id}}" {% if thread.Rating == 40 %} checked {% endif %} >
<label for="comment-r2-{{thread.Id}}"></label>
<input type="radio" value="20" name="rating-{{thread.Id}}" id="comment-r1-{{thread.Id}}" {% if thread.Rating == 20 %} checked {% endif %} >
<label for="comment-r1-{{thread.Id}}"></label>
</div>
</div>
</div>
<div class="cms_comment__content">
<p> {{ thread.body | replace: "\n", "<br>" }}</p>
</div>
<div class="cms_comment__bottom">
<div class="cms_comment__buttons">
{% if request.is_logged == true %}
<a href="javascript:" class="cms_comment__button cms_comment__button--indent cmsOpenReplyCommentFormButton">
<svg width="12" heright="12" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="reply" class="svg-inline--fa fa-reply fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path fill="currentColor" d="M8.309 189.836L184.313 37.851C199.719 24.546 224 35.347 224 56.015v80.053c160.629 1.839 288 34.032 288 186.258 0 61.441-39.581 122.309-83.333 154.132-13.653 9.931-33.111-2.533-28.077-18.631 45.344-145.012-21.507-183.51-176.59-185.742V360c0 20.7-24.3 31.453-39.687 18.164l-176.004-152c-11.071-9.562-11.086-26.753 0-36.328z"></path>
</svg>
REPLY</a>
{% endif %}
</div>
{% if thread.Author.Id == request.currentmember.id %}
<div class="cms_comment__buttons">
<a href="javascript:" class="cms_comment__button cms_comment__button--light cmsOpenEditCommentFormButton">Edit</a>
<a href="/public/api/comment/delete/{{thread.id}}" class="cms_comment__button cms_comment__button--light cmsDeleteThreadButton">Delete</a>
</div>
{% endif %}
</div>
{% if thread.Author.Id == request.currentmember.id %}
<div class="cms_comment__form cmsEditCommentFormHolder" style="display: none;">
<form class="cmsEditCommentForm" action="/public/api/comment/{{ thread.Id }}?layout={{this.ThreadLayout}}&threadLayout={{this.ThreadLayout}}&commentLayout={{this.commentLayout}}">
<textarea name="postComment" id="" cols="30" rows="10" class="cms_comment__textarea">{{ thread.body }}</textarea>
<input type="submit" value="Save" class="system_button">
</form>
</div>
{% endif %}
<div class="cms_comment__form cmsReplyCommentFormHolder" style="display: none;">
<form class="cmsReplyCommentForm" action="/public/api/comment/{{this.moduleItemId}}/{{thread.id}}?layout={{this.commentlayout}}&threadLayout={{this.ThreadLayout}}&commentLayout={{this.commentLayout}}" method="post">
<textarea name="postComment" id="" cols="30" rows="10" class="cms_comment__textarea"></textarea>
<input type="submit" value="Post" class="system_button" />
</form>
</div>
</div>
<div class="cms_subcomments cmsSubCommentsHolder">
{% assign realthis = this %}
{% assign this = thread %}
{% include "/{{realthis.CommentLayout}}", layout: realthis.commentlayout %}
{% assign this = realthis %}
</div>
{% assign commentlimit = this.params.commentlimit | plus: 0 %}
{% if commentlimit < thread.TotalItemsCount %}
<a href="/public/api/comment/thread/load-more/{{this.moduleItemId}}/{{thread.id}}" data-current_page="1" data-total_items_count="{{ thread.TotalItemsCount }}" data-page="2" data-limit="{{this.params.commentLimit}}" data-layout="{{ this.commentlayout }}" class="cms_comment__button cms_comment__button cms_comment__button--indent cmsLoadMoreCommentsButton">
<svg width="14" height="14" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="caret-down" class="svg-inline--fa fa-caret-down fa-w-10" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
<path fill="currentColor" d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"></path>
</svg>
SHOW MORE</a>
{% endif %}
</div>
{% endfor %}
Comment Layout
{% for comment in this.items %}
<div class="cms_comment cmsCommentHolder">
<div class="cms_comment__top">
<div class="cms_comment__title">
<h3 class="cms_comment__user">{{ comment.AuthorFirstName }} {{ comment.AuthorLastName }}</h3>
<time class="cms_comment__date" datetime="2020-02-04">{{ comment.DateAdded | date: '%B %d, %Y at %l:%M %P' }}</time>
</div>
</div>
<div class="cms_comment__content">
<p> {{ comment.body | replace: "\n", "<br>" }}</p>
</div>
<div class="cms_comment__bottom">
<div class="cms_comment__buttons">
{% if request.is_logged %}
<a href="javascript:" class="cms_comment__button cms_comment__button--indent cmsOpenReplyCommentFormButton">
<svg width="12" heright="12" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="reply" class="svg-inline--fa fa-reply fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path fill="currentColor" d="M8.309 189.836L184.313 37.851C199.719 24.546 224 35.347 224 56.015v80.053c160.629 1.839 288 34.032 288 186.258 0 61.441-39.581 122.309-83.333 154.132-13.653 9.931-33.111-2.533-28.077-18.631 45.344-145.012-21.507-183.51-176.59-185.742V360c0 20.7-24.3 31.453-39.687 18.164l-176.004-152c-11.071-9.562-11.086-26.753 0-36.328z"></path>
</svg>
REPLY</a>
{% endif %}
</div>
{% if comment.Author.Id == request.currentmember.id %}
<div class="cms_comment__buttons">
<a href="javascript:" class="cms_comment__button cms_comment__button--light cmsOpenEditCommentFormButton">Edit</a>
<a href="/public/api/comment/delete/{{ comment.Id }}" class="cms_comment__button cms_comment__button--light cmsDeleteCommentButton">Delete</a>
</div>
{% endif %}
</div>
{% if comment.Author.Id == request.currentmember.id %}
<div class="cms_comment__form cmsEditCommentFormHolder" style="display: none;">
<form class="cmsEditCommentForm" action="/public/api/comment/{{comment.id}}?layout={{this.layout | default: layout}}&threadLayout={{this.layout | default: layout}}&commentLayout={{this.layout | default: layout}}">
<textarea name="postComment" id="" cols="30" rows="10" class="cms_comment__textarea">{{ comment.body }}</textarea>
<input type="submit" value="Save" class="system_button">
</form>
</div>
{% endif %}
<div class="cms_comment__form cmsReplyCommentFormHolder" style="display: none;">
<form class="cmsReplyCommentForm" action="/public/api/comment/{{comment.moduleItemId}}/{{comment.id}}?layout={{this.layout | default: layout}}&threadLayout={{this.layout | default: layout}}&commentLayout={{this.layout | default: layout}}" method="post">
<textarea name="postComment" id="" cols="30" rows="10" class="cms_comment__textarea"></textarea>
<input type="submit" value="Post" class="system_button" />
</form>
</div>
</div>
{% endfor %}
Rendering the threaded list:
Accessing the Data
JSON Output
You can output the full JSON for your component data by referencing the root Liquid object {{this}}
in your module’s layouts, or directly on your page, if using the collectionVariable
parameter in your component tag.
For example:
{% component type: ... collectionVariable: "myData" %}
You can then render the JSON like so:
{{myData}}
For more details on using this approach, see Part 2 of the free ‘Learning Liquid Course’.
Rendering Property Values
This data is also accessible directly on the Page or Template via a Liquid Collection by adding collectionVariable
to the Component.
An example using collectionVariable
with value "commentsData":
{% component moduleItemId: "2280", type: "commentThreads", collectionVariable: "commentsData" %}
Accessing a specific item within the collection. In this case the second item (zero based index), which in our example would render the value Great post! Thanks for writing it.
{{commentsData.items[1]['Body']}}
Related Articles
- Liquid Objects & Usage
{{ member }} object
This liquid object will output the Member's details of whom submitted a Form. You can... - Content Modules
Secure Zones
Secure Zones provide a way of creating restricted content on your website that only registered Secure Zone Members are able to access after successfully logging in. - Content Modules
Comments
Allow logged-in users to post comments and ratings against items and/or respond to other user’s comments. - Liquid Components
member_update_form
This component renders a contact update form for a specified CRM contact so that a CRM Admin role, who is logged in to the front-end, can update the specified contact’s CRM info or secure zone subscriptions. - Liquid Components
comments
This component fetches a single list of Comments (and star ratings) assigned to a given module item along with the Comment submission form and author edit links for logged-in members. - Liquid Components
favorites
The Favorites functionality allows logged-in users to save an item reference (from any module) to their account and render those items on a page for them to refer back to as needed. - Liquid Components
frontend_API
External Resources
There are currently no external resources available.
Please let us know if you have any other contributions or know of any helpful resources you'd like to see added here.
Questions?
We are always happy to help with any questions you may have.
Visit the Treepl Forum for community support and to search previously asked questions or send us a message at support@webinone.com and we will consult you as soon as possible.
Alex Smith
Love the writing style. Keep it up.
Alex Smith
You're welcome :)
Adam Wilson
Thank you for the nice words of encouragement.
Joe Test
Great post! Thanks for writing it.