In AnQi CMS template, how to define a reusable custom function or code snippet (such as looping to render article list items)?

Behind the powerful functions of AnQi CMS, the flexible use of templates is the key to improving efficiency and ensuring website consistency.As an experienced website operations expert, I know that in our daily work, we always hope to achieve twice the results with half the effort.Today, let's delve deeply into a topic that can greatly enhance the efficiency of template development and maintenance: how to define and use reusable custom functions or code snippets in Anqi CMS templates, especially for common scenarios like looping to render article list items.

Why do we need reusable code snippets?

In the digital age, content is king, and the form of content presentation is ever-changing.A corporate website may need to display the latest news articles on the homepage, recommend popular products in the sidebar, display related article lists on specific category pages, and even embed different content modules in other corners of the website.If we rewrite the code every time we encounter a similar display requirement, it will be a huge waste of time and effort.

What is more, duplicate code brings a series of maintenance problems: any slight change in style or structure requires modification in multiple places;The code logic is inconsistent, which may lead to uneven user experience;Low development efficiency also slows down the website iteration speed. By defining reusable code snippets, we can easily achieve consistency, maintainability, improved development efficiency, and smoother update iteration.This is the practice of the 'DRY' (Don’t Repeat Yourself) principle that we often talk about in template development.

The AnQi CMS uses a syntax similar to the Django template engine, which provides a very friendly way to implement code reuse, mainly reflected ininclude/extendsandmacrothese three tags.

Core Reuse Mechanism:includewithextends

The most direct way to reuse code in Anqi CMS is to useincludeThe tag allows us to extract a fragment of HTML code (such as a header, footer, sidebar, or navigation menu) into an independent file and then simply reference it where needed.This, regardless of how many pages need these common elements, we only need to maintain the code in one place, greatly simplifying the update work.

For example, we usually extract the header (header.html) and footer (footer.html) of the website and then include them like this on each page:

{# 引入网站头部 #}
{% include "partial/header.html" %}

{# 页面主体内容 #}
<main>
    <!-- 这里是页面的具体内容 -->
</main>

{# 引入网站底部 #}
{% include "partial/footer.html" %}

If thispartial/header.htmlWe can use some dynamic data, such as the title of the current page, bywithParameter passing:

{% include "partial/header.html" with page_title="关于我们" %}

AndextendsTags provide a more macroscopic code reuse strategy, allowing us to define a "master" or "skeleton" template that other page templates can inherit. The skeleton template defines someblockThe region, sub-templates can overwrite these regions to fill their own content. It's like making a PowerPoint master, where the theme and layout are fixed, and the content can be customized as needed.

A typicalbase.htmlThe skeleton may include a header, navigation, sidebar, footer, and a namedcontentmain content area:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}默认标题 - {% system with name="SiteName" %}{% endblock %}</title>
    {# 其他公共CSS和JS文件 #}
</head>
<body>
    {% include "partial/header.html" %}
    <div class="container">
        {% block content %}
            <!-- 默认内容或为空 -->
        {% endblock %}
    </div>
    {% include "partial/footer.html" %}
</body>
</html>

Then, a specific page, such as an article list pagearticle/list.htmlcan inherit thisbase.htmlFill in your own content:

{% extends 'base.html' %}

{% block title %}文章列表 - {% system with name="SiteName" %}{% endblock %}

{% block content %}
    <div class="article-list">
        <h1>最新文章</h1>
        <!-- 这里将是文章列表的具体渲染逻辑 -->
    </div>
{% endblock %}

ByextendsWe ensure that the overall structure and common elements of all pages are consistent, while only focusing on the unique content part of each page.

Define reusable code functions:macroThe art of tags

AlthoughincludeandextendsIt provides strong reuse capabilities at the structural level, but when we face finer-grained, parameterized dynamic content rendering needs,macroTags are particularly important.macroIt can be understood as a “function” in the template, which accepts parameters and renders a specific HTML fragment based on these parameters.This is tailor-made for scenarios like looping through list items.

Imagine that we need to display the article list in different places on the website (such as the "Latest Articles" block on the homepage, the article list on the category page, and the search results page).The display format of each article may include the title, summary, publication time, thumbnail, etc., and these formats may vary slightly between different blocks or may need to be hidden for certain elements in some cases.If we were to write complex HTML structures in each list loop, it would be very long and difficult to maintain.

At this time,macroCould excel. We can define a macro specifically responsible for rendering a single article list item:

Firstly, we can define this macro in an independent template file (such as)macros/article_items.html) to define this macro:

{# macros/article_items.html #}
{% macro render_article_item(article, show_thumbnail=true, custom_class='') %}
<li class="article-item {{ custom_class }}">
    {% if show_thumbnail and article.Thumb %}
    <a href="{{ article.Link }}" class="article-thumb">
        <img src="{{ article.Thumb }}" alt="{{ article.Title }}">
    </a>
    {% endif %}
    <div class="article-content">
        <h3 class="article-title"><a href="{{ article.Link }}">{{ article.Title }}</a></h3>
        <p class="article-description">{{ article.Description|truncatechars:100 }}</p>
        <div class="article-meta">
            <span>发布日期:{{ stampToDate(article.CreatedTime, "2006-01-02") }}</span>
            <span>浏览量:{{ article.Views }}</span>
        </div>
    </div>
</li>
{% endmacro %}

In this macro,render_article_itemaccepts three parameters:

  • article: The article object to be rendered, usuallyarchiveListin the loopitem.
  • show_thumbnail: A boolean value, defaulting totrue, to control whether to display the article thumbnail.
  • custom_classA string, default is empty, allowing us to add a custom CSS class to list items.

After defining the macro, we can import it first in any place where we need to render the article list, then in aarchiveListcall it in the loop.

For example, in the "Latest Articles" block on the homepage:

{# index.html 或其他需要用到宏的模板 #}
{% import "macros/article_items.html" as article_macros %}

<div class="latest-articles">
    <h2>最新文章</h2>
    <ul>
    {% archiveList archives with type="list" moduleId="1" limit="5" %}
        {% for item in archives %}
            {{ article_macros.render_article_item(item, show_thumbnail=true, custom_class='latest-item') }}
        {% empty %}
            <li>暂无最新文章。</li>
        {% endfor %}
    {% endarchiveList %}
    </ul>
</div>

And in the "Hot Recommendations" sidebar, we may not want to display thumbnails and use a different style:

<div class="hot-recommendations">
    <h3>热门推荐</h3>
    <ul>
    {% archiveList hot_articles with type="list" moduleId="1" flag="c" order="views desc" limit="3" %}
        {% for item in hot_articles %}
            {{ article_macros.render_article_item(item, show_thumbnail=false, custom_class='hot-item') }}
        {% empty %}
            <li>暂无热门推荐。</li>
        {% endfor %}
    {% endarchiveList %}
    </ul>
</div>

As can be seen, by:macroWe successfully encapsulated the complex list item rendering logic and can flexibly control its display behavior through parameters.This not only makes the template code more tidy, but also makes it easy to modify or extend the display style of the article list.

Flexible variables and data transmission:withandset

In usinginclude/extends