As an expert in the operation of Anqi CMS website content, I am well aware of the readers' demand for interactivity and information transparency.The comment feature is an important way for users to participate in website content construction and express their opinions, and multi-level replies can effectively promote in-depth communication between users.AnQi CMS provides us with a powerful and flexible comment management mechanism, making it efficient and convenient to obtain and display comment lists, including multi-level replies.

In Anqi CMS, retrieving and displaying the website's comment list mainly relies on its powerful template tag system, especiallycommentListThe tag allows us to filter, sort, and display comment data according to different needs, and naturally supports the structure of multi-level replies, greatly simplifying the development work.

Get comment data

To display the comment list, we first need to usecommentListTag to retrieve comment data.This tag is usually used on the document detail page because it needs to be associated with a specific article or product.It accepts multiple parameters to precisely control the range and display of the comments.

first, archiveIdThe parameter is mandatory, it specifies which document (article or product) we want to retrieve comments for. For example, if the current page is a document detail page, we can access it by{% archiveDetail with name="Id" %}Dynamically obtain the ID of the current document and use it asarchiveIdthe value.

secondly,typeThe parameter determines the display type of the comment list. When we want to display all comments at once, or need to customize pagination logic, we can usetype="list". If we need to use the CMS built-in pagination function to manage a large number of comments, then we shouldtypeis set to"page".

limitParameters are used to control the number of comments retrieved each time. This is very useful when displaying "Latest Comments" or limiting the number of comments per page. For example,limit="10"It will display 10 comments. If we need to start fetching from a certain offset, we can also use a comma-separated format, such aslimit="2,10"It means fetching 10 comments starting from the 3rd comment.

Furthermore,orderParameters allow us to define the sorting method for comments, for exampleorder="id desc"Comments can be sorted in descending order by comment ID (usually meaning the most recent comments are at the top),order="id asc"The items are sorted in ascending order by ID. For operators with multiple sites,siteIdThe parameter can be used to specify the comment data of a specific site, but it is generally not necessary to fill in if there is no need to call across sites.

All passcommentListThe comment data obtained by the tag will be assigned to the variable name we specify in the form of an array object. For example, if we use{% commentList comments with archiveId=archive.Id type="list" limit="6" %}thencommentsThe variable will contain an array of comment objects, we can iterate through and display these comments.forTo display the comment list with multi-level replies.

Displaying the comment list with multi-level replies.

After obtaining the comment data, we can use it in the templateforto loop throughcommentsthe variable and display each comment. Each comment object contains a series of fields such asId(Comment ID),UserName(commenter username),Content(comment content),CreatedTime(comment time) etc.

An important consideration when displaying comment content is the comment's review status.StatusThe field indicates whether the comment has passed the review. Usually, we only displayStatusThe comment for review 1 (approved).For comments under review, we can choose to display a prompt message or truncate the content to protect user privacy and avoid displaying inappropriate material.

Implementing multi-level replies is the core highlight of the comment feature. In the Anqi CMS comment data structure, each comment object contains aParentField. If the current comment is a reply to another comment, thenParentthe field will contain the full data of the replied comment (including itsUserName/Contentetc.). We can judge byitem.ParentWhether it exists to determine whether the current comment is a reply.

Whenitem.ParentIf it exists, we can nest the content of the replied comment in the template, usually in a quotation block (<blockquote>Presented in the form of ) to clearly distinguish the relationship between replies. At the same time, we also need to processParentthe comments.StatusCheck to ensure that only approved parent comments are displayed. This design makes the comment hierarchy clear, allowing users to easily track the conversation context.

This is an example of a template code for displaying regular comments and multi-level replies.

{# 假设我们已经在文档详情页获取了当前文档的ID,并赋值给 archive.Id #}
<div class="comment-section">
    <h3>用户评论</h3>
    {% commentList comments with archiveId=archive.Id type="list" limit="6" %}
        {% for item in comments %}
            <div class="comment-item">
                <div class="comment-header">
                    <span class="comment-user">
                        {% if item.Status != 1 %}
                            审核中:{{item.UserName|truncatechars:6}}
                        {% else %}
                            {{item.UserName}}
                        {% endif %}
                    </span>
                    {% if item.Parent %}
                        <span class="comment-reply-indicator">回复</span>
                        <span class="comment-parent-user">
                            {% if item.Parent.Status != 1 %}
                                审核中:{{item.Parent.UserName|truncatechars:6}}
                            {% else %}
                                {{item.Parent.UserName}}
                            {% endif %}
                        </span>
                    {% endif %}
                    <span class="comment-time">{{stampToDate(item.CreatedTime, "2006-01-02 15:04")}}</span>
                </div>
                <div class="comment-content">
                    {% if item.Parent %}
                        <blockquote class="comment-quote">
                            {% if item.Parent.Status != 1 %}
                                该父评论正在审核中:{{item.Parent.Content|truncatechars:9}}
                            {% else %}
                                {{item.Parent.Content|truncatechars:100}}
                            {% endif %}
                        </blockquote>
                    {% endif %}
                    {% if item.Status != 1 %}
                        该评论正在审核中:{{item.Content|truncatechars:9}}
                    {% else %}
                        {{item.Content}}
                    {% endif %}
                </div>
                <div class="comment-actions" data-id="{{item.Id}}" data-user="{{item.UserName}}">
                    <a class="action-item comment-praise" data-id="praise">赞(<span class="vote-count">{{item.VoteCount}}</span>)</a>
                    <a class="action-item comment-reply" data-id="reply">回复</a>
                </div>
            </div>
        {% empty %}
            <p>暂无评论,快来发表您的看法吧!</p>
        {% endfor %}
    {% endcommentList %}
</div>

Comments list pagination display.

When the number of comments is high, pagination can improve page loading speed and user experience. By using the built-in pagination function of Anqi CMS, subsequentcommentListoftypethe parameter to"page", we can combine withpaginationTags, you can generate a complete comment pagination navigation.paginationThe tag provides rich data such as total number of items, total pages, current page, first page, last page, previous page, next page, and middle page numbers, allowing us to flexibly construct pagination links.

{# 假设 comments 变量已通过 type="page" 获取评论数据 #}
<div class="comment-pagination">
    {% pagination pages with show="5" %}
        <ul>
            <li class="page-info">总计:{{pages.TotalItems}}条评论,共{{pages.TotalPages}}页,当前第{{pages.CurrentPage}}页</li>
            <li class="page-item {% if pages.FirstPage.IsCurrent %}active{% endif %}"><a href="{{pages.FirstPage.Link}}">首页</a></li>
            {% if pages.PrevPage %}
                <li class="page-item"><a href="{{pages.PrevPage.Link}}">上一页</a></li>
            {% endif %}
            {% for item in pages.Pages %}
                <li class="page-item {% if item.IsCurrent %}active{% endif %}"><a href="{{item.Link}}">{{item.Name}}</a></li>
            {% endfor %}
            {% if pages.NextPage %}
                <li class="page-item"><a href="{{pages.NextPage.Link}}">下一页</a></li>
            {% endif %}
            <li class="page-item {% if pages.LastPage.IsCurrent %}active{% endif %}"><a href="{{pages.LastPage.Link}}">末页</a></li>
        </ul>
    {% endpagination %}
</div>

Submit comment and reply form

Users submit comments and replies through HTML forms. The target address for submission is/comment/publish. To implement the reply feature, in addition to the regulararchive_id(document ID),user_name(Commenter name),content(Comment content) in addition, we need aparent_idfield. When a user replies to a comment, the front-end JavaScript will fill in theIdwith the comment'sparent_idin the field.

Moreover, in order to ensure the security of the comment system, integrating captcha functionality is indispensable. Anqi CMS supports throughtag-/anqiapi-other/167.htmlThe method described in the document enables captcha in the background and adds a captcha field and image to the front-end form. This can effectively prevent spam comments and malicious screen scraping.

<form method="post" action="/comment/publish" class="comment-submit-form">
    <input type="hidden" name="return" value="html"> {# 可选值:html 或 json,决定后端返回格式 #}
    <input type="hidden" name="archive_id" value="{% archiveDetail with name="Id" %}">
    <input type="hidden" name="parent_id" id="parent_comment_id" value=""> {# 用于存储回复的父评论ID #}

    <div class="form-group">
        <label for="user_name">您的昵称:</label>
        <input type="text" name="user_name" id="user_name" required placeholder="请填写您的昵称">
    </div>

    <div class="form-group" id="reply-to-info" style="display: none;">
        回复 <span id="reply-to-user"></span>:<a href="javascript:void(0);" id="cancel-reply">取消回复</a>
    </div>

    <div class="form-group">
        <label for="content">评论内容:</label>
        <textarea name="content" id="content" required placeholder="请输入您的评论内容" rows="5"></textarea>
    </div>

    <div class="form-group captcha-group">
        <input type="hidden" name="captcha_id" id="captcha_id">
        <input type="text" name="captcha" required placeholder="请填写验证码">
        <img src="" id="get-captcha" alt="验证码">
    </div>

    <div class="form-actions">
        <button type="submit">提交评论</button>
        <button type="reset">重置</button>
    </div>
</form>

<script>
    // 验证码加载逻辑 (根据 tag-/anqiapi-other/167.html 调整)
    document.getElementById('get-captcha').addEventListener("click", function () {
        fetch('/api/captcha')
            .then(response => response.json())
            .then(res => {
                document.getElementById('captcha_id').value = res.data.captcha_id;
                document.getElementById('get-captcha').src = res.data.captcha;
            }).catch(err => console.error('Error loading captcha:', err));
    });
    document.getElementById('get-captcha').click(); // 首次加载验证码

    // 回复功能逻辑
    document.querySelectorAll('.comment-reply').forEach(button => {
        button.addEventListener('click', function() {
            const commentId = this.closest('.comment-actions').dataset.id;
            const userName = this.closest('.comment-actions').dataset.user;
            document.getElementById('parent_comment_id').value = commentId;
            document.getElementById('reply-to-user').textContent = userName;
            document.getElementById('reply-to-info').style.display = 'block';
            document.getElementById('content').focus();
        });
    });

    document.getElementById('cancel-reply').addEventListener('click', function() {
        document.getElementById('parent_comment_id').value = '';
        document.getElementById('reply-to-user').textContent = '';
        document.getElementById('reply-to-info').style.display = 'none';
    });

    // 评论点赞功能 (AJAX 示例)
    document.querySelectorAll('.comment-praise').forEach(button => {
        button.addEventListener('click', function() {
            const commentId = this.closest('.comment-actions').dataset.id;
            const voteCountSpan = this.querySelector('.vote-count');
            fetch('/comment/praise', {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                body: `id=${commentId}`
            })
            .then(response => response.json())
            .then(res => {
                if (res.code === 0) {
                    alert(res.msg);
                    voteCountSpan.textContent = res.data.vote_count;
                } else {
                    alert(res.msg);
                }
            })
            .catch(err => console.error('Error praising comment:', err));
        });
    });
</script>

In template design, the template file for the comment list page is usually namedcomment/list.htmlto comply with the template conventions of AnQi CMS.This system can automatically identify and apply the template.By following these steps, we can not only obtain and display a clear structure of the comment list, including its multi-level reply relationship, but also provide a complete comment submission and interaction function, bringing a richer user participation experience to the website.

Frequently Asked Questions

  1. How to enable and manage the comment feature?The AnQi CMS is built with content comment management functionality.You can find the 'Content Comment' option under the 'Function Management' menu in the background, where you can enable or disable the comment function, set whether comments need to be reviewed, and manage published comments, including deleting, modifying, or replying to them.

  2. Why doesn't my comment list show multi-level replies?Please check your template code, make sure to iterate through the comment list when